mirror of
https://gitee.com/bootx/dax-pay-ui
synced 2026-08-12 23:45:39 +08:00
feat: 支付宝商户应用管理页面及国际化
This commit is contained in:
@@ -59,6 +59,17 @@ export const AlipayMchAppApi = {
|
||||
saveKeyConfig(data: AlipayMchAppKeyConfig): Promise<Result<void>> {
|
||||
return defHttp.post({ url: '/admin/alipay/mch-app/save-key-config', data });
|
||||
},
|
||||
/** 查询应用授权认证配置 */
|
||||
findAuthConfigByAppId(appId: string): Promise<Result<AlipayMchAppAuthConfig>> {
|
||||
return defHttp.get({
|
||||
url: '/admin/alipay/mch-app/find-auth-config-by-app-id',
|
||||
params: { appId },
|
||||
});
|
||||
},
|
||||
/** 保存应用授权认证配置 */
|
||||
saveAuthConfig(data: AlipayMchAppAuthConfig): Promise<Result<void>> {
|
||||
return defHttp.post({ url: '/admin/alipay/mch-app/save-auth-config', data });
|
||||
},
|
||||
};
|
||||
|
||||
/** 支付宝通道商户应用 */
|
||||
@@ -94,3 +105,17 @@ export interface AlipayMchAppKeyConfig {
|
||||
/** AES 通信密钥 */
|
||||
secretKey?: string;
|
||||
}
|
||||
|
||||
/** 支付宝通道商户应用授权认证配置 */
|
||||
export interface AlipayMchAppAuthConfig {
|
||||
/** 应用 ID */
|
||||
appId?: string;
|
||||
/** 商户号 */
|
||||
mchNo?: string;
|
||||
/** 通道商户号 */
|
||||
channelMchNo?: string;
|
||||
/** 用户标识类型 */
|
||||
userIdType?: string;
|
||||
/** 授权回调地址 */
|
||||
authCallbackUrl?: string;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
"payment": {
|
||||
"title": "Payment Management",
|
||||
"platform": "Platform Management",
|
||||
"isvList": "ISV List",
|
||||
"isvManage": "ISV Management",
|
||||
"isvInfoManage": "ISV Info",
|
||||
"isvEntityManage": "Entity Info",
|
||||
"merchantList": "Merchant List",
|
||||
"merchantManage": "Merchant Management",
|
||||
"merchantChannelMerchant": "Merchant Channel Merchant",
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
"aliAppIdPrefix": "App ID: {appId}",
|
||||
"detailTitle": "{name} - App Management",
|
||||
"tabBasicInfo": "Basic Info",
|
||||
"tabKeyConfig": "Key Config"
|
||||
"tabKeyConfig": "Key Config",
|
||||
"tabAuthConfig": "Authorization"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
"title": "Alipay Direct Management",
|
||||
"groupApp": "App Management",
|
||||
"cardMchApp": "Alipay Channel Merchant Apps",
|
||||
"cardMchAppDesc": "Manage Alipay channel merchant applications"
|
||||
"cardMchAppDesc": "Manage Alipay channel merchant applications",
|
||||
"cardAddMchApp": "Add Alipay App",
|
||||
"cardAddMchAppDesc": "Create a new Alipay channel merchant app"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"missingIsvNo": "Missing ISV number. Open from the ISV list",
|
||||
"missingMchNo": "Missing merchant number. Open from the merchant list",
|
||||
"missingAppContext": "Open channel routing from App Management",
|
||||
"productDetail": {
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
"payment": {
|
||||
"title": "支付管理",
|
||||
"platform": "平台管理",
|
||||
"isvList": "服务商列表",
|
||||
"isvManage": "服务商管理",
|
||||
"isvInfoManage": "服务商信息",
|
||||
"isvEntityManage": "主体信息",
|
||||
"merchantList": "商户列表",
|
||||
"merchantManage": "商户管理",
|
||||
"merchantChannelMerchant": "商户通道商户",
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
"aliAppIdPrefix": "AppId:{appId}",
|
||||
"detailTitle": "{name} - 应用管理",
|
||||
"tabBasicInfo": "基础信息",
|
||||
"tabKeyConfig": "密钥配置"
|
||||
"tabKeyConfig": "密钥配置",
|
||||
"tabAuthConfig": "授权认证"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
"title": "支付宝直连管理",
|
||||
"groupApp": "应用管理",
|
||||
"cardMchApp": "支付宝通道商户应用",
|
||||
"cardMchAppDesc": "管理支付宝通道商户应用"
|
||||
"cardMchAppDesc": "管理支付宝通道商户应用",
|
||||
"cardAddMchApp": "添加支付宝应用",
|
||||
"cardAddMchAppDesc": "创建新的支付宝通道商户应用"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"missingIsvNo": "缺少服务商编号,请从服务商列表进入",
|
||||
"missingMchNo": "缺少商户编号,请从商户列表进入",
|
||||
"missingAppContext": "请从应用管理进入通道路由配置",
|
||||
"productDetail": {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { ChannelMerchantAlipayApi } from '#/api/payment/channelMerchant.api';
|
||||
import ChannelLogo from '#/components/channel/ChannelLogo.vue';
|
||||
import { channelI18nMap, channelNameMap } from '#/enums/payment';
|
||||
import { ProductEnum } from '#/enums/payment/productEnum';
|
||||
import { channelI18nMap, channelNameMap, productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
|
||||
defineOptions({ name: 'AlipayDirectMchCreateConfig' });
|
||||
@@ -17,7 +17,6 @@ const emit = defineEmits<{
|
||||
(e: 'close'): void;
|
||||
}>();
|
||||
|
||||
const router = useRouter();
|
||||
const { message } = useMessage();
|
||||
|
||||
const mchNo = ref('');
|
||||
@@ -30,6 +29,7 @@ const form = ref({
|
||||
});
|
||||
|
||||
const visible = ref(false);
|
||||
const createSuccess = ref(false);
|
||||
const submitLoading = ref(false);
|
||||
|
||||
const channelDisplayName = computed(() => {
|
||||
@@ -42,6 +42,17 @@ const channelDisplayName = computed(() => {
|
||||
return channelNameMap[channel] || channel;
|
||||
});
|
||||
|
||||
/** 支付产品展示名称,区分服务商/直连等模式 */
|
||||
const productDisplayName = computed(() => {
|
||||
const product = productCode.value;
|
||||
if (!product) return '-';
|
||||
const i18nKey = productI18nMap[product];
|
||||
if (i18nKey) {
|
||||
return $t(i18nKey);
|
||||
}
|
||||
return productNameMap[product] || product;
|
||||
});
|
||||
|
||||
const rules = computed(() => ({
|
||||
channelMerchantName: [{ required: true, message: $t('payment.merchant.channelMerchant.channelMerchantNameRequired') }],
|
||||
alipayUserId: [{ required: true, message: $t('payment.channel.alipay.validation.alipayUserIdRequired') }],
|
||||
@@ -52,6 +63,7 @@ function init(no: string, product: string, channel: string) {
|
||||
productCode.value = product;
|
||||
channelCode.value = channel;
|
||||
visible.value = true;
|
||||
createSuccess.value = false;
|
||||
resetForm();
|
||||
}
|
||||
|
||||
@@ -68,16 +80,9 @@ function handleSubmit() {
|
||||
channel: 'alipay',
|
||||
...form.value,
|
||||
})
|
||||
.then(({ data }) => {
|
||||
.then(() => {
|
||||
createSuccess.value = true;
|
||||
message.success($t('payment.merchant.channelMerchant.createSuccess'));
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant/detail',
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
id: data ? String(data) : '',
|
||||
product: productCode.value || ProductEnum.ALIPAY,
|
||||
},
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
submitLoading.value = false;
|
||||
@@ -100,44 +105,61 @@ defineExpose({ init });
|
||||
|
||||
<template>
|
||||
<div v-if="visible">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
:validate-trigger="['blur', 'change']"
|
||||
>
|
||||
<!-- 国际化:支付产品 -->
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.product')">
|
||||
<div class="flex items-center gap-2 h-8">
|
||||
<ChannelLogo v-if="channelCode" :channel="channelCode" :size="24" />
|
||||
<span class="text-foreground">{{ channelDisplayName }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 国际化:商户名称 -->
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.channelMerchantName')" name="channelMerchantName">
|
||||
<a-input
|
||||
v-model:value="form.channelMerchantName"
|
||||
:placeholder="$t('payment.merchant.channelMerchant.pleaseInputName')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- 国际化:支付宝商家用户 ID(PID) -->
|
||||
<a-form-item :label="$t('payment.channel.alipay.alipayUserId')" name="alipayUserId">
|
||||
<a-input
|
||||
v-model:value="form.alipayUserId"
|
||||
:placeholder="$t('payment.channel.alipay.validation.alipayUserIdRequired')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<div v-if="!createSuccess">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
:label-col="{ span: 6 }"
|
||||
:wrapper-col="{ span: 16 }"
|
||||
:validate-trigger="['blur', 'change']"
|
||||
>
|
||||
<!-- 国际化:支付产品 -->
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.product')">
|
||||
<div class="flex items-center gap-2 h-8">
|
||||
<ChannelLogo v-if="channelCode" :channel="channelCode" :size="24" />
|
||||
<span class="text-foreground">{{ productDisplayName }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 国际化:商户名称 -->
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.channelMerchantName')" name="channelMerchantName">
|
||||
<a-input
|
||||
v-model:value="form.channelMerchantName"
|
||||
:placeholder="$t('payment.merchant.channelMerchant.pleaseInputName')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- 国际化:支付宝商家用户 ID(PID) -->
|
||||
<a-form-item :label="$t('payment.channel.alipay.alipayUserId')" name="alipayUserId">
|
||||
<a-input
|
||||
v-model:value="form.alipayUserId"
|
||||
:placeholder="$t('payment.channel.alipay.validation.alipayUserIdRequired')"
|
||||
/>
|
||||
</a-form-item>
|
||||
|
||||
<div class="flex justify-center gap-4 mt-8 pt-6 border-t border-border">
|
||||
<a-button @click="handlePrev">
|
||||
{{ $t('payment.merchant.channelMerchant.prevStep') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
{{ $t('payment.merchant.channelMerchant.create') }}
|
||||
</a-button>
|
||||
<div class="flex justify-center gap-4 mt-8 pt-6 border-t border-border">
|
||||
<a-button @click="handlePrev">
|
||||
{{ $t('payment.merchant.channelMerchant.prevStep') }}
|
||||
</a-button>
|
||||
<a-button type="primary" :loading="submitLoading" @click="handleSubmit">
|
||||
{{ $t('payment.merchant.channelMerchant.create') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
</div>
|
||||
|
||||
<div v-else class="flex flex-col items-center justify-center py-12">
|
||||
<div class="w-20 h-20 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center mb-6">
|
||||
<IconifyIcon icon="ant-design:check-circle-filled" class="text-4xl text-green-500" />
|
||||
</div>
|
||||
</a-form>
|
||||
<div class="text-xl font-bold text-foreground mb-2">{{
|
||||
$t('payment.merchant.channelMerchant.createSuccess')
|
||||
}}</div>
|
||||
<div class="text-sm text-muted-foreground mb-8">{{
|
||||
$t('payment.merchant.channelMerchant.createSuccessDesc')
|
||||
}}</div>
|
||||
<a-button type="primary" @click="emit('close')">
|
||||
{{ $t('payment.merchant.channelMerchant.closePage') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { IconifyIcon } from '@vben-core/icons';
|
||||
import { type AlipayIsvApp, AlipayIsvAppApi } from '#/api/payment/alipayIsvApp.api';
|
||||
import { ChannelMerchantAlipayApi } from '#/api/payment/channelMerchant.api';
|
||||
import ChannelLogo from '#/components/channel/ChannelLogo.vue';
|
||||
import { channelI18nMap, channelNameMap } from '#/enums/payment';
|
||||
import { channelI18nMap, channelNameMap, productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
|
||||
defineOptions({ name: 'AlipayMchCreateConfig' });
|
||||
@@ -21,7 +21,6 @@ const emit = defineEmits<{
|
||||
const { message } = useMessage();
|
||||
|
||||
const mchNo = ref('');
|
||||
const isvNo = ref('');
|
||||
const productCode = ref('');
|
||||
const channelCode = ref('');
|
||||
const formRef = ref();
|
||||
@@ -49,6 +48,17 @@ const channelDisplayName = computed(() => {
|
||||
return channelNameMap[channel] || channel;
|
||||
});
|
||||
|
||||
/** 支付产品展示名称,区分服务商/直连等模式 */
|
||||
const productDisplayName = computed(() => {
|
||||
const product = productCode.value;
|
||||
if (!product) return '-';
|
||||
const i18nKey = productI18nMap[product];
|
||||
if (i18nKey) {
|
||||
return $t(i18nKey);
|
||||
}
|
||||
return productNameMap[product] || product;
|
||||
});
|
||||
|
||||
const rules = computed(() => ({
|
||||
channelMerchantName: [{ required: true, message: $t('payment.merchant.channelMerchant.channelMerchantNameRequired') }],
|
||||
isvAppId: [{ required: true, message: $t('payment.merchant.channelMerchant.alipayIsvAppRequired') }],
|
||||
@@ -64,13 +74,10 @@ const isvAppOptions = computed(() =>
|
||||
})),
|
||||
);
|
||||
|
||||
/** 加载支付宝服务商应用下拉列表(开源版全局共享,无服务商号隔离) */
|
||||
function loadIsvAppList() {
|
||||
if (!isvNo.value) {
|
||||
isvAppList.value = [];
|
||||
return;
|
||||
}
|
||||
isvAppLoading.value = true;
|
||||
AlipayIsvAppApi.listByIsvNo(isvNo.value)
|
||||
AlipayIsvAppApi.listAll()
|
||||
.then(({ data }) => {
|
||||
isvAppList.value = data || [];
|
||||
})
|
||||
@@ -79,9 +86,8 @@ function loadIsvAppList() {
|
||||
});
|
||||
}
|
||||
|
||||
function init(no: string, product: string, channel: string, isv: string) {
|
||||
function init(no: string, product: string, channel: string) {
|
||||
mchNo.value = no;
|
||||
isvNo.value = isv;
|
||||
productCode.value = product;
|
||||
channelCode.value = channel;
|
||||
visible.value = true;
|
||||
@@ -163,7 +169,7 @@ defineExpose({ init, validate, getData, submit });
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.product')">
|
||||
<div class="flex items-center gap-2 h-8">
|
||||
<ChannelLogo v-if="channelCode" :channel="channelCode" :size="24" />
|
||||
<span class="text-foreground">{{ channelDisplayName }}</span>
|
||||
<span class="text-foreground">{{ productDisplayName }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 国际化:商户名称 -->
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import type { ChannelMerchantResult } from '#/api/payment/channelMerchant.api';
|
||||
|
||||
import AlipayChannelMerchantBasicInfo from './AlipayChannelMerchantBasicInfo.vue';
|
||||
import AlipayMchAppEdit from './app/AlipayMchAppEdit.vue';
|
||||
|
||||
defineOptions({ name: 'AlipayMchManage' });
|
||||
|
||||
@@ -18,6 +19,7 @@
|
||||
const channelMchNo = ref('');
|
||||
const channelMerchant = ref<ChannelMerchantResult>({});
|
||||
const basicInfoRef = ref<InstanceType<typeof AlipayChannelMerchantBasicInfo>>();
|
||||
const mchAppEditRef = ref<InstanceType<typeof AlipayMchAppEdit>>();
|
||||
|
||||
/** 功能卡片配置 */
|
||||
const functionCards = computed(() => [
|
||||
@@ -40,6 +42,14 @@
|
||||
group: $t('payment.channel.alipayMchManage.groupApp'),
|
||||
color: 'blue',
|
||||
cards: [
|
||||
{
|
||||
key: 'addMchApp',
|
||||
// 国际化:添加支付宝应用
|
||||
title: $t('payment.channel.alipayMchManage.cardAddMchApp'),
|
||||
icon: 'ant-design:plus-circle-outlined',
|
||||
// 国际化:创建新的支付宝通道商户应用
|
||||
description: $t('payment.channel.alipayMchManage.cardAddMchAppDesc'),
|
||||
},
|
||||
{
|
||||
key: 'mchApp',
|
||||
// 国际化:通道商户应用
|
||||
@@ -78,21 +88,33 @@
|
||||
channelMerchant.value = summary;
|
||||
}
|
||||
|
||||
/** 添加应用成功,跳转到应用管理页 */
|
||||
function handleAddAppOk() {
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant/alipay-app-manage',
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
channelMchNo: channelMchNo.value,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** 卡片点击 */
|
||||
function handleCardClick(card: { key: string; route?: string }) {
|
||||
if (card.key === 'basicInfo') {
|
||||
basicInfoRef.value?.open();
|
||||
return;
|
||||
}
|
||||
if (card.key === 'addMchApp') {
|
||||
mchAppEditRef.value?.show(mchNo.value, channelMchNo.value);
|
||||
return;
|
||||
}
|
||||
if (card.route) {
|
||||
router.push({
|
||||
path: card.route,
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
channelMchNo: channelMchNo.value,
|
||||
channelMerchantName: channelMerchant.value.channelMerchantName || '',
|
||||
channelMerchantId: channelMerchant.value.id || '',
|
||||
product: channelMerchant.value.product || '',
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -154,6 +176,7 @@
|
||||
:channel-mch-no="channelMchNo"
|
||||
:channel-merchant="channelMerchant"
|
||||
/>
|
||||
<AlipayMchAppEdit ref="mchAppEditRef" @ok="handleAddAppOk" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { AlipayMchAppApi, type AlipayMchApp } from '#/api/payment/alipayMchApp.api';
|
||||
|
||||
import AlipayMchAppAuthConfig from './tabs/AlipayMchAppAuthConfig.vue';
|
||||
import AlipayMchAppBasicInfo from './tabs/AlipayMchAppBasicInfo.vue';
|
||||
import AlipayMchAppKeyConfig from './tabs/AlipayMchAppKeyConfig.vue';
|
||||
|
||||
@@ -77,6 +78,13 @@
|
||||
:ali-app-id="appDetail.aliAppId"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="auth" :tab="$t('payment.channel.alipayMchApp.tabAuthConfig')">
|
||||
<AlipayMchAppAuthConfig
|
||||
:app-id="appDetail.id!"
|
||||
:mch-no="mchNo"
|
||||
:channel-mch-no="channelMchNo"
|
||||
/>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
|
||||
@@ -82,18 +82,21 @@
|
||||
channelMerchantName.value = normalizeRouteQueryValue(route.query.channelMerchantName);
|
||||
}
|
||||
|
||||
/** 返回通道商户详情 */
|
||||
/** 返回通道商户详情或列表 */
|
||||
function handleBack() {
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
const product = normalizeRouteQueryValue(route.query.product) || ProductEnum.ALIPAY;
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant/detail',
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
id,
|
||||
product,
|
||||
},
|
||||
});
|
||||
if (id) {
|
||||
const product = normalizeRouteQueryValue(route.query.product) || ProductEnum.ALIPAY;
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant/detail',
|
||||
query: { mchNo: mchNo.value, id, product },
|
||||
});
|
||||
} else {
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant',
|
||||
query: { mchNo: mchNo.value },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { AlipayMchAppApi, type AlipayMchAppAuthConfig } from '#/api/payment/alipayMchApp.api';
|
||||
import { PermCodes } from '#/constants/perm-codes';
|
||||
import { useFormEdit } from '#/hooks/useFormEdit';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
import { usePermission } from '#/hooks/usePermission';
|
||||
|
||||
const props = defineProps<{
|
||||
appId?: string;
|
||||
mchNo?: string;
|
||||
channelMchNo?: string;
|
||||
}>();
|
||||
|
||||
const { labelCol, wrapperCol } = useFormEdit();
|
||||
const { confirm, message } = useMessage();
|
||||
const { hasPermission } = usePermission();
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
// 编辑模式
|
||||
const isEditing = ref(false);
|
||||
const formRef = ref();
|
||||
const formState = ref<AlipayMchAppAuthConfig>({
|
||||
userIdType: 'openid',
|
||||
});
|
||||
|
||||
const canEdit = computed(() => hasPermission(PermCodes.Payment.ChannelMerchant.EDIT));
|
||||
|
||||
/** 表单校验规则 */
|
||||
const formRules = computed(() => ({
|
||||
userIdType: [{ required: true, message: $t('payment.channel.alipayIsv.validation.userIdType') }],
|
||||
authCallbackUrl: [
|
||||
{ required: true, message: $t('payment.channel.alipayIsv.validation.authCallbackUrl') },
|
||||
],
|
||||
}));
|
||||
|
||||
/**
|
||||
* 加载授权认证配置
|
||||
*/
|
||||
function loadConfig() {
|
||||
if (!props.appId) return;
|
||||
loading.value = true;
|
||||
AlipayMchAppApi.findAuthConfigByAppId(props.appId)
|
||||
.then(({ data }) => {
|
||||
formState.value = {
|
||||
userIdType: 'openid',
|
||||
...data,
|
||||
appId: props.appId,
|
||||
mchNo: props.mchNo,
|
||||
channelMchNo: props.channelMchNo,
|
||||
};
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 进入编辑模式
|
||||
*/
|
||||
function handleEdit() {
|
||||
isEditing.value = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消编辑
|
||||
*/
|
||||
function handleCancel() {
|
||||
confirm({
|
||||
title: $t('common.confirm'),
|
||||
content: $t('common.confirmCancelContent'),
|
||||
okText: $t('common.okText'),
|
||||
cancelText: $t('common.cancelText'),
|
||||
onOk() {
|
||||
loadConfig();
|
||||
isEditing.value = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置
|
||||
*/
|
||||
async function handleSave() {
|
||||
await formRef.value?.validate();
|
||||
confirm({
|
||||
title: $t('common.confirm'),
|
||||
content: $t('common.confirmSaveContent'),
|
||||
okText: $t('common.okText'),
|
||||
cancelText: $t('common.cancelText'),
|
||||
onOk() {
|
||||
saving.value = true;
|
||||
const submitData: AlipayMchAppAuthConfig = {
|
||||
...formState.value,
|
||||
appId: props.appId,
|
||||
mchNo: props.mchNo,
|
||||
channelMchNo: props.channelMchNo,
|
||||
};
|
||||
return AlipayMchAppApi.saveAuthConfig(submitData)
|
||||
.then(() => {
|
||||
message.success($t('common.saveSuccess'));
|
||||
isEditing.value = false;
|
||||
loadConfig();
|
||||
})
|
||||
.finally(() => {
|
||||
saving.value = false;
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.appId,
|
||||
(appId) => {
|
||||
if (appId) {
|
||||
isEditing.value = false;
|
||||
loadConfig();
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="auth-config-panel">
|
||||
<a-card variant="borderless" class="rounded-xl shadow-sm">
|
||||
<template #title>
|
||||
<!-- 国际化:授权认证配置 -->
|
||||
<span class="text-base font-semibold text-foreground">
|
||||
{{ $t('payment.channel.alipayIsv.authConfigTitle') }}
|
||||
</span>
|
||||
</template>
|
||||
<template #extra>
|
||||
<template v-if="canEdit && !isEditing">
|
||||
<!-- 国际化:编辑 -->
|
||||
<a-button type="primary" @click="handleEdit">{{ $t('common.edit') }}</a-button>
|
||||
</template>
|
||||
<template v-else-if="canEdit && isEditing">
|
||||
<a-space>
|
||||
<a-button @click="handleCancel">{{ $t('common.cancelText') }}</a-button>
|
||||
<a-button type="primary" :loading="saving" @click="handleSave">
|
||||
{{ $t('common.save') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<a-spin :spinning="loading">
|
||||
<a-form
|
||||
ref="formRef"
|
||||
:model="formState"
|
||||
:rules="formRules"
|
||||
:label-col="labelCol"
|
||||
:wrapper-col="wrapperCol"
|
||||
:validate-trigger="['blur', 'change']"
|
||||
class="form-compact max-w-3xl"
|
||||
>
|
||||
<!-- 用户标识类型 -->
|
||||
<a-form-item :label="$t('payment.channel.alipayIsv.userIdType')" name="userIdType">
|
||||
<a-radio-group v-model:value="formState.userIdType" :disabled="!isEditing">
|
||||
<a-radio value="openid">{{ $t('payment.channel.alipayIsv.userIdTypeOpenid') }}</a-radio>
|
||||
<a-radio value="userid">{{ $t('payment.channel.alipayIsv.userIdTypeUserid') }}</a-radio>
|
||||
<a-radio value="openid_userid">{{ $t('payment.channel.alipayIsv.userIdTypeBoth') }}</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 授权回调地址 -->
|
||||
<a-form-item :label="$t('payment.channel.alipayIsv.authCallbackUrl')" name="authCallbackUrl">
|
||||
<a-input
|
||||
v-model:value="formState.authCallbackUrl"
|
||||
:placeholder="$t('payment.channel.alipayIsv.authCallbackUrlPlaceholder')"
|
||||
:disabled="!isEditing"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-spin>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.auth-config-panel {
|
||||
padding: 4px 0;
|
||||
}
|
||||
</style>
|
||||
@@ -7,7 +7,7 @@ import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { ChannelMerchantDouyinApi } from '#/api/payment/channelMerchant.api';
|
||||
import ChannelLogo from '#/components/channel/ChannelLogo.vue';
|
||||
import { channelI18nMap, channelNameMap } from '#/enums/payment';
|
||||
import { channelI18nMap, channelNameMap, productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
|
||||
defineOptions({ name: 'DouyinMchCreateConfig' });
|
||||
@@ -44,6 +44,17 @@ const channelDisplayName = computed(() => {
|
||||
return channelNameMap[channel] || channel;
|
||||
});
|
||||
|
||||
/** 支付产品展示名称,区分服务商/直连等模式 */
|
||||
const productDisplayName = computed(() => {
|
||||
const product = productCode.value;
|
||||
if (!product) return '-';
|
||||
const i18nKey = productI18nMap[product];
|
||||
if (i18nKey) {
|
||||
return $t(i18nKey);
|
||||
}
|
||||
return productNameMap[product] || product;
|
||||
});
|
||||
|
||||
const rules = computed(() => ({
|
||||
channelMerchantName: [{ required: true, message: $t('payment.merchant.channelMerchant.channelMerchantNameRequired') }],
|
||||
douyinMchId: [{ required: true, message: $t('payment.channel.douyin.validation.douyinMchIdRequired') }],
|
||||
@@ -113,7 +124,7 @@ defineExpose({ init });
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.product')">
|
||||
<div class="flex items-center gap-2 h-8">
|
||||
<ChannelLogo v-if="channelCode" :channel="channelCode" :size="24" />
|
||||
<span class="text-foreground">{{ channelDisplayName }}</span>
|
||||
<span class="text-foreground">{{ productDisplayName }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 国际化:商户名称 -->
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { ChannelMerchantLakalaApi } from '#/api/payment/channelMerchant.api';
|
||||
import ChannelLogo from '#/components/channel/ChannelLogo.vue';
|
||||
import { channelI18nMap, channelNameMap } from '#/enums/payment';
|
||||
import { channelI18nMap, channelNameMap, productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
|
||||
defineOptions({ name: 'LakalaMchCreateConfig' });
|
||||
@@ -42,6 +42,17 @@ const channelDisplayName = computed(() => {
|
||||
return channelNameMap[channel] || channel;
|
||||
});
|
||||
|
||||
/** 支付产品展示名称,区分服务商/直连等模式 */
|
||||
const productDisplayName = computed(() => {
|
||||
const product = productCode.value;
|
||||
if (!product) return '-';
|
||||
const i18nKey = productI18nMap[product];
|
||||
if (i18nKey) {
|
||||
return $t(i18nKey);
|
||||
}
|
||||
return productNameMap[product] || product;
|
||||
});
|
||||
|
||||
const rules = computed(() => ({
|
||||
channelMerchantName: [{ required: true, message: $t('payment.merchant.channelMerchant.channelMerchantNameRequired') }],
|
||||
termNo: [{ required: true, message: $t('payment.channel.lakalaIsv.validation.termNo') }],
|
||||
@@ -123,7 +134,7 @@ defineExpose({ init, validate, getData, submit });
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.product')">
|
||||
<div class="flex items-center gap-2 h-8">
|
||||
<ChannelLogo v-if="channelCode" :channel="channelCode" :size="24" />
|
||||
<span class="text-foreground">{{ channelDisplayName }}</span>
|
||||
<span class="text-foreground">{{ productDisplayName }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 国际化:商户名称 -->
|
||||
|
||||
@@ -7,7 +7,7 @@ import { IconifyIcon } from '@vben-core/icons';
|
||||
|
||||
import { ChannelMerchantWechatApi } from '#/api/payment/channelMerchant.api';
|
||||
import ChannelLogo from '#/components/channel/ChannelLogo.vue';
|
||||
import { channelI18nMap, channelNameMap } from '#/enums/payment';
|
||||
import { channelI18nMap, channelNameMap, productI18nMap, productNameMap } from '#/enums/payment';
|
||||
import { useMessage } from '#/hooks/useMessage';
|
||||
|
||||
defineOptions({ name: 'WechatMchCreateConfig' });
|
||||
@@ -42,6 +42,17 @@ const channelDisplayName = computed(() => {
|
||||
return channelNameMap[channel] || channel;
|
||||
});
|
||||
|
||||
/** 支付产品展示名称,区分服务商/直连等模式 */
|
||||
const productDisplayName = computed(() => {
|
||||
const product = productCode.value;
|
||||
if (!product) return '-';
|
||||
const i18nKey = productI18nMap[product];
|
||||
if (i18nKey) {
|
||||
return $t(i18nKey);
|
||||
}
|
||||
return productNameMap[product] || product;
|
||||
});
|
||||
|
||||
/** 是否为微信直连产品 */
|
||||
const isDirectProduct = computed(() => productCode.value === 'wechat_pay');
|
||||
|
||||
@@ -145,7 +156,7 @@ defineExpose({ init, validate, getData, submit });
|
||||
<a-form-item :label="$t('payment.merchant.channelMerchant.product')">
|
||||
<div class="flex items-center gap-2 h-8">
|
||||
<ChannelLogo v-if="channelCode" :channel="channelCode" :size="24" />
|
||||
<span class="text-foreground">{{ channelDisplayName }}</span>
|
||||
<span class="text-foreground">{{ productDisplayName }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
<!-- 国际化:商户名称 -->
|
||||
|
||||
@@ -89,9 +89,6 @@
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
channelMchNo: channelMchNo.value,
|
||||
channelMerchantName: channelMerchant.value.channelMerchantName || '',
|
||||
channelMerchantId: channelMerchant.value.id || '',
|
||||
product: channelMerchant.value.product || '',
|
||||
},
|
||||
});
|
||||
return;
|
||||
|
||||
@@ -83,17 +83,21 @@
|
||||
channelMerchantName.value = normalizeRouteQueryValue(route.query.channelMerchantName);
|
||||
}
|
||||
|
||||
/** 返回通道商户详情或列表 */
|
||||
function handleBack() {
|
||||
const id = normalizeRouteQueryValue(route.query.channelMerchantId);
|
||||
const product = normalizeRouteQueryValue(route.query.product) || ProductEnum.WECHAT_ISV;
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant/detail',
|
||||
query: {
|
||||
mchNo: mchNo.value,
|
||||
id,
|
||||
product,
|
||||
},
|
||||
});
|
||||
if (id) {
|
||||
const product = normalizeRouteQueryValue(route.query.product) || ProductEnum.WECHAT_ISV;
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant/detail',
|
||||
query: { mchNo: mchNo.value, id, product },
|
||||
});
|
||||
} else {
|
||||
router.push({
|
||||
path: '/payment/merchant/channel-merchant',
|
||||
query: { mchNo: mchNo.value },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
|
||||
@@ -126,7 +126,6 @@
|
||||
selectedProduct.value!.code!,
|
||||
mchNo.value,
|
||||
selectedProduct.value!.channel || '',
|
||||
'',
|
||||
selectedProduct.value!.name || getProductName(selectedProduct.value!.code || ''),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -39,12 +39,12 @@ function isUmsProduct(product: string) {
|
||||
/**
|
||||
* 初始化对应通道的配置组件
|
||||
*/
|
||||
function init(product: string, mchNo: string, channel: string, isvNo = '', productName = '') {
|
||||
function init(product: string, mchNo: string, channel: string, productName = '') {
|
||||
currentProduct.value = { product, channel };
|
||||
nextTick(() => {
|
||||
switch (product) {
|
||||
case ProductEnum.ALIPAY_ISV: {
|
||||
alipayRef.value?.init(mchNo, product, channel, isvNo);
|
||||
alipayRef.value?.init(mchNo, product, channel);
|
||||
break;
|
||||
}
|
||||
case ProductEnum.ALIPAY: {
|
||||
|
||||
@@ -240,7 +240,7 @@
|
||||
|
||||
<vxe-toolbar ref="xToolbar" custom refresh :refresh-options="{ queryMethod: loadList }">
|
||||
<template #buttons>
|
||||
<a-button v-if="hasPermission(PermCodes.Payment.ChannelMerchant.ADD)" type="primary" @click="handleCreate">
|
||||
<a-button v-if="hasPermission(PermCodes.Payment.ChannelMerchant.EDIT)" type="primary" @click="handleCreate">
|
||||
<template #icon><IconifyIcon icon="ant-design:plus-outlined" /></template>
|
||||
{{ $t('payment.merchant.channelMerchant.create') }}
|
||||
</a-button>
|
||||
|
||||
@@ -128,7 +128,6 @@
|
||||
<vxe-column field="mchNo" :title="$t('payment.merchant.base.field.mchNo')" :min-width="180" />
|
||||
<vxe-column field="mchName" :title="$t('payment.merchant.base.field.mchName')" :min-width="200" />
|
||||
<vxe-column field="mchShortName" :title="$t('payment.merchant.base.field.mchShortName')" :min-width="150" />
|
||||
<vxe-column field="isvName" :title="$t('payment.merchant.base.field.isvName')" :min-width="150" />
|
||||
<vxe-column
|
||||
field="subjectType"
|
||||
:title="$t('payment.merchant.base.field.subjectType')"
|
||||
|
||||
Reference in New Issue
Block a user