diff --git a/saiadmin-artd/src/views/plugin/dice/api/lottery_pool_config/index.ts b/saiadmin-artd/src/views/plugin/dice/api/lottery_pool_config/index.ts index 104f75e..989aca0 100644 --- a/saiadmin-artd/src/views/plugin/dice/api/lottery_pool_config/index.ts +++ b/saiadmin-artd/src/views/plugin/dice/api/lottery_pool_config/index.ts @@ -17,13 +17,14 @@ export default { }, /** - * 获取 DiceLotteryPoolConfig 列表数据,仅含 id、name,用于 lottery_config_id 下拉 - * @returns DiceLotteryPoolConfig['id','name','t1_weight'..'t5_weight'] 列表 + * 获取 DiceLotteryPoolConfig 列表数据,含 id、name、type、t1_weight~t5_weight,用于一键测试权重档位类型下拉 + * type:0=付费抽奖券,1=免费抽奖券;付费默认选 type=0,免费默认选 type=1 */ async getOptions(): Promise< Array<{ id: number name: string + type: number t1_weight: number t2_weight: number t3_weight: number @@ -34,13 +35,12 @@ export default { const res = await request.get({ url: '/core/dice/lottery_pool_config/DiceLotteryPoolConfig/getOptions' }) - // 兼容:request.get 通常返回后端 success(data) 的 data(数组);部分环境可能返回整包 { data: [] } 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 ?? ''), + type: Number(r.type ?? 0), t1_weight: Number(r.t1_weight ?? 0), t2_weight: Number(r.t2_weight ?? 0), t3_weight: Number(r.t3_weight ?? 0), diff --git a/saiadmin-artd/src/views/plugin/dice/api/reward/index.ts b/saiadmin-artd/src/views/plugin/dice/api/reward/index.ts index 7629689..c24b104 100644 --- a/saiadmin-artd/src/views/plugin/dice/api/reward/index.ts +++ b/saiadmin-artd/src/views/plugin/dice/api/reward/index.ts @@ -57,9 +57,22 @@ export default { }, /** - * 一键测试权重:创建测试记录并启动后台执行,返回 record_id 用于轮询进度 + * 一键测试权重:创建测试记录并启动后台执行,按付费/免费、顺逆方向交替抽奖 + * 可选 lottery_config_id;不选则传 paid_tier_weights / free_tier_weights(T1-T5) */ - startWeightTest(params: { lottery_config_id: number; s_count: number; n_count: number }) { + startWeightTest(params: { + lottery_config_id?: number + paid_lottery_config_id?: number + free_lottery_config_id?: number + s_count?: number + n_count?: number + paid_s_count?: number + paid_n_count?: number + free_s_count?: number + free_n_count?: number + paid_tier_weights?: Record + free_tier_weights?: Record + }) { return request.post<{ record_id: number }>({ url: '/core/dice/reward/DiceReward/startWeightTest', data: params diff --git a/saiadmin-artd/src/views/plugin/dice/api/reward_config_record/index.ts b/saiadmin-artd/src/views/plugin/dice/api/reward_config_record/index.ts index b2c77ca..df144d9 100644 --- a/saiadmin-artd/src/views/plugin/dice/api/reward_config_record/index.ts +++ b/saiadmin-artd/src/views/plugin/dice/api/reward_config_record/index.ts @@ -64,11 +64,18 @@ export default { }, /** - * 导入:将测试记录的权重写入 DiceRewardConfig 与 DiceLotteryPoolConfig,并刷新缓存 + * 导入:测试记录 → DiceReward、DiceRewardConfig(BIGWIN)、DiceLotteryPoolConfig(付费/免费 T1-T5) * @param record_id 测试记录 ID - * @param lottery_config_id 可选,导入档位权重到的奖池配置 ID,不传则用记录内的 lottery_config_id + * @param paid_lottery_config_id 可选,导入付费档位概率到的奖池(type=0) + * @param free_lottery_config_id 可选,导入免费档位概率到的奖池(type=1) + * @param lottery_config_id 兼容旧版,不传 paid/free 时用作统一奖池 */ - importFromRecord(params: { record_id: number; lottery_config_id?: number | null }) { + importFromRecord(params: { + record_id: number + paid_lottery_config_id?: number | null + free_lottery_config_id?: number | null + lottery_config_id?: number | null + }) { return request.post({ url: '/dice/reward_config_record/DiceRewardConfigRecord/importFromRecord', data: params diff --git a/saiadmin-artd/src/views/plugin/dice/play_record_test/index/index.vue b/saiadmin-artd/src/views/plugin/dice/play_record_test/index/index.vue index e22ccc1..6f11760 100644 --- a/saiadmin-artd/src/views/plugin/dice/play_record_test/index/index.vue +++ b/saiadmin-artd/src/views/plugin/dice/play_record_test/index/index.vue @@ -8,19 +8,9 @@ diff --git a/saiadmin-artd/src/views/plugin/dice/reward/index/modules/weight-test-dialog.vue b/saiadmin-artd/src/views/plugin/dice/reward/index/modules/weight-test-dialog.vue index 091691c..ab839ba 100644 --- a/saiadmin-artd/src/views/plugin/dice/reward/index/modules/weight-test-dialog.vue +++ b/saiadmin-artd/src/views/plugin/dice/reward/index/modules/weight-test-dialog.vue @@ -2,42 +2,131 @@ - - - - - - - - - - - - - - - - + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + + + + + + + + +
@@ -46,49 +135,166 @@ import api from '../../../api/reward/index' import lotteryPoolApi from '../../../api/lottery_pool_config/index' - const countOptions = [100, 500, 1000, 5000] + const countOptions = [0, 100, 500, 1000, 5000] + const tierKeys = ['T1', 'T2', 'T3', 'T4', 'T5'] as const const visible = defineModel({ default: false }) const emit = defineEmits<{ (e: 'success'): void }>() const formRef = ref() + const currentStep = ref(0) const form = reactive({ - lottery_config_id: undefined as number | undefined, - s_count: 100, - n_count: 100 + paid_lottery_config_id: undefined as number | undefined, + free_lottery_config_id: undefined as number | undefined, + paid_tier_weights: { T1: 20, T2: 20, T3: 20, T4: 20, T5: 20 } as Record, + free_tier_weights: { T1: 20, T2: 20, T3: 20, T4: 20, T5: 20 } as Record, + paid_s_count: 100, + paid_n_count: 100, + free_s_count: 100, + free_n_count: 100 + }) + const lotteryOptions = ref>([]) + /** 将 type 转为数字(接口可能返回字符串 "0"/"1") */ + function tierTypeNum(r: { type?: number | string }): number { + const t = r.type ?? 0 + return typeof t === 'number' ? t : Number(t) || 0 + } + /** 付费抽奖券可选档位:type=0 */ + const paidLotteryOptions = computed(() => + lotteryOptions.value.filter((r) => tierTypeNum(r) === 0) + ) + /** + * 免费抽奖券可选档位:优先 type=1(DiceLotteryPoolConfig.type=1),若无则显示全部以便下拉有选项 + */ + const freeLotteryOptions = computed(() => { + const type1List = lotteryOptions.value.filter((r) => tierTypeNum(r) === 1) + return type1List.length > 0 ? type1List : lotteryOptions.value }) - const lotteryOptions = ref>([]) const running = ref(false) function onClose() { running.value = false + currentStep.value = 0 } + function getPaidTier(t: string): string { + const v = form.paid_tier_weights[t] + return v !== undefined && v !== null ? String(v) : '' + } + function setPaidTier(t: string, val: string | Event) { + const raw = + typeof val === 'string' + ? val + : ((val as Event & { target: HTMLInputElement }).target?.value ?? '') + const num = raw === '' ? 0 : Math.max(0, Math.min(100, Number(raw) || 0)) + form.paid_tier_weights[t] = num + } + const paidTierSum = computed(() => + tierKeys.reduce((s, t) => s + (form.paid_tier_weights[t] ?? 0), 0) + ) + function getFreeTier(t: string): string { + const v = form.free_tier_weights[t] + return v !== undefined && v !== null ? String(v) : '' + } + function setFreeTier(t: string, val: string | Event) { + const raw = + typeof val === 'string' + ? val + : ((val as Event & { target: HTMLInputElement }).target?.value ?? '') + const num = raw === '' ? 0 : Math.max(0, Math.min(100, Number(raw) || 0)) + form.free_tier_weights[t] = num + } + const freeTierSum = computed(() => + tierKeys.reduce((s, t) => s + (form.free_tier_weights[t] ?? 0), 0) + ) + async function loadLotteryOptions() { try { const list = await lotteryPoolApi.getOptions() - lotteryOptions.value = list.map((r: { id: number; name: string }) => ({ id: r.id, name: r.name })) - if (list.length && !form.lottery_config_id) { - form.lottery_config_id = list[0].id + lotteryOptions.value = list.map( + (r: { id: number; name: string; type?: number | string }) => ({ + id: r.id, + name: r.name, + type: tierTypeNum(r) + }) + ) + // 付费抽奖券默认使用 type=0 的档位类型 + const type0 = list.find((r: { type?: number | string }) => tierTypeNum(r) === 0) + if (type0) { + form.paid_lottery_config_id = type0.id + } + // 免费抽奖券默认使用 type=1 的档位类型(DiceLotteryPoolConfig.type=1);若无 type=1 则默认选第一项 + const type1 = list.find((r: { type?: number | string }) => tierTypeNum(r) === 1) + if (type1) { + form.free_lottery_config_id = type1.id + } else if (list.length > 0) { + form.free_lottery_config_id = list[0].id } } catch (_) { lotteryOptions.value = [] } } - async function handleStart() { - if (!form.lottery_config_id) { - ElMessage.warning('请选择测试数据档位类型') - return + function buildPayload() { + const payload: Record = { + paid_s_count: form.paid_s_count, + paid_n_count: form.paid_n_count, + free_s_count: form.free_s_count, + free_n_count: form.free_n_count } + if (form.paid_lottery_config_id != null && form.paid_lottery_config_id !== '') { + payload.paid_lottery_config_id = form.paid_lottery_config_id + } else { + payload.paid_tier_weights = { ...form.paid_tier_weights } + } + if (form.free_lottery_config_id != null && form.free_lottery_config_id !== '') { + payload.free_lottery_config_id = form.free_lottery_config_id + } else { + payload.free_tier_weights = { ...form.free_tier_weights } + } + return payload + } + + function validateForm(): boolean { + if (form.paid_s_count + form.paid_n_count + form.free_s_count + form.free_n_count <= 0) { + ElMessage.warning('付费或免费至少一种方向次数之和大于 0') + return false + } + const needPaidTier = form.paid_lottery_config_id == null || form.paid_lottery_config_id === '' + const needFreeTier = form.free_lottery_config_id == null || form.free_lottery_config_id === '' + if (needPaidTier) { + const sum = paidTierSum.value + if (sum <= 0) { + ElMessage.warning('付费未选奖池时,T1~T5 档位概率之和需大于 0') + return false + } + if (sum > 100) { + ElMessage.warning('付费档位概率 T1~T5 之和不能超过 100%') + return false + } + } + if (needFreeTier) { + const sum = freeTierSum.value + if (sum <= 0) { + ElMessage.warning('免费未选奖池时,T1~T5 档位概率之和需大于 0') + return false + } + if (sum > 100) { + ElMessage.warning('免费档位概率 T1~T5 之和不能超过 100%') + return false + } + } + return true + } + + async function handleStart() { + if (!validateForm()) return running.value = true try { - await api.startWeightTest({ - lottery_config_id: form.lottery_config_id, - s_count: form.s_count, - n_count: form.n_count - }) - ElMessage.success('测试任务已创建,后台将自动执行。请在【玩家抽奖记录(测试数据)】中查看生成的测试数据') + await api.startWeightTest(buildPayload()) + ElMessage.success( + '测试任务已创建,后台将自动执行。请在【玩家抽奖记录(测试数据)】中查看生成的测试数据' + ) visible.value = false emit('success') } catch (e: any) { @@ -105,4 +311,71 @@ onClose() } }) + + // 切换到免费步骤时,若当前选中 id 不在免费档位列表中,则重置为第一个 type=1 的选项,避免显示错误 + watch(currentStep, (step) => { + if (step === 1) { + const freeOpts = freeLotteryOptions.value + const id = form.free_lottery_config_id + if (freeOpts.length && (id == null || !freeOpts.some((o) => o.id === id))) { + form.free_lottery_config_id = freeOpts[0].id + } + } + }) + + diff --git a/saiadmin-artd/src/views/plugin/dice/reward_config_record/index/index.vue b/saiadmin-artd/src/views/plugin/dice/reward_config_record/index/index.vue index 41e53f3..c635f59 100644 --- a/saiadmin-artd/src/views/plugin/dice/reward_config_record/index/index.vue +++ b/saiadmin-artd/src/views/plugin/dice/reward_config_record/index/index.vue @@ -8,16 +8,6 @@