feat: 排行榜奖励后台配置页
- 小程序配置下新增排行榜奖励菜单与 RankReward 页面 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -144,6 +144,7 @@
|
||||
<el-menu-item v-if="canShow('miniapp.leixing')" index="/miniapp/leixing">抢单商品类型</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.kaohe-tags')" index="/miniapp/kaohe-tags">抢单考核标签</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.dashou-exam')" index="/miniapp/dashou-exam">打手接单考试</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.rank-reward')" index="/miniapp/rank-reward">排行榜奖励</el-menu-item>
|
||||
<el-menu-item v-if="canShow('miniapp.withdraw-settings')" index="/withdraw/settings">提现与收款设置</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
|
||||
259
src/views/miniapp/RankReward.vue
Normal file
259
src/views/miniapp/RankReward.vue
Normal file
@@ -0,0 +1,259 @@
|
||||
<template>
|
||||
<div class="rank-reward-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 class="no-permission-icon">🔒</div>
|
||||
<div>无排行榜奖励配置权限(phbj666 / 8080a)</div>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div class="header-bar">
|
||||
<h2>排行榜奖励配置</h2>
|
||||
<p class="desc">按俱乐部分奖;小程序可展示集团总榜,奖金仅发给本俱乐部用户。结算周期:昨日 / 上周 / 上月。</p>
|
||||
</div>
|
||||
|
||||
<el-tabs v-model="activeShenfen" @tab-change="loadSchemes">
|
||||
<el-tab-pane label="接单员" name="dashou" />
|
||||
<el-tab-pane label="管事" name="guanshi" />
|
||||
<el-tab-pane label="组长" name="zuzhang" />
|
||||
<el-tab-pane label="商家" name="shangjia" />
|
||||
</el-tabs>
|
||||
|
||||
<el-tabs v-model="activePeriod" type="card" @tab-change="selectScheme">
|
||||
<el-tab-pane label="日榜(昨日)" name="day" />
|
||||
<el-tab-pane label="周榜(上周)" name="week" />
|
||||
<el-tab-pane label="月榜(上月)" name="month" />
|
||||
</el-tabs>
|
||||
|
||||
<el-card v-loading="loading">
|
||||
<el-form :model="form" label-width="120px" :disabled="isAllClubScope">
|
||||
<el-form-item label="启用">
|
||||
<el-switch v-model="form.enabled" />
|
||||
</el-form-item>
|
||||
<el-form-item label="标题">
|
||||
<el-input v-model="form.title" placeholder="如:星阙接单员周榜奖励" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序指标">
|
||||
<el-select v-model="form.sort_field" style="width: 280px">
|
||||
<el-option v-for="o in sortOptions" :key="o.key" :label="o.label" :value="o.key" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="最低指标">
|
||||
<el-input-number v-model="form.min_metric" :min="0" :precision="2" />
|
||||
</el-form-item>
|
||||
<el-form-item label="领取有效天">
|
||||
<el-input-number v-model="form.claim_days" :min="1" :max="365" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规则说明">
|
||||
<el-input v-model="form.description" type="textarea" :rows="3" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div class="tier-toolbar">
|
||||
<span>奖励档位</span>
|
||||
<el-button size="small" :disabled="isAllClubScope" @click="addTier">+ 添加档位</el-button>
|
||||
</div>
|
||||
<el-table :data="form.tiers" border size="small">
|
||||
<el-table-column label="名次起" width="100">
|
||||
<template #default="{ row }"><el-input-number v-model="row.rank_from" :min="1" size="small" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名次止" width="100">
|
||||
<template #default="{ row }"><el-input-number v-model="row.rank_to" :min="1" size="small" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="奖金(元)" width="120">
|
||||
<template #default="{ row }"><el-input-number v-model="row.reward_amount" :min="0" :precision="2" size="small" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="标签">
|
||||
<template #default="{ row }"><el-input v-model="row.label" size="small" placeholder="冠军" /></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80">
|
||||
<template #default="{ $index }">
|
||||
<el-button type="danger" link :disabled="isAllClubScope" @click="form.tiers.splice($index, 1)">删</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="actions">
|
||||
<el-button type="primary" :loading="saving" :disabled="isAllClubScope" @click="save">保存配置</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card class="claims-card" header="领取明细(最近100条)">
|
||||
<el-table :data="claims" border size="small" v-loading="claimsLoading">
|
||||
<el-table-column prop="yonghuid" label="用户ID" width="100" />
|
||||
<el-table-column prop="shenfen" label="身份" width="90" />
|
||||
<el-table-column prop="mingci" label="名次" width="70" />
|
||||
<el-table-column prop="amount" label="金额" width="90" />
|
||||
<el-table-column prop="status_text" label="状态" width="90" />
|
||||
<el-table-column prop="claimed_at" label="领取时间" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import request from '@/utils/request'
|
||||
import ClubScopeHint from '@/components/ClubScopeHint.vue'
|
||||
import { getAdminClubScope } from '@/utils/club-context'
|
||||
|
||||
const username = ref(localStorage.getItem('username') || '')
|
||||
const hasPermission = ref(true)
|
||||
const loading = ref(false)
|
||||
const saving = ref(false)
|
||||
const claimsLoading = ref(false)
|
||||
const schemes = ref([])
|
||||
const claims = ref([])
|
||||
const activeShenfen = ref('dashou')
|
||||
const activePeriod = ref('week')
|
||||
const isAllClubScope = computed(() => getAdminClubScope() === 'all')
|
||||
|
||||
const SORT_OPTIONS = {
|
||||
dashou: [
|
||||
{ key: 'chengjiao_zongliang', label: '成交量' },
|
||||
{ key: 'chengjiao_zonge', label: '成交总额' },
|
||||
{ key: 'jiedan_zongliang', label: '接单量' },
|
||||
{ key: 'jiedan_zonge', label: '接单总额' },
|
||||
],
|
||||
guanshi: [
|
||||
{ key: 'chongzhi_dashou_shu', label: '有效打手数' },
|
||||
{ key: 'shouru_zonge', label: '收益总额' },
|
||||
{ key: 'yaoqing_dashou_shu', label: '邀请打手数' },
|
||||
],
|
||||
zuzhang: [
|
||||
{ key: 'yaoqing_guanshi_shu', label: '邀请管事数' },
|
||||
{ key: 'shouru_zonge', label: '收入总额' },
|
||||
{ key: 'fenyong_jine', label: '分佣金额' },
|
||||
],
|
||||
shangjia: [
|
||||
{ key: 'jiesuan_jine', label: '结算金额' },
|
||||
{ key: 'jiesuan_dingdan_shu', label: '结算单量' },
|
||||
{ key: 'paifa_jine', label: '派单流水' },
|
||||
],
|
||||
}
|
||||
|
||||
const sortOptions = computed(() => SORT_OPTIONS[activeShenfen.value] || [])
|
||||
|
||||
const form = reactive({
|
||||
enabled: false,
|
||||
title: '',
|
||||
sort_field: 'chengjiao_zongliang',
|
||||
min_metric: 0,
|
||||
claim_days: 30,
|
||||
description: '',
|
||||
tiers: [{ rank_from: 1, rank_to: 1, reward_amount: 0, label: '冠军' }],
|
||||
})
|
||||
|
||||
const loadSchemes = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/phbjhq', { username: username.value })
|
||||
if (res.code === 403) {
|
||||
hasPermission.value = false
|
||||
return
|
||||
}
|
||||
if (res.code === 0) {
|
||||
schemes.value = res.data.schemes || []
|
||||
selectScheme()
|
||||
}
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const selectScheme = () => {
|
||||
const hit = schemes.value.find(
|
||||
(s) => s.shenfen === activeShenfen.value && s.period_type === activePeriod.value,
|
||||
)
|
||||
const defaults = SORT_OPTIONS[activeShenfen.value]?.[0]?.key || 'chengjiao_zongliang'
|
||||
if (hit) {
|
||||
Object.assign(form, {
|
||||
enabled: hit.enabled,
|
||||
title: hit.title || '',
|
||||
sort_field: hit.sort_field || defaults,
|
||||
min_metric: hit.min_metric || 0,
|
||||
claim_days: hit.claim_days || 30,
|
||||
description: hit.description || '',
|
||||
tiers: hit.tiers?.length
|
||||
? hit.tiers.map((t) => ({ ...t, reward_amount: Number(t.reward_amount) }))
|
||||
: [{ rank_from: 1, rank_to: 1, reward_amount: 0, label: '冠军' }],
|
||||
})
|
||||
} else {
|
||||
Object.assign(form, {
|
||||
enabled: false,
|
||||
title: '',
|
||||
sort_field: defaults,
|
||||
min_metric: 0,
|
||||
claim_days: 30,
|
||||
description: '',
|
||||
tiers: [{ rank_from: 1, rank_to: 1, reward_amount: 0, label: '冠军' }],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const addTier = () => {
|
||||
form.tiers.push({ rank_from: 1, rank_to: 3, reward_amount: 0, label: '' })
|
||||
}
|
||||
|
||||
const save = async () => {
|
||||
if (!form.tiers.length) {
|
||||
ElMessage.warning('请配置奖励档位')
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/phbjbc', {
|
||||
username: username.value,
|
||||
shenfen: activeShenfen.value,
|
||||
period_type: activePeriod.value,
|
||||
...form,
|
||||
})
|
||||
if (res.code === 0) {
|
||||
ElMessage.success('保存成功')
|
||||
await loadSchemes()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败')
|
||||
}
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const loadClaims = async () => {
|
||||
claimsLoading.value = true
|
||||
try {
|
||||
const res = await request.post('/houtai/phbjjl', { username: username.value })
|
||||
if (res.code === 0) claims.value = res.data.list || []
|
||||
} finally {
|
||||
claimsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadSchemes()
|
||||
loadClaims()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.rank-reward-page { padding: 16px; }
|
||||
.scope-alert { margin-bottom: 12px; }
|
||||
.header-bar { margin-bottom: 16px; }
|
||||
.header-bar h2 { margin: 0 0 8px; }
|
||||
.desc { margin: 0; color: #888; font-size: 13px; }
|
||||
.tier-toolbar { display: flex; justify-content: space-between; margin: 16px 0 8px; }
|
||||
.actions { margin-top: 16px; }
|
||||
.claims-card { margin-top: 20px; }
|
||||
.no-permission { text-align: center; padding: 80px 20px; }
|
||||
</style>
|
||||
Reference in New Issue
Block a user