mirror of
https://gitee.com/bootx/dax-pay-ui
synced 2026-08-12 23:45:39 +08:00
refactor(admin,merchant): 通道商户路由参数精简, 冗余字段改接收端反查
URL 透传的 channelMerchantId/channelMerchantName/sandbox/product 改为 接收端用 findAll/findAllByMchNo 反查, 避免中文暴露、sandbox 快照过期、URL 冗余。
This commit is contained in:
@@ -109,12 +109,12 @@
|
||||
return;
|
||||
}
|
||||
if (card.route) {
|
||||
// 仅传 mchNo + channelMchNo, 接收端反查名称等元数据
|
||||
router.push({
|
||||
path: card.route,
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
channelMchNo: channelMchNo.value,
|
||||
channelMerchantId: channelMerchant.value.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { type AlipayMchApp, AlipayMchAppApi } from '#/api/payment/channel/alipay/mch-app.api';
|
||||
import { ChannelMerchantApi } from '#/api/payment/global/channel-merchant/channel-merchant.api';
|
||||
import RouteQueryMissingState from '#/components/route/RouteQueryMissingState.vue';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
import { ProductEnum } from '#/enums/payment/productEnum';
|
||||
@@ -33,12 +34,6 @@
|
||||
}),
|
||||
fallbackPath: computed(() => {
|
||||
const mchNo = normalizeRouteQueryValue(route.query.mchNo);
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
// product 由本页所属渠道决定(支付宝直连),无需从路由读取
|
||||
const product = ProductEnum.ALIPAY;
|
||||
if (mchNo && id) {
|
||||
return { path: '/payment/global/channel-merchant/detail', query: { mchNo, id, product } };
|
||||
}
|
||||
return mchNo ? { path: '/payment/global/channel-merchant', query: { mchNo } } : '/payment/merchant';
|
||||
}),
|
||||
});
|
||||
@@ -47,6 +42,7 @@
|
||||
const mchNo = ref('');
|
||||
const channelMchNo = ref('');
|
||||
const channelMerchantName = ref('');
|
||||
const channelMerchantId = ref('');
|
||||
const appList = ref<AlipayMchApp[]>([]);
|
||||
const editRef = ref<InstanceType<typeof AlipayMchAppEdit>>();
|
||||
const detailRef = ref<InstanceType<typeof AlipayMchAppDetail>>();
|
||||
@@ -79,18 +75,31 @@
|
||||
}
|
||||
mchNo.value = routeContext.query.value.mchNo;
|
||||
channelMchNo.value = routeContext.query.value.channelMchNo;
|
||||
channelMerchantName.value = normalizeRouteQueryValue(route.query.channelMerchantName);
|
||||
}
|
||||
|
||||
/** 反查通道商户元数据(名称/主键), 替代 URL 透传, 保证数据实时 */
|
||||
function loadMerchantMeta() {
|
||||
if (!mchNo.value || !channelMchNo.value) {
|
||||
return;
|
||||
}
|
||||
ChannelMerchantApi.findAllByMchNo(mchNo.value)
|
||||
.then(({ data }) => {
|
||||
const merchant = (data || []).find((m) => m.channelMchNo === channelMchNo.value);
|
||||
if (merchant) {
|
||||
channelMerchantName.value = merchant.channelMerchantName ?? '';
|
||||
channelMerchantId.value = String(merchant.id ?? '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 返回通道商户详情或列表 */
|
||||
function handleBack() {
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
if (id) {
|
||||
if (channelMerchantId.value) {
|
||||
// product 由本页所属渠道决定(支付宝直连)
|
||||
const product = ProductEnum.ALIPAY;
|
||||
router.push({
|
||||
path: '/payment/global/channel-merchant/detail',
|
||||
query: { mchNo: mchNo.value, id, product },
|
||||
query: { mchNo: mchNo.value, id: channelMerchantId.value, product },
|
||||
});
|
||||
} else {
|
||||
router.push({
|
||||
@@ -118,6 +127,8 @@
|
||||
return;
|
||||
}
|
||||
loadAppList();
|
||||
// 反查通道商户元数据(标题/返回)
|
||||
loadMerchantMeta();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -150,14 +161,6 @@
|
||||
</a-button>
|
||||
<span class="text-lg font-bold text-foreground">{{ pageTitle }}</span>
|
||||
</div>
|
||||
<a
|
||||
href="https://open.alipay.com/develop/manage"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="shrink-0 text-sm font-normal text-primary"
|
||||
>
|
||||
{{ $t('payment.channel.alipayMchApp.consoleLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -115,13 +115,12 @@
|
||||
keyConfigRef.value?.init();
|
||||
}
|
||||
if (card.key === 'appManage') {
|
||||
const id = channelMerchant.value.id;
|
||||
// 应用管理: 仅传 mchNo + channelMchNo, 接收端反查名称等元数据
|
||||
router.push({
|
||||
path: '/payment/global/channel-merchant/douyin-app-manage',
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
channelMchNo: channelMchNo.value,
|
||||
channelMerchantId: id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { DouyinMchAppApi, type DouyinMchApp } from '#/api/payment/channel/douyin/mch-app.api';
|
||||
import { ChannelMerchantApi } from '#/api/payment/global/channel-merchant/channel-merchant.api';
|
||||
import RouteQueryMissingState from '#/components/route/RouteQueryMissingState.vue';
|
||||
import { ProductEnum } from '#/enums/payment/productEnum';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
@@ -33,12 +34,6 @@
|
||||
}),
|
||||
fallbackPath: computed(() => {
|
||||
const mchNo = normalizeRouteQueryValue(route.query.mchNo);
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
// product 由本页所属渠道决定(抖音直连),无需从路由读取
|
||||
const product = ProductEnum.DOUYIN_PAY;
|
||||
if (mchNo && id) {
|
||||
return { path: '/payment/global/channel-merchant/detail', query: { mchNo, id, product } };
|
||||
}
|
||||
return mchNo
|
||||
? { path: '/payment/global/channel-merchant', query: { mchNo } }
|
||||
: '/payment/merchant';
|
||||
@@ -49,6 +44,7 @@
|
||||
const mchNo = ref('');
|
||||
const channelMchNo = ref('');
|
||||
const channelMerchantName = ref('');
|
||||
const channelMerchantId = ref('');
|
||||
const appList = ref<DouyinMchApp[]>([]);
|
||||
const editRef = ref<InstanceType<typeof DouyinMchAppEdit>>();
|
||||
const detailRef = ref<InstanceType<typeof DouyinMchAppDetail>>();
|
||||
@@ -80,17 +76,30 @@
|
||||
}
|
||||
mchNo.value = routeContext.query.value.mchNo!;
|
||||
channelMchNo.value = routeContext.query.value.channelMchNo!;
|
||||
channelMerchantName.value = normalizeRouteQueryValue(route.query.channelMerchantName);
|
||||
}
|
||||
|
||||
/** 反查通道商户元数据(名称/主键), 替代 URL 透传, 保证数据实时 */
|
||||
function loadMerchantMeta() {
|
||||
if (!mchNo.value || !channelMchNo.value) {
|
||||
return;
|
||||
}
|
||||
ChannelMerchantApi.findAllByMchNo(mchNo.value)
|
||||
.then(({ data }) => {
|
||||
const merchant = (data || []).find((m) => m.channelMchNo === channelMchNo.value);
|
||||
if (merchant) {
|
||||
channelMerchantName.value = merchant.channelMerchantName ?? '';
|
||||
channelMerchantId.value = String(merchant.id ?? '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleBack() {
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
if (id) {
|
||||
if (channelMerchantId.value) {
|
||||
// product 由本页所属渠道决定(抖音直连)
|
||||
const product = ProductEnum.DOUYIN_PAY;
|
||||
router.push({
|
||||
path: '/payment/global/channel-merchant/detail',
|
||||
query: { mchNo: mchNo.value, id, product },
|
||||
query: { mchNo: mchNo.value, id: channelMerchantId.value, product },
|
||||
});
|
||||
} else {
|
||||
router.push({
|
||||
@@ -118,6 +127,8 @@
|
||||
return;
|
||||
}
|
||||
loadAppList();
|
||||
// 反查通道商户元数据(标题/返回)
|
||||
loadMerchantMeta();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
query: {
|
||||
mchNo: record.mchNo!,
|
||||
id: record.id!,
|
||||
product: record.product || '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
id: record.id!,
|
||||
product: record.product || '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -31,15 +31,12 @@
|
||||
const router = useRouter();
|
||||
|
||||
const routeContext = useRequiredRouteQuery({
|
||||
keys: ['mchNo', 'id', 'product'],
|
||||
keys: ['mchNo', 'id'],
|
||||
messageKey: computed(() => {
|
||||
if (!normalizeRouteQueryValue(route.query.mchNo)) {
|
||||
return 'payment.common.route.missingMchNo';
|
||||
}
|
||||
if (!normalizeRouteQueryValue(route.query.id)) {
|
||||
return 'payment.merchant.channelMerchant.missingId';
|
||||
}
|
||||
return 'payment.common.route.missingProduct';
|
||||
return 'payment.merchant.channelMerchant.missingId';
|
||||
}),
|
||||
fallbackPath: computed(() => {
|
||||
const no = normalizeRouteQueryValue(route.query.mchNo);
|
||||
@@ -53,6 +50,9 @@
|
||||
const channelMerchant = ref<ChannelMerchantResult>({});
|
||||
const loading = ref(false);
|
||||
|
||||
/** product 优先取路由(可选), 缺失时用详情反查回填 */
|
||||
const resolvedProduct = computed(() => product.value || channelMerchant.value.product || '');
|
||||
|
||||
const alipayMchManageRef = ref<InstanceType<typeof AlipayMchManage>>();
|
||||
const alipayChannelMerchantManageRef = ref<InstanceType<typeof AlipayChannelMerchantManage>>();
|
||||
const wechatManageRef = ref<InstanceType<typeof WechatChannelMerchantManage>>();
|
||||
@@ -147,7 +147,7 @@
|
||||
return $t('payment.merchant.channelMerchant.manageTitleDefault');
|
||||
}
|
||||
|
||||
const pageTitle = computed(() => resolvePageTitle(product.value));
|
||||
const pageTitle = computed(() => resolvePageTitle(resolvedProduct.value));
|
||||
|
||||
/** 银联商务产品类型展示名称(多产品共页时区分具体产品) */
|
||||
const productTypeName = computed(() => {
|
||||
@@ -170,6 +170,10 @@
|
||||
.then(({ data }) => {
|
||||
if (data) {
|
||||
channelMerchant.value = data;
|
||||
// product 缺失时用详情回填
|
||||
if (!product.value && data.product) {
|
||||
product.value = data.product;
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@@ -242,7 +246,8 @@
|
||||
}
|
||||
mchNo.value = routeContext.query.value.mchNo;
|
||||
channelMerchantId.value = routeContext.query.value.id;
|
||||
product.value = routeContext.query.value.product;
|
||||
// product 可选(不在 keys), 缺失时由 loadChannelMerchant 回填
|
||||
product.value = normalizeRouteQueryValue(route.query.product) || '';
|
||||
}
|
||||
|
||||
watch(() => route.query, syncRouteState, { deep: true });
|
||||
@@ -266,13 +271,11 @@
|
||||
<template>
|
||||
<RouteQueryMissingState
|
||||
v-if="!routeContext.isValid"
|
||||
:description="
|
||||
:description="
|
||||
$t(
|
||||
!routeContext.query.value.mchNo
|
||||
? 'payment.common.route.missingMchNo'
|
||||
: !routeContext.query.value.id
|
||||
? 'payment.merchant.channelMerchant.missingId'
|
||||
: 'payment.common.route.missingProduct',
|
||||
: 'payment.merchant.channelMerchant.missingId',
|
||||
)
|
||||
"
|
||||
:back-text="$t('payment.merchant.workbench.workbench.backToList')"
|
||||
@@ -291,94 +294,84 @@
|
||||
<!-- 国际化:按通道动态展示页头标题 -->
|
||||
<span class="text-lg font-bold text-foreground">{{ pageTitle }}</span>
|
||||
<!-- 银联商务多产品共页, 用标签区分具体产品类型(如"银联商务(C扫B)") -->
|
||||
<a-tag v-if="isUmsProduct(product) && productTypeName" color="blue" class="!ml-1">
|
||||
<a-tag v-if="isUmsProduct(resolvedProduct) && productTypeName" color="blue" class="!ml-1">
|
||||
{{ productTypeName }}
|
||||
</a-tag>
|
||||
<span v-if="channelMerchant.channelMerchantName" class="text-sm text-muted-foreground">
|
||||
({{ channelMerchant.channelMerchantName }})
|
||||
</span>
|
||||
</div>
|
||||
<!-- 国际化:支付宝开放平台外链(直连产品) -->
|
||||
<a
|
||||
v-if="product === ProductEnum.ALIPAY"
|
||||
href="https://open.alipay.com/develop/manage"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="shrink-0 text-sm font-normal text-primary"
|
||||
>
|
||||
{{ $t('payment.channel.alipayMchApp.consoleLink') }}
|
||||
</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<AlipayMchManage
|
||||
v-if="product === ProductEnum.ALIPAY"
|
||||
v-if="resolvedProduct === ProductEnum.ALIPAY"
|
||||
ref="alipayMchManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<AlipayChannelMerchantManage
|
||||
v-else-if="product === ProductEnum.ALIPAY_ISV"
|
||||
v-else-if="resolvedProduct === ProductEnum.ALIPAY_ISV"
|
||||
ref="alipayChannelMerchantManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<WechatChannelMerchantManage
|
||||
v-else-if="product === ProductEnum.WECHAT_ISV"
|
||||
v-else-if="resolvedProduct === ProductEnum.WECHAT_ISV"
|
||||
ref="wechatManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<WechatDirectMchManage
|
||||
v-else-if="product === ProductEnum.WECHAT_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.WECHAT_PAY"
|
||||
ref="wechatDirectManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<DouyinDirectMchManage
|
||||
v-else-if="product === ProductEnum.DOUYIN_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.DOUYIN_PAY"
|
||||
ref="douyinDirectManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<UmsDirectMchManage v-else-if="isUmsProduct(product)" ref="umsDirectManageRef" @success="loadChannelMerchant" />
|
||||
<UmsDirectMchManage v-else-if="isUmsProduct(resolvedProduct)" ref="umsDirectManageRef" @success="loadChannelMerchant" />
|
||||
<LakalaMchManage
|
||||
v-else-if="product === ProductEnum.LAKALA_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.LAKALA_PAY"
|
||||
ref="lakalaManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<AdapayDirectMchManage
|
||||
v-else-if="product === ProductEnum.ADA_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.ADA_PAY"
|
||||
ref="adapayDirectManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<HkrtMchManage
|
||||
v-else-if="product === ProductEnum.HKRT_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.HKRT_PAY"
|
||||
ref="hkrtManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<LeshuaMchManage
|
||||
v-else-if="product === ProductEnum.LESHUA_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.LESHUA_PAY"
|
||||
ref="leshuaManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<DougongMchManage
|
||||
v-else-if="product === ProductEnum.DOUGONG_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.DOUGONG_PAY"
|
||||
ref="dougongManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<VbillMchManage
|
||||
v-else-if="product === ProductEnum.VBILL_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.VBILL_PAY"
|
||||
ref="vbillManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<FuyouMchManage
|
||||
v-else-if="product === ProductEnum.FUYOU_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.FUYOU_PAY"
|
||||
ref="fuyouManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<HmpayMchManage
|
||||
v-else-if="product === ProductEnum.HM_PAY"
|
||||
v-else-if="resolvedProduct === ProductEnum.HM_PAY"
|
||||
ref="hmpayManageRef"
|
||||
@success="loadChannelMerchant"
|
||||
/>
|
||||
<div v-else-if="!isSupported(product)" class="flex items-center justify-center" style="min-height: 400px">
|
||||
<div v-else-if="!isSupported(resolvedProduct)" class="flex items-center justify-center" style="min-height: 400px">
|
||||
<a-empty :description="$t('payment.merchant.channelMerchant.detailNotSupportYet')" />
|
||||
</div>
|
||||
</a-spin>
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import {
|
||||
ChannelMerchantApi,
|
||||
type ChannelMerchantResult,
|
||||
@@ -62,13 +60,12 @@
|
||||
return source || '-';
|
||||
}
|
||||
|
||||
/** 进入详情(仅传 id/product,不带 mchNo) */
|
||||
/** 进入详情(仅传 id, product 由 detail 页反查回填) */
|
||||
function handleManage(record: ChannelMerchantResult) {
|
||||
router.push({
|
||||
path: '/mch/channel-merchant/detail',
|
||||
query: {
|
||||
id: record.id!,
|
||||
product: record.product || '',
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -96,11 +93,6 @@
|
||||
loadList();
|
||||
}
|
||||
|
||||
/** 创建通道商户 */
|
||||
function handleCreate() {
|
||||
router.push({ path: '/mch/channel-merchant/create' });
|
||||
}
|
||||
|
||||
/** 切换启用状态 */
|
||||
function handleToggleEnable(record: ChannelMerchantResult, checked: boolean) {
|
||||
const isEnabling = checked;
|
||||
@@ -157,14 +149,7 @@
|
||||
<template>
|
||||
<div class="m-4">
|
||||
<a-card variant="borderless" class="rounded-xl shadow-sm">
|
||||
<vxe-toolbar ref="xToolbar" custom refresh :refresh-options="{ queryMethod: loadList }">
|
||||
<template #buttons>
|
||||
<a-button v-if="hasPermission(PermCodes.Channel.Merchant.MANAGE)" type="primary" @click="handleCreate">
|
||||
<template #icon><IconifyIcon icon="ant-design:plus-outlined" /></template>
|
||||
{{ $t('payment.merchant.channelMerchant.create') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</vxe-toolbar>
|
||||
<vxe-toolbar ref="xToolbar" custom refresh :refresh-options="{ queryMethod: loadList }" />
|
||||
|
||||
<vxe-table ref="xTable" :row-config="{ keyField: 'id' }" :data="list" :loading="loading">
|
||||
<vxe-column type="seq" :title="$t('common.seq')" width="60" align="center" />
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
import type { ChannelMerchantResult } from '#/api/payment/global/channel-merchant/channel-merchant.api';
|
||||
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import AlipayDirectAppDrawer from '#/views/payment/channel-merchant/detail/alipay-direct/AlipayDirectAppDrawer.vue';
|
||||
import ChannelMerchantNameEditModal from '#/views/payment/channel-merchant/detail/ChannelMerchantNameEditModal.vue';
|
||||
import CommonChannelMerchantBasicInfo from '#/views/payment/channel-merchant/detail/CommonChannelMerchantBasicInfo.vue';
|
||||
|
||||
import AlipayChannelMerchantBasicInfo from './AlipayChannelMerchantBasicInfo.vue';
|
||||
import AlipayMchAppCapability from './AlipayMchAppCapability.vue';
|
||||
|
||||
defineOptions({ name: 'AlipayMchManage' });
|
||||
|
||||
@@ -17,10 +19,11 @@
|
||||
(e: 'success'): void;
|
||||
}>();
|
||||
|
||||
const router = useRouter();
|
||||
const channelMchNo = ref('');
|
||||
const channelMerchant = ref<ChannelMerchantResult>({});
|
||||
const basicInfoRef = ref<InstanceType<typeof CommonChannelMerchantBasicInfo>>();
|
||||
const alipayAppRef = ref<InstanceType<typeof AlipayDirectAppDrawer>>();
|
||||
const basicInfoRef = ref<InstanceType<typeof AlipayChannelMerchantBasicInfo>>();
|
||||
const capabilityRef = ref<InstanceType<typeof AlipayMchAppCapability>>();
|
||||
const editNameRef = ref<InstanceType<typeof ChannelMerchantNameEditModal>>();
|
||||
|
||||
/** 功能卡片配置(按组分组的卡片布局) */
|
||||
@@ -53,6 +56,12 @@
|
||||
icon: 'ant-design:appstore-outlined',
|
||||
description: $t('payment.merchant.channelMerchant.cardAppDesc'),
|
||||
},
|
||||
{
|
||||
key: 'capabilityBinding',
|
||||
title: $t('payment.merchant.alipayDirectApp.cardCapabilityBinding'),
|
||||
icon: 'ant-design:api-outlined',
|
||||
description: $t('payment.merchant.alipayDirectApp.cardCapabilityBindingDesc'),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -86,12 +95,24 @@
|
||||
function handleCardClick(card: { key: string }) {
|
||||
if (card.key === 'basicInfo') {
|
||||
basicInfoRef.value?.open();
|
||||
return;
|
||||
}
|
||||
if (card.key === 'editMerchantName') {
|
||||
editNameRef.value?.open();
|
||||
return;
|
||||
}
|
||||
if (card.key === 'capabilityBinding') {
|
||||
capabilityRef.value?.show(channelMchNo.value);
|
||||
return;
|
||||
}
|
||||
if (card.key === 'mchApp') {
|
||||
alipayAppRef.value?.show();
|
||||
// 应用管理: 仅传 channelMchNo, 接收端反查名称/沙箱等元数据
|
||||
router.push({
|
||||
path: '/mch/channel-merchant/alipay-app-manage',
|
||||
query: {
|
||||
channelMchNo: channelMchNo.value,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,17 +165,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CommonChannelMerchantBasicInfo
|
||||
<AlipayChannelMerchantBasicInfo
|
||||
ref="basicInfoRef"
|
||||
:channel-mch-no="channelMchNo"
|
||||
:channel-merchant="channelMerchant"
|
||||
/>
|
||||
<ChannelMerchantNameEditModal ref="editNameRef" :channel-merchant="channelMerchant" @success="emit('success')" />
|
||||
<AlipayDirectAppDrawer
|
||||
ref="alipayAppRef"
|
||||
:channel-mch-no="channelMchNo"
|
||||
:sandbox="channelMerchant.sandbox ?? false"
|
||||
/>
|
||||
<AlipayMchAppCapability ref="capabilityRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
<script lang="ts" setup>
|
||||
import type { AlipayDirectAppResult } from '#/api/payment/alipay/alipay-direct-app.api';
|
||||
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { AlipayDirectAppApi } from '#/api/payment/alipay/alipay-direct-app.api';
|
||||
import { ChannelMerchantApi } from '#/api/payment/global/channel-merchant/channel-merchant.api';
|
||||
import RouteQueryMissingState from '#/components/route/RouteQueryMissingState.vue';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
import { usePermission } from '#/hooks/usePermission';
|
||||
import { useRequiredRouteQuery } from '#/hooks/useRequiredRouteQuery';
|
||||
|
||||
import AlipayMchAppCard from './AlipayMchAppCard.vue';
|
||||
import AlipayMchAppDetail from './AlipayMchAppDetail.vue';
|
||||
import AlipayMchAppEdit from './AlipayMchAppEdit.vue';
|
||||
|
||||
defineOptions({ name: 'AlipayMchAppManage' });
|
||||
|
||||
const router = useRouter();
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
// 商户端仅需 channelMchNo(mchNo 由后端 PaymentContext 强制)
|
||||
const routeContext = useRequiredRouteQuery({
|
||||
keys: ['channelMchNo'],
|
||||
messageKey: 'payment.merchant.channelMerchant.missingChannelMchNo',
|
||||
fallbackPath: '/mch/channel-merchant',
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const channelMchNo = ref('');
|
||||
const channelMerchantName = ref('');
|
||||
const channelMerchantId = ref('');
|
||||
// 沙箱标识(跟随通道商户, 透传给密钥 Tab)
|
||||
const sandbox = ref(false);
|
||||
const appList = ref<AlipayDirectAppResult[]>([]);
|
||||
const editRef = ref<InstanceType<typeof AlipayMchAppEdit>>();
|
||||
const detailRef = ref<InstanceType<typeof AlipayMchAppDetail>>();
|
||||
|
||||
const canAdd = computed(() => hasPermission(PermCodes.Channel.App.MANAGE));
|
||||
|
||||
const pageTitle = computed(() => {
|
||||
const base = $t('payment.merchant.alipayDirectApp.manageTitle');
|
||||
return channelMerchantName.value ? `${base} (${channelMerchantName.value})` : base;
|
||||
});
|
||||
|
||||
/** 加载应用列表 */
|
||||
function loadAppList() {
|
||||
if (!channelMchNo.value) {
|
||||
return;
|
||||
}
|
||||
loading.value = true;
|
||||
AlipayDirectAppApi.listByChannelMchNo(channelMchNo.value)
|
||||
.then(({ data }) => {
|
||||
appList.value = data || [];
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function syncRouteState() {
|
||||
if (!routeContext.isValid.value) {
|
||||
return;
|
||||
}
|
||||
channelMchNo.value = routeContext.query.value.channelMchNo;
|
||||
}
|
||||
|
||||
/** 反查通道商户元数据(名称/沙箱/主键), 替代 URL 透传, 保证数据实时 */
|
||||
function loadMerchantMeta() {
|
||||
if (!channelMchNo.value) {
|
||||
return;
|
||||
}
|
||||
ChannelMerchantApi.findAll()
|
||||
.then(({ data }) => {
|
||||
const merchant = (data || []).find((m) => m.channelMchNo === channelMchNo.value);
|
||||
if (merchant) {
|
||||
channelMerchantName.value = merchant.channelMerchantName ?? '';
|
||||
channelMerchantId.value = String(merchant.id ?? '');
|
||||
sandbox.value = merchant.sandbox ?? false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** 返回通道商户详情或列表 */
|
||||
function handleBack() {
|
||||
if (channelMerchantId.value) {
|
||||
router.push({
|
||||
path: '/mch/channel-merchant/detail',
|
||||
query: { id: channelMerchantId.value },
|
||||
});
|
||||
} else {
|
||||
router.push({ path: '/mch/channel-merchant' });
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
editRef.value?.show(channelMchNo.value);
|
||||
}
|
||||
|
||||
function handleManage(record: AlipayDirectAppResult) {
|
||||
detailRef.value?.show(channelMchNo.value, record);
|
||||
}
|
||||
|
||||
function handleEdit(record: AlipayDirectAppResult) {
|
||||
editRef.value?.showEdit(channelMchNo.value, record);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
syncRouteState();
|
||||
if (!routeContext.isValid.value) {
|
||||
return;
|
||||
}
|
||||
loadAppList();
|
||||
// 反查通道商户元数据(标题/返回/sandbox)
|
||||
loadMerchantMeta();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<RouteQueryMissingState
|
||||
v-if="!routeContext.isValid"
|
||||
:description="$t('payment.merchant.channelMerchant.missingChannelMchNo')"
|
||||
:back-text="$t('payment.merchant.channelMerchant.back')"
|
||||
@back="routeContext.goFallback"
|
||||
/>
|
||||
<div v-else class="m-4">
|
||||
<a-card variant="borderless" class="rounded-xl shadow-sm">
|
||||
<template #title>
|
||||
<div class="flex w-full items-center justify-between gap-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<a-button
|
||||
type="text"
|
||||
class="flex items-center justify-center rounded-full hover:bg-accent"
|
||||
@click="handleBack"
|
||||
>
|
||||
<template #icon>
|
||||
<IconifyIcon icon="ant-design:arrow-left-outlined" class="text-lg" />
|
||||
</template>
|
||||
</a-button>
|
||||
<span class="text-lg font-bold text-foreground">{{ pageTitle }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<a-empty
|
||||
v-if="!loading && appList.length === 0 && !canAdd"
|
||||
class="py-12"
|
||||
:description="$t('payment.merchant.alipayDirectApp.emptyAppList')"
|
||||
/>
|
||||
<div v-else class="app-card-grid">
|
||||
<AlipayMchAppCard
|
||||
v-for="app in appList"
|
||||
:key="app.id ?? app.aliAppId"
|
||||
:record="app"
|
||||
@edit="handleEdit(app)"
|
||||
@manage="handleManage(app)"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="canAdd"
|
||||
class="add-card flex h-full min-h-[128px] cursor-pointer flex-col items-center justify-center gap-2 rounded-xl border border-dashed border-border bg-muted/30 text-muted-foreground transition-all hover:border-primary hover:bg-primary/5 hover:text-primary"
|
||||
@click="handleAdd"
|
||||
>
|
||||
<IconifyIcon icon="ant-design:plus-outlined" class="text-3xl" />
|
||||
<span class="text-sm font-medium">{{ $t('payment.merchant.alipayDirectApp.addCard') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
|
||||
<AlipayMchAppEdit ref="editRef" @ok="loadAppList" />
|
||||
<AlipayMchAppDetail ref="detailRef" :sandbox="sandbox" @deleted="loadAppList" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.app-card-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 20px;
|
||||
padding: 4px;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
@media (max-width: 1400px) {
|
||||
.app-card-grid {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.app-card-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.app-card-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -113,12 +113,11 @@
|
||||
keyConfigRef.value?.init();
|
||||
}
|
||||
if (card.key === 'appManage') {
|
||||
const id = channelMerchant.value.id;
|
||||
// 应用管理: 仅传 channelMchNo, 接收端反查名称等元数据
|
||||
router.push({
|
||||
path: '/mch/channel-merchant/douyin-app-manage',
|
||||
query: {
|
||||
channelMchNo: channelMchNo.value,
|
||||
channelMerchantId: id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { type DouyinMchApp, DouyinMchAppApi } from '#/api/payment/channel/douyin/mch-app.api';
|
||||
import { ChannelMerchantApi } from '#/api/payment/global/channel-merchant/channel-merchant.api';
|
||||
import RouteQueryMissingState from '#/components/route/RouteQueryMissingState.vue';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
import { ProductEnum } from '#/enums/payment';
|
||||
import { usePermission } from '#/hooks/usePermission';
|
||||
import { normalizeRouteQueryValue, useRequiredRouteQuery } from '#/hooks/useRequiredRouteQuery';
|
||||
import { useRequiredRouteQuery } from '#/hooks/useRequiredRouteQuery';
|
||||
|
||||
import DouyinMchAppCard from './DouyinMchAppCard.vue';
|
||||
import DouyinMchAppDetail from './DouyinMchAppDetail.vue';
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
defineOptions({ name: 'DouyinMchAppManage' });
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
@@ -27,20 +26,13 @@
|
||||
const routeContext = useRequiredRouteQuery({
|
||||
keys: ['channelMchNo'],
|
||||
messageKey: 'payment.merchant.channelMerchant.missingChannelMchNo',
|
||||
fallbackPath: computed(() => {
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
// product 由本页所属渠道决定(抖音直连)
|
||||
const product = ProductEnum.DOUYIN_PAY;
|
||||
if (id) {
|
||||
return { path: '/mch/channel-merchant/detail', query: { id, product } };
|
||||
}
|
||||
return '/mch/channel-merchant';
|
||||
}),
|
||||
fallbackPath: '/mch/channel-merchant',
|
||||
});
|
||||
|
||||
const loading = ref(false);
|
||||
const channelMchNo = ref('');
|
||||
const channelMerchantName = ref('');
|
||||
const channelMerchantId = ref('');
|
||||
const appList = ref<DouyinMchApp[]>([]);
|
||||
const editRef = ref<InstanceType<typeof DouyinMchAppEdit>>();
|
||||
const detailRef = ref<InstanceType<typeof DouyinMchAppDetail>>();
|
||||
@@ -71,17 +63,28 @@
|
||||
return;
|
||||
}
|
||||
channelMchNo.value = routeContext.query.value.channelMchNo!;
|
||||
channelMerchantName.value = normalizeRouteQueryValue(route.query.channelMerchantName);
|
||||
}
|
||||
|
||||
/** 反查通道商户元数据(名称/主键), 替代 URL 透传, 保证数据实时 */
|
||||
function loadMerchantMeta() {
|
||||
if (!channelMchNo.value) {
|
||||
return;
|
||||
}
|
||||
ChannelMerchantApi.findAll()
|
||||
.then(({ data }) => {
|
||||
const merchant = (data || []).find((m) => m.channelMchNo === channelMchNo.value);
|
||||
if (merchant) {
|
||||
channelMerchantName.value = merchant.channelMerchantName ?? '';
|
||||
channelMerchantId.value = String(merchant.id ?? '');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handleBack() {
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
// product 由本页所属渠道决定(抖音直连)
|
||||
const product = ProductEnum.DOUYIN_PAY;
|
||||
if (id) {
|
||||
if (channelMerchantId.value) {
|
||||
router.push({
|
||||
path: '/mch/channel-merchant/detail',
|
||||
query: { id, product },
|
||||
query: { id: channelMerchantId.value },
|
||||
});
|
||||
} else {
|
||||
router.push({ path: '/mch/channel-merchant' });
|
||||
@@ -106,6 +109,8 @@
|
||||
return;
|
||||
}
|
||||
loadAppList();
|
||||
// 反查通道商户元数据(标题/返回)
|
||||
loadMerchantMeta();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user