mirror of
https://gitee.com/bootx/dax-pay-ui
synced 2026-08-11 23:25:33 +08:00
feat(admin): 收银台支付项配置优化——图标对齐渠道编码、商户去重、能力批量加载、真实图标展示
- 图标选项对齐 PayProviderEnum 7 项编码,新增/迁移 union→union_pay、aggregate→aggregate_pay - DIRECT 模式商户列表扁平去重,支付能力改用 batch API 合并该商户全部 method 组合 - 图标联动从商户选择移到支付能力选择(从 batch key 反推 provider) - 图标下拉与已选回显均显示真实 SVG(optionRender + labelRender) - 列表图标列显示 SVG 图标 + 名称 - 弹窗改为抽屉(:size=800),表单字段重排,图标必填 - 新增支付能力 29 项 i18n(zh-CN / en-US)
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
"capabilityPlaceholder": "Select capability",
|
||||
"methodFilterHint": "Used to load channel merchant candidates; not stored in DIRECT mode",
|
||||
"validationName": "Please enter name",
|
||||
"validationIcon": "Please select an icon",
|
||||
"validationResolveMode": "Please select resolve mode",
|
||||
"validationMethod": "Please select payment method",
|
||||
"validationChannelMch": "Please select channel merchant",
|
||||
@@ -39,11 +40,43 @@
|
||||
"douyin": "Douyin"
|
||||
},
|
||||
"icons": {
|
||||
"aggregate_pay": "Aggregate Pay",
|
||||
"wechat": "WeChat",
|
||||
"alipay": "Alipay",
|
||||
"union": "UnionPay",
|
||||
"douyin": "Douyin",
|
||||
"aggregate": "Aggregate"
|
||||
"union_pay": "UnionPay",
|
||||
"visa": "Visa",
|
||||
"mastercard": "Mastercard",
|
||||
"douyin": "Douyin"
|
||||
},
|
||||
"capabilities": {
|
||||
"aggregate_pay_qrcode": "Aggregate QR Code",
|
||||
"aggregate_pay_barcode": "Aggregate Barcode",
|
||||
"wechat_cashier": "WeChat Mini Cashier",
|
||||
"wechat_jsapi": "WeChat JSAPI",
|
||||
"wechat_app": "WeChat App",
|
||||
"wechat_h5": "WeChat H5",
|
||||
"wechat_qr": "WeChat QR",
|
||||
"wechat_mini": "WeChat Mini",
|
||||
"wechat_barcode": "WeChat Barcode",
|
||||
"alipay_barcode": "Alipay Barcode",
|
||||
"alipay_qr": "Alipay QR",
|
||||
"alipay_app": "Alipay App",
|
||||
"alipay_h5": "Alipay H5",
|
||||
"alipay_pc": "Alipay PC",
|
||||
"alipay_jsapi": "Alipay JSAPI",
|
||||
"alipay_mini": "Alipay Mini",
|
||||
"union_pay_qr": "UnionPay QR",
|
||||
"union_pay_barcode": "UnionPay Barcode",
|
||||
"union_pay_h5": "UnionPay H5",
|
||||
"union_pay_jsapi": "UnionPay JSAPI",
|
||||
"douyin_qr": "Douyin QR",
|
||||
"douyin_jsapi": "Douyin JSAPI",
|
||||
"douyin_h5": "Douyin H5",
|
||||
"douyin_app": "Douyin App",
|
||||
"visa_card_gateway": "Visa Gateway",
|
||||
"visa_card_present": "Visa Present",
|
||||
"mastercard_card_gateway": "Mastercard Gateway",
|
||||
"mastercard_card_present": "Mastercard Present"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"capabilityPlaceholder": "请选择支付能力",
|
||||
"methodFilterHint": "用于加载通道商户候选, 保存时不落库",
|
||||
"validationName": "请输入名称",
|
||||
"validationIcon": "请选择图标",
|
||||
"validationResolveMode": "请选择解析模式",
|
||||
"validationMethod": "请选择支付方式",
|
||||
"validationChannelMch": "请选择通道商户",
|
||||
@@ -39,11 +40,43 @@
|
||||
"douyin": "抖音"
|
||||
},
|
||||
"icons": {
|
||||
"aggregate_pay": "聚合支付",
|
||||
"wechat": "微信",
|
||||
"alipay": "支付宝",
|
||||
"union": "银联",
|
||||
"douyin": "抖音",
|
||||
"aggregate": "聚合"
|
||||
"union_pay": "银联",
|
||||
"visa": "Visa",
|
||||
"mastercard": "Mastercard",
|
||||
"douyin": "抖音"
|
||||
},
|
||||
"capabilities": {
|
||||
"aggregate_pay_qrcode": "聚合扫码",
|
||||
"aggregate_pay_barcode": "聚合付款码",
|
||||
"wechat_cashier": "微信小程序收银台",
|
||||
"wechat_jsapi": "微信 JSAPI",
|
||||
"wechat_app": "微信 APP",
|
||||
"wechat_h5": "微信 H5",
|
||||
"wechat_qr": "微信扫码",
|
||||
"wechat_mini": "微信小程序",
|
||||
"wechat_barcode": "微信付款码",
|
||||
"alipay_barcode": "支付宝付款码",
|
||||
"alipay_qr": "支付宝扫码",
|
||||
"alipay_app": "支付宝 APP",
|
||||
"alipay_h5": "支付宝 H5",
|
||||
"alipay_pc": "支付宝电脑",
|
||||
"alipay_jsapi": "支付宝 JSAPI",
|
||||
"alipay_mini": "支付宝小程序",
|
||||
"union_pay_qr": "银联扫码",
|
||||
"union_pay_barcode": "银联付款码",
|
||||
"union_pay_h5": "银联 H5",
|
||||
"union_pay_jsapi": "银联 JSAPI",
|
||||
"douyin_qr": "抖音扫码",
|
||||
"douyin_jsapi": "抖音 JSAPI",
|
||||
"douyin_h5": "抖音 H5",
|
||||
"douyin_app": "抖音 APP",
|
||||
"visa_card_gateway": "Visa 网关",
|
||||
"visa_card_present": "Visa 线下",
|
||||
"mastercard_card_gateway": "万事达网关",
|
||||
"mastercard_card_present": "万事达线下"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { normalizeRouteQueryValue, useRequiredRouteQuery } from '#/hooks/useRequiredRouteQuery';
|
||||
import { usePermission } from '#/hooks/usePermission';
|
||||
import { getProviderSvgUrl } from '#/views/payment/shared/payProviderDisplay';
|
||||
|
||||
import CashierItemEdit from './CashierItemEdit.vue';
|
||||
import {
|
||||
@@ -58,6 +59,8 @@
|
||||
const appInfo = ref<MchAppInfoResult>({});
|
||||
const tableData = ref<CashierItemResult[]>([]);
|
||||
const methodLabelMap = ref<Record<string, string>>({});
|
||||
// DIRECT 模式列表展示用:通道商户号 → 名称
|
||||
const channelMchLabelMap = ref<Record<string, string>>({});
|
||||
|
||||
// 一级 / 二级 Tab
|
||||
const activeType = ref<CashierType>(CASHIER_TYPE.H5);
|
||||
@@ -89,7 +92,12 @@
|
||||
/** 支付解析摘要 */
|
||||
function paySummary(row: CashierItemResult) {
|
||||
if (row.resolveMode === RESOLVE_MODE.DIRECT) {
|
||||
const parts = [row.channelMchNo, row.capability].filter(Boolean);
|
||||
const mchLabel = channelMchLabelMap.value[row.channelMchNo || ''] || row.channelMchNo || '';
|
||||
// 支付能力为固定枚举(PayCapabilityEnum),直接用 i18n 静态翻译
|
||||
const capLabel = row.capability
|
||||
? $t(`payment.merchant.cashier.cashier.capabilities.${row.capability}`)
|
||||
: '';
|
||||
const parts = [mchLabel, capLabel].filter(Boolean);
|
||||
return parts.join(' / ') || '-';
|
||||
}
|
||||
return methodLabelMap.value[row.method || ''] || row.method || '-';
|
||||
@@ -113,6 +121,26 @@
|
||||
methodLabelMap.value = map;
|
||||
}
|
||||
|
||||
/** 加载通道商户标签(每应用仅加载一次) */
|
||||
async function loadChannelMchLabels() {
|
||||
if (Object.keys(channelMchLabelMap.value).length > 0) {
|
||||
return;
|
||||
}
|
||||
const { data } = await PayRouteApi.listSceneChannelMchCandidatesBatch({
|
||||
appId: appId.value,
|
||||
});
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
const labelMap: Record<string, string> = {};
|
||||
for (const list of Object.values(data)) {
|
||||
for (const item of list || []) {
|
||||
labelMap[item.value] = item.label;
|
||||
}
|
||||
}
|
||||
channelMchLabelMap.value = labelMap;
|
||||
}
|
||||
|
||||
/** 加载当前桶列表 */
|
||||
async function loadList() {
|
||||
if (!appId.value) return;
|
||||
@@ -181,7 +209,7 @@
|
||||
|
||||
onMounted(async () => {
|
||||
if (!routeContext.isValid.value) return;
|
||||
await Promise.all([loadAppInfo(), loadMethodLabels()]);
|
||||
await Promise.all([loadAppInfo(), loadMethodLabels(), loadChannelMchLabels()]);
|
||||
await loadList();
|
||||
});
|
||||
</script>
|
||||
@@ -239,10 +267,18 @@
|
||||
<a-spin :spinning="loading">
|
||||
<vxe-table :data="tableData" :row-config="{ keyField: 'id' }" min-height="200">
|
||||
<vxe-column type="seq" :title="$t('common.seq')" width="60" align="center" />
|
||||
<vxe-column field="name" :title="$t('payment.merchant.cashier.cashier.name')" min-width="140" />
|
||||
<vxe-column field="icon" :title="$t('payment.merchant.cashier.cashier.icon')" width="100" align="center">
|
||||
<vxe-column field="name" :title="$t('payment.merchant.cashier.cashier.name')" min-width="70" />
|
||||
<vxe-column field="icon" :title="$t('payment.merchant.cashier.cashier.icon')" width="120" align="center">
|
||||
<template #default="{ row }">
|
||||
{{ iconLabel(row.icon) }}
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
<img
|
||||
v-if="getProviderSvgUrl(row.icon)"
|
||||
:src="getProviderSvgUrl(row.icon)"
|
||||
class="h-5 w-5 object-contain"
|
||||
:alt="row.icon"
|
||||
/>
|
||||
<span>{{ iconLabel(row.icon) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
type CashierItemResult,
|
||||
} from '#/api/payment/merchant/cashier.api';
|
||||
import { PayRouteApi } from '#/api/payment/route/pay-route.api';
|
||||
import { FormEditType } from '#/enums/formEditType';
|
||||
import { useFormEdit } from '#/hooks/useFormEdit';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { FormEditType } from '#/enums/formEditType';
|
||||
import { useFormEdit } from '#/hooks/useFormEdit';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { getProviderSvgUrl } from '#/views/payment/shared/payProviderDisplay';
|
||||
|
||||
import {
|
||||
CASHIER_ICON_OPTIONS,
|
||||
@@ -40,8 +41,10 @@
|
||||
cashierType: CASHIER_TYPE.H5,
|
||||
});
|
||||
|
||||
// DIRECT 模式用:目录 method 仅作候选过滤,不落库
|
||||
const filterMethod = ref('');
|
||||
// DIRECT 模式:通道商户扁平选项(去重)+ 商户→method 组合映射 + 能力→provider 映射(图标联动)
|
||||
const channelMchOptions = ref<LabelValue[]>([]);
|
||||
const channelMchCombosMap = ref<Record<string, Array<{ method: string; provider: string }>>>({});
|
||||
const capabilityProviderMap = ref<Record<string, string>>({});
|
||||
|
||||
const formState = ref<CashierItemParam>({
|
||||
mchNo: '',
|
||||
@@ -54,9 +57,8 @@
|
||||
});
|
||||
|
||||
const methodOptions = ref<LabelValue[]>([]);
|
||||
// method value → provider(加载通道商户用)
|
||||
// method value → provider(METHOD 模式联动图标用)
|
||||
const methodProviderMap = ref<Record<string, string>>({});
|
||||
const channelMchOptions = ref<LabelValue[]>([]);
|
||||
const capabilityOptions = ref<LabelValue[]>([]);
|
||||
|
||||
const iconOptions = computed(() =>
|
||||
@@ -69,6 +71,7 @@
|
||||
const formRules = computed(() => {
|
||||
const rules: Record<string, any[]> = {
|
||||
name: [{ required: true, message: $t('payment.merchant.cashier.cashier.validationName') }],
|
||||
icon: [{ required: true, message: $t('payment.merchant.cashier.cashier.validationIcon') }],
|
||||
resolveMode: [{ required: true, message: $t('payment.merchant.cashier.cashier.validationResolveMode') }],
|
||||
};
|
||||
if (formState.value.resolveMode === RESOLVE_MODE.METHOD) {
|
||||
@@ -100,8 +103,9 @@
|
||||
channelMchNo: undefined,
|
||||
capability: undefined,
|
||||
};
|
||||
filterMethod.value = '';
|
||||
channelMchOptions.value = [];
|
||||
channelMchCombosMap.value = {};
|
||||
capabilityProviderMap.value = {};
|
||||
capabilityOptions.value = [];
|
||||
formRef.value?.resetFields();
|
||||
}
|
||||
@@ -113,9 +117,9 @@
|
||||
const providerMap: Record<string, string> = {};
|
||||
for (const item of data || []) {
|
||||
const label = item.methodLabel || item.method;
|
||||
const providerLabel = item.provider || '';
|
||||
// 只展示方式名称,不显示 provider 编码前缀
|
||||
options.push({
|
||||
label: providerLabel ? `${providerLabel} / ${label}` : label,
|
||||
label,
|
||||
value: item.method,
|
||||
});
|
||||
providerMap[item.method] = item.provider;
|
||||
@@ -124,42 +128,90 @@
|
||||
methodProviderMap.value = providerMap;
|
||||
}
|
||||
|
||||
/** DIRECT:按 filterMethod 加载通道商户 */
|
||||
async function loadChannelMchOptions(method: string) {
|
||||
/** DIRECT:批量加载全部通道商户(扁平去重,记录每商户的全部 provider|method 组合) */
|
||||
async function loadAllChannelMchOptions() {
|
||||
channelMchOptions.value = [];
|
||||
capabilityOptions.value = [];
|
||||
if (!method || !context.value.appId) {
|
||||
channelMchCombosMap.value = {};
|
||||
if (!context.value.appId) {
|
||||
return;
|
||||
}
|
||||
const provider = methodProviderMap.value[method];
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
const { data } = await PayRouteApi.listSceneChannelMchCandidates({
|
||||
const { data } = await PayRouteApi.listSceneChannelMchCandidatesBatch({
|
||||
appId: context.value.appId,
|
||||
provider,
|
||||
method,
|
||||
});
|
||||
channelMchOptions.value = data || [];
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
// 按 channelMchNo 去重,同时收集每商户的全部 provider|method 组合
|
||||
const labelMap = new Map<string, string>();
|
||||
const combosMap: Record<string, Array<{ method: string; provider: string }>> = {};
|
||||
for (const [key, list] of Object.entries(data)) {
|
||||
const parts = key.split('|');
|
||||
const provider = parts[0] || '';
|
||||
const method = parts.length >= 2 ? parts[1]! : '';
|
||||
if (!method) {
|
||||
continue;
|
||||
}
|
||||
for (const item of list || []) {
|
||||
labelMap.set(item.value, item.label);
|
||||
if (!combosMap[item.value]) {
|
||||
combosMap[item.value] = [];
|
||||
}
|
||||
combosMap[item.value]!.push({ method, provider });
|
||||
}
|
||||
}
|
||||
channelMchOptions.value = [...labelMap.entries()].map(([value, label]) => ({
|
||||
label,
|
||||
value,
|
||||
}));
|
||||
channelMchCombosMap.value = combosMap;
|
||||
}
|
||||
|
||||
/** DIRECT:加载支付能力 */
|
||||
async function loadCapabilityOptions(method: string, channelMchNo: string) {
|
||||
/** DIRECT:按通道商户加载支付能力候选(batch API 合并该商户全部 method 组合) */
|
||||
async function loadCapabilityByChannelMch(channelMchNo: string) {
|
||||
capabilityOptions.value = [];
|
||||
if (!method || !channelMchNo || !context.value.appId) {
|
||||
capabilityProviderMap.value = {};
|
||||
if (!channelMchNo || !context.value.appId) {
|
||||
return;
|
||||
}
|
||||
const provider = methodProviderMap.value[method];
|
||||
if (!provider) {
|
||||
const combos = channelMchCombosMap.value[channelMchNo];
|
||||
if (!combos?.length) {
|
||||
return;
|
||||
}
|
||||
const { data } = await PayRouteApi.listSceneCapabilityCandidates({
|
||||
const { data } = await PayRouteApi.listSceneCapabilityCandidatesBatch({
|
||||
appId: context.value.appId,
|
||||
provider,
|
||||
method,
|
||||
channelMchNo,
|
||||
items: combos.map((c) => ({
|
||||
provider: c.provider,
|
||||
method: c.method,
|
||||
channelMchNo,
|
||||
})),
|
||||
});
|
||||
capabilityOptions.value = data || [];
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
// 合并去重,同时建立 capability → provider 映射(用于图标联动)
|
||||
const capLabelMap = new Map<string, string>();
|
||||
const capProviderMap: Record<string, string> = {};
|
||||
for (const [key, list] of Object.entries(data)) {
|
||||
const provider = key.split('|')[0] || '';
|
||||
for (const item of list || []) {
|
||||
capLabelMap.set(item.value, item.label);
|
||||
capProviderMap[item.value] = provider;
|
||||
}
|
||||
}
|
||||
capabilityProviderMap.value = capProviderMap;
|
||||
// label 统一用 i18n 翻译
|
||||
const toLabel = (code: string) =>
|
||||
$t(`payment.merchant.cashier.cashier.capabilities.${code}`) || code;
|
||||
let options = [...capLabelMap.keys()].map((value) => ({
|
||||
label: toLabel(value),
|
||||
value,
|
||||
}));
|
||||
// 编辑回显兜底:确保已选值在选项中
|
||||
const currentCap = formState.value.capability;
|
||||
if (currentCap && !options.some((o) => o.value === currentCap)) {
|
||||
options = [...options, { label: toLabel(currentCap), value: currentCap }];
|
||||
}
|
||||
capabilityOptions.value = options;
|
||||
}
|
||||
|
||||
/** 解析模式切换 */
|
||||
@@ -167,27 +219,37 @@
|
||||
formState.value.method = undefined;
|
||||
formState.value.channelMchNo = undefined;
|
||||
formState.value.capability = undefined;
|
||||
filterMethod.value = '';
|
||||
channelMchOptions.value = [];
|
||||
capabilityOptions.value = [];
|
||||
capabilityProviderMap.value = {};
|
||||
}
|
||||
|
||||
/** DIRECT 过滤 method 变更 */
|
||||
async function onFilterMethodChange(method: any) {
|
||||
filterMethod.value = method || '';
|
||||
formState.value.channelMchNo = undefined;
|
||||
formState.value.capability = undefined;
|
||||
await loadChannelMchOptions(filterMethod.value);
|
||||
/** METHOD 模式支付方式变更 — 联动图标(icon = provider) */
|
||||
function onMethodChange(method: any) {
|
||||
const provider = method ? methodProviderMap.value[method as string] : undefined;
|
||||
if (provider) {
|
||||
formState.value.icon = provider;
|
||||
}
|
||||
}
|
||||
|
||||
/** 通道商户变更 */
|
||||
/** DIRECT 通道商户变更 — 加载该商户全部支付能力 */
|
||||
async function onChannelMchChange(channelMchNo: any) {
|
||||
formState.value.channelMchNo = channelMchNo || undefined;
|
||||
formState.value.capability = undefined;
|
||||
if (channelMchNo && filterMethod.value) {
|
||||
await loadCapabilityOptions(filterMethod.value, channelMchNo);
|
||||
} else {
|
||||
if (!channelMchNo) {
|
||||
capabilityOptions.value = [];
|
||||
return;
|
||||
}
|
||||
await loadCapabilityByChannelMch(channelMchNo as string);
|
||||
}
|
||||
|
||||
/** DIRECT 支付能力变更 — 联动图标(icon = provider,从 batch key 反推) */
|
||||
function onCapabilityChange(capability: any) {
|
||||
if (!capability) {
|
||||
return;
|
||||
}
|
||||
const provider = capabilityProviderMap.value[capability as string];
|
||||
if (provider) {
|
||||
formState.value.icon = provider;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,6 +264,7 @@
|
||||
initFormEditType(FormEditType.Add);
|
||||
resetForm();
|
||||
await loadMethodDirectory();
|
||||
await loadAllChannelMchOptions();
|
||||
}
|
||||
|
||||
/** 编辑 */
|
||||
@@ -221,6 +284,7 @@
|
||||
initFormEditType(FormEditType.Edit);
|
||||
resetForm();
|
||||
await loadMethodDirectory();
|
||||
await loadAllChannelMchOptions();
|
||||
confirmLoading.value = true;
|
||||
try {
|
||||
const { data } = await CashierConfigApi.getById(opts.record.id!);
|
||||
@@ -240,46 +304,15 @@
|
||||
channelMchNo: row.channelMchNo || undefined,
|
||||
capability: row.capability || undefined,
|
||||
};
|
||||
// DIRECT 编辑时无法还原 filterMethod,需用户重选目录方式加载候选;若已有 channelMch 则尝试 batch 匹配
|
||||
// DIRECT 编辑时还原支付能力候选
|
||||
if (formState.value.resolveMode === RESOLVE_MODE.DIRECT && row.channelMchNo) {
|
||||
await tryRestoreDirectCandidates(row.channelMchNo, row.capability);
|
||||
await loadCapabilityByChannelMch(row.channelMchNo);
|
||||
}
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑 DIRECT 项时尝试用 batch 候选还原 filterMethod / 选项
|
||||
*/
|
||||
async function tryRestoreDirectCandidates(channelMchNo: string, capability?: string) {
|
||||
const { data } = await PayRouteApi.listSceneChannelMchCandidatesBatch({
|
||||
appId: context.value.appId,
|
||||
});
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
for (const [key, list] of Object.entries(data)) {
|
||||
const hit = (list || []).some((item) => item.value === channelMchNo);
|
||||
if (!hit) {
|
||||
continue;
|
||||
}
|
||||
// key = provider|method
|
||||
const parts = key.split('|');
|
||||
const method = parts.length >= 2 ? parts[1]! : '';
|
||||
if (method) {
|
||||
filterMethod.value = method;
|
||||
await loadChannelMchOptions(method);
|
||||
if (channelMchNo) {
|
||||
formState.value.channelMchNo = channelMchNo;
|
||||
await loadCapabilityOptions(method, channelMchNo);
|
||||
formState.value.capability = capability;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 保存 */
|
||||
async function handleOk() {
|
||||
try {
|
||||
@@ -322,15 +355,13 @@
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
<a-drawer
|
||||
v-model:open="visible"
|
||||
:title="title"
|
||||
:width="720"
|
||||
:confirm-loading="confirmLoading"
|
||||
:size="800"
|
||||
:destroy-on-hidden="true"
|
||||
:mask-closable="showable"
|
||||
destroy-on-close
|
||||
@ok="handleOk"
|
||||
@cancel="handleCancel"
|
||||
@close="handleCancel"
|
||||
>
|
||||
<a-spin :spinning="confirmLoading">
|
||||
<a-form
|
||||
@@ -360,29 +391,6 @@
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="$t('payment.merchant.cashier.cashier.recommend')" name="recommend">
|
||||
<a-radio-group v-model:value="formState.recommend" button-style="solid" :disabled="showable">
|
||||
<a-radio-button :value="false">{{
|
||||
$t('payment.merchant.cashier.cashier.recommendNo')
|
||||
}}</a-radio-button>
|
||||
<a-radio-button :value="true">{{
|
||||
$t('payment.merchant.cashier.cashier.recommendYes')
|
||||
}}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="$t('payment.merchant.cashier.cashier.icon')" name="icon">
|
||||
<a-select
|
||||
v-model:value="formState.icon"
|
||||
:disabled="showable"
|
||||
allow-clear
|
||||
:options="iconOptions"
|
||||
:placeholder="$t('payment.merchant.cashier.cashier.iconPlaceholder')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-form-item :label="$t('payment.merchant.cashier.cashier.resolveMode')" name="resolveMode">
|
||||
<a-radio-group
|
||||
@@ -411,28 +419,13 @@
|
||||
option-filter-prop="label"
|
||||
:options="methodOptions"
|
||||
:placeholder="$t('payment.merchant.cashier.cashier.methodPlaceholder')"
|
||||
@change="onMethodChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<a-col :span="24">
|
||||
<a-form-item :label="$t('payment.merchant.cashier.cashier.method')">
|
||||
<a-select
|
||||
v-model:value="filterMethod"
|
||||
:disabled="showable"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
:options="methodOptions"
|
||||
:placeholder="$t('payment.merchant.cashier.cashier.methodPlaceholder')"
|
||||
@change="onFilterMethodChange"
|
||||
/>
|
||||
<div class="mt-1 text-xs text-muted-foreground">
|
||||
{{ $t('payment.merchant.cashier.cashier.methodFilterHint') }}
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item
|
||||
:label="$t('payment.merchant.cashier.cashier.channelMerchant')"
|
||||
@@ -440,7 +433,7 @@
|
||||
>
|
||||
<a-select
|
||||
v-model:value="formState.channelMchNo"
|
||||
:disabled="showable || !filterMethod"
|
||||
:disabled="showable"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
:options="channelMchOptions"
|
||||
@@ -458,12 +451,77 @@
|
||||
option-filter-prop="label"
|
||||
:options="capabilityOptions"
|
||||
:placeholder="$t('payment.merchant.cashier.cashier.capabilityPlaceholder')"
|
||||
@change="onCapabilityChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</template>
|
||||
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="$t('payment.merchant.cashier.cashier.recommend')" name="recommend">
|
||||
<a-radio-group v-model:value="formState.recommend" button-style="solid" :disabled="showable">
|
||||
<a-radio-button :value="false">{{
|
||||
$t('payment.merchant.cashier.cashier.recommendNo')
|
||||
}}</a-radio-button>
|
||||
<a-radio-button :value="true">{{
|
||||
$t('payment.merchant.cashier.cashier.recommendYes')
|
||||
}}</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item :label="$t('payment.merchant.cashier.cashier.icon')" name="icon">
|
||||
<a-select
|
||||
v-model:value="formState.icon"
|
||||
:disabled="showable"
|
||||
show-search
|
||||
option-filter-prop="label"
|
||||
:options="iconOptions"
|
||||
:placeholder="$t('payment.merchant.cashier.cashier.iconPlaceholder')"
|
||||
>
|
||||
<template #optionRender="{ option }">
|
||||
<img
|
||||
v-if="getProviderSvgUrl(option.data.value)"
|
||||
:src="getProviderSvgUrl(option.data.value)"
|
||||
class="icon-inline"
|
||||
:alt="option.data.label"
|
||||
/>
|
||||
<span>{{ option.data.label }}</span>
|
||||
</template>
|
||||
<template #labelRender="{ label, value }">
|
||||
<img
|
||||
v-if="getProviderSvgUrl(value)"
|
||||
:src="getProviderSvgUrl(value)"
|
||||
class="icon-inline"
|
||||
:alt="label"
|
||||
/>
|
||||
<span>{{ label }}</span>
|
||||
</template>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
|
||||
<template #footer>
|
||||
<a-space>
|
||||
<a-button @click="handleCancel">{{ showable ? $t('common.close') : $t('common.cancel') }}</a-button>
|
||||
<a-button v-if="!showable" type="primary" :loading="confirmLoading" @click="handleOk">
|
||||
{{ $t('common.save') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</a-drawer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.icon-inline {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: 4px;
|
||||
vertical-align: -3px;
|
||||
object-fit: contain;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -33,11 +33,16 @@ export const CASHIER_H5_SCENES: CashierSceneConfig[] = [
|
||||
{ scene: 'douyin', provider: 'douyin' },
|
||||
];
|
||||
|
||||
/** 图标选项 */
|
||||
/**
|
||||
* 图标选项(值与 PayProviderEnum.code 完全对齐)
|
||||
* 选支付方式/通道商户时 icon = provider 直接赋值,实现联动
|
||||
*/
|
||||
export const CASHIER_ICON_OPTIONS = [
|
||||
{ value: 'aggregate_pay', labelKey: 'payment.merchant.cashier.cashier.icons.aggregate_pay' },
|
||||
{ value: 'wechat', labelKey: 'payment.merchant.cashier.cashier.icons.wechat' },
|
||||
{ value: 'alipay', labelKey: 'payment.merchant.cashier.cashier.icons.alipay' },
|
||||
{ value: 'union', labelKey: 'payment.merchant.cashier.cashier.icons.union' },
|
||||
{ value: 'union_pay', labelKey: 'payment.merchant.cashier.cashier.icons.union_pay' },
|
||||
{ value: 'visa', labelKey: 'payment.merchant.cashier.cashier.icons.visa' },
|
||||
{ value: 'mastercard', labelKey: 'payment.merchant.cashier.cashier.icons.mastercard' },
|
||||
{ value: 'douyin', labelKey: 'payment.merchant.cashier.cashier.icons.douyin' },
|
||||
{ value: 'aggregate', labelKey: 'payment.merchant.cashier.cashier.icons.aggregate' },
|
||||
] as const;
|
||||
|
||||
Reference in New Issue
Block a user