新增: 轮询管理
All checks were successful
构建并部署前端到测试环境 / build-and-deploy (push) Successful in 5m17s

This commit is contained in:
sexygoat
2026-03-30 14:59:56 +08:00
parent dbe6070207
commit a05717c2ed
28 changed files with 6865 additions and 103 deletions

View File

@@ -60,10 +60,11 @@
<ElDialog
v-model="dialogVisible"
:title="dialogType === 'add' ? '新增支付配置' : '编辑支付配置'"
width="800px"
width="900px"
:close-on-click-modal="false"
@closed="handleDialogClosed"
>
<ElForm ref="formRef" :model="form" :rules="rules" label-width="130px">
<ElForm ref="formRef" :model="form" :rules="rules" label-width="140px" class="config-form">
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="配置名称" prop="name">
@@ -77,6 +78,7 @@
placeholder="请选择支付渠道类型"
style="width: 100%"
:disabled="dialogType === 'edit'"
@change="handleProviderTypeChange"
>
<ElOption label="微信直连" value="wechat" />
<ElOption label="富友支付" value="fuiou" />
@@ -95,11 +97,17 @@
<!-- 微信相关配置 -->
<template v-if="form.provider_type === 'wechat'">
<ElDivider content-position="left">小程序配置</ElDivider>
<ElDivider content-position="left">
<span class="divider-title">小程序配置</span>
</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="小程序AppID" prop="miniapp_app_id">
<ElInput v-model="form.miniapp_app_id" placeholder="请输入小程序AppID" />
<ElInput
v-model="form.miniapp_app_id"
placeholder="请输入小程序AppID"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
@@ -114,11 +122,17 @@
</ElCol>
</ElRow>
<ElDivider content-position="left">公众号配置</ElDivider>
<ElDivider content-position="left">
<span class="divider-title">公众号配置</span>
</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="公众号AppID" prop="oa_app_id">
<ElInput v-model="form.oa_app_id" placeholder="请输入公众号AppID" />
<ElInput
v-model="form.oa_app_id"
placeholder="请输入公众号AppID"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
@@ -155,19 +169,33 @@
</ElCol>
</ElRow>
<ElFormItem label="OAuth回调地址" prop="oa_oauth_redirect_url">
<ElInput v-model="form.oa_oauth_redirect_url" placeholder="请输入OAuth回调地址" />
<ElInput
v-model="form.oa_oauth_redirect_url"
placeholder="请输入OAuth回调地址"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
<ElDivider content-position="left">微信支付配置</ElDivider>
<ElDivider content-position="left">
<span class="divider-title">微信支付配置</span>
</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="微信商户号" prop="wx_mch_id">
<ElInput v-model="form.wx_mch_id" placeholder="请输入微信商户号" />
<ElInput
v-model="form.wx_mch_id"
placeholder="请输入微信商户号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="证书序列号" prop="wx_serial_no">
<ElInput v-model="form.wx_serial_no" placeholder="请输入微信证书序列号" />
<ElInput
v-model="form.wx_serial_no"
placeholder="请输入微信证书序列号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
</ElRow>
@@ -194,7 +222,11 @@
</ElCol>
</ElRow>
<ElFormItem label="支付回调地址" prop="wx_notify_url">
<ElInput v-model="form.wx_notify_url" placeholder="请输入微信支付回调地址" />
<ElInput
v-model="form.wx_notify_url"
placeholder="请输入微信支付回调地址"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
<ElRow :gutter="20">
<ElCol :span="12">
@@ -222,33 +254,207 @@
<!-- 富友支付配置 -->
<template v-if="form.provider_type === 'fuiou'">
<ElDivider content-position="left">富友支付配置</ElDivider>
<ElDivider content-position="left">小程序配置</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="小程序AppID" prop="miniapp_app_id">
<ElInput
v-model="form.miniapp_app_id"
placeholder="请输入小程序AppID"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="小程序AppSecret" prop="miniapp_app_secret">
<ElInput
v-model="form.miniapp_app_secret"
type="password"
show-password
placeholder="请输入小程序AppSecret"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElDivider content-position="left">
<span class="divider-title">公众号配置</span>
</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="公众号AppID" prop="oa_app_id">
<ElInput
v-model="form.oa_app_id"
placeholder="请输入公众号AppID"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="公众号AppSecret" prop="oa_app_secret">
<ElInput
v-model="form.oa_app_secret"
type="password"
show-password
placeholder="请输入公众号AppSecret"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="公众号Token" prop="oa_token">
<ElInput
v-model="form.oa_token"
type="password"
show-password
placeholder="请输入公众号Token"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="公众号AES Key" prop="oa_aes_key">
<ElInput
v-model="form.oa_aes_key"
type="password"
show-password
placeholder="请输入公众号AES加密Key"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElFormItem label="OAuth回调地址" prop="oa_oauth_redirect_url">
<ElInput
v-model="form.oa_oauth_redirect_url"
placeholder="请输入OAuth回调地址"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
<ElDivider content-position="left">
<span class="divider-title">微信支付配置</span>
</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="微信商户号" prop="wx_mch_id">
<ElInput
v-model="form.wx_mch_id"
placeholder="请输入微信商户号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="证书序列号" prop="wx_serial_no">
<ElInput
v-model="form.wx_serial_no"
placeholder="请输入微信证书序列号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="APIv2密钥" prop="wx_api_v2_key">
<ElInput
v-model="form.wx_api_v2_key"
type="password"
show-password
placeholder="请输入微信APIv2密钥"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="APIv3密钥" prop="wx_api_v3_key">
<ElInput
v-model="form.wx_api_v3_key"
type="password"
show-password
placeholder="请输入微信APIv3密钥"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElFormItem label="支付回调地址" prop="wx_notify_url">
<ElInput
v-model="form.wx_notify_url"
placeholder="请输入微信支付回调地址"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="支付证书" prop="wx_cert_content">
<ElInput
v-model="form.wx_cert_content"
type="textarea"
:rows="3"
placeholder="请粘贴PEM格式证书内容"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="支付密钥" prop="wx_key_content">
<ElInput
v-model="form.wx_key_content"
type="textarea"
:rows="3"
placeholder="请粘贴PEM格式密钥内容"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElDivider content-position="left">
<span class="divider-title">富友支付配置</span>
</ElDivider>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="富友API地址" prop="fy_api_url">
<ElInput v-model="form.fy_api_url" placeholder="请输入富友API地址" />
<ElInput
v-model="form.fy_api_url"
placeholder="请输入富友API地址"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="富友机构号" prop="fy_ins_cd">
<ElInput v-model="form.fy_ins_cd" placeholder="请输入富友机构号" />
<ElInput
v-model="form.fy_ins_cd"
placeholder="请输入富友机构号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElRow :gutter="20">
<ElCol :span="12">
<ElFormItem label="富友商户号" prop="fy_mchnt_cd">
<ElInput v-model="form.fy_mchnt_cd" placeholder="请输入富友商户号" />
<ElInput
v-model="form.fy_mchnt_cd"
placeholder="请输入富友商户号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="富友终端号" prop="fy_term_id">
<ElInput v-model="form.fy_term_id" placeholder="请输入富友终端号" />
<ElInput
v-model="form.fy_term_id"
placeholder="请输入富友终端号"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
</ElCol>
</ElRow>
<ElFormItem label="支付回调地址" prop="fy_notify_url">
<ElInput v-model="form.fy_notify_url" placeholder="请输入富友支付回调地址" />
<ElInput
v-model="form.fy_notify_url"
placeholder="请输入富友支付回调地址"
:disabled="dialogType === 'edit'"
/>
</ElFormItem>
<ElRow :gutter="20">
<ElCol :span="12">
@@ -289,7 +495,7 @@
</template>
<script setup lang="ts">
import { h } from 'vue'
import { h, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import { WechatConfigService } from '@/api/modules'
import { ElMessage, ElTag, ElMessageBox, ElSwitch, ElButton } from 'element-plus'
@@ -387,51 +593,73 @@
{ label: '更新时间', prop: 'updated_at' }
]
// 动态表单验证规则
const rules = computed<FormRules>(() => {
const baseRules: FormRules = {
name: [{ required: true, message: '请输入配置名称', trigger: 'blur' }],
provider_type: [{ required: true, message: '请选择支付渠道类型', trigger: 'change' }]
// URL格式验证规则
const urlValidator = (rule: any, value: any, callback: any) => {
if (!value) {
callback()
return
}
const urlPattern = /^(https?:\/\/)[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?$/
if (!urlPattern.test(value)) {
callback(new Error('请输入正确的URL格式(http://或https://)'))
} else {
callback()
}
}
// 只在创建模式下添加必填验证
if (dialogType.value === 'add') {
if (form.provider_type === 'wechat') {
// 微信直连必填字段
baseRules.wx_mch_id = [{ required: true, message: '请输入微信商户号', trigger: 'blur' }]
baseRules.wx_api_v3_key = [
{ required: true, message: '请输入微信APIv3密钥', trigger: 'blur' }
]
baseRules.wx_cert_content = [
{ required: true, message: '请输入微信支付证书内容', trigger: 'blur' }
]
baseRules.wx_key_content = [
{ required: true, message: '请输入微信支付密钥内容', trigger: 'blur' }
]
baseRules.wx_serial_no = [
{ required: true, message: '请输入微信证书序列号', trigger: 'blur' }
]
baseRules.wx_notify_url = [
{ required: true, message: '请输入微信支付回调地址', trigger: 'blur' }
]
} else if (form.provider_type === 'fuiou') {
// 富友支付必填字段
baseRules.fy_api_url = [{ required: true, message: '请输入富友API地址', trigger: 'blur' }]
baseRules.fy_ins_cd = [{ required: true, message: '请输入富友机构号', trigger: 'blur' }]
baseRules.fy_mchnt_cd = [{ required: true, message: '请输入富友商户号', trigger: 'blur' }]
baseRules.fy_term_id = [{ required: true, message: '请输入富友终端号', trigger: 'blur' }]
baseRules.fy_private_key = [{ required: true, message: '请输入富友私钥', trigger: 'blur' }]
baseRules.fy_public_key = [{ required: true, message: '请输入富友公钥', trigger: 'blur' }]
baseRules.fy_notify_url = [
{ required: true, message: '请输入富友支付回调地址', trigger: 'blur' }
]
// 自定义验证器 - 编辑模式下允许为空,新增模式下必填
const createRequiredValidator = (fieldName: string) => {
return (rule: any, value: any, callback: any) => {
if (dialogType.value === 'add' && !value) {
callback(new Error(`请输入${fieldName}`))
} else {
callback()
}
}
}
return baseRules
// 静态验证规则 - 一次性定义所有规则
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入配置名称', trigger: 'blur' }],
provider_type: [{ required: true, message: '请选择支付渠道类型', trigger: 'change' }],
// 所有字段的验证规则都定义好
miniapp_app_id: [{ required: true, validator: createRequiredValidator('小程序AppID'), trigger: 'blur' }],
miniapp_app_secret: [{ required: true, validator: createRequiredValidator('小程序AppSecret'), trigger: 'blur' }],
oa_app_id: [{ required: true, validator: createRequiredValidator('公众号AppID'), trigger: 'blur' }],
oa_app_secret: [{ required: true, validator: createRequiredValidator('公众号AppSecret'), trigger: 'blur' }],
oa_token: [{ required: true, validator: createRequiredValidator('公众号Token'), trigger: 'blur' }],
oa_aes_key: [{ required: true, validator: createRequiredValidator('公众号AES Key'), trigger: 'blur' }],
oa_oauth_redirect_url: [
{ required: true, validator: createRequiredValidator('OAuth回调地址'), trigger: 'blur' },
{ validator: urlValidator, trigger: 'blur' }
],
wx_mch_id: [{ required: true, validator: createRequiredValidator('微信商户号'), trigger: 'blur' }],
wx_api_v2_key: [{ required: true, validator: createRequiredValidator('微信APIv2密钥'), trigger: 'blur' }],
wx_api_v3_key: [{ required: true, validator: createRequiredValidator('微信APIv3密钥'), trigger: 'blur' }],
wx_serial_no: [{ required: true, validator: createRequiredValidator('微信证书序列号'), trigger: 'blur' }],
wx_cert_content: [{ required: true, validator: createRequiredValidator('微信支付证书内容'), trigger: 'blur' }],
wx_key_content: [{ required: true, validator: createRequiredValidator('微信支付密钥内容'), trigger: 'blur' }],
wx_notify_url: [
{ required: true, validator: createRequiredValidator('微信支付回调地址'), trigger: 'blur' },
{ validator: urlValidator, trigger: 'blur' }
],
fy_api_url: [
{ required: true, validator: createRequiredValidator('富友API地址'), trigger: 'blur' },
{ validator: urlValidator, trigger: 'blur' }
],
fy_ins_cd: [{ required: true, validator: createRequiredValidator('富友机构号'), trigger: 'blur' }],
fy_mchnt_cd: [{ required: true, validator: createRequiredValidator('富友商户号'), trigger: 'blur' }],
fy_term_id: [{ required: true, validator: createRequiredValidator('富友终端号'), trigger: 'blur' }],
fy_private_key: [{ required: true, validator: createRequiredValidator('富友私钥'), trigger: 'blur' }],
fy_public_key: [{ required: true, validator: createRequiredValidator('富友公钥'), trigger: 'blur' }],
fy_notify_url: [
{ required: true, validator: createRequiredValidator('富友支付回调地址'), trigger: 'blur' },
{ validator: urlValidator, trigger: 'blur' }
]
})
const initialFormState = {
const form = reactive({
id: 0,
name: '',
provider_type: 'wechat' as PaymentProviderType,
description: '',
@@ -456,9 +684,36 @@
fy_notify_url: '',
fy_private_key: '',
fy_public_key: ''
}
})
const form = reactive({ id: 0, ...initialFormState })
// 重置表单数据
const resetForm = () => {
form.id = 0
form.name = ''
form.provider_type = 'wechat'
form.description = ''
form.miniapp_app_id = ''
form.miniapp_app_secret = ''
form.oa_app_id = ''
form.oa_app_secret = ''
form.oa_token = ''
form.oa_aes_key = ''
form.oa_oauth_redirect_url = ''
form.wx_mch_id = ''
form.wx_api_v2_key = ''
form.wx_api_v3_key = ''
form.wx_notify_url = ''
form.wx_serial_no = ''
form.wx_cert_content = ''
form.wx_key_content = ''
form.fy_api_url = ''
form.fy_ins_cd = ''
form.fy_mchnt_cd = ''
form.fy_term_id = ''
form.fy_notify_url = ''
form.fy_private_key = ''
form.fy_public_key = ''
}
const configList = ref<WechatConfig[]>([])
@@ -583,16 +838,6 @@
}
])
// 监听支付渠道类型变化,清除表单验证
watch(
() => form.provider_type,
() => {
nextTick(() => {
formRef.value?.clearValidate()
})
}
)
onMounted(() => {
getTableData()
})
@@ -650,45 +895,72 @@
// 显示创建对话框
const showCreateDialog = () => {
resetForm()
dialogType.value = 'add'
Object.assign(form, { id: 0, ...initialFormState })
dialogVisible.value = true
nextTick(() => {
formRef.value?.clearValidate()
})
}
// 处理敏感字段值 - 如果是***或[已配置]等特殊值,转换为空字符串
const processSensitiveField = (value: string | undefined | null): string => {
if (!value || value === '***' || value.includes('[已配置]') || value.includes('[未配置]')) {
return ''
}
return value
}
// 显示编辑对话框
const showEditDialog = (row: WechatConfig) => {
dialogType.value = 'edit'
Object.assign(form, {
id: row.id,
name: row.name,
provider_type: row.provider_type,
description: row.description,
miniapp_app_id: row.miniapp_app_id,
miniapp_app_secret: '',
oa_app_id: row.oa_app_id,
oa_app_secret: '',
oa_token: '',
oa_aes_key: '',
oa_oauth_redirect_url: row.oa_oauth_redirect_url,
wx_mch_id: row.wx_mch_id,
wx_api_v2_key: '',
wx_api_v3_key: '',
wx_notify_url: row.wx_notify_url,
wx_serial_no: row.wx_serial_no,
wx_cert_content: '',
wx_key_content: '',
fy_api_url: row.fy_api_url,
fy_ins_cd: row.fy_ins_cd,
fy_mchnt_cd: row.fy_mchnt_cd,
fy_term_id: row.fy_term_id,
fy_notify_url: row.fy_notify_url,
fy_private_key: '',
fy_public_key: ''
})
dialogVisible.value = true
const showEditDialog = async (row: WechatConfig) => {
// 先调用详情接口获取完整数据
try {
const res = await WechatConfigService.getWechatConfigById(row.id)
if (res.code === 0 && res.data) {
const detail = res.data
// 赋值表单数据
Object.assign(form, {
id: detail.id,
name: detail.name,
provider_type: detail.provider_type,
description: detail.description || '',
miniapp_app_id: detail.miniapp_app_id || '',
miniapp_app_secret: processSensitiveField(detail.miniapp_app_secret),
oa_app_id: detail.oa_app_id || '',
oa_app_secret: processSensitiveField(detail.oa_app_secret),
oa_token: processSensitiveField(detail.oa_token),
oa_aes_key: processSensitiveField(detail.oa_aes_key),
oa_oauth_redirect_url: detail.oa_oauth_redirect_url || '',
wx_mch_id: detail.wx_mch_id || '',
wx_api_v2_key: processSensitiveField(detail.wx_api_v2_key),
wx_api_v3_key: processSensitiveField(detail.wx_api_v3_key),
wx_notify_url: detail.wx_notify_url || '',
wx_serial_no: detail.wx_serial_no || '',
wx_cert_content: processSensitiveField(detail.wx_cert_content),
wx_key_content: processSensitiveField(detail.wx_key_content),
fy_api_url: detail.fy_api_url || '',
fy_ins_cd: detail.fy_ins_cd || '',
fy_mchnt_cd: detail.fy_mchnt_cd || '',
fy_term_id: detail.fy_term_id || '',
fy_notify_url: detail.fy_notify_url || '',
fy_private_key: processSensitiveField(detail.fy_private_key),
fy_public_key: processSensitiveField(detail.fy_public_key)
})
dialogType.value = 'edit'
dialogVisible.value = true
nextTick(() => {
formRef.value?.clearValidate()
})
}
} catch (error) {
console.error('获取详情失败:', error)
ElMessage.error('获取配置详情失败')
}
}
// 处理支付渠道类型变化
const handleProviderTypeChange = () => {
// 清除验证状态
nextTick(() => {
formRef.value?.clearValidate()
})
@@ -696,8 +968,8 @@
// 对话框关闭后的清理
const handleDialogClosed = () => {
formRef.value?.resetFields()
Object.assign(form, { id: 0, ...initialFormState })
// 不调用resetFields,因为会把数据也重置了
// 只需要什么都不做,下次打开时会重新赋值
}
// 提交表单
@@ -772,7 +1044,6 @@
}
dialogVisible.value = false
formRef.value?.resetFields()
await getTableData()
} catch (error) {
console.error(error)
@@ -898,4 +1169,46 @@
:deep(.el-table__row.table-row-with-context-menu) {
cursor: pointer;
}
.config-form {
max-height: 600px;
overflow-y: auto;
padding-right: 10px;
.divider-title {
font-size: 14px;
font-weight: 600;
color: var(--el-text-color-primary);
}
:deep(.el-divider) {
margin: 24px 0 20px 0;
}
:deep(.el-form-item) {
margin-bottom: 18px;
}
:deep(.el-input__wrapper) {
transition: all 0.3s ease;
}
:deep(.el-textarea__inner) {
transition: all 0.3s ease;
}
}
// 优化滚动条样式
.config-form::-webkit-scrollbar {
width: 6px;
}
.config-form::-webkit-scrollbar-thumb {
background-color: var(--el-border-color-darker);
border-radius: 3px;
}
.config-form::-webkit-scrollbar-track {
background-color: var(--el-fill-color-lighter);
}
</style>