+
+
+ 新增商户
+ 刷新
+ 证书目录:{{ mchCertBase || '加载后显示' }}
+
+
+
+
+
+
+
+
+ {{ row.enabled ? '是' : '否' }}
+
+
+
+
+
+ {{ row.private_key_exists ? '已上传' : '缺失' }}
+
+
+
+
+
+
+ {{ row.platform_pub_key_exists ? '已上传' : '可选' }}
+
+
+
+
+
+ 编辑
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 数字越小越优先
+
+
+
+
+
+
+
+ 上传 apiclient_key.pem
+
+
+
+
+
+ 上传 pub_key.pem
+
+
+
+
+ 取消
+ 保存
+
+
+
@@ -209,6 +313,147 @@ const assetList = ref([])
const assetLoading = ref(false)
const assetSaving = ref(false)
+const mchLoading = ref(false)
+const mchSaving = ref(false)
+const mchList = ref([])
+const mchCertBase = ref('')
+const mchDialogVisible = ref(false)
+const mchForm = reactive({
+ id: null,
+ mch_id: '',
+ name: '',
+ appid: '',
+ api_v3_key: '',
+ cert_serial_no: '',
+ transfer_scene_id: '1005',
+ notify_url: '',
+ priority: 100,
+ enabled: true,
+ private_key_path: '',
+ platform_pub_key_path: '',
+})
+
+const loadMchList = async () => {
+ mchLoading.value = true
+ try {
+ const res = await request.post('/peizhi/wxmchlb', { username: username.value })
+ if (res.code === 403) {
+ hasPermission.value = false
+ return
+ }
+ if (res.code === 0 && res.data) {
+ mchList.value = res.data.list || []
+ mchCertBase.value = res.data.cert_base_dir || ''
+ } else {
+ ElMessage.error(res.msg || '加载商户失败')
+ }
+ } catch {
+ ElMessage.error('网络错误')
+ } finally {
+ mchLoading.value = false
+ }
+}
+
+const openMchDialog = (row) => {
+ if (row) {
+ Object.assign(mchForm, {
+ id: row.id,
+ mch_id: row.mch_id,
+ name: row.name || '',
+ appid: row.appid || '',
+ api_v3_key: '',
+ cert_serial_no: row.cert_serial_no || '',
+ transfer_scene_id: row.transfer_scene_id || '1005',
+ notify_url: row.notify_url || '',
+ priority: row.priority ?? 100,
+ enabled: !!row.enabled,
+ private_key_path: row.private_key_path || '',
+ platform_pub_key_path: row.platform_pub_key_path || '',
+ })
+ } else {
+ Object.assign(mchForm, {
+ id: null,
+ mch_id: '',
+ name: '',
+ appid: sysForm.weixin_appid || '',
+ api_v3_key: '',
+ cert_serial_no: '',
+ transfer_scene_id: '1005',
+ notify_url: '',
+ priority: 100,
+ enabled: true,
+ private_key_path: '',
+ platform_pub_key_path: '',
+ })
+ }
+ mchDialogVisible.value = true
+}
+
+const saveMch = async () => {
+ if (!mchForm.mch_id || !mchForm.appid || !mchForm.cert_serial_no) {
+ ElMessage.warning('请填写商户号、AppID、证书序列号')
+ return
+ }
+ if (!mchForm.id && !mchForm.api_v3_key) {
+ ElMessage.warning('新建必须填写 APIv3 密钥')
+ return
+ }
+ mchSaving.value = true
+ try {
+ const payload = {
+ username: username.value,
+ id: mchForm.id,
+ mch_id: mchForm.mch_id,
+ name: mchForm.name,
+ appid: mchForm.appid,
+ cert_serial_no: mchForm.cert_serial_no,
+ transfer_scene_id: mchForm.transfer_scene_id || '1005',
+ notify_url: mchForm.notify_url,
+ priority: mchForm.priority,
+ enabled: mchForm.enabled,
+ private_key_path: mchForm.private_key_path,
+ platform_pub_key_path: mchForm.platform_pub_key_path,
+ }
+ if (mchForm.api_v3_key) payload.api_v3_key = mchForm.api_v3_key
+ const res = await request.post('/peizhi/wxmchbj', payload)
+ if (res.code === 0) {
+ ElMessage.success(res.msg || '保存成功')
+ mchDialogVisible.value = false
+ await loadMchList()
+ } else {
+ ElMessage.error(res.msg || '保存失败')
+ }
+ } catch {
+ ElMessage.error('网络错误')
+ } finally {
+ mchSaving.value = false
+ }
+}
+
+const uploadMchFile = async (opt, fileType) => {
+ if (!mchForm.mch_id) {
+ ElMessage.warning('请先填写商户号')
+ return
+ }
+ const formData = new FormData()
+ formData.append('username', username.value)
+ formData.append('mch_id', mchForm.mch_id)
+ formData.append('file_type', fileType)
+ formData.append('file', opt.file)
+ try {
+ const res = await request.post('/peizhi/wxmchscwj', formData)
+ if (res.code === 0 && res.data) {
+ ElMessage.success('上传成功')
+ if (fileType === 'private_key') mchForm.private_key_path = res.data.saved_path
+ if (fileType === 'platform_pub_key') mchForm.platform_pub_key_path = res.data.saved_path
+ } else {
+ ElMessage.error(res.msg || '上传失败')
+ }
+ } catch {
+ ElMessage.error('上传失败')
+ }
+}
+
const fullUrl = (path) => {
if (!path) return ''
if (path.startsWith('http')) return path
@@ -358,6 +603,7 @@ const uploadAsset = async ({ file }, row) => {
onMounted(() => {
loadSysConfig()
loadAssets()
+ loadMchList()
})
diff --git a/src/views/user/GuanliDetail.vue b/src/views/user/GuanliDetail.vue
index cd3f0a3..0e4a14b 100644
--- a/src/views/user/GuanliDetail.vue
+++ b/src/views/user/GuanliDetail.vue
@@ -279,6 +279,7 @@
title="管事分红"
:is-edit-mode="true"
class="freeze-section"
+ @unfrozen="onFreezeUnfrozen"
/>
@@ -495,6 +496,17 @@ const fetchGuanliDetail = async () => {
}
}
+const onFreezeUnfrozen = async (payload) => {
+ const ur = payload?.unfreeze_result
+ if (ur) {
+ const after = parseFloat(ur.balance_after)
+ if (!Number.isNaN(after)) {
+ balanceForm.yue = after
+ }
+ }
+ await fetchGuanliDetail()
+}
+
// 进入编辑模式:备份原始数据
const enterEditMode = () => {
originalData = {
diff --git a/src/views/user/PlayerDetail.vue b/src/views/user/PlayerDetail.vue
index 4ae72ed..5ff3e5c 100644
--- a/src/views/user/PlayerDetail.vue
+++ b/src/views/user/PlayerDetail.vue
@@ -354,6 +354,7 @@
:leixing="1"
title="打手佣金"
:is-edit-mode="true"
+ @unfrozen="onFreezeUnfrozen"
/>