feat: configure dual game king rankings

This commit is contained in:
zhx 2026-07-22 18:54:53 +08:00
parent 36999097d8
commit cc455ccfb8

View File

@ -38,7 +38,8 @@
</el-table-column>
<el-table-column label="抽奖门槛" min-width="125" align="right">
<template slot-scope="scope">
{{ formatNumber(scope.row.coinPerDraw) }} 金币
<div> {{ formatNumber(scope.row.coinPerDraw) }} 金币</div>
<div class="secondary-text">每日最多 {{ scope.row.dailyChanceLimit }} </div>
</template>
</el-table-column>
<el-table-column label="状态" min-width="130" align="center">
@ -157,6 +158,20 @@
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="每日最多获次数" prop="dailyChanceLimit">
<el-input-number
v-model="form.dailyChanceLimit"
:min="1"
:max="10000"
:precision="0"
controls-position="right"
style="width: 100%"
:disabled="startedLocked"
/>
<div class="form-help">按活动时区自然日封顶超出部分仍计入两个榜单但不再增加抽奖次数</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结算等待(分钟)" prop="settlementDelayMinutes">
<el-input-number
@ -172,8 +187,8 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排行口径">
<el-input value="消费金币榜TYCOON" disabled />
<el-form-item label="榜单配置">
<el-input value="消耗榜TYCOON+ 中奖入账榜VICTORIOUS" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
@ -245,14 +260,21 @@
</el-table>
<div class="weight-summary">当前总权重{{ totalPrizeWeight }}</div>
<div class="section-title">排行榜结算奖励固定六档</div>
<div class="section-title">排行榜结算奖励每个榜单固定六档</div>
<el-alert
type="warning"
:closable="false"
show-icon
title="名次范围不可增删或修改;活动结束后按最终消费榜快照结算,失败记录可在结算记录中单独重试。"
title="消费榜和中奖榜分别配置六档奖励;名次范围不可增删或修改,失败记录可在结算记录中单独重试。"
/>
<el-table :data="form.rankRewards" border class="config-table">
<el-table-column label="榜单" width="110" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.rankingType === 'VICTORIOUS' ? 'warning' : 'primary'">
{{ rankingTypeText(scope.row.rankingType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="名次范围" width="130" align="center">
<template slot-scope="scope">
<el-tag type="success">{{ rankRangeText(scope.row) }}</el-tag>
@ -346,10 +368,17 @@
</el-table>
</template>
</el-table-column>
<el-table-column label="榜单" width="110" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.rankingType === 'VICTORIOUS' ? 'warning' : 'primary'">
{{ rankingTypeText(scope.row.rankingType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="名次" width="70" align="center" prop="rank" />
<el-table-column label="用户 ID" min-width="160" prop="userId" />
<el-table-column label="消费金币" min-width="120" align="right">
<template slot-scope="scope">{{ formatNumber(scope.row.totalConsumed) }}</template>
<el-table-column label="榜单数值" min-width="120" align="right">
<template slot-scope="scope">{{ formatNumber(scope.row.score === undefined ? scope.row.totalConsumed : scope.row.score) }}</template>
</el-table-column>
<el-table-column label="资源组" min-width="145" prop="resourceGroupId" />
<el-table-column label="发放状态" width="110" align="center">
@ -543,6 +572,7 @@ const REQUIRED_RANK_RANGES = [
[8, 10],
[11, 30]
]
const RANKING_TYPES = ['TYCOON', 'VICTORIOUS']
export default {
name: 'ActivityGameKing',
@ -619,6 +649,7 @@ export default {
timeZone: 'Asia/Riyadh',
timeRange: [],
coinPerDraw: 1,
dailyChanceLimit: 10,
settlementDelayMinutes: 30,
rankingType: 'TYCOON',
rankingPeriod: 'OVERALL',
@ -642,15 +673,18 @@ export default {
}))
},
emptyRankRewards() {
return REQUIRED_RANK_RANGES.map((range, index) => ({
id: '',
activityId: '',
startRank: range[0],
endRank: range[1],
resourceGroupId: '',
rewardName: index < 3 ? `Top ${index + 1} 奖励` : `Top ${range[0]}-${range[1]} 奖励`,
rewards: []
}))
return RANKING_TYPES.reduce((result, rankingType) => result.concat(
REQUIRED_RANK_RANGES.map((range, index) => ({
id: '',
activityId: '',
rankingType,
startRank: range[0],
endRank: range[1],
resourceGroupId: '',
rewardName: index < 3 ? `Top ${index + 1} 奖励` : `Top ${range[0]}-${range[1]} 奖励`,
rewards: []
}))
), [])
},
loadActivities() {
this.listLoading = true
@ -681,6 +715,8 @@ export default {
timeZone: activity.timeZone || 'Asia/Riyadh',
settlementDelayMinutes: activity.settlementDelayMinutes === null || activity.settlementDelayMinutes === undefined
? 30 : Number(activity.settlementDelayMinutes),
dailyChanceLimit: activity.dailyChanceLimit === null || activity.dailyChanceLimit === undefined
? 10 : Number(activity.dailyChanceLimit),
timeRange: [activity.startTime, activity.endTime],
prizes,
rankRewards
@ -708,7 +744,13 @@ export default {
mergeRankRewards(rankRewards) {
const result = this.emptyRankRewards()
rankRewards.forEach(item => {
const index = REQUIRED_RANK_RANGES.findIndex(range => range[0] === Number(item.startRank) && range[1] === Number(item.endRank))
//
const rankingType = item.rankingType || 'TYCOON'
const index = result.findIndex(target =>
target.rankingType === rankingType &&
target.startRank === Number(item.startRank) &&
target.endRank === Number(item.endRank)
)
if (index >= 0) {
result.splice(index, 1, Object.assign({}, result[index], item, {
rewards: item.rewardItems || item.rewards || []
@ -735,7 +777,7 @@ export default {
}
const payload = this.buildSavePayload()
this.saveLoading = true
//
//
saveAslanGameKingActivity(payload).then(() => {
this.$message.success('活动配置已保存')
this.editorVisible = false
@ -755,6 +797,10 @@ export default {
this.$message.error('每次抽奖金币数必须是大于 0 的安全整数')
return false
}
if (!Number.isSafeInteger(Number(this.form.dailyChanceLimit)) || Number(this.form.dailyChanceLimit) < 1 || Number(this.form.dailyChanceLimit) > 10000) {
this.$message.error('每日最多获得次数必须是 1 到 10000 的整数')
return false
}
if (!Number.isInteger(Number(this.form.settlementDelayMinutes)) ||
Number(this.form.settlementDelayMinutes) < 0 || Number(this.form.settlementDelayMinutes) > 1440) {
this.$message.error('结算等待必须是 0 到 1440 的整数分钟')
@ -777,14 +823,15 @@ export default {
this.$message.error('请补全 7 个奖项的名称、图片、正整数权重、合法库存和奖励资源组')
return false
}
const rangesValid = this.form.rankRewards.length === REQUIRED_RANK_RANGES.length &&
const rangesValid = this.form.rankRewards.length === REQUIRED_RANK_RANGES.length * RANKING_TYPES.length &&
this.form.rankRewards.every((item, index) =>
Number(item.startRank) === REQUIRED_RANK_RANGES[index][0] &&
Number(item.endRank) === REQUIRED_RANK_RANGES[index][1] &&
item.rankingType === RANKING_TYPES[Math.floor(index / REQUIRED_RANK_RANGES.length)] &&
Number(item.startRank) === REQUIRED_RANK_RANGES[index % REQUIRED_RANK_RANGES.length][0] &&
Number(item.endRank) === REQUIRED_RANK_RANGES[index % REQUIRED_RANK_RANGES.length][1] &&
Boolean(item.resourceGroupId)
)
if (!rangesValid) {
this.$message.error('六档名次范围必须保持固定,并为每档选择奖励资源组')
this.$message.error('两个榜单的六档名次范围必须保持固定,并为每档选择奖励资源组')
return false
}
return true
@ -802,6 +849,7 @@ export default {
endTime: Number(this.form.timeRange[1]),
settlementDelayMinutes: Number(this.form.settlementDelayMinutes),
coinPerDraw: Number(this.form.coinPerDraw),
dailyChanceLimit: Number(this.form.dailyChanceLimit),
rankingType: 'TYCOON',
rankingPeriod: 'OVERALL',
enabled: Boolean(this.form.enabled)
@ -821,6 +869,7 @@ export default {
payload.rankRewards = this.form.rankRewards.map(item => ({
id: item.id || null,
activityId: this.form.id || null,
rankingType: item.rankingType,
startRank: Number(item.startRank),
endRank: Number(item.endRank),
resourceGroupId: String(item.resourceGroupId),
@ -1051,6 +1100,9 @@ export default {
rankRangeText(row) {
return row.startRank === row.endRank ? `Top ${row.startRank}` : `Top ${row.startRank}-${row.endRank}`
},
rankingTypeText(rankingType) {
return rankingType === 'VICTORIOUS' ? '中奖榜' : '消耗榜'
},
formatTime(value) {
if (!value) {
return '-'