1.优化彩金池配置UI显示

This commit is contained in:
2026-06-03 16:45:57 +08:00
parent 136c18e413
commit 51105dd1e0
5 changed files with 95 additions and 31 deletions

View File

@@ -21,20 +21,22 @@
"currentPoolTitle": "Current Lottery Pool", "currentPoolTitle": "Current Lottery Pool",
"loading": "Loading...", "loading": "Loading...",
"poolName": "Pool Name", "poolName": "Pool Name",
"playerProfit": "Player Total Profit (profit_amount):", "poolProfitAmount": "Pool cumulative profit (profit_amount):",
"realtime": "Live", "realtime": "Live",
"profitCalcHint": "Profit per round: paid = win_coin (incl. BIGWIN) - paid_amount (= ante×1); free = win_coin. Refreshes every 2s while open.", "profitCalcHint": "Accumulated on name=default (Normal) pool: paid += win_coin paid_amount (ante×1); free += win_coin. Compared with safety line to decide paid-draw kill switch. Refreshes every 2s while open.",
"tierRuleTitle": "Tier Rule", "tierRuleTitle": "Paid draw tier rule",
"tierRuleContent": "When player profit in this pool is below safety line, use player T*_weight; when above or equal, use pool T*_weight (kill).", "tierRuleContent": "Compares default pool profit_amount (not per-player profit). Below safety line or kill off: use player T*_weight; at or above safety line with kill on: use killScore pool T*_weight. Free draws always use killScore weights (safety line N/A).",
"enableKillScore": "Enable kill score", "enableKillScore": "Enable kill score",
"killScoreWeights": "Kill weights", "killScoreWeights": "Kill weights (killScore)",
"killWeightNote": "(Kill weights from pool config type=1; edit in list.)", "killWeightNote": "Edit killScore (Force Kill) row in the list for kill weights. This dialog only configures default pool safety line and kill switch.",
"btnResetProfit": "Reset Player Total Profit", "btnResetProfit": "Reset pool cumulative profit",
"btnSaveSafetyLine": "Save Safety Line", "btnSaveSafetyLine": "Save safety line & kill switch",
"safetyLineDefaultOnlyHint": "Only the default (Normal) pool safety line affects kill logic; do not set safety line on other pool types.",
"safetyLineNotUsedReadonly": "This pool type does not use safety line for kill logic. Edit the Normal (default) row or use View Current Pool.",
"ruleSafetyLineRequired": "Please enter safety line", "ruleSafetyLineRequired": "Please enter safety line",
"msgGetPoolFailed": "Failed to get lottery pool", "msgGetPoolFailed": "Failed to get lottery pool",
"msgSaveSuccess": "Save Success", "msgSaveSuccess": "Save Success",
"msgResetProfitSuccess": "Player total profit reset to 0", "msgResetProfitSuccess": "Pool cumulative profit reset to 0",
"msgResetFailed": "Reset failed", "msgResetFailed": "Reset failed",
"ruleNameRequired": "Name is required", "ruleNameRequired": "Name is required",
"rulePoolTypeRequired": "Please select pool type", "rulePoolTypeRequired": "Please select pool type",
@@ -62,6 +64,8 @@
"name": "Name", "name": "Name",
"poolType": "Pool Type", "poolType": "Pool Type",
"safetyLine": "Safety Line", "safetyLine": "Safety Line",
"safetyLineNotUsed": "Not used for kill",
"safetyLineTip": "Normal (default) row only",
"t1PoolWeight": "T1 Pool Weight", "t1PoolWeight": "T1 Pool Weight",
"t2PoolWeight": "T2 Pool Weight", "t2PoolWeight": "T2 Pool Weight",
"t3PoolWeight": "T3 Pool Weight", "t3PoolWeight": "T3 Pool Weight",

View File

