feat: 打手中心充值横幅与全页图标后台分组配置
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -296,6 +296,7 @@ export const JITUAN_API = {
|
||||
penaltyStats: '/jituan/houtai/htglyhqcfsltj',
|
||||
penaltyList: '/jituan/houtai/hthqfklb',
|
||||
penaltyAction: '/jituan/houtai/glyclfk',
|
||||
penaltyPlatformAudit: '/jituan/houtai/glyptshfk',
|
||||
penaltyCreate: '/jituan/houtai/htfksc',
|
||||
kefuCfgl: '/jituan/houtai/kefu-cfgl',
|
||||
adminAssignments: '/jituan/houtai/admin-assignments',
|
||||
@@ -306,6 +307,7 @@ export const JITUAN_API = {
|
||||
memberCatalog: '/jituan/houtai/hthycatalog',
|
||||
memberEnable: '/jituan/houtai/hthysj',
|
||||
memberDisable: '/jituan/houtai/hthyxj',
|
||||
memberCardUpload: '/jituan/houtai/hy-card-upload',
|
||||
identityTagList: '/jituan/houtai/identity-tag/list',
|
||||
identityTagManage: '/jituan/houtai/identity-tag/manage',
|
||||
identityTagBindList: '/jituan/houtai/identity-tag/bind-list',
|
||||
|
||||
@@ -133,6 +133,38 @@
|
||||
<el-form-item label="详细规则介绍" prop="jtjieshao">
|
||||
<el-input v-model="currentMember.jtjieshao" type="textarea" rows="4" :disabled="!isEditMode" />
|
||||
</el-form-item>
|
||||
<template v-if="!isAllClubScope">
|
||||
<el-form-item label="充值页卡片装饰图">
|
||||
<div class="member-card-upload">
|
||||
<el-image v-if="currentMember.card_image" :src="memberCardUrl(currentMember.card_image)" fit="contain" class="member-card-preview" />
|
||||
<el-upload
|
||||
v-if="isEditMode"
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="(f) => uploadMemberCard(f, 'card_image')"
|
||||
accept="image/jpeg,image/png,image/jpg,image/webp"
|
||||
>
|
||||
<el-button size="small" type="primary" :loading="cardUploadField === 'card_image'">上传装饰图</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="充值页卡片背景图">
|
||||
<div class="member-card-upload">
|
||||
<el-image v-if="currentMember.card_bg" :src="memberCardUrl(currentMember.card_bg)" fit="contain" class="member-card-preview" />
|
||||
<el-upload
|
||||
v-if="isEditMode"
|
||||
action="#"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:on-change="(f) => uploadMemberCard(f, 'card_bg')"
|
||||
accept="image/jpeg,image/png,image/jpg,image/webp"
|
||||
>
|
||||
<el-button size="small" type="primary" :loading="cardUploadField === 'card_bg'">上传背景图</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item label="购买次数" v-if="!isEditMode">
|
||||
<el-input :value="currentMember.goumai_cishu || 0" disabled />
|
||||
</el-form-item>
|
||||
@@ -274,6 +306,39 @@ const isEditMode = ref(false)
|
||||
const currentMember = ref({})
|
||||
const detailFormRef = ref(null)
|
||||
const saving = ref(false)
|
||||
const cardUploadField = ref('')
|
||||
|
||||
function memberCardUrl(rel) {
|
||||
if (!rel) return ''
|
||||
if (rel.startsWith('http')) return rel
|
||||
const base = window.$ossURL || ''
|
||||
return base + rel
|
||||
}
|
||||
|
||||
async function uploadMemberCard(file, field) {
|
||||
if (!file?.raw || !currentMember.value?.huiyuan_id) return
|
||||
cardUploadField.value = field
|
||||
try {
|
||||
const fd = new FormData()
|
||||
fd.append('username', username.value)
|
||||
fd.append('huiyuan_id', currentMember.value.huiyuan_id)
|
||||
fd.append('field', field)
|
||||
fd.append('file', file.raw)
|
||||
const res = await request.post(JITUAN_API.memberCardUpload, fd, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' },
|
||||
})
|
||||
if (res.code === 0) {
|
||||
currentMember.value[field] = res.data?.[field] || ''
|
||||
ElMessage.success('上传成功')
|
||||
} else {
|
||||
ElMessage.error(res.msg || '上传失败')
|
||||
}
|
||||
} catch (e) {
|
||||
ElMessage.error('上传失败')
|
||||
} finally {
|
||||
cardUploadField.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const addDialogVisible = ref(false)
|
||||
const addFormRef = ref(null)
|
||||
@@ -321,7 +386,9 @@ function normalizeMember(member) {
|
||||
trial_price: Number(member.trial_price || 0),
|
||||
trial_days: Number(member.trial_days || 0),
|
||||
trial_guanshifc: Number(member.trial_guanshifc || 0),
|
||||
trial_zuzhangfc: Number(member.trial_zuzhangfc || 0)
|
||||
trial_zuzhangfc: Number(member.trial_zuzhangfc || 0),
|
||||
card_image: member.card_image || '',
|
||||
card_bg: member.card_bg || '',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,6 +521,8 @@ const saveMember = async () => {
|
||||
guanshifc: m.guanshifc,
|
||||
zuzhangfc: m.zuzhangfc,
|
||||
jtjieshao: m.jtjieshao || '',
|
||||
card_image: m.card_image || '',
|
||||
card_bg: m.card_bg || '',
|
||||
...buildTrialPayload(m)
|
||||
})
|
||||
if (res.code === 0) {
|
||||
@@ -779,6 +848,18 @@ onMounted(() => {
|
||||
color: #8ab3cf;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.member-card-upload {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.member-card-preview {
|
||||
width: 160px;
|
||||
height: 100px;
|
||||
border-radius: 8px;
|
||||
background: #0d2137;
|
||||
}
|
||||
.no-permission {
|
||||
text-align: center;
|
||||
padding: 80px 20px;
|
||||
|
||||
@@ -36,9 +36,111 @@
|
||||
</el-card>
|
||||
|
||||
<el-card class="section-card" shadow="never">
|
||||
<template #header><strong>功能图标(按俱乐部)</strong></template>
|
||||
<template #header><strong>商家端图标</strong></template>
|
||||
<div class="icon-grid">
|
||||
<div v-for="item in funcIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div v-for="item in merchantIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div class="icon-label">{{ item.label }}</div>
|
||||
<div class="icon-key">{{ item.icon_key }}</div>
|
||||
<el-image :src="fullUrl(item.image_path)" fit="contain" class="icon-preview" />
|
||||
<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">更换</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="section-card" shadow="never">
|
||||
<template #header><strong>打手中心-充值横幅(会员/保证金大图标)</strong></template>
|
||||
<p class="hint">打手「我的」页钱包下方左右两张可点击大图,上传后立即生效。</p>
|
||||
<div class="icon-grid">
|
||||
<div v-for="item in fighterBannerIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div class="icon-label">{{ item.label }}</div>
|
||||
<div class="icon-key">{{ item.icon_key }}</div>
|
||||
<el-image :src="fullUrl(item.image_path)" fit="contain" class="poster-preview" />
|
||||
<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">更换横幅</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="section-card" shadow="never">
|
||||
<template #header><strong>打手中心-我的页图标</strong></template>
|
||||
<p class="hint">订单区、交易明细、好友邀请、快手提现、复制/编辑、切片横幅、罚单提示等。</p>
|
||||
<div class="icon-grid">
|
||||
<div v-for="item in fighterMinePageIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div class="icon-label">{{ item.label }}</div>
|
||||
<div class="icon-key">{{ item.icon_key }}</div>
|
||||
<el-image :src="fullUrl(item.image_path)" fit="contain" class="icon-preview" />
|
||||
<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">更换</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="section-card" shadow="never">
|
||||
<template #header><strong>打手中心-更多功能图标</strong></template>
|
||||
<div class="icon-grid">
|
||||
<div v-for="item in fighterMoreFuncIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div class="icon-label">{{ item.label }}</div>
|
||||
<div class="icon-key">{{ item.icon_key }}</div>
|
||||
<el-image :src="fullUrl(item.image_path)" fit="contain" class="icon-preview" />
|
||||
<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">更换</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="section-card" shadow="never">
|
||||
<template #header><strong>打手中心-会员/保证金充值页图标</strong></template>
|
||||
<div class="icon-grid">
|
||||
<div v-for="item in fighterRechargeIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div class="icon-label">{{ item.label }}</div>
|
||||
<div class="icon-key">{{ item.icon_key }}</div>
|
||||
<el-image :src="fullUrl(item.image_path)" fit="contain" class="icon-preview" />
|
||||
<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">更换</el-button>
|
||||
</el-upload>
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="section-card" shadow="never">
|
||||
<template #header><strong>通用图标</strong></template>
|
||||
<div class="icon-grid">
|
||||
<div v-for="item in commonIcons" :key="item.icon_key" class="icon-cell">
|
||||
<div class="icon-label">{{ item.label }}</div>
|
||||
<div class="icon-key">{{ item.icon_key }}</div>
|
||||
<el-image :src="fullUrl(item.image_path)" fit="contain" class="icon-preview" />
|
||||
@@ -105,8 +207,28 @@ const REQUIRED_PERMISSION = '8080a'
|
||||
const hasPermission = ref(true)
|
||||
const icons = ref([])
|
||||
const POSTER_KEYS = new Set(['guanshi_poster_bg', 'zuzhang_poster_bg'])
|
||||
const COMMON_KEYS = new Set(['mine_pindao', 'icon_refresh'])
|
||||
const FIGHTER_BANNER_KEYS = new Set(['fighter_recharge_member', 'fighter_recharge_deposit'])
|
||||
const FIGHTER_MINE_PAGE_KEYS = new Set([
|
||||
'fighter_order_pending', 'fighter_order_settling', 'fighter_order_done', 'fighter_order_closed',
|
||||
'fighter_trade_commission', 'fighter_trade_withdraw', 'fighter_trade_settle', 'fighter_trade_deduct', 'fighter_trade_recharge',
|
||||
'fighter_invite_subordinate', 'fighter_invite_poster', 'fighter_invite_code',
|
||||
'fighter_kuaishou_cash', 'fighter_mine_copy', 'fighter_mine_edit', 'fighter_mine_qiepian', 'fighter_mine_penalty_tip',
|
||||
])
|
||||
const posterIcons = computed(() => icons.value.filter((i) => POSTER_KEYS.has(i.icon_key)))
|
||||
const funcIcons = computed(() => icons.value.filter((i) => !POSTER_KEYS.has(i.icon_key)))
|
||||
const merchantIcons = computed(() => icons.value.filter((i) => i.icon_key.startsWith('merchant_')))
|
||||
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 fighterMoreFuncIcons = computed(() => icons.value.filter((i) => {
|
||||
const k = i.icon_key
|
||||
return k.startsWith('fighter_mine_') && !FIGHTER_MINE_PAGE_KEYS.has(k)
|
||||
}))
|
||||
const fighterRechargeIcons = computed(() => icons.value.filter((i) => {
|
||||
const k = i.icon_key
|
||||
if (FIGHTER_BANNER_KEYS.has(k)) return false
|
||||
return k.startsWith('fighter_recharge_') || k.startsWith('fighter_deposit_')
|
||||
}))
|
||||
const commonIcons = computed(() => icons.value.filter((i) => COMMON_KEYS.has(i.icon_key)))
|
||||
const uploadingKey = ref('')
|
||||
const pindao = ref({ channel_no: '', title: '频道' })
|
||||
const pindaoImages = ref([])
|
||||
|
||||
Reference in New Issue
Block a user