305 lines
9.7 KiB
Vue
305 lines
9.7 KiB
Vue
<template>
|
||
<div class="club-config-page">
|
||
<el-alert
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
title="俱乐部主数据与小程序/支付/GoEasy 密钥"
|
||
description="仅超级管理员可编辑。修改后影响该俱乐部小程序登录、支付回调、IM 等,请谨慎操作。"
|
||
class="tip"
|
||
/>
|
||
|
||
<div class="toolbar">
|
||
<el-select v-model="currentClubId" placeholder="选择俱乐部" @change="loadClub" style="width: 200px">
|
||
<el-option v-for="c in clubList" :key="c.club_id" :label="c.name" :value="c.club_id" />
|
||
</el-select>
|
||
<el-button type="success" @click="openCreateDialog">新建俱乐部</el-button>
|
||
<el-button type="primary" :loading="saving" @click="saveClub">保存配置</el-button>
|
||
<el-button :icon="Refresh" circle @click="loadClub" :loading="loading" />
|
||
</div>
|
||
|
||
<el-dialog v-model="createVisible" title="新建俱乐部 / 小程序" width="480px">
|
||
<el-form label-width="120px">
|
||
<el-form-item label="俱乐部 ID" required>
|
||
<el-input v-model="createForm.new_club_id" placeholder="如 xy、al(与小程序 club-config 一致)" />
|
||
</el-form-item>
|
||
<el-form-item label="展示名称" required>
|
||
<el-input v-model="createForm.name" placeholder="如:逍遥梦俱乐部" />
|
||
</el-form-item>
|
||
<el-form-item label="小程序 AppID">
|
||
<el-input v-model="createForm.wx_appid" placeholder="新建小程序的 AppID" />
|
||
</el-form-item>
|
||
<el-form-item label="复制模板">
|
||
<el-select v-model="createForm.from_club" style="width: 100%">
|
||
<el-option v-for="c in clubList" :key="c.club_id" :label="c.name" :value="c.club_id" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer>
|
||
<el-button @click="createVisible = false">取消</el-button>
|
||
<el-button type="primary" :loading="creating" @click="createClub">创建</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
|
||
<el-form v-loading="loading" :model="form" label-width="140px" class="config-form">
|
||
<el-divider content-position="left">小程序微信</el-divider>
|
||
<el-form-item label="wx_appid">
|
||
<el-input v-model="form.wx_appid" placeholder="小程序 AppID" />
|
||
</el-form-item>
|
||
<el-form-item label="wx_secret">
|
||
<el-input v-model="form.wx_secret" type="password" show-password placeholder="小程序 Secret" />
|
||
</el-form-item>
|
||
|
||
<el-divider content-position="left">微信支付(同一商户号,V2 收款 / V3 提现 密钥分开配)</el-divider>
|
||
<el-form-item label="商户号 mch_id">
|
||
<el-input v-model="form.mch_id" />
|
||
</el-form-item>
|
||
<el-form-item label="pay_app_id">
|
||
<el-input v-model="form.pay_app_id" placeholder="可与 wx_appid 相同,或留空" />
|
||
</el-form-item>
|
||
<el-form-item label="APIv2 密钥 mch_key">
|
||
<el-input
|
||
v-model="form.mch_key"
|
||
type="password"
|
||
show-password
|
||
placeholder="小程序 JSAPI 收款(会员/点单/押金等)"
|
||
/>
|
||
<div class="field-help">微信商户平台 → API安全 → 设置APIv2密钥。与下方 APIv3 不是同一个。</div>
|
||
</el-form-item>
|
||
<el-form-item label="APIv3 密钥 api_v3_key">
|
||
<el-input
|
||
v-model="form.api_v3_key"
|
||
type="password"
|
||
show-password
|
||
placeholder="自动提现 / 转账到零钱 / 回调解密"
|
||
/>
|
||
<div class="field-help">微信商户平台 → API安全 → 设置APIv3密钥。仅用于提现,不用于小程序收款。</div>
|
||
</el-form-item>
|
||
<el-alert
|
||
v-if="payWarnings.length"
|
||
type="warning"
|
||
:closable="false"
|
||
show-icon
|
||
class="pay-warn"
|
||
:title="payWarnings.join(';')"
|
||
/>
|
||
<el-form-item label="cert_serial_no">
|
||
<el-input v-model="form.cert_serial_no" placeholder="APIv3 商户证书序列号(提现签名用)" />
|
||
</el-form-item>
|
||
<el-form-item label="private_key_path">
|
||
<el-input v-model="form.private_key_path" placeholder="服务器上 apiclient_key.pem 路径(提现签名用)" />
|
||
</el-form-item>
|
||
<el-form-item label="platform_cert_dir">
|
||
<el-input v-model="form.platform_cert_dir" placeholder="微信平台证书目录(提现回调验签用)" />
|
||
</el-form-item>
|
||
|
||
<el-divider content-position="left">服务号</el-divider>
|
||
<el-form-item label="official_appid">
|
||
<el-input v-model="form.official_appid" />
|
||
</el-form-item>
|
||
<el-form-item label="official_secret">
|
||
<el-input v-model="form.official_secret" type="password" show-password />
|
||
</el-form-item>
|
||
<el-form-item label="official_token">
|
||
<el-input v-model="form.official_token" />
|
||
</el-form-item>
|
||
<el-form-item label="encoding_aes_key">
|
||
<el-input v-model="form.encoding_aes_key" />
|
||
</el-form-item>
|
||
|
||
<el-divider content-position="left">GoEasy / OSS / 域名</el-divider>
|
||
<el-form-item label="goeasy_appkey">
|
||
<el-input v-model="form.goeasy_appkey" />
|
||
</el-form-item>
|
||
<el-form-item label="goeasy_secret">
|
||
<el-input v-model="form.goeasy_secret" type="password" show-password />
|
||
</el-form-item>
|
||
<el-form-item label="oss_prefix">
|
||
<el-input v-model="form.oss_prefix" placeholder="同一 COS 桶内目录前缀,如 xq/" />
|
||
</el-form-item>
|
||
<el-form-item label="h5_domain">
|
||
<el-input v-model="form.h5_domain" placeholder="商家 H5 域名" />
|
||
</el-form-item>
|
||
<el-form-item label="template_id">
|
||
<el-input v-model="form.template_id" />
|
||
</el-form-item>
|
||
<el-form-item label="展示名称">
|
||
<el-input v-model="form.name" />
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import { Refresh } from '@element-plus/icons-vue'
|
||
import request from '@/utils/request'
|
||
import { JITUAN_API } from '@/utils/club-context'
|
||
|
||
const loading = ref(false)
|
||
const saving = ref(false)
|
||
const creating = ref(false)
|
||
const createVisible = ref(false)
|
||
const clubList = ref([])
|
||
const currentClubId = ref('xq')
|
||
const createForm = reactive({
|
||
new_club_id: '',
|
||
name: '',
|
||
wx_appid: '',
|
||
from_club: 'xq',
|
||
})
|
||
const payWarnings = ref([])
|
||
const form = reactive({
|
||
name: '',
|
||
wx_appid: '',
|
||
wx_secret: '',
|
||
mch_id: '',
|
||
pay_app_id: '',
|
||
mch_key: '',
|
||
api_v3_key: '',
|
||
cert_serial_no: '',
|
||
private_key_path: '',
|
||
platform_cert_dir: '',
|
||
official_appid: '',
|
||
official_secret: '',
|
||
official_token: '',
|
||
encoding_aes_key: '',
|
||
goeasy_appkey: '',
|
||
goeasy_secret: '',
|
||
oss_prefix: '',
|
||
h5_domain: '',
|
||
template_id: '',
|
||
template_max_per_minute: 950,
|
||
sort_order: 0,
|
||
status: 1,
|
||
})
|
||
|
||
const phone = localStorage.getItem('username')
|
||
|
||
const loadClubList = async () => {
|
||
const res = await request.post(JITUAN_API.clubManage, { phone, action: 'list' })
|
||
if (res.code === 0) {
|
||
clubList.value = res.data || []
|
||
if (!currentClubId.value && clubList.value.length) {
|
||
currentClubId.value = clubList.value[0].club_id
|
||
}
|
||
}
|
||
}
|
||
|
||
const loadClub = async () => {
|
||
if (!currentClubId.value) return
|
||
loading.value = true
|
||
try {
|
||
const res = await request.post(JITUAN_API.clubManage, {
|
||
phone,
|
||
action: 'get',
|
||
club_id: currentClubId.value,
|
||
})
|
||
if (res.code === 0 && res.data) {
|
||
Object.assign(form, res.data)
|
||
payWarnings.value = (res.data.pay_config && res.data.pay_config.warnings) || []
|
||
} else {
|
||
ElMessage.error(res.msg || '加载失败')
|
||
}
|
||
} catch {
|
||
ElMessage.error('加载俱乐部配置失败,请确认已部署最新后端且账号为超级管理员')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
const saveClub = async () => {
|
||
saving.value = true
|
||
try {
|
||
const res = await request.post(JITUAN_API.clubManage, {
|
||
phone,
|
||
action: 'update',
|
||
club_id: currentClubId.value,
|
||
...form,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('保存成功')
|
||
await loadClubList()
|
||
} else {
|
||
ElMessage.error(res.msg || '保存失败')
|
||
}
|
||
} catch {
|
||
ElMessage.error('保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
const openCreateDialog = () => {
|
||
createForm.new_club_id = ''
|
||
createForm.name = ''
|
||
createForm.wx_appid = ''
|
||
createForm.from_club = currentClubId.value || 'xq'
|
||
createVisible.value = true
|
||
}
|
||
|
||
const createClub = async () => {
|
||
if (!createForm.new_club_id || !createForm.name) {
|
||
ElMessage.warning('请填写俱乐部 ID 和名称')
|
||
return
|
||
}
|
||
creating.value = true
|
||
try {
|
||
const res = await request.post(JITUAN_API.clubManage, {
|
||
phone,
|
||
action: 'create',
|
||
new_club_id: createForm.new_club_id.trim(),
|
||
name: createForm.name.trim(),
|
||
wx_appid: createForm.wx_appid.trim(),
|
||
from_club: createForm.from_club,
|
||
})
|
||
if (res.code === 0) {
|
||
ElMessage.success('俱乐部创建成功,请继续填写密钥并保存')
|
||
createVisible.value = false
|
||
await loadClubList()
|
||
currentClubId.value = createForm.new_club_id.trim()
|
||
await loadClub()
|
||
} else {
|
||
ElMessage.error(res.msg || '创建失败')
|
||
}
|
||
} catch {
|
||
ElMessage.error('创建失败,请确认账号有 000001 权限且后端已部署')
|
||
} finally {
|
||
creating.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await loadClubList()
|
||
await loadClub()
|
||
})
|
||
</script>
|
||
|
||
<style scoped>
|
||
.club-config-page {
|
||
padding: 8px 4px;
|
||
}
|
||
.tip {
|
||
margin-bottom: 16px;
|
||
}
|
||
.toolbar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.config-form {
|
||
max-width: 720px;
|
||
}
|
||
.field-help {
|
||
font-size: 12px;
|
||
color: #909399;
|
||
line-height: 1.5;
|
||
margin-top: 4px;
|
||
}
|
||
.pay-warn {
|
||
margin-bottom: 16px;
|
||
}
|
||
</style>
|