@@ -21,20 +21,22 @@
"currentPoolTitle": "当前彩金池", "currentPoolTitle": "当前彩金池",
"loading": "加载中...", "loading": "加载中...",
"poolName": "池子名称", "poolName": "池子名称",
"playerProfit": "玩家累计盈利profit_amount", "poolProfitAmount": "彩金池累计盈利profit_amount",
"realtime": "实时", "realtime": "实时",
"profitCalcHint": "计算方式:付费每局按“赢取平台币 win_coin含 BIGWIN减去付费金额 压注金额paid_amount= 压注倍数ante×1”累加;免费每局按“玩家赢得平台币win_coin”累加。弹窗打开期间每 2 秒自动刷新", "profitCalcHint": "累计在 name=default正常奖池上付费每局 += win_coin paid_amountante×1免费每局 += win_coin。用于与安全线比较判定付费抽奖是否切换杀分。弹窗打开期间每 2 秒自动刷新",
"tierRuleTitle": "抽奖档位规则", "tierRuleTitle": "付费抽奖档位规则",
"tierRuleContent": "当玩家在当前彩金池的累计盈利 低于安全线 时,按 玩家 T*_weight 权重抽取档位;当累计盈利 高于或等于安全线 时,按 当前彩金池 的 T*_weight 权重抽取档位(杀分)。", "tierRuleContent": "比较对象为 default 奖池的 profit_amount非单个玩家盈利。当 profit_amount 低于安全线或未开启杀分时,按玩家 T*_weight 抽档;当 profit_amount 高于或等于安全线且已开启杀分时,按 killScore 奖池的 T*_weight 抽档。免费抽奖始终按 killScore 权重(与安全线无关)。",
"enableKillScore": "开启杀分", "enableKillScore": "开启杀分",
"killScoreWeights": "杀分权重", "killScoreWeights": "杀分权重killScore",
"killWeightNote": "杀分权重来自奖池配置,请在列表中编辑对应记录)", "killWeightNote": "杀分权重请在列表中编辑 name=killScore强制杀猪记录本弹窗仅配置 default 奖池的安全线与杀分开关。",
"btnResetProfit": "重置玩家累计盈利", "btnResetProfit": "重置彩金池累计盈利",
"btnSaveSafetyLine": "保存安全线", "btnSaveSafetyLine": "保存安全线与杀分开关",
"safetyLineDefaultOnlyHint": "仅 name=default正常奖池的安全线参与杀分判定其它奖池类型请勿在此配置安全线。",
"safetyLineNotUsedReadonly": "当前奖池类型不参与杀分判定,安全线仅对「正常(default)」奖池生效,请通过「查看当前彩金池」或编辑正常行修改。",
"ruleSafetyLineRequired": "请输入安全线", "ruleSafetyLineRequired": "请输入安全线",
"msgGetPoolFailed": "获取彩金池失败", "msgGetPoolFailed": "获取彩金池失败",
"msgSaveSuccess": "保存成功", "msgSaveSuccess": "保存成功",
"msgResetProfitSuccess": "玩家累计盈利已重置为 0", "msgResetProfitSuccess": "彩金池累计盈利已重置为 0",
"msgResetFailed": "重置失败", "msgResetFailed": "重置失败",
"ruleNameRequired": "名称必需填写", "ruleNameRequired": "名称必需填写",
"rulePoolTypeRequired": "请选择奖池类型", "rulePoolTypeRequired": "请选择奖池类型",
@@ -62,6 +64,8 @@
"name": "名称", "name": "名称",
"poolType": "奖池类型", "poolType": "奖池类型",
"safetyLine": "安全线", "safetyLine": "安全线",
"safetyLineNotUsed": "不参与杀分判定",
"safetyLineTip": "仅「正常(default)」行有效",
"t1PoolWeight": "T1池权重", "t1PoolWeight": "T1池权重",
"t2PoolWeight": "T2池权重", "t2PoolWeight": "T2池权重",
"t3PoolWeight": "T3池权重", "t3PoolWeight": "T3池权重",

View File

