商品配置

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

View File

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