1.新增默认彩金池配置
2.优化关联彩金池配置的名称显示 3.优化一键测试权重 4.优化底注配置
This commit is contained in:
@@ -27,6 +27,8 @@
|
||||
"labelIsDefault": "Default Ante",
|
||||
"placeholderName": "Please enter name",
|
||||
"placeholderTitle": "Please enter title",
|
||||
"placeholderNameAuto": "Auto from multiplier, e.g. x5",
|
||||
"placeholderTitleAuto": "Auto from multiplier, e.g. x5",
|
||||
"ruleNameRequired": "Please enter name",
|
||||
"ruleTitleRequired": "Please enter title",
|
||||
"ruleMultRequired": "Please enter ante multiplier",
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
"dialogTitleEdit": "Edit Lottery Pool Config",
|
||||
"placeholderName": "Please enter name",
|
||||
"placeholderRemark": "Please enter remark",
|
||||
"placeholderPoolName": "Pool display name, e.g. Normal pool",
|
||||
"placeholderConfigNote": "Optional notes about this pool",
|
||||
"poolType": "Pool Type",
|
||||
"placeholderPoolType": "Please select pool type",
|
||||
"poolTypeNormal": "Normal",
|
||||
"poolTypeFree": "Free",
|
||||
"poolTypeKill": "Kill",
|
||||
"poolTypeKill": "Force score kill",
|
||||
"poolTypeT1": "T1 High",
|
||||
"safetyLine": "Safety Line",
|
||||
"t1Weight": "T1 Pool Weight (%)",
|
||||
@@ -59,11 +61,13 @@
|
||||
"placeholderPoolType": "Please select pool type",
|
||||
"poolTypeNormal": "Normal",
|
||||
"poolTypeFree": "Free",
|
||||
"poolTypeKill": "Force Kill",
|
||||
"poolTypeKill": "Force Score Kill",
|
||||
"poolTypeT1": "T1 High Rate"
|
||||
},
|
||||
"table": {
|
||||
"name": "Name",
|
||||
"name": "Code",
|
||||
"poolName": "Pool Name",
|
||||
"configNote": "Remark",
|
||||
"poolType": "Pool Type",
|
||||
"safetyLine": "Safety Line",
|
||||
"safetyLineNotUsed": "Not used for kill",
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
"placeholderLotteryPool": "Leave empty for custom weights below, or select pool",
|
||||
"currentConfig": "Current Config",
|
||||
"configLabelName": "Name",
|
||||
"configLabelPoolName": "Pool name",
|
||||
"configLabelCode": "Code",
|
||||
"configLabelType": "Type",
|
||||
"configLabelWeights": "T1–T5 Weights",
|
||||
"configLabelRemark": "Remark",
|
||||
|
||||
@@ -73,8 +73,10 @@
|
||||
"labelLotteryTypeFree": "Free tier pool",
|
||||
"labelAnte": "Ante",
|
||||
"placeholderAnte": "Select ante config",
|
||||
"placeholderPaidPool": "Leave empty for custom tier odds below (default: default)",
|
||||
"placeholderFreePool": "Leave empty for custom tier odds below (default: free pool)",
|
||||
"anteRandomOption": "Random (pick from channel ante configs)",
|
||||
"placeholderPaidPool": "Leave empty to set T1–T5 weights manually",
|
||||
"placeholderFreePool": "Leave empty to set T1–T5 weights manually",
|
||||
"selectedPoolHint": "Selected pool: {name}",
|
||||
"tierProbHint": "Custom tier odds (T1–T5), each 0–100%, sum of five must not exceed 100%",
|
||||
"tierFieldLabel": "Tier {tier} (%)",
|
||||
"tierSumError": "Current sum of five tiers is {sum}%, cannot exceed 100%",
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
"chainModeNo": "No",
|
||||
"paidPlannedSpins": "Planned paid spins",
|
||||
"ante": "Ante",
|
||||
"anteRandom": "Random",
|
||||
"testSafetyLine": "Safety line",
|
||||
"playAgainCount": "Play-again count",
|
||||
"progressDraws": "{over} done",
|
||||
"progressFailed": "{over} before fail",
|
||||
@@ -51,11 +53,13 @@
|
||||
"testCountProgress": "In progress: {over} done",
|
||||
"testCountFailed": "{over} before failure",
|
||||
"chainModeLabel": "Chain play-again",
|
||||
"killModeOff": "Kill mode off",
|
||||
"paidPlannedSpins": "Planned paid spins",
|
||||
"testSafetyLine": "Test safety line",
|
||||
"createTime": "Created at",
|
||||
"admin": "Operator",
|
||||
"paidPoolId": "Paid lottery pool config ID",
|
||||
"freePoolId": "Free lottery pool config ID",
|
||||
"paidPoolId": "Paid lottery pool",
|
||||
"freePoolId": "Free lottery pool",
|
||||
"bigwinSnapshot": "BIGWIN weight snapshot",
|
||||
"sectionPaidTier": "Paid draw tier odds (T1–T5, used in test)",
|
||||
"sectionFreeTier": "Free draw tier odds (T1–T5, used in test)",
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
"labelIsDefault": "默认底注",
|
||||
"placeholderName": "请输入名称",
|
||||
"placeholderTitle": "请输入标题",
|
||||
"placeholderNameAuto": "随底注倍率自动生成,如 x5",
|
||||
"placeholderTitleAuto": "随底注倍率自动生成,如 x5",
|
||||
"ruleNameRequired": "请输入名称",
|
||||
"ruleTitleRequired": "请输入标题",
|
||||
"ruleMultRequired": "请输入底注倍率",
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
"dialogTitleEdit": "编辑色子奖池配置",
|
||||
"placeholderName": "请输入名称",
|
||||
"placeholderRemark": "请输入备注",
|
||||
"placeholderPoolName": "请输入奖池名称,如:正常池",
|
||||
"placeholderConfigNote": "选填,用于说明该奖池用途或规则",
|
||||
"poolType": "奖池类型",
|
||||
"poolName": "奖池名称",
|
||||
"placeholderPoolType": "请选择奖池类型",
|
||||
"poolTypeNormal": "正常",
|
||||
"poolTypeFree": "免费",
|
||||
"poolTypeKill": "强制杀猪",
|
||||
"poolTypeKill": "强制杀分",
|
||||
"poolTypeT1": "T1高倍率",
|
||||
"safetyLine": "安全线",
|
||||
"t1Weight": "T1池权重(%)",
|
||||
@@ -29,7 +32,7 @@
|
||||
"tierRuleContent": "比较对象为 default 奖池的 profit_amount(非单个玩家盈利)。当 profit_amount 低于安全线或未开启杀分时,付费按玩家 T*_weight 抽档;当 profit_amount 高于或等于安全线且已开启杀分时,付费按 killScore 奖池抽档。免费抽奖始终按本渠道 name=free 奖池权重(无 free 时回退 default),与安全线无关。",
|
||||
"enableKillScore": "开启杀分",
|
||||
"killScoreWeights": "杀分权重(killScore)",
|
||||
"killWeightNote": "杀分权重请在列表中编辑 name=killScore(强制杀猪)记录;本弹窗仅配置 default 奖池的安全线与杀分开关。",
|
||||
"killWeightNote": "杀分权重请在列表中编辑 name=killScore(强制杀分)记录;本弹窗仅配置 default 奖池的安全线与杀分开关。",
|
||||
"btnResetProfit": "重置彩金池累计盈利",
|
||||
"btnSaveSafetyLine": "保存安全线与杀分开关",
|
||||
"safetyLineDefaultOnlyHint": "仅 name=default(正常)奖池的安全线参与杀分判定;其它奖池类型请勿在此配置安全线。",
|
||||
@@ -55,15 +58,18 @@
|
||||
},
|
||||
"search": {
|
||||
"poolType": "奖池类型",
|
||||
"poolName": "奖池名称",
|
||||
"placeholderName": "请输入名称",
|
||||
"placeholderPoolType": "请选择奖池类型",
|
||||
"poolTypeNormal": "正常",
|
||||
"poolTypeFree": "免费",
|
||||
"poolTypeKill": "强制杀猪",
|
||||
"poolTypeKill": "强制杀分",
|
||||
"poolTypeT1": "T1高倍率"
|
||||
},
|
||||
"table": {
|
||||
"name": "名称",
|
||||
"name": "内部标识",
|
||||
"poolName": "奖池名称",
|
||||
"configNote": "备注",
|
||||
"poolType": "奖池类型",
|
||||
"safetyLine": "安全线",
|
||||
"safetyLineNotUsed": "不参与杀分判定",
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
"placeholderLotteryPool": "留空则使用下方自定义权重,或选择彩金池",
|
||||
"currentConfig": "当前配置",
|
||||
"configLabelName": "名称",
|
||||
"configLabelPoolName": "奖池名称",
|
||||
"configLabelCode": "内部标识",
|
||||
"configLabelType": "类型",
|
||||
"configLabelWeights": "T1~T5 权重",
|
||||
"configLabelRemark": "备注",
|
||||
|
||||
@@ -73,8 +73,10 @@
|
||||
"labelLotteryTypeFree": "免费档位奖池",
|
||||
"labelAnte": "底注",
|
||||
"placeholderAnte": "请选择底注配置",
|
||||
"placeholderPaidPool": "不选则下方自定义档位概率(默认 default)",
|
||||
"placeholderFreePool": "不选则下方自定义档位概率(默认 free 免费奖池)",
|
||||
"anteRandomOption": "随机(从当前渠道底注配置中抽取)",
|
||||
"placeholderPaidPool": "不选则下方手动设定 T1–T5 档位权重",
|
||||
"placeholderFreePool": "不选则下方手动设定 T1–T5 档位权重",
|
||||
"selectedPoolHint": "已选奖池:{name}",
|
||||
"tierProbHint": "自定义档位概率(T1~T5),每档 0-100%,五档之和不能超过 100%",
|
||||
"tierFieldLabel": "档位 {tier}(%)",
|
||||
"tierSumError": "当前五档之和为 {sum}%,不能超过 100%",
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
"chainModeNo": "否",
|
||||
"paidPlannedSpins": "计划付费次数",
|
||||
"ante": "底注",
|
||||
"anteRandom": "随机",
|
||||
"testSafetyLine": "安全线",
|
||||
"playAgainCount": "再来一次次数",
|
||||
"progressDraws": "已完成 {over} 次",
|
||||
"progressFailed": "失败前 {over} 次",
|
||||
@@ -51,11 +53,13 @@
|
||||
"testCountProgress": "进行中:已完成 {over} 次",
|
||||
"testCountFailed": "失败前 {over} 次",
|
||||
"chainModeLabel": "链式再来一次",
|
||||
"killModeOff": "未开启杀分",
|
||||
"paidPlannedSpins": "计划付费次数",
|
||||
"testSafetyLine": "测试安全线",
|
||||
"createTime": "创建时间",
|
||||
"admin": "执行管理员",
|
||||
"paidPoolId": "付费奖池配置ID",
|
||||
"freePoolId": "免费奖池配置ID",
|
||||
"paidPoolId": "付费彩金池",
|
||||
"freePoolId": "免费彩金池",
|
||||
"bigwinSnapshot": "BIGWIN 权重快照",
|
||||
"sectionPaidTier": "付费抽奖档位概率(T1-T5,测试时使用)",
|
||||
"sectionFreeTier": "免费抽奖档位概率(T1-T5,测试时使用)",
|
||||
|
||||
@@ -9,13 +9,19 @@
|
||||
>
|
||||
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
|
||||
<el-form-item :label="$t('page.form.labelName')" prop="name">
|
||||
<el-input v-model="formData.name" :placeholder="$t('page.form.placeholderName')" />
|
||||
<el-input v-model="formData.name" disabled :placeholder="$t('page.form.placeholderNameAuto')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.form.labelTitle')" prop="title">
|
||||
<el-input v-model="formData.title" :placeholder="$t('page.form.placeholderTitle')" />
|
||||
<el-input v-model="formData.title" disabled :placeholder="$t('page.form.placeholderTitleAuto')" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.form.labelMult')" prop="mult">
|
||||
<el-input-number v-model="formData.mult" :min="1" :step="1" style="width: 100%" />
|
||||
<el-input-number
|
||||
v-model="formData.mult"
|
||||
:min="1"
|
||||
:step="1"
|
||||
style="width: 100%"
|
||||
@update:model-value="syncNameTitleFromMult"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.form.labelIsDefault')" prop="is_default">
|
||||
<el-radio-group v-model="formData.is_default">
|
||||
@@ -87,6 +93,13 @@
|
||||
|
||||
const formData = reactive({ ...initialFormData })
|
||||
|
||||
function syncNameTitleFromMult() {
|
||||
const mult = Number(formData.mult) || 1
|
||||
const label = `x${mult}`
|
||||
formData.name = label
|
||||
formData.title = label
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
async (newVal) => {
|
||||
@@ -99,6 +112,7 @@
|
||||
if (typeof props.data.title === 'string') formData.title = props.data.title
|
||||
formData.mult = Number(props.data.mult ?? 1) || 1
|
||||
formData.is_default = Number(props.data.is_default ?? 0) === 1 ? 1 : 0
|
||||
syncNameTitleFromMult()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import request from '@/utils/http'
|
||||
import {
|
||||
normalizeLotteryPoolOption,
|
||||
type LotteryPoolOption
|
||||
} from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
export type LotteryPoolConfigOption = LotteryPoolOption & {
|
||||
t1_weight: number
|
||||
t2_weight: number
|
||||
t3_weight: number
|
||||
t4_weight: number
|
||||
t5_weight: number
|
||||
}
|
||||
|
||||
/**
|
||||
* 色子奖池配置 API 接口
|
||||
@@ -20,32 +32,24 @@ export default {
|
||||
* 获取 DiceLotteryPoolConfig 列表数据,含 id、name、t1_weight~t5_weight,用于一键测试权重档位类型下拉
|
||||
* name 映射:default=原 type=0,killScore=原 type=1,up=原 type=2
|
||||
*/
|
||||
async getOptions(params?: Record<string, unknown>): Promise<
|
||||
Array<{
|
||||
id: number
|
||||
name: string
|
||||
t1_weight: number
|
||||
t2_weight: number
|
||||
t3_weight: number
|
||||
t4_weight: number
|
||||
t5_weight: number
|
||||
}>
|
||||
> {
|
||||
async getOptions(params?: Record<string, unknown>): Promise<LotteryPoolConfigOption[]> {
|
||||
const res = await request.get<any>({
|
||||
url: '/core/dice/lottery_pool_config/DiceLotteryPoolConfig/getOptions',
|
||||
params
|
||||
})
|
||||
const rows = Array.isArray(res) ? res : (Array.isArray((res as any)?.data) ? (res as any).data : [])
|
||||
if (!Array.isArray(rows)) return []
|
||||
return rows.map((r: any) => ({
|
||||
id: Number(r.id),
|
||||
name: String(r.name ?? r.id ?? ''),
|
||||
t1_weight: Number(r.t1_weight ?? 0),
|
||||
t2_weight: Number(r.t2_weight ?? 0),
|
||||
t3_weight: Number(r.t3_weight ?? 0),
|
||||
t4_weight: Number(r.t4_weight ?? 0),
|
||||
t5_weight: Number(r.t5_weight ?? 0)
|
||||
}))
|
||||
return rows.map((r: Record<string, unknown>) => {
|
||||
const base = normalizeLotteryPoolOption(r)
|
||||
return {
|
||||
...base,
|
||||
t1_weight: Number(r.t1_weight ?? 0),
|
||||
t2_weight: Number(r.t2_weight ?? 0),
|
||||
t3_weight: Number(r.t3_weight ?? 0),
|
||||
t4_weight: Number(r.t4_weight ?? 0),
|
||||
t5_weight: Number(r.t5_weight ?? 0)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import request from '@/utils/http'
|
||||
import { normalizeLotteryPoolOption, type LotteryPoolOption } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
/**
|
||||
* 玩家抽奖记录 API接口
|
||||
@@ -59,11 +60,13 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
/** 获取彩金池配置选项(id、name) */
|
||||
getLotteryConfigOptions(params?: Record<string, unknown>) {
|
||||
return request.get<{ id: number; name: string }[]>({
|
||||
/** 获取彩金池配置选项(含奖池名称) */
|
||||
async getLotteryConfigOptions(params?: Record<string, unknown>): Promise<LotteryPoolOption[]> {
|
||||
const res = await request.get<any>({
|
||||
url: '/core/dice/play_record/DicePlayRecord/getLotteryConfigOptions',
|
||||
params
|
||||
})
|
||||
const rows = (Array.isArray(res) ? res : (res?.data ?? [])) as Array<Record<string, unknown>>
|
||||
return rows.map((r) => normalizeLotteryPoolOption(r))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import request from '@/utils/http'
|
||||
import { normalizeLotteryPoolOption } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
/**
|
||||
* 大富翁-玩家 API接口
|
||||
@@ -84,16 +85,15 @@ export default {
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取彩金池配置选项(DiceLotteryPoolConfig.id、name),供 lottery_config_id 下拉使用
|
||||
* @returns [ { id, name } ]
|
||||
* 获取彩金池配置选项,供 lottery_config_id 下拉使用(含奖池名称 display_name)
|
||||
*/
|
||||
async getLotteryConfigOptions(params?: Record<string, unknown>): Promise<Array<{ id: number; name: string }>> {
|
||||
async getLotteryConfigOptions(params?: Record<string, unknown>) {
|
||||
const res = await request.get<any>({
|
||||
url: '/core/dice/player/DicePlayer/getLotteryConfigOptions',
|
||||
params
|
||||
})
|
||||
const rows = (Array.isArray(res) ? res : (res?.data ?? [])) as Array<{ id: number; name: string }>
|
||||
return rows.map((r) => ({ id: Number(r.id), name: String(r.name ?? r.id ?? '') }))
|
||||
const rows = (Array.isArray(res) ? res : (res?.data ?? [])) as Array<Record<string, unknown>>
|
||||
return rows.map((r) => normalizeLotteryPoolOption(r))
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,14 +87,10 @@
|
||||
getData()
|
||||
}
|
||||
|
||||
// 奖池类型展示:按 name 映射
|
||||
const typeFormatter = (row: Record<string, unknown>) => {
|
||||
const n = String(row.name ?? '')
|
||||
if (n === 'default') return t('page.search.poolTypeNormal')
|
||||
if (n === 'free') return t('page.search.poolTypeFree')
|
||||
if (n === 'killScore') return t('page.search.poolTypeKill')
|
||||
if (n === 'up') return t('page.search.poolTypeT1')
|
||||
return n || '-'
|
||||
const poolNameFormatter = (row: Record<string, unknown>) => {
|
||||
const remark = String(row.remark ?? '').trim()
|
||||
if (remark) return remark
|
||||
return String(row.name ?? '').trim() || '-'
|
||||
}
|
||||
|
||||
// 权重列带 %
|
||||
@@ -132,8 +128,19 @@
|
||||
core: {
|
||||
apiFn: api.list,
|
||||
columnsFactory: () => [
|
||||
{ prop: 'name', label: 'page.table.name', align: 'center' },
|
||||
{ prop: 'name', label: 'page.table.poolType', width: 100, align: 'center', formatter: typeFormatter },
|
||||
{ prop: 'remark', label: 'page.table.poolName', minWidth: 120, align: 'center', formatter: poolNameFormatter },
|
||||
{
|
||||
prop: 'config_note',
|
||||
label: 'page.table.configNote',
|
||||
minWidth: 140,
|
||||
align: 'center',
|
||||
showOverflowTooltip: true,
|
||||
formatter: (row: Record<string, unknown>) => {
|
||||
const v = String(row.config_note ?? '').trim()
|
||||
return v || '-'
|
||||
}
|
||||
},
|
||||
{ prop: 'name', label: 'page.table.name', width: 110, align: 'center' },
|
||||
{
|
||||
prop: 'safety_line',
|
||||
label: 'page.table.safetyLine',
|
||||
|
||||
@@ -15,12 +15,20 @@
|
||||
:disabled="dialogType === 'edit'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('form.labelRemark')" prop="remark">
|
||||
<el-form-item :label="$t('page.form.poolName')" prop="remark">
|
||||
<el-input
|
||||
v-model="formData.remark"
|
||||
:placeholder="$t('page.form.placeholderPoolName')"
|
||||
maxlength="200"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('form.labelRemark')" prop="config_note">
|
||||
<el-input
|
||||
v-model="formData.config_note"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
:placeholder="$t('page.form.placeholderRemark')"
|
||||
:placeholder="$t('page.form.placeholderConfigNote')"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
@@ -159,6 +167,7 @@
|
||||
dept_id: undefined as number | undefined,
|
||||
name: '',
|
||||
remark: '',
|
||||
config_note: '',
|
||||
safety_line: 0 as number,
|
||||
t1_weight: 0 as number,
|
||||
t2_weight: 0 as number,
|
||||
|
||||
@@ -143,6 +143,7 @@
|
||||
import api from '../../api/play_record/index'
|
||||
import TableSearch from './modules/table-search.vue'
|
||||
import EditDialog from './modules/edit-dialog.vue'
|
||||
import { lotteryPoolRowLabel } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
const { t } = useI18n()
|
||||
|
||||
// 搜索表单
|
||||
@@ -177,8 +178,7 @@
|
||||
|
||||
const usernameFormatter = (row: Record<string, any>) =>
|
||||
row?.dicePlayer?.username ?? row?.player_id ?? '-'
|
||||
const lotteryConfigNameFormatter = (row: Record<string, any>) =>
|
||||
row?.diceLotteryPoolConfig?.name ?? row?.lottery_config_id ?? '-'
|
||||
const lotteryConfigNameFormatter = (row: Record<string, any>) => lotteryPoolRowLabel(row)
|
||||
const rewardTierFormatter = (row: Record<string, any>) => row?.reward_tier ?? '-'
|
||||
|
||||
/** 摇取点数格式化为 1,3,4,5,6,6 */
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<el-option
|
||||
v-for="item in lotteryConfigOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:label="lotteryPoolOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -180,6 +180,10 @@
|
||||
<script setup lang="ts">
|
||||
import api from '../../../api/play_record/index'
|
||||
import { getChannelDeptRequestParams } from '@/composables/useChannelDeptScope'
|
||||
import {
|
||||
lotteryPoolOptionLabel,
|
||||
type LotteryPoolOption
|
||||
} from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
import type { FormInstance } from 'element-plus'
|
||||
|
||||
interface Props {
|
||||
@@ -209,7 +213,7 @@
|
||||
})
|
||||
|
||||
const playerOptions = ref<Array<{ id: number; username: string }>>([])
|
||||
const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([])
|
||||
const lotteryConfigOptions = ref<LotteryPoolOption[]>([])
|
||||
|
||||
const initialFormData = {
|
||||
id: null as number | null,
|
||||
|
||||
@@ -155,6 +155,7 @@
|
||||
import TableSearch from './modules/table-search.vue'
|
||||
import EditDialog from './modules/edit-dialog.vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { lotteryPoolRowLabel } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
const { t } = useI18n()
|
||||
|
||||
// 搜索表单(与 play_record 对齐:方向、赢取平台币范围、是否中大奖、中奖档位、点数和)
|
||||
@@ -181,8 +182,7 @@
|
||||
return res
|
||||
}
|
||||
|
||||
const lotteryConfigNameFormatter = (row: Record<string, any>) =>
|
||||
row?.diceLotteryPoolConfig?.name ?? row?.lottery_config_id ?? '-'
|
||||
const lotteryConfigNameFormatter = (row: Record<string, any>) => lotteryPoolRowLabel(row)
|
||||
const rewardTierFormatter = (row: Record<string, any>) => row?.reward_tier ?? '-'
|
||||
|
||||
/** 摇取点数格式化为 1,3,4,5,6 */
|
||||
|
||||
@@ -148,6 +148,11 @@
|
||||
getChannelDeptRequestParams,
|
||||
useInjectedChannelDept
|
||||
} from '@/composables/useChannelDeptScope'
|
||||
import {
|
||||
filterLotteryPoolOptionsByQuery,
|
||||
lotteryPoolOptionLabel,
|
||||
type LotteryPoolOption
|
||||
} from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
interface Props {
|
||||
modelValue: Record<string, any>
|
||||
@@ -162,8 +167,8 @@
|
||||
const isExpanded = ref<boolean>(false)
|
||||
const channelScope = useInjectedChannelDept()
|
||||
|
||||
const lotteryPoolAllOptions = ref<Array<{ id: number; name: string }>>([])
|
||||
const lotteryPoolOptions = ref<Array<{ id: number; name: string }>>([])
|
||||
const lotteryPoolAllOptions = ref<LotteryPoolOption[]>([])
|
||||
const lotteryPoolOptions = ref<LotteryPoolOption[]>([])
|
||||
const lotteryPoolLoading = ref(false)
|
||||
|
||||
function resolveDeptParams(): Record<string, unknown> {
|
||||
@@ -177,11 +182,6 @@
|
||||
return {}
|
||||
}
|
||||
|
||||
function lotteryPoolOptionLabel(item: { id: number; name: string }): string {
|
||||
const name = (item.name || '').trim()
|
||||
return name ? `${name} (#${item.id})` : `#${item.id}`
|
||||
}
|
||||
|
||||
async function loadLotteryPoolOptions() {
|
||||
lotteryPoolLoading.value = true
|
||||
try {
|
||||
@@ -197,15 +197,7 @@
|
||||
}
|
||||
|
||||
function filterLotteryPoolOptions(query: string) {
|
||||
const q = (query || '').trim().toLowerCase()
|
||||
if (!q) {
|
||||
lotteryPoolOptions.value = [...lotteryPoolAllOptions.value]
|
||||
return
|
||||
}
|
||||
lotteryPoolOptions.value = lotteryPoolAllOptions.value.filter((item) => {
|
||||
const name = (item.name || '').toLowerCase()
|
||||
return name.includes(q) || String(item.id).includes(q)
|
||||
})
|
||||
lotteryPoolOptions.value = filterLotteryPoolOptionsByQuery(lotteryPoolAllOptions.value, query)
|
||||
}
|
||||
|
||||
function onLotteryPoolDropdownVisible(visible: boolean) {
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
import TableSearch from './modules/table-search.vue'
|
||||
import EditDialog from './modules/edit-dialog.vue'
|
||||
import WalletOperateDialog from './modules/WalletOperateDialog.vue'
|
||||
import { lotteryPoolRowLabel } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
const { t } = useI18n()
|
||||
const { copy } = useClipboard()
|
||||
@@ -141,10 +142,13 @@
|
||||
return cellValue != null && cellValue !== '' ? `${cellValue}%` : '-'
|
||||
}
|
||||
|
||||
// 根据 lottery_config_id 显示彩金池配置名称
|
||||
const lotteryConfigNameFormatter = (row: any) =>
|
||||
row?.diceLotteryPoolConfig?.name ??
|
||||
(row?.lottery_config_id ? `#${row.lottery_config_id}` : t('page.table.customConfig'))
|
||||
const lotteryConfigNameFormatter = (row: any) => {
|
||||
const label = lotteryPoolRowLabel(row)
|
||||
if (label === '-' && !row?.lottery_config_id) {
|
||||
return t('page.table.customConfig')
|
||||
}
|
||||
return label
|
||||
}
|
||||
|
||||
// 表格
|
||||
const {
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<el-option
|
||||
v-for="item in lotteryConfigOptions"
|
||||
:key="item.id"
|
||||
:label="(item.name && String(item.name).trim()) || `#${item.id}`"
|
||||
:label="lotteryPoolOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -97,12 +97,12 @@
|
||||
<el-form-item v-if="currentLotteryConfig" :label="$t('page.form.currentConfig')" class="current-config-block">
|
||||
<div class="current-lottery-config">
|
||||
<div class="config-row">
|
||||
<span class="config-label">{{ $t('page.form.configLabelName') }}:</span>
|
||||
<span>{{ currentLotteryConfig.name ?? '-' }}</span>
|
||||
<span class="config-label">{{ $t('page.form.configLabelPoolName') }}:</span>
|
||||
<span>{{ lotteryPoolDisplayLabel(currentLotteryConfig) }}</span>
|
||||
</div>
|
||||
<div class="config-row">
|
||||
<span class="config-label">{{ $t('page.form.configLabelType') }}:</span>
|
||||
<span>{{ lotteryConfigTypeText(currentLotteryConfig.name) }}</span>
|
||||
<span class="config-label">{{ $t('page.form.configLabelCode') }}:</span>
|
||||
<span>{{ currentLotteryConfig.name ?? '-' }}</span>
|
||||
</div>
|
||||
<div class="config-row">
|
||||
<span class="config-label">{{ $t('page.form.configLabelWeights') }}:</span>
|
||||
@@ -185,6 +185,7 @@
|
||||
import api from '../../../api/player/index'
|
||||
import lotteryConfigApi from '../../../api/lottery_pool_config/index'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { lotteryPoolDisplayLabel, lotteryPoolOptionLabel } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
import { getChannelDeptRequestParams, withChannelDeptParams } from '@/composables/useChannelDeptScope'
|
||||
import { isSuperAdminUser } from '@/utils/channelLayout'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
<el-option
|
||||
v-for="item in lotteryConfigOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:label="lotteryPoolOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -65,6 +65,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import api from '../../../api/player/index'
|
||||
import { lotteryPoolOptionLabel } from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
interface Props {
|
||||
modelValue: Record<string, any>
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
style="width: 100%"
|
||||
@change="syncAnteFromSelect"
|
||||
>
|
||||
<ElOption
|
||||
:label="$t('page.weightTest.anteRandomOption')"
|
||||
:value="RANDOM_ANTE_CONFIG_ID"
|
||||
/>
|
||||
<ElOption
|
||||
v-for="item in anteOptions"
|
||||
:key="item.id"
|
||||
@@ -85,12 +89,18 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in paidLotteryOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
v-for="item in lotteryOptions"
|
||||
:key="'paid-pool-' + item.id"
|
||||
:label="lotteryPoolOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
<div v-if="selectedPaidPool" class="pool-selected-hint">
|
||||
{{ $t('page.weightTest.selectedPoolHint', { name: lotteryPoolDisplayLabel(selectedPaidPool) }) }}
|
||||
</div>
|
||||
<div v-if="selectedPaidPool" class="pool-weights-preview">
|
||||
{{ poolTierWeightsText(selectedPaidPool) }}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<template v-if="form.paid_lottery_config_id == null">
|
||||
<div class="tier-label">{{ $t('page.weightTest.tierProbHint') }}</div>
|
||||
@@ -155,12 +165,18 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<ElOption
|
||||
v-for="item in freeLotteryOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
v-for="item in lotteryOptions"
|
||||
:key="'free-pool-' + item.id"
|
||||
:label="lotteryPoolOptionLabel(item)"
|
||||
:value="item.id"
|
||||
/>
|
||||
</ElSelect>
|
||||
<div v-if="selectedFreePool" class="pool-selected-hint">
|
||||
{{ $t('page.weightTest.selectedPoolHint', { name: lotteryPoolDisplayLabel(selectedFreePool) }) }}
|
||||
</div>
|
||||
<div v-if="selectedFreePool" class="pool-weights-preview">
|
||||
{{ poolTierWeightsText(selectedFreePool) }}
|
||||
</div>
|
||||
</ElFormItem>
|
||||
<template v-if="form.free_lottery_config_id == null">
|
||||
<div class="tier-label">{{ $t('page.weightTest.tierProbHintFreeChain') }}</div>
|
||||
@@ -218,6 +234,13 @@
|
||||
useInjectedChannelDept,
|
||||
withChannelDeptParams
|
||||
} from '@/composables/useChannelDeptScope'
|
||||
import {
|
||||
lotteryPoolDisplayLabel,
|
||||
lotteryPoolOptionLabel
|
||||
} from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
|
||||
/** 底注下拉「随机」选项值(非真实 ante_config.id) */
|
||||
const RANDOM_ANTE_CONFIG_ID = -1
|
||||
|
||||
const props = defineProps<{
|
||||
/** 父页面渠道栏选中值(弹窗 teleport 后 inject 可能失效) */
|
||||
@@ -247,16 +270,26 @@
|
||||
paid_s_count: 100,
|
||||
paid_n_count: 100,
|
||||
kill_mode_enabled: false,
|
||||
test_safety_line: 5000
|
||||
test_safety_line: 0
|
||||
})
|
||||
const lotteryOptions = ref<Array<{ id: number; name: string }>>([])
|
||||
const paidLotteryOptions = computed(() =>
|
||||
lotteryOptions.value.filter((r) => r.name === 'default')
|
||||
type LotteryPoolOption = {
|
||||
id: number
|
||||
name: string
|
||||
remark?: string
|
||||
display_name?: string
|
||||
t1_weight?: number
|
||||
t2_weight?: number
|
||||
t3_weight?: number
|
||||
t4_weight?: number
|
||||
t5_weight?: number
|
||||
}
|
||||
const lotteryOptions = ref<LotteryPoolOption[]>([])
|
||||
const selectedPaidPool = computed(() =>
|
||||
lotteryOptions.value.find((r) => r.id === form.paid_lottery_config_id) ?? null
|
||||
)
|
||||
const selectedFreePool = computed(() =>
|
||||
lotteryOptions.value.find((r) => r.id === form.free_lottery_config_id) ?? null
|
||||
)
|
||||
const freeLotteryOptions = computed(() => {
|
||||
const list = lotteryOptions.value.filter((r) => r.name === 'free')
|
||||
return list.length > 0 ? list : lotteryOptions.value.filter((r) => r.name === 'default')
|
||||
})
|
||||
const defaultPoolInfo = ref<{ safety_line: number; kill_enabled: number; profit_amount: number } | null>(null)
|
||||
const running = ref(false)
|
||||
|
||||
@@ -322,6 +355,15 @@
|
||||
return label ? `${label} (×${item.mult})` : `×${item.mult}`
|
||||
}
|
||||
|
||||
function poolTierWeightsText(pool: LotteryPoolOption): string {
|
||||
const parts = tierKeys.map((t) => {
|
||||
const key = `${t.toLowerCase()}_weight` as keyof LotteryPoolOption
|
||||
const v = pool[key]
|
||||
return `${t} ${v ?? 0}%`
|
||||
})
|
||||
return parts.join(' · ')
|
||||
}
|
||||
|
||||
function syncAnteFromSelect() {
|
||||
const opt = anteOptions.value.find((o) => o.id === form.ante_config_id)
|
||||
if (opt) {
|
||||
@@ -350,11 +392,13 @@
|
||||
async function loadDefaultPoolInfo() {
|
||||
try {
|
||||
const pool = await lotteryPoolApi.getCurrentPool(resolveDeptParams())
|
||||
const safetyLine = Number(pool?.safety_line ?? 0)
|
||||
defaultPoolInfo.value = {
|
||||
safety_line: Number(pool?.safety_line ?? 0),
|
||||
safety_line: safetyLine,
|
||||
kill_enabled: Number(pool?.kill_enabled ?? 1),
|
||||
profit_amount: Number(pool?.profit_amount ?? 0)
|
||||
}
|
||||
form.test_safety_line = safetyLine
|
||||
} catch {
|
||||
defaultPoolInfo.value = null
|
||||
}
|
||||
@@ -363,12 +407,34 @@
|
||||
async function loadLotteryOptions() {
|
||||
try {
|
||||
const list = await lotteryPoolApi.getOptions(resolveDeptParams())
|
||||
lotteryOptions.value = list.map((r: { id: number; name: string }) => ({
|
||||
id: r.id,
|
||||
name: r.name
|
||||
}))
|
||||
lotteryOptions.value = list.map(
|
||||
(r: {
|
||||
id: number
|
||||
name: string
|
||||
remark?: string
|
||||
display_name?: string
|
||||
t1_weight?: number
|
||||
t2_weight?: number
|
||||
t3_weight?: number
|
||||
t4_weight?: number
|
||||
t5_weight?: number
|
||||
}) => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
remark: r.remark,
|
||||
display_name: r.display_name,
|
||||
t1_weight: r.t1_weight,
|
||||
t2_weight: r.t2_weight,
|
||||
t3_weight: r.t3_weight,
|
||||
t4_weight: r.t4_weight,
|
||||
t5_weight: r.t5_weight
|
||||
})
|
||||
)
|
||||
const playerDefault = list.find((r: { name?: string }) => r.name === 'playerDefault')
|
||||
const normal = list.find((r: { name?: string }) => r.name === 'default')
|
||||
if (normal) {
|
||||
if (playerDefault) {
|
||||
form.paid_lottery_config_id = playerDefault.id
|
||||
} else if (normal) {
|
||||
form.paid_lottery_config_id = normal.id
|
||||
}
|
||||
const freePool = list.find((r: { name?: string }) => r.name === 'free')
|
||||
@@ -385,7 +451,6 @@
|
||||
function buildPayload() {
|
||||
const payload: Record<string, unknown> = {
|
||||
ante: form.ante,
|
||||
ante_config_id: form.ante_config_id,
|
||||
paid_s_count: form.paid_s_count,
|
||||
paid_n_count: form.paid_n_count,
|
||||
free_s_count: 0,
|
||||
@@ -394,6 +459,11 @@
|
||||
kill_mode_enabled: form.kill_mode_enabled,
|
||||
test_safety_line: form.test_safety_line
|
||||
}
|
||||
if (form.ante_config_id === RANDOM_ANTE_CONFIG_ID) {
|
||||
payload.ante_random = true
|
||||
} else {
|
||||
payload.ante_config_id = form.ante_config_id
|
||||
}
|
||||
if (form.paid_lottery_config_id != null) {
|
||||
payload.paid_lottery_config_id = form.paid_lottery_config_id
|
||||
} else {
|
||||
@@ -408,12 +478,15 @@
|
||||
}
|
||||
|
||||
function validateForm(): boolean {
|
||||
if (form.ante_config_id == null || form.ante_config_id <= 0) {
|
||||
const isRandomAnte = form.ante_config_id === RANDOM_ANTE_CONFIG_ID
|
||||
if (!isRandomAnte && (form.ante_config_id == null || form.ante_config_id <= 0)) {
|
||||
ElMessage.warning(t('page.weightTest.warnAnte'))
|
||||
return false
|
||||
}
|
||||
syncAnteFromSelect()
|
||||
if (form.ante == null || form.ante <= 0) {
|
||||
if (!isRandomAnte) {
|
||||
syncAnteFromSelect()
|
||||
}
|
||||
if (!isRandomAnte && (form.ante == null || form.ante <= 0)) {
|
||||
ElMessage.warning(t('page.weightTest.warnAnte'))
|
||||
return false
|
||||
}
|
||||
@@ -563,6 +636,20 @@
|
||||
border-top: 1px dashed var(--el-border-color);
|
||||
}
|
||||
|
||||
.pool-selected-hint {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-secondary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.pool-weights-preview {
|
||||
margin-top: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--el-text-color-regular);
|
||||
font-family: ui-monospace, monospace;
|
||||
}
|
||||
|
||||
.kill-mode-field {
|
||||
max-width: 280px;
|
||||
}
|
||||
|
||||
@@ -143,6 +143,33 @@
|
||||
return Number(row.paid_n_count ?? 0)
|
||||
}
|
||||
|
||||
function formatTestSafetyLine(row: Record<string, unknown>): string {
|
||||
const dash = t('page.detail.dash')
|
||||
if (Number(row.kill_mode_enabled ?? 0) !== 1) {
|
||||
return dash
|
||||
}
|
||||
const line = row.test_safety_line
|
||||
if (line === null || line === undefined || line === '') {
|
||||
return dash
|
||||
}
|
||||
const n = Number(line)
|
||||
return Number.isFinite(n) ? String(n) : dash
|
||||
}
|
||||
|
||||
function formatAnteCell(row: Record<string, unknown>): string {
|
||||
const ante = row.ante
|
||||
if (ante === null || ante === undefined || ante === '') {
|
||||
return t('page.detail.dash')
|
||||
}
|
||||
const snap = row.tier_weights_snapshot
|
||||
const isRandom =
|
||||
snap &&
|
||||
typeof snap === 'object' &&
|
||||
(snap as { ante_random?: boolean }).ante_random === true
|
||||
const base = String(ante)
|
||||
return isRandom ? `${base} (${t('page.table.anteRandom')})` : base
|
||||
}
|
||||
|
||||
// 平台赚取金额展示(未完成或空显示 —)
|
||||
function formatPlatformProfit(v: unknown): string {
|
||||
const dash = t('page.detail.dash')
|
||||
@@ -228,8 +255,16 @@
|
||||
{
|
||||
prop: 'ante',
|
||||
label: 'page.table.ante',
|
||||
width: 90,
|
||||
align: 'center'
|
||||
width: 100,
|
||||
align: 'center',
|
||||
formatter: (row: Record<string, unknown>) => formatAnteCell(row)
|
||||
},
|
||||
{
|
||||
prop: 'test_safety_line',
|
||||
label: 'page.table.testSafetyLine',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
formatter: (row: Record<string, unknown>) => formatTestSafetyLine(row)
|
||||
},
|
||||
{
|
||||
prop: 'play_again_count',
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
<el-descriptions-item :label="$t('page.detail.paidPlannedSpins')">
|
||||
{{ record.paid_planned_spins ?? $t('page.detail.dash') }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('page.detail.testSafetyLine')">
|
||||
{{ formatTestSafetyLineDetail(record) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('page.table.ante')">
|
||||
{{ formatAnteDetail(record) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('page.detail.testCount')">
|
||||
{{ formatTestCountDisplay(record) }}
|
||||
</el-descriptions-item>
|
||||
@@ -30,10 +36,10 @@
|
||||
{{ record.admin_name ?? record.admin_id ?? $t('page.detail.dash') }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('page.detail.paidPoolId')">
|
||||
{{ record.paid_lottery_config_id ?? record.lottery_config_id ?? $t('page.detail.dash') }}
|
||||
{{ formatRecordPaidPoolName(record) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('page.detail.freePoolId')">
|
||||
{{ record.free_lottery_config_id ?? $t('page.detail.dash') }}
|
||||
{{ formatRecordFreePoolName(record) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item :label="$t('page.detail.bigwinSnapshot')">
|
||||
<template v-if="bigwinWeightDisplay.length">
|
||||
@@ -182,7 +188,7 @@
|
||||
<el-option
|
||||
v-for="opt in paidLotteryOptions"
|
||||
:key="opt.id"
|
||||
:label="opt.name"
|
||||
:label="lotteryPoolOptionLabel(opt)"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -199,7 +205,7 @@
|
||||
<el-option
|
||||
v-for="opt in freeLotteryOptions"
|
||||
:key="opt.id"
|
||||
:label="opt.name"
|
||||
:label="lotteryPoolOptionLabel(opt)"
|
||||
:value="opt.id"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -224,6 +230,11 @@
|
||||
import ArtBarChart from '@/components/core/charts/art-bar-chart/index.vue'
|
||||
import recordApi from '../../../api/reward_config_record/index'
|
||||
import lotteryConfigApi from '../../../api/lottery_pool_config/index'
|
||||
import {
|
||||
lotteryPoolLabelById,
|
||||
lotteryPoolOptionLabel,
|
||||
type LotteryPoolOption
|
||||
} from '@/views/plugin/dice/utils/lotteryPoolDisplay'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
@@ -242,6 +253,9 @@
|
||||
over_play_count?: number
|
||||
chain_free_mode?: number | boolean | string
|
||||
paid_planned_spins?: number
|
||||
ante?: number
|
||||
kill_mode_enabled?: number
|
||||
test_safety_line?: number
|
||||
create_time?: string
|
||||
admin_id?: number | null
|
||||
admin_name?: string
|
||||
@@ -278,6 +292,33 @@
|
||||
return t('page.table.chainModeNo')
|
||||
}
|
||||
|
||||
function formatTestSafetyLineDetail(record: RecordRow | null): string {
|
||||
if (!record) return t('page.detail.dash')
|
||||
if (Number(record.kill_mode_enabled ?? 0) !== 1) {
|
||||
return t('page.detail.killModeOff')
|
||||
}
|
||||
const line = record.test_safety_line
|
||||
if (line === null || line === undefined || line === '') {
|
||||
return t('page.detail.dash')
|
||||
}
|
||||
return String(line)
|
||||
}
|
||||
|
||||
function formatAnteDetail(record: RecordRow | null): string {
|
||||
if (!record) return t('page.detail.dash')
|
||||
const ante = record.ante
|
||||
if (ante === null || ante === undefined || ante === '') {
|
||||
return t('page.detail.dash')
|
||||
}
|
||||
const snap = record.tier_weights_snapshot
|
||||
const isRandom =
|
||||
snap &&
|
||||
typeof snap === 'object' &&
|
||||
(snap as { ante_random?: boolean }).ante_random === true
|
||||
const base = String(ante)
|
||||
return isRandom ? `${base} (${t('page.table.anteRandom')})` : base
|
||||
}
|
||||
|
||||
function formatTestCountDisplay(record: RecordRow | null): string {
|
||||
if (!record) return t('page.detail.dash')
|
||||
const status = Number(record.status)
|
||||
@@ -316,7 +357,18 @@
|
||||
const importing = ref(false)
|
||||
const importPaidLotteryConfigId = ref<number | null>(null)
|
||||
const importFreeLotteryConfigId = ref<number | null>(null)
|
||||
const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([])
|
||||
const lotteryConfigOptions = ref<LotteryPoolOption[]>([])
|
||||
|
||||
function formatRecordPaidPoolName(record: RecordRow | null): string {
|
||||
if (!record) return t('page.detail.dash')
|
||||
const id = record.paid_lottery_config_id ?? record.lottery_config_id ?? null
|
||||
return lotteryPoolLabelById(id, lotteryConfigOptions.value)
|
||||
}
|
||||
|
||||
function formatRecordFreePoolName(record: RecordRow | null): string {
|
||||
if (!record) return t('page.detail.dash')
|
||||
return lotteryPoolLabelById(record.free_lottery_config_id ?? null, lotteryConfigOptions.value)
|
||||
}
|
||||
|
||||
function tierWeightsToTableData(weightsMap: Record<string, number> | null | undefined) {
|
||||
const dash = t('page.detail.dash')
|
||||
@@ -496,6 +548,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(open) => {
|
||||
if (open) {
|
||||
void loadLotteryOptions()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function openImport() {
|
||||
importPaidLotteryConfigId.value =
|
||||
props.record?.paid_lottery_config_id ?? props.record?.lottery_config_id ?? null
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/** 彩金池选项/关联行通用结构 */
|
||||
export interface LotteryPoolOption {
|
||||
id: number
|
||||
name?: string
|
||||
remark?: string
|
||||
display_name?: string
|
||||
}
|
||||
|
||||
/** 彩金池后台展示名(奖池名称):优先 display_name / remark,不用内部 name 作为首选 */
|
||||
export function lotteryPoolDisplayLabel(item?: LotteryPoolOption | null): string {
|
||||
if (!item) {
|
||||
return '-'
|
||||
}
|
||||
const display = String(item.display_name ?? '').trim()
|
||||
if (display) {
|
||||
return display
|
||||
}
|
||||
const remark = String(item.remark ?? '').trim()
|
||||
if (remark) {
|
||||
return remark
|
||||
}
|
||||
return String(item.name ?? '').trim() || '-'
|
||||
}
|
||||
|
||||
/** 下拉选项文案:默认仅奖池名称;withId=true 时附带 ID */
|
||||
export function lotteryPoolOptionLabel(
|
||||
item: LotteryPoolOption,
|
||||
options?: { withId?: boolean }
|
||||
): string {
|
||||
const label = lotteryPoolDisplayLabel(item)
|
||||
if (options?.withId && item.id > 0) {
|
||||
return label !== '-' ? `${label} (#${item.id})` : `#${item.id}`
|
||||
}
|
||||
return label !== '-' ? label : `#${item.id}`
|
||||
}
|
||||
|
||||
/** 列表行关联彩金池(含 diceLotteryPoolConfig 关联) */
|
||||
export function lotteryPoolRowLabel(row?: {
|
||||
diceLotteryPoolConfig?: LotteryPoolOption | null
|
||||
lottery_config_id?: number | null | string
|
||||
} | null): string {
|
||||
if (!row) {
|
||||
return '-'
|
||||
}
|
||||
const pool = row.diceLotteryPoolConfig
|
||||
if (pool && (pool.id || pool.remark || pool.name || pool.display_name)) {
|
||||
return lotteryPoolDisplayLabel(pool)
|
||||
}
|
||||
const id = row.lottery_config_id
|
||||
if (id !== null && id !== undefined && id !== '') {
|
||||
return `#${id}`
|
||||
}
|
||||
return '-'
|
||||
}
|
||||
|
||||
/** 规范化接口返回的彩金池选项 */
|
||||
export function normalizeLotteryPoolOption(raw: Record<string, unknown>): LotteryPoolOption {
|
||||
const id = Number(raw.id ?? 0)
|
||||
const name = String(raw.name ?? '')
|
||||
const remark = String(raw.remark ?? '')
|
||||
const displayName = String(raw.display_name ?? '').trim()
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
remark,
|
||||
display_name: displayName !== '' ? displayName : remark !== '' ? remark : name
|
||||
}
|
||||
}
|
||||
|
||||
/** 按奖池名称 / 内部标识 / ID 过滤下拉 */
|
||||
export function filterLotteryPoolOptionsByQuery(
|
||||
list: LotteryPoolOption[],
|
||||
query: string
|
||||
): LotteryPoolOption[] {
|
||||
const q = (query || '').trim().toLowerCase()
|
||||
if (!q) {
|
||||
return [...list]
|
||||
}
|
||||
return list.filter((item) => {
|
||||
const label = lotteryPoolDisplayLabel(item).toLowerCase()
|
||||
const code = String(item.name ?? '').toLowerCase()
|
||||
return label.includes(q) || code.includes(q) || String(item.id).includes(q)
|
||||
})
|
||||
}
|
||||
|
||||
/** 根据 ID 从选项列表解析奖池名称 */
|
||||
export function lotteryPoolLabelById(
|
||||
poolId: number | null | undefined,
|
||||
options: LotteryPoolOption[]
|
||||
): string {
|
||||
if (poolId == null || poolId <= 0) {
|
||||
return '-'
|
||||
}
|
||||
const found = options.find((o) => o.id === poolId)
|
||||
if (found) {
|
||||
return lotteryPoolDisplayLabel(found)
|
||||
}
|
||||
return `#${poolId}`
|
||||
}
|
||||
Reference in New Issue
Block a user