@@ -29,6 +29,12 @@
@pagination:size-change="handleSizeChange" @pagination:size-change="handleSizeChange"
@pagination:current-change="handleCurrentChange" @pagination:current-change="handleCurrentChange"
> >
<template #safety_line="{ row }">
<span v-if="isDefaultPoolRow(row)" class="font-mono">{{
formatSafetyLine(row.safety_line)
}}</span>
<span v-else class="text-gray-400 text-xs">{{ $t('page.table.safetyLineNotUsed') }}</span>
</template>
<!-- 操作列 --> <!-- 操作列 -->
<template #operation="{ row }"> <template #operation="{ row }">
<div class="flex gap-2"> <div class="flex gap-2">
@@ -96,6 +102,17 @@
return v != null && v !== '' ? `${v}%` : '-' return v != null && v !== '' ? `${v}%` : '-'
} }
/** 仅 name=default正常奖池的安全线参与杀分判定 */
function isDefaultPoolRow(row: Record<string, unknown>): boolean {
return String(row.name ?? '') === 'default'
}
function formatSafetyLine(val: unknown): string {
if (val === null || val === undefined || val === '') return '-'
const n = typeof val === 'number' ? val : Number(val)
return Number.isFinite(n) ? n.toFixed(2) : '-'
}
// 表格配置 // 表格配置
const { const {
columns, columns,
@@ -116,7 +133,13 @@
columnsFactory: () => [ columnsFactory: () => [
{ prop: 'name', label: 'page.table.name', align: 'center' }, { prop: 'name', label: 'page.table.name', align: 'center' },
{ prop: 'name', label: 'page.table.poolType', width: 100, align: 'center', formatter: typeFormatter }, { prop: 'name', label: 'page.table.poolType', width: 100, align: 'center', formatter: typeFormatter },
{ prop: 'safety_line', label: 'page.table.safetyLine', align: 'center' }, {
prop: 'safety_line',
label: 'page.table.safetyLine',
minWidth: 120,
align: 'center',
useSlot: true
},
{ {
prop: 't1_weight', prop: 't1_weight',
label: 'page.table.t1PoolWeight', label: 'page.table.t1PoolWeight',

View File

@@ -16,7 +16,7 @@
</div> </div>
<div class="profit-row mb-3"> <div class="profit-row mb-3">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<span class="text-gray-500">{{ $t('page.form.playerProfit') }}</span> <span class="text-gray-500">{{ $t('page.form.poolProfitAmount') }}</span>
<span class="font-mono text-lg" :class="profitAmountClass">{{ <span class="font-mono text-lg" :class="profitAmountClass">{{
displayProfitAmount displayProfitAmount
}}</span> }}</span>
@@ -41,6 +41,7 @@
:precision="2" :precision="2"
style="width: 100%" style="width: 100%"
/> />
<div class="text-gray-500 text-xs mt-1">{{ $t('page.table.safetyLineTip') }}</div>
</el-form-item> </el-form-item>
<el-form-item :label="$t('page.form.enableKillScore')"> <el-form-item :label="$t('page.form.enableKillScore')">
<el-switch v-model="formData.kill_enabled" :active-value="1" :inactive-value="0" /> <el-switch v-model="formData.kill_enabled" :active-value="1" :inactive-value="0" />

View File

@@ -26,13 +26,22 @@
/> />
</el-form-item> </el-form-item>
<!-- dice_lottery_pool_config 已移除 type 字段 name 区分 default/killScore/upname --> <!-- dice_lottery_pool_config 已移除 type 字段 name 区分 default/killScore/upname -->
<el-form-item :label="$t('page.form.safetyLine')" prop="safety_line"> <el-form-item v-if="showSafetyLineField" :label="$t('page.form.safetyLine')" prop="safety_line">
<el-input-number <el-input-number
v-model="formData.safety_line" v-model="formData.safety_line"
:min="0" :min="0"
:precision="2" :precision="2"
style="width: 100%" style="width: 100%"
/> />
<div class="text-gray-500 text-xs mt-1">{{ $t('page.table.safetyLineTip') }}</div>
</el-form-item>
<el-form-item v-else-if="showSafetyLineReadonlyHint" :label="$t('page.form.safetyLine')">
<el-alert
type="info"
:closable="false"
show-icon
:title="$t('page.form.safetyLineNotUsedReadonly')"
/>
</el-form-item> </el-form-item>
<el-form-item :label="$t('page.form.t1Weight')" prop="t1_weight"> <el-form-item :label="$t('page.form.t1Weight')" prop="t1_weight">
<el-slider v-model="formData.t1_weight" :min="0" :max="100" :step="0.01" show-input /> <el-slider v-model="formData.t1_weight" :min="0" :max="100" :step="0.01" show-input />
@@ -111,17 +120,36 @@
return WEIGHT_KEYS.reduce((sum, key) => sum + Number(formData[key] ?? 0), 0) return WEIGHT_KEYS.reduce((sum, key) => sum + Number(formData[key] ?? 0), 0)
}) })
function isDefaultPoolName(name: unknown): boolean {
return String(name ?? '') === 'default'
}
const showSafetyLineField = computed(() => isDefaultPoolName(formData.name))
const showSafetyLineReadonlyHint = computed(() => {
const n = String(formData.name ?? '').trim()
return n !== '' && !isDefaultPoolName(n)
})
/** /**
* 表单验证规则 * 表单验证规则
*/ */
const rules = computed<FormRules>(() => ({ const rules = computed<FormRules>(() => {
name: [{ required: true, message: t('page.form.ruleNameRequired'), trigger: 'blur' }], const base: FormRules = {
t1_weight: [{ required: true, message: t('page.form.ruleT1Required'), trigger: 'blur' }], name: [{ required: true, message: t('page.form.ruleNameRequired'), trigger: 'blur' }],
t2_weight: [{ required: true, message: t('page.form.ruleT2Required'), trigger: 'blur' }], t1_weight: [{ required: true, message: t('page.form.ruleT1Required'), trigger: 'blur' }],
t3_weight: [{ required: true, message: t('page.form.ruleT3Required'), trigger: 'blur' }], t2_weight: [{ required: true, message: t('page.form.ruleT2Required'), trigger: 'blur' }],
t4_weight: [{ required: true, message: t('page.form.ruleT4Required'), trigger: 'blur' }], t3_weight: [{ required: true, message: t('page.form.ruleT3Required'), trigger: 'blur' }],
t5_weight: [{ required: true, message: t('page.form.ruleT5Required'), trigger: 'blur' }] t4_weight: [{ required: true, message: t('page.form.ruleT4Required'), trigger: 'blur' }],
})) t5_weight: [{ required: true, message: t('page.form.ruleT5Required'), trigger: 'blur' }]
}
if (showSafetyLineField.value) {
base.safety_line = [
{ required: true, message: t('page.form.ruleSafetyLineRequired'), trigger: 'blur' }
]
}
return base
})
/** /**
* 初始数据(权重为数字便于输入与校验) * 初始数据(权重为数字便于输入与校验)
@@ -224,11 +252,15 @@
props.data?.dept_id ?? props.data?.dept_id ??
channelScope?.selectedDeptId.value channelScope?.selectedDeptId.value
}) })
const { safety_line, ...submitWithoutSafetyLine } = submitData
const payload = isDefaultPoolName(submitData.name)
? submitData
: submitWithoutSafetyLine
if (props.dialogType === 'add') { if (props.dialogType === 'add') {
await api.save(submitData) await api.save(payload)
ElMessage.success(t('page.form.msgAddSuccess')) ElMessage.success(t('page.form.msgAddSuccess'))
} else { } else {
await api.update(submitData) await api.update(payload)
ElMessage.success(t('page.form.msgUpdateSuccess')) ElMessage.success(t('page.form.msgUpdateSuccess'))
} }
emit('success') emit('success')