chore: 冻结资金功能开工前客服后台检查点
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
345
src/views/club/RechargePageCopy.vue
Normal file
345
src/views/club/RechargePageCopy.vue
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
<template>
|
||||||
|
<div class="recharge-copy-page">
|
||||||
|
<el-alert
|
||||||
|
v-if="isAllClubScope"
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
title="充值页文案需在具体俱乐部视图下配置,请切换顶栏俱乐部。"
|
||||||
|
class="scope-alert"
|
||||||
|
/>
|
||||||
|
<ClubScopeHint v-else />
|
||||||
|
|
||||||
|
<div v-if="!hasPermission" class="no-permission">
|
||||||
|
<div>无充值页文案配置权限(需 8080a)</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else>
|
||||||
|
<div class="header-bar">
|
||||||
|
<h2>充值页文案配置</h2>
|
||||||
|
<p class="desc">按俱乐部配置会员页 / 履约金页规则、权益、平台优势文案与图标。关闭启用或条目为空时,小程序回退默认写死文案。价格与支付逻辑不受影响。</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-tabs v-model="pageKey" @tab-change="loadRegions">
|
||||||
|
<el-tab-pane label="会员页" name="huiyuan" />
|
||||||
|
<el-tab-pane label="履约金页" name="yajin" />
|
||||||
|
</el-tabs>
|
||||||
|
|
||||||
|
<div v-loading="loading" class="regions">
|
||||||
|
<el-card
|
||||||
|
v-for="rk in regionKeys"
|
||||||
|
:key="rk"
|
||||||
|
class="region-card"
|
||||||
|
shadow="never"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="region-header">
|
||||||
|
<strong>{{ regionLabel(rk) }}</strong>
|
||||||
|
<div class="region-actions">
|
||||||
|
<span class="enabled-label">启用</span>
|
||||||
|
<el-switch v-model="forms[rk].enabled" :disabled="isAllClubScope" />
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:loading="savingKey === rk"
|
||||||
|
:disabled="isAllClubScope"
|
||||||
|
@click="saveRegion(rk)"
|
||||||
|
>保存本区</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-form label-width="88px" :disabled="isAllClubScope">
|
||||||
|
<el-form-item label="区域标题">
|
||||||
|
<el-input
|
||||||
|
v-model="forms[rk].title"
|
||||||
|
maxlength="64"
|
||||||
|
show-word-limit
|
||||||
|
:placeholder="defaultTitle(rk)"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="item-toolbar">
|
||||||
|
<span>条目列表</span>
|
||||||
|
<el-button size="small" :disabled="isAllClubScope" @click="addItem(rk)">+ 添加</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table :data="forms[rk].items" border size="small">
|
||||||
|
<el-table-column type="index" label="#" width="50" />
|
||||||
|
<template v-if="rk === 'rules'">
|
||||||
|
<el-table-column label="规则文案">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.text" type="textarea" :rows="2" placeholder="规则说明" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<template v-else-if="pageKey === 'yajin' && rk === 'benefits'">
|
||||||
|
<el-table-column label="权益名称" min-width="140">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.label" placeholder="如:平台订单优先" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="图标 URL" min-width="200">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.icon_url" placeholder="OSS 相对路径或完整 URL" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-table-column label="标题" min-width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.title" placeholder="标题" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="描述" min-width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.desc" type="textarea" :rows="2" placeholder="描述文案" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="图标 URL" min-width="180">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.icon_url" placeholder="OSS 相对路径或完整 URL" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-if="rk === 'benefits'" label="强调色" width="120">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-input v-model="row.accent_color" placeholder="#E8A317" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</template>
|
||||||
|
<el-table-column label="操作" width="140" fixed="right">
|
||||||
|
<template #default="{ $index }">
|
||||||
|
<el-button link :disabled="isAllClubScope || $index === 0" @click="moveItem(rk, $index, -1)">上</el-button>
|
||||||
|
<el-button
|
||||||
|
link
|
||||||
|
:disabled="isAllClubScope || $index >= forms[rk].items.length - 1"
|
||||||
|
@click="moveItem(rk, $index, 1)"
|
||||||
|
>下</el-button>
|
||||||
|
<el-button type="danger" link :disabled="isAllClubScope" @click="removeItem(rk, $index)">删</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
<p v-if="rk === 'rules'" class="hint">会员页规则建议最多 4 条,与现有 UI 一致。</p>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
import { JITUAN_API, getAdminClubScope } from '@/utils/club-context'
|
||||||
|
import ClubScopeHint from '@/components/ClubScopeHint.vue'
|
||||||
|
|
||||||
|
const REGIONS = {
|
||||||
|
huiyuan: ['rules', 'benefits', 'advantages'],
|
||||||
|
yajin: ['rules', 'benefits'],
|
||||||
|
}
|
||||||
|
|
||||||
|
const REGION_LABELS = {
|
||||||
|
rules: '规则',
|
||||||
|
benefits: '专属权益',
|
||||||
|
advantages: '平台优势',
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_TITLES = {
|
||||||
|
huiyuan: { rules: '会员规则', benefits: '专属权益', advantages: '平台优势' },
|
||||||
|
yajin: { rules: '履约金规则', benefits: '平台履约金权益' },
|
||||||
|
}
|
||||||
|
|
||||||
|
const username = ref(localStorage.getItem('username') || '')
|
||||||
|
const hasPermission = ref(true)
|
||||||
|
const isAllClubScope = computed(() => getAdminClubScope() === 'all')
|
||||||
|
const pageKey = ref('huiyuan')
|
||||||
|
const loading = ref(false)
|
||||||
|
const savingKey = ref('')
|
||||||
|
const forms = reactive({
|
||||||
|
rules: emptyForm(),
|
||||||
|
benefits: emptyForm(),
|
||||||
|
advantages: emptyForm(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const regionKeys = computed(() => REGIONS[pageKey.value] || [])
|
||||||
|
|
||||||
|
function emptyForm() {
|
||||||
|
return { title: '', items: [], enabled: false, sort_order: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
function regionLabel(rk) {
|
||||||
|
return REGION_LABELS[rk] || rk
|
||||||
|
}
|
||||||
|
|
||||||
|
function defaultTitle(rk) {
|
||||||
|
return (DEFAULT_TITLES[pageKey.value] || {})[rk] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function blankItem(rk) {
|
||||||
|
if (rk === 'rules') return { text: '' }
|
||||||
|
if (pageKey.value === 'yajin' && rk === 'benefits') return { label: '', icon_url: '' }
|
||||||
|
if (rk === 'benefits') return { title: '', desc: '', icon_url: '', accent_color: '' }
|
||||||
|
return { title: '', desc: '', icon_url: '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyRegions(regions) {
|
||||||
|
for (const rk of ['rules', 'benefits', 'advantages']) {
|
||||||
|
const src = regions?.[rk]
|
||||||
|
if (!src) {
|
||||||
|
Object.assign(forms[rk], emptyForm())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
forms[rk].title = src.title || ''
|
||||||
|
forms[rk].enabled = !!src.enabled
|
||||||
|
forms[rk].sort_order = src.sort_order || 0
|
||||||
|
forms[rk].items = Array.isArray(src.items)
|
||||||
|
? src.items.map((it) => ({ ...blankItem(rk), ...it }))
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadRegions = async () => {
|
||||||
|
if (isAllClubScope.value) {
|
||||||
|
applyRegions({})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const res = await request.post(JITUAN_API.rechargePageCopyGet, {
|
||||||
|
phone: username.value,
|
||||||
|
page_key: pageKey.value,
|
||||||
|
})
|
||||||
|
if (res.code === 0) {
|
||||||
|
hasPermission.value = true
|
||||||
|
applyRegions(res.data?.regions || {})
|
||||||
|
} else if (res.code === 403) {
|
||||||
|
hasPermission.value = false
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || '加载失败')
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
ElMessage.error('加载充值页文案失败')
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addItem = (rk) => {
|
||||||
|
forms[rk].items.push(blankItem(rk))
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeItem = (rk, index) => {
|
||||||
|
forms[rk].items.splice(index, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const moveItem = (rk, index, delta) => {
|
||||||
|
const list = forms[rk].items
|
||||||
|
const next = index + delta
|
||||||
|
if (next < 0 || next >= list.length) return
|
||||||
|
const tmp = list[index]
|
||||||
|
list[index] = list[next]
|
||||||
|
list[next] = tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
const saveRegion = async (rk) => {
|
||||||
|
if (isAllClubScope.value) return
|
||||||
|
savingKey.value = rk
|
||||||
|
try {
|
||||||
|
const form = forms[rk]
|
||||||
|
const res = await request.post(JITUAN_API.rechargePageCopySave, {
|
||||||
|
phone: username.value,
|
||||||
|
page_key: pageKey.value,
|
||||||
|
region_key: rk,
|
||||||
|
title: form.title,
|
||||||
|
enabled: form.enabled,
|
||||||
|
sort_order: form.sort_order,
|
||||||
|
items: form.items,
|
||||||
|
})
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success(`${regionLabel(rk)}已保存`)
|
||||||
|
if (res.data?.region) {
|
||||||
|
const r = res.data.region
|
||||||
|
forms[rk].title = r.title || ''
|
||||||
|
forms[rk].enabled = !!r.enabled
|
||||||
|
forms[rk].items = Array.isArray(r.items)
|
||||||
|
? r.items.map((it) => ({ ...blankItem(rk), ...it }))
|
||||||
|
: []
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || '保存失败')
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
ElMessage.error('保存失败')
|
||||||
|
} finally {
|
||||||
|
savingKey.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(pageKey, () => {
|
||||||
|
// tab-change 也会触发 load;此处兜底
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadRegions()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.recharge-copy-page {
|
||||||
|
padding: 16px 20px 40px;
|
||||||
|
}
|
||||||
|
.scope-alert {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.header-bar h2 {
|
||||||
|
margin: 0 0 6px;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
color: #666;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
.regions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
.region-card {
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
.region-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
.region-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.enabled-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
.item-toolbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 4px 0 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
.hint {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.no-permission {
|
||||||
|
padding: 48px;
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -16,9 +16,16 @@
|
|||||||
<el-option v-for="opt in pageOptions" :key="opt.key" :label="opt.label" :value="opt.key" />
|
<el-option v-for="opt in pageOptions" :key="opt.key" :label="opt.label" :value="opt.key" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
<el-alert
|
||||||
|
type="warning"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
class="page-alert"
|
||||||
|
title="点单小程序(UFO)首页公告/主轮播只读「点单页主轮播」,不读「抢单池」。改公告前请确认右上角已切到 ufo,且下拉选中「点单页主轮播」。"
|
||||||
|
/>
|
||||||
<p class="page-hint">
|
<p class="page-hint">
|
||||||
UFO 点单端:主轮播选「点单页主轮播」;公告下第二横幅选「点单页第二横幅(可多图)」;
|
UFO:主轮播+首页公告 →「点单页主轮播」;公告下第二横幅 →「点单页第二横幅」;「我的」顶区 →「点单个人中心背景」。
|
||||||
「我的」顶区背景选「点单个人中心背景(可多图)」。改图前请切到具体俱乐部(如 ufo),勿在集团视图下上传。
|
勿在集团视图下修改。星阙抢单端才用「抢单池」。
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<el-card class="section-card" shadow="never">
|
<el-card class="section-card" shadow="never">
|
||||||
@@ -143,13 +150,15 @@ function mergePageOptions(fromServer) {
|
|||||||
|
|
||||||
const username = ref(localStorage.getItem('username') || '')
|
const username = ref(localStorage.getItem('username') || '')
|
||||||
const hasPermission = ref(true)
|
const hasPermission = ref(true)
|
||||||
const pageKey = ref('order_pool')
|
/** 默认点单页:UFO/点单端改公告最容易误停在「抢单池」 */
|
||||||
|
const pageKey = ref('accept_order')
|
||||||
const pageOptions = ref(mergePageOptions([]))
|
const pageOptions = ref(mergePageOptions([]))
|
||||||
const gonggaoTitle = computed(() => {
|
const gonggaoTitle = computed(() => {
|
||||||
const opt = pageOptions.value.find((o) => o.key === pageKey.value)
|
const opt = pageOptions.value.find((o) => o.key === pageKey.value)
|
||||||
const label = opt ? opt.label : pageKey.value
|
const label = opt ? opt.label : pageKey.value
|
||||||
return `${label} · 页面公告`
|
return `${label} · 页面公告`
|
||||||
})
|
})
|
||||||
|
const activeClubId = ref('')
|
||||||
const lunboList = ref([])
|
const lunboList = ref([])
|
||||||
const gonggaoContent = ref('')
|
const gonggaoContent = ref('')
|
||||||
const scopeHint = ref('')
|
const scopeHint = ref('')
|
||||||
@@ -174,10 +183,11 @@ const fetchGonggao = async () => {
|
|||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
gonggaoContent.value = res.data?.content || ''
|
gonggaoContent.value = res.data?.content || ''
|
||||||
|
activeClubId.value = res.data?.club_id || ''
|
||||||
if (res.data?.scope === 'ALL_CLUBS') {
|
if (res.data?.scope === 'ALL_CLUBS') {
|
||||||
scopeHint.value = '集团视图下仅可查看;修改轮播/公告请切换到具体子公司'
|
scopeHint.value = '集团视图下仅可查看;修改轮播/公告请切换到具体子公司'
|
||||||
} else if (res.data?.club_id) {
|
} else if (res.data?.club_id) {
|
||||||
scopeHint.value = `以下配置仅作用于俱乐部 ${res.data.club_id}`
|
scopeHint.value = `以下配置仅作用于俱乐部 ${res.data.club_id} · 当前页 ${pageKey.value}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@@ -227,7 +237,10 @@ const saveGonggao = async () => {
|
|||||||
content,
|
content,
|
||||||
})
|
})
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
ElMessage.success('保存成功')
|
const opt = pageOptions.value.find((o) => o.key === pageKey.value)
|
||||||
|
const label = opt ? opt.label : pageKey.value
|
||||||
|
const club = activeClubId.value || '当前俱乐部'
|
||||||
|
ElMessage.success(`已保存到 ${club} · ${label}`)
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.msg || '保存失败')
|
ElMessage.error(res.msg || '保存失败')
|
||||||
}
|
}
|
||||||
@@ -384,6 +397,9 @@ onMounted(async () => {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.55;
|
line-height: 1.55;
|
||||||
}
|
}
|
||||||
|
.page-alert {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
.header-bar {
|
.header-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -168,6 +168,35 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
|
<el-card class="section-card" shadow="never">
|
||||||
|
<template #header><strong>打手「我的」- VIP条背景/图标</strong></template>
|
||||||
|
<p class="hint">仅影响「我的」页 VIP 会员条。未上传时小程序继续用黑金硬编码样式;上传后按俱乐部覆盖(云溪/小西等各自独立)。</p>
|
||||||
|
<div class="icon-grid">
|
||||||
|
<div v-for="item in fighterMineVipIcons" :key="item.icon_key" class="icon-cell">
|
||||||
|
<div class="icon-label">{{ item.label }}</div>
|
||||||
|
<div class="icon-key">{{ item.icon_key }}</div>
|
||||||
|
<el-image
|
||||||
|
v-if="previewUrl(item)"
|
||||||
|
:src="previewUrl(item)"
|
||||||
|
fit="contain"
|
||||||
|
class="poster-preview"
|
||||||
|
/>
|
||||||
|
<div v-else class="empty-preview">暂无图片</div>
|
||||||
|
<el-upload
|
||||||
|
action="#"
|
||||||
|
:auto-upload="false"
|
||||||
|
:show-file-list="false"
|
||||||
|
:on-change="(f) => uploadIcon(f, item.icon_key)"
|
||||||
|
accept="image/jpeg,image/png,image/jpg,image/webp"
|
||||||
|
>
|
||||||
|
<el-button size="small" type="primary" :loading="uploadingKey === item.icon_key">
|
||||||
|
{{ item.is_uploaded ? '更换' : '上传' }}
|
||||||
|
</el-button>
|
||||||
|
</el-upload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
<el-card class="section-card" shadow="never">
|
<el-card class="section-card" shadow="never">
|
||||||
<template #header><strong>打手「我的」- 会员/保证金充值页大背景</strong></template>
|
<template #header><strong>打手「我的」- 会员/保证金充值页大背景</strong></template>
|
||||||
<p class="hint">会员充值页顶图、保证金页顶图与右侧装饰。未上传时小程序用默认样式;此处始终可直接上传。</p>
|
<p class="hint">会员充值页顶图、保证金页顶图与右侧装饰。未上传时小程序用默认样式;此处始终可直接上传。</p>
|
||||||
@@ -314,9 +343,16 @@ const FIGHTER_PAGE_BG_META = [
|
|||||||
{ icon_key: 'fighter_deposit_hero', label: '打手保证金页-卡片右侧装饰图' },
|
{ icon_key: 'fighter_deposit_hero', label: '打手保证金页-卡片右侧装饰图' },
|
||||||
]
|
]
|
||||||
const FIGHTER_PAGE_BG_KEYS = new Set(FIGHTER_PAGE_BG_META.map((i) => i.icon_key))
|
const FIGHTER_PAGE_BG_KEYS = new Set(FIGHTER_PAGE_BG_META.map((i) => i.icon_key))
|
||||||
|
/** 「我的」VIP 条:新增背景/图标,未上传不下发,小程序走硬编码 */
|
||||||
|
const FIGHTER_MINE_VIP_META = [
|
||||||
|
{ icon_key: 'fighter_mine_vip_bg', label: '打手「我的」-VIP条背景图' },
|
||||||
|
{ icon_key: 'fighter_mine_vip_icon', label: '打手「我的」-VIP条左侧图标' },
|
||||||
|
]
|
||||||
|
const FIGHTER_MINE_VIP_KEYS = new Set(FIGHTER_MINE_VIP_META.map((i) => i.icon_key))
|
||||||
const CONFIG_ONLY_PREVIEW_KEYS = new Set([
|
const CONFIG_ONLY_PREVIEW_KEYS = new Set([
|
||||||
...GRAB_CARD_BG_KEYS,
|
...GRAB_CARD_BG_KEYS,
|
||||||
...FIGHTER_PAGE_BG_KEYS,
|
...FIGHTER_PAGE_BG_KEYS,
|
||||||
|
...FIGHTER_MINE_VIP_KEYS,
|
||||||
])
|
])
|
||||||
const FIGHTER_BANNER_KEYS = new Set(['fighter_recharge_member', 'fighter_recharge_deposit'])
|
const FIGHTER_BANNER_KEYS = new Set(['fighter_recharge_member', 'fighter_recharge_deposit'])
|
||||||
const FIGHTER_MINE_PAGE_KEYS = new Set([
|
const FIGHTER_MINE_PAGE_KEYS = new Set([
|
||||||
@@ -349,15 +385,17 @@ const cuserMineIcons = computed(() => icons.value.filter((i) => CUSER_MINE_KEYS.
|
|||||||
const merchantIcons = computed(() => icons.value.filter((i) => i.icon_key.startsWith('merchant_')))
|
const merchantIcons = computed(() => icons.value.filter((i) => i.icon_key.startsWith('merchant_')))
|
||||||
const grabCardBgIcons = computed(() => mergeFixedIcons(GRAB_CARD_BG_META, icons.value))
|
const grabCardBgIcons = computed(() => mergeFixedIcons(GRAB_CARD_BG_META, icons.value))
|
||||||
const fighterPageBgIcons = computed(() => mergeFixedIcons(FIGHTER_PAGE_BG_META, icons.value))
|
const fighterPageBgIcons = computed(() => mergeFixedIcons(FIGHTER_PAGE_BG_META, icons.value))
|
||||||
|
const fighterMineVipIcons = computed(() => mergeFixedIcons(FIGHTER_MINE_VIP_META, icons.value))
|
||||||
const fighterBannerIcons = computed(() => icons.value.filter((i) => FIGHTER_BANNER_KEYS.has(i.icon_key)))
|
const fighterBannerIcons = computed(() => icons.value.filter((i) => FIGHTER_BANNER_KEYS.has(i.icon_key)))
|
||||||
const fighterMinePageIcons = computed(() => icons.value.filter((i) => FIGHTER_MINE_PAGE_KEYS.has(i.icon_key)))
|
const fighterMinePageIcons = computed(() => icons.value.filter((i) => FIGHTER_MINE_PAGE_KEYS.has(i.icon_key)))
|
||||||
const fighterMoreFuncIcons = computed(() => icons.value.filter((i) => {
|
const fighterMoreFuncIcons = computed(() => icons.value.filter((i) => {
|
||||||
const k = i.icon_key
|
const k = i.icon_key
|
||||||
|
if (FIGHTER_MINE_VIP_KEYS.has(k)) return false
|
||||||
return k.startsWith('fighter_mine_') && !FIGHTER_MINE_PAGE_KEYS.has(k)
|
return k.startsWith('fighter_mine_') && !FIGHTER_MINE_PAGE_KEYS.has(k)
|
||||||
}))
|
}))
|
||||||
const fighterRechargeIcons = computed(() => icons.value.filter((i) => {
|
const fighterRechargeIcons = computed(() => icons.value.filter((i) => {
|
||||||
const k = i.icon_key
|
const k = i.icon_key
|
||||||
if (FIGHTER_BANNER_KEYS.has(k) || FIGHTER_PAGE_BG_KEYS.has(k)) return false
|
if (FIGHTER_BANNER_KEYS.has(k) || FIGHTER_PAGE_BG_KEYS.has(k) || FIGHTER_MINE_VIP_KEYS.has(k)) return false
|
||||||
return k.startsWith('fighter_recharge_') || k.startsWith('fighter_deposit_')
|
return k.startsWith('fighter_recharge_') || k.startsWith('fighter_deposit_')
|
||||||
}))
|
}))
|
||||||
const commonIcons = computed(() => icons.value.filter((i) => COMMON_KEYS.has(i.icon_key)))
|
const commonIcons = computed(() => icons.value.filter((i) => COMMON_KEYS.has(i.icon_key)))
|
||||||
|
|||||||
@@ -394,9 +394,16 @@ const enterEditMode = () => {
|
|||||||
zhuanqu_id: product.value.zhuanqu_id,
|
zhuanqu_id: product.value.zhuanqu_id,
|
||||||
yaoqiuleixing: product.value.yaoqiuleixing,
|
yaoqiuleixing: product.value.yaoqiuleixing,
|
||||||
huiyuan_id: product.value.huiyuan_id || '',
|
huiyuan_id: product.value.huiyuan_id || '',
|
||||||
yongjin: product.value.yongjin !== null ? product.value.yongjin : null,
|
yongjin: product.value.yongjin !== null && product.value.yongjin !== undefined ? Number(product.value.yongjin) : null,
|
||||||
kaioi_ewai_dashou_fencheng: product.value.kaioi_ewai_dashou_fencheng,
|
kaioi_ewai_dashou_fencheng: !!(
|
||||||
ewai_dashou_fencheng: product.value.ewai_dashou_fencheng || 0,
|
product.value.kaioi_ewai_dashou_fencheng
|
||||||
|
?? product.value.kaioi_ewai_PlayerCommission
|
||||||
|
),
|
||||||
|
ewai_dashou_fencheng: Number(
|
||||||
|
product.value.ewai_dashou_fencheng
|
||||||
|
?? product.value.ewai_PlayerCommission
|
||||||
|
?? 0
|
||||||
|
),
|
||||||
jieshao: product.value.jieshao || '',
|
jieshao: product.value.jieshao || '',
|
||||||
xiadan_xuzhi: product.value.xiadan_xuzhi || '',
|
xiadan_xuzhi: product.value.xiadan_xuzhi || '',
|
||||||
tupian_url: product.value.tupian_url,
|
tupian_url: product.value.tupian_url,
|
||||||
@@ -414,9 +421,16 @@ const enterEditMode = () => {
|
|||||||
zhuanqu_id: product.value.zhuanqu_id,
|
zhuanqu_id: product.value.zhuanqu_id,
|
||||||
yaoqiuleixing: product.value.yaoqiuleixing,
|
yaoqiuleixing: product.value.yaoqiuleixing,
|
||||||
huiyuan_id: product.value.huiyuan_id || '',
|
huiyuan_id: product.value.huiyuan_id || '',
|
||||||
yongjin: product.value.yongjin !== null ? product.value.yongjin : null,
|
yongjin: product.value.yongjin !== null && product.value.yongjin !== undefined ? Number(product.value.yongjin) : null,
|
||||||
kaioi_ewai_dashou_fencheng: product.value.kaioi_ewai_dashou_fencheng,
|
kaioi_ewai_dashou_fencheng: !!(
|
||||||
ewai_dashou_fencheng: product.value.ewai_dashou_fencheng || 0,
|
product.value.kaioi_ewai_dashou_fencheng
|
||||||
|
?? product.value.kaioi_ewai_PlayerCommission
|
||||||
|
),
|
||||||
|
ewai_dashou_fencheng: Number(
|
||||||
|
product.value.ewai_dashou_fencheng
|
||||||
|
?? product.value.ewai_PlayerCommission
|
||||||
|
?? 0
|
||||||
|
),
|
||||||
jieshao: product.value.jieshao || '',
|
jieshao: product.value.jieshao || '',
|
||||||
xiadan_xuzhi: product.value.xiadan_xuzhi || '',
|
xiadan_xuzhi: product.value.xiadan_xuzhi || '',
|
||||||
tupian_url: product.value.tupian_url,
|
tupian_url: product.value.tupian_url,
|
||||||
@@ -480,8 +494,11 @@ const saveProduct = async () => {
|
|||||||
} else {
|
} else {
|
||||||
formData.append('yongjin', form.yongjin !== null ? form.yongjin : 0)
|
formData.append('yongjin', form.yongjin !== null ? form.yongjin : 0)
|
||||||
}
|
}
|
||||||
formData.append('kaioi_ewai_dashou_fencheng', form.kaioi_ewai_dashou_fencheng)
|
formData.append('kaioi_ewai_dashou_fencheng', form.kaioi_ewai_dashou_fencheng ? 'true' : 'false')
|
||||||
formData.append('ewai_dashou_fencheng', form.ewai_dashou_fencheng)
|
formData.append('ewai_dashou_fencheng', form.ewai_dashou_fencheng)
|
||||||
|
// 兼容旧后端字段名
|
||||||
|
formData.append('kaioi_ewai_PlayerCommission', form.kaioi_ewai_dashou_fencheng ? 'true' : 'false')
|
||||||
|
formData.append('ewai_PlayerCommission', form.ewai_dashou_fencheng)
|
||||||
formData.append('jieshao', form.jieshao || '')
|
formData.append('jieshao', form.jieshao || '')
|
||||||
formData.append('xiadan_xuzhi', form.xiadan_xuzhi || '')
|
formData.append('xiadan_xuzhi', form.xiadan_xuzhi || '')
|
||||||
formData.append('shenhezhuangtai', form.shenhezhuangtai)
|
formData.append('shenhezhuangtai', form.shenhezhuangtai)
|
||||||
@@ -628,9 +645,16 @@ const fetchProductDetail = async () => {
|
|||||||
zhuanqu_id: product.value.zhuanqu_id,
|
zhuanqu_id: product.value.zhuanqu_id,
|
||||||
yaoqiuleixing: product.value.yaoqiuleixing,
|
yaoqiuleixing: product.value.yaoqiuleixing,
|
||||||
huiyuan_id: product.value.huiyuan_id || '',
|
huiyuan_id: product.value.huiyuan_id || '',
|
||||||
yongjin: product.value.yongjin !== null ? product.value.yongjin : null,
|
yongjin: product.value.yongjin !== null && product.value.yongjin !== undefined ? Number(product.value.yongjin) : null,
|
||||||
kaioi_ewai_dashou_fencheng: product.value.kaioi_ewai_dashou_fencheng,
|
kaioi_ewai_dashou_fencheng: !!(
|
||||||
ewai_dashou_fencheng: product.value.ewai_dashou_fencheng || 0,
|
product.value.kaioi_ewai_dashou_fencheng
|
||||||
|
?? product.value.kaioi_ewai_PlayerCommission
|
||||||
|
),
|
||||||
|
ewai_dashou_fencheng: Number(
|
||||||
|
product.value.ewai_dashou_fencheng
|
||||||
|
?? product.value.ewai_PlayerCommission
|
||||||
|
?? 0
|
||||||
|
),
|
||||||
jieshao: product.value.jieshao || '',
|
jieshao: product.value.jieshao || '',
|
||||||
xiadan_xuzhi: product.value.xiadan_xuzhi || '',
|
xiadan_xuzhi: product.value.xiadan_xuzhi || '',
|
||||||
tupian_url: product.value.tupian_url,
|
tupian_url: product.value.tupian_url,
|
||||||
|
|||||||
@@ -744,6 +744,7 @@ const submitAddProduct = async () => {
|
|||||||
}
|
}
|
||||||
if (addForm.fencheng_type === 'custom') {
|
if (addForm.fencheng_type === 'custom') {
|
||||||
formData.append('ewai_dashou_fencheng', addForm.ewai_dashou_fencheng)
|
formData.append('ewai_dashou_fencheng', addForm.ewai_dashou_fencheng)
|
||||||
|
formData.append('ewai_PlayerCommission', addForm.ewai_dashou_fencheng)
|
||||||
}
|
}
|
||||||
formData.append('file', addForm.imageFile)
|
formData.append('file', addForm.imageFile)
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<el-button type="primary" @click="handleSearch" :loading="loading">搜索</el-button>
|
<el-button type="primary" @click="handleSearch" :loading="loading">搜索</el-button>
|
||||||
|
<el-button type="success" @click="openAddDialog">添加商家</el-button>
|
||||||
<el-button :icon="Refresh" @click="handleResetFilters" circle />
|
<el-button :icon="Refresh" @click="handleResetFilters" circle />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -151,6 +152,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<el-dialog v-model="addDialogVisible" title="添加商家" width="420px" destroy-on-close>
|
||||||
|
<el-form label-width="88px" @submit.prevent>
|
||||||
|
<el-form-item label="用户ID" required>
|
||||||
|
<el-input
|
||||||
|
v-model="addForm.yonghuid"
|
||||||
|
placeholder="填写小程序用户 UID"
|
||||||
|
clearable
|
||||||
|
maxlength="16"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="商家昵称">
|
||||||
|
<el-input
|
||||||
|
v-model="addForm.nicheng"
|
||||||
|
placeholder="可选,默认用用户昵称"
|
||||||
|
clearable
|
||||||
|
maxlength="50"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="addDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="addLoading" @click="submitAddMerchant">确认添加</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -175,6 +201,9 @@ const username = ref(localStorage.getItem('username') || '')
|
|||||||
const hasPermission = ref(true)
|
const hasPermission = ref(true)
|
||||||
const totalCount = ref(0) // 商家总数
|
const totalCount = ref(0) // 商家总数
|
||||||
const validMerchantCount = ref(0) // 有效商家数(状态为正常的商家数)
|
const validMerchantCount = ref(0) // 有效商家数(状态为正常的商家数)
|
||||||
|
const addDialogVisible = ref(false)
|
||||||
|
const addLoading = ref(false)
|
||||||
|
const addForm = ref({ yonghuid: '', nicheng: '' })
|
||||||
|
|
||||||
// 筛选条件
|
// 筛选条件
|
||||||
const balanceOp = ref('gte') // 余额比较符: gte(>=) / lte(<=)
|
const balanceOp = ref('gte') // 余额比较符: gte(>=) / lte(<=)
|
||||||
@@ -284,6 +313,40 @@ const goToDetail = (yonghuid) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openAddDialog = () => {
|
||||||
|
addForm.value = { yonghuid: '', nicheng: '' }
|
||||||
|
addDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitAddMerchant = async () => {
|
||||||
|
const yonghuid = (addForm.value.yonghuid || '').trim()
|
||||||
|
if (!yonghuid) {
|
||||||
|
ElMessage.warning('请填写用户ID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addLoading.value = true
|
||||||
|
try {
|
||||||
|
const res = await request.post(JITUAN_API.shangjiaAdd, {
|
||||||
|
username: username.value,
|
||||||
|
yonghuid,
|
||||||
|
nicheng: (addForm.value.nicheng || '').trim(),
|
||||||
|
})
|
||||||
|
if (res.code === 0) {
|
||||||
|
ElMessage.success(res.msg || '商家添加成功')
|
||||||
|
addDialogVisible.value = false
|
||||||
|
page.value = 1
|
||||||
|
fetchMerchants()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg || '添加失败')
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
ElMessage.error('添加商家失败,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
addLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化加载
|
// 初始化加载
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchMerchants()
|
fetchMerchants()
|
||||||
|
|||||||
Reference in New Issue
Block a user