商品配置

This commit is contained in:
zhx 2026-06-24 12:56:42 +08:00
parent cd9cbea7d6
commit 5befd6297b
2 changed files with 102 additions and 29 deletions

View File

@ -1,11 +1,6 @@
<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue';
import {
addOrUpdatePayCommodity,
listCountrytSupportAmountChannels,
} from '#/api/legacy/pay';
import {
Collapse,
CollapsePanel,
@ -13,11 +8,16 @@ import {
FormItem,
Image,
Input,
message,
Modal,
Select,
message,
} from 'antdv-next';
import {
addOrUpdatePayCommodity,
listCountrytSupportAmountChannels,
} from '#/api/legacy/pay';
import { WEB_PRODUCT_TYPE_OPTIONS } from '../pay-shared';
const props = withDefaults(
@ -60,6 +60,7 @@ const form = reactive<Record<string, any>>({
content: '',
id: '',
payCountryId: '',
payCountryIds: [],
regionId: '',
shelf: true,
type: 'GOLD',
@ -68,7 +69,27 @@ const form = reactive<Record<string, any>>({
const isUpdate = computed(() => Boolean(form.id));
const modalTitle = computed(() => (isUpdate.value ? '修改商品' : '创建商品'));
const selectedApp = computed(() => props.row?.selectApp || {});
const selectedCountry = computed(() => props.row?.country || {});
const supportCountries = computed(() => props.row?.supportCountries || []);
const countryOptions = computed(() =>
supportCountries.value.map((item: Record<string, any>) => ({
label:
item.country?.aliasName ||
item.country?.enName ||
item.country?.countryName ||
'-',
value: item.id,
})),
);
const selectedCountry = computed(() => {
const currentPayCountryId = form.payCountryId || form.payCountryIds?.[0];
const current = supportCountries.value.find(
(item: Record<string, any>) => String(item.id) === String(currentPayCountryId),
);
if (!current) {
return props.row?.country || {};
}
return toCountryMeta(current);
});
const regionName = computed(() => props.row?.regionName || '');
watch(
@ -84,6 +105,14 @@ watch(
form.content = row.content ?? '';
form.id = row.id ?? '';
form.payCountryId = row.payCountryId ?? '';
form.payCountryIds = Array.isArray(row.payCountryIds)
? [...row.payCountryIds]
: (row.payCountryId
? [row.payCountryId]
: []);
if (props.mode === 'country' && !form.payCountryId && form.payCountryIds.length > 0) {
form.payCountryId = form.payCountryIds[0];
}
form.regionId = row.regionId ?? '';
form.shelf = row.shelf ?? true;
form.type = row.type ?? 'GOLD';
@ -92,12 +121,26 @@ watch(
{ immediate: true },
);
function toCountryMeta(country: Record<string, any>) {
return {
countryName:
country.country?.aliasName ||
country.country?.enName ||
country.country?.countryName ||
'-',
currency: country.currency || '',
exchangeRate: country.usdExchangeRate || '',
icon: country.country?.nationalFlag || '',
};
}
function isPositiveNumberPointTwo(value: string) {
return /^\d+(\.\d{1,2})?$/.test(value);
}
async function loadSupportAmountChannels() {
if (props.mode !== 'country' || !form.payCountryId || !isPositiveNumberPointTwo(String(form.amountUsd || ''))) {
const currentPayCountryId = form.payCountryId || form.payCountryIds?.[0];
if (props.mode !== 'country' || !currentPayCountryId || !isPositiveNumberPointTwo(String(form.amountUsd || ''))) {
supportAmounts.value = [];
computedAmount.value = '';
amountUsdText.value = '';
@ -105,8 +148,9 @@ async function loadSupportAmountChannels() {
}
associateLoading.value = true;
try {
// .
const result = await listCountrytSupportAmountChannels(
form.payCountryId,
currentPayCountryId,
form.amountUsd,
);
supportAmounts.value = result?.channels || [];
@ -124,11 +168,20 @@ function handleAmountChange() {
void loadSupportAmountChannels();
}
function handleCountryIdsChange(value: Array<number | string>) {
form.payCountryId = value?.[0] || '';
void loadSupportAmountChannels();
}
function validateForm() {
if (props.mode === 'country' && !form.payCountryId) {
if (props.mode === 'country' && isUpdate.value && !form.payCountryId) {
message.warning('缺少支付国家');
return false;
}
if (props.mode === 'country' && !isUpdate.value && form.payCountryIds.length === 0) {
message.warning('请选择售卖国家');
return false;
}
if (props.mode === 'region' && !form.regionId) {
message.warning('缺少区域');
return false;
@ -162,13 +215,16 @@ async function handleSubmit() {
}
loading.value = true;
try {
const createCountryIds =
props.mode === 'country' && !isUpdate.value ? form.payCountryIds : undefined;
await addOrUpdatePayCommodity({
amountUsd: form.amountUsd,
applicationId: form.applicationId,
awardContent: form.awardContent,
content: form.content,
id: form.id,
payCountryId: form.payCountryId,
payCountryId: form.payCountryId || form.payCountryIds?.[0],
payCountryIds: createCountryIds,
regionId: form.regionId,
shelf: form.shelf,
type: form.type,
@ -199,7 +255,16 @@ async function handleSubmit() {
<Form layout="vertical">
<FormItem v-if="mode === 'country'" label="售卖国家">
<div class="inline-meta">
<Select
v-if="!isUpdate"
v-model:value="form.payCountryIds"
mode="multiple"
:options="countryOptions"
option-label-prop="label"
placeholder="请选择售卖国家"
@change="handleCountryIdsChange"
/>
<div v-else class="inline-meta">
<Image
v-if="selectedCountry.icon"
:preview="false"
@ -252,7 +317,7 @@ async function handleSubmit() {
<div v-else-if="supportAmounts.length === 0" class="support-empty">
暂无可展示渠道
</div>
<Collapse v-else v-model:activeKey="activeKeys">
<Collapse v-else v-model:active-key="activeKeys">
<CollapsePanel
v-for="item in supportAmounts"
:key="String(item.channel?.channelCode || '')"

View File

@ -1,14 +1,6 @@
<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue';
import { regionConfigTable } from '#/api/legacy/system';
import {
listPayOpenCountry,
pagePayCommodity,
switchShelfCommodity,
} from '#/api/legacy/pay';
import { formatDate } from '#/views/system/shared';
import {
Button,
Card,
@ -19,8 +11,15 @@ import {
Table,
} from 'antdv-next';
import { WEB_PRODUCT_TYPE_OPTIONS } from '../pay-shared';
import {
listPayOpenCountry,
pagePayCommodity,
switchShelfCommodity,
} from '#/api/legacy/pay';
import { regionConfigTable } from '#/api/legacy/system';
import { formatDate } from '#/views/system/shared';
import { WEB_PRODUCT_TYPE_OPTIONS } from '../pay-shared';
import PayCommodityEditModal from './pay-commodity-edit-modal.vue';
const props = withDefaults(
@ -185,7 +184,7 @@ function handlePageChange(page: number, pageSize: number) {
void loadData();
}
function handleApplicationChange(value: string | number) {
function handleApplicationChange(value: number | string) {
selectedApp.value =
props.appInfo?.appList?.find((item: Record<string, any>) => item.id === value) ||
{};
@ -193,7 +192,7 @@ function handleApplicationChange(value: string | number) {
void loadSupportData().then(() => loadData(true));
}
function handleDimensionChange(value: string | number) {
function handleDimensionChange(value: number | string) {
selectedDimension.value =
supportList.value.find((item) => item.id === value) || {};
if (props.mode === 'country') {
@ -218,10 +217,12 @@ function openCreate() {
amountUsd: '',
applicationId: query.applicationId,
payCountryId: query.payCountryId,
payCountryIds: props.mode === 'country' ? [query.payCountryId].filter(Boolean) : [],
regionId: query.regionId,
regionName: selectedDimension.value.regionName || '',
selectApp: selectedApp.value,
shelf: true,
supportCountries: props.mode === 'country' ? supportList.value : [],
type: query.type,
...(props.mode === 'country'
? {
@ -243,8 +244,11 @@ function openCreate() {
function openEdit(record: Record<string, any>) {
activeRow.value = {
...record,
payCountryIds:
props.mode === 'country' ? [record.payCountryId || query.payCountryId].filter(Boolean) : [],
regionName: record.regionName || selectedDimension.value.regionName || '',
selectApp: selectedApp.value,
supportCountries: props.mode === 'country' ? supportList.value : [],
...(props.mode === 'country'
? {
country: {
@ -266,20 +270,23 @@ function openEdit(record: Record<string, any>) {
<template>
<Card :title="title">
<div class="toolbar">
<Select option-label-prop="label"
<Select
option-label-prop="label"
v-model:value="query.type"
:options="productTypeOptions"
style="width: 180px"
@change="handleSearch"
/>
<Select option-label-prop="label"
<Select
option-label-prop="label"
v-model:value="query.applicationId"
:options="applicationOptions"
placeholder="应用"
style="width: 200px"
@change="handleApplicationChange"
/>
<Select option-label-prop="label"
<Select
option-label-prop="label"
v-model:value="selectedDimensionId"
:loading="supportLoading"
:options="supportOptions"
@ -287,7 +294,8 @@ function openEdit(record: Record<string, any>) {
style="width: 200px"
@change="handleDimensionChange"
/>
<Select option-label-prop="label"
<Select
option-label-prop="label"
v-model:value="query.shelf"
:options="shelfOptions"
style="width: 140px"
@ -341,7 +349,7 @@ function openEdit(record: Record<string, any>) {
:total="total"
show-size-changer
@change="handlePageChange"
@showSizeChange="handlePageChange"
@show-size-change="handlePageChange"
/>
</div>