Compare commits

...

2 Commits

19 changed files with 400 additions and 181 deletions

View File

@@ -5,7 +5,7 @@ import request from '@/utils/http'
*/
export default {
/**
* 获取数据列表
* 获取数据列表DiceLotteryConfig
* @param params 搜索参数
* @returns 数据列表
*/
@@ -16,6 +16,21 @@ export default {
})
},
/**
* 获取彩金池配置下拉选项(来自 DiceLotteryConfig用于 lottery_config_id 选择)
* @returns { id, name }[]
*/
async getOptions(): Promise<Array<{ id: number; name: string }>> {
const res = await request.get<any>({
url: '/dice/lottery_config/DiceLotteryConfig/index',
params: { limit: 500, page: 1 }
})
const rows = (res?.data?.data ?? res?.data?.rows ?? []) as Array<{ id: number; name: string }>
return Array.isArray(rows)
? rows.map((r) => ({ id: Number(r.id), name: String(r.name ?? r.id) }))
: []
},
/**
* 读取数据
* @param id 数据ID

View File

@@ -125,39 +125,39 @@
{ prop: 'type', label: '奖池类型', width: 100, align: 'center', formatter: typeFormatter },
{ prop: 'safety_line', label: '安全线', align: 'center' },
{
prop: 't1_wight',
prop: 't1_weight',
label: 'T1池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t1_wight')
formatter: weightFormatter('t1_weight')
},
{
prop: 't2_wight',
prop: 't2_weight',
label: 'T2池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t2_wight')
formatter: weightFormatter('t2_weight')
},
{
prop: 't3_wight',
prop: 't3_weight',
label: 'T3池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t3_wight')
formatter: weightFormatter('t3_weight')
},
{
prop: 't4_wight',
prop: 't4_weight',
label: 'T4池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t4_wight')
formatter: weightFormatter('t4_weight')
},
{
prop: 't5_wight',
prop: 't5_weight',
label: 'T5池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t5_wight')
formatter: weightFormatter('t5_weight')
},
{
prop: 'operation',

View File

@@ -46,20 +46,20 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item label="T1池权重(%)" prop="t1_wight">
<el-slider v-model="formData.t1_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item label="T1池权重(%)" prop="t1_weight">
<el-slider v-model="formData.t1_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T2池权重(%)" prop="t2_wight">
<el-slider v-model="formData.t2_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item label="T2池权重(%)" prop="t2_weight">
<el-slider v-model="formData.t2_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T3池权重(%)" prop="t3_wight">
<el-slider v-model="formData.t3_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item label="T3池权重(%)" prop="t3_weight">
<el-slider v-model="formData.t3_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T4池权重(%)" prop="t4_wight">
<el-slider v-model="formData.t4_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item label="T4池权重(%)" prop="t4_weight">
<el-slider v-model="formData.t4_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T5池权重(%)" prop="t5_wight">
<el-slider v-model="formData.t5_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item label="T5池权重(%)" prop="t5_weight">
<el-slider v-model="formData.t5_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item>
<div class="text-gray-500 text-sm">
@@ -112,7 +112,7 @@
})
/** 五个权重字段名,用于总和校验 */
const WEIGHT_KEYS = ['t1_wight', 't2_wight', 't3_wight', 't4_wight', 't5_wight'] as const
const WEIGHT_KEYS = ['t1_weight', 't2_weight', 't3_weight', 't4_weight', 't5_weight'] as const
/** 五个池权重总和(用于展示与校验) */
const weightsSum = computed(() => {
@@ -125,11 +125,11 @@
const rules = reactive<FormRules>({
name: [{ required: true, message: '名称必需填写', trigger: 'blur' }],
type: [{ required: true, message: '请选择奖池类型', trigger: 'change' }],
t1_wight: [{ required: true, message: 'T1池权重必需填写', trigger: 'blur' }],
t2_wight: [{ required: true, message: 'T2池权重必需填写', trigger: 'blur' }],
t3_wight: [{ required: true, message: 'T3池权重必需填写', trigger: 'blur' }],
t4_wight: [{ required: true, message: 'T4池权重必需填写', trigger: 'blur' }],
t5_wight: [{ required: true, message: 'T5池权重必需填写', trigger: 'blur' }]
t1_weight: [{ required: true, message: 'T1池权重必需填写', trigger: 'blur' }],
t2_weight: [{ required: true, message: 'T2池权重必需填写', trigger: 'blur' }],
t3_weight: [{ required: true, message: 'T3池权重必需填写', trigger: 'blur' }],
t4_weight: [{ required: true, message: 'T4池权重必需填写', trigger: 'blur' }],
t5_weight: [{ required: true, message: 'T5池权重必需填写', trigger: 'blur' }]
})
/**
@@ -141,11 +141,11 @@
remark: '',
type: null as number | null,
safety_line: 0 as number,
t1_wight: 0 as number,
t2_wight: 0 as number,
t3_wight: 0 as number,
t4_wight: 0 as number,
t5_wight: 0 as number
t1_weight: 0 as number,
t2_weight: 0 as number,
t3_weight: 0 as number,
t4_weight: 0 as number,
t5_weight: 0 as number
}
/**
@@ -187,11 +187,11 @@
'id',
'type',
'safety_line',
't1_wight',
't2_wight',
't3_wight',
't4_wight',
't5_wight'
't1_weight',
't2_weight',
't3_weight',
't4_weight',
't5_weight'
]
for (const key of Object.keys(formData)) {
if (!(key in props.data)) continue

View File

@@ -56,10 +56,10 @@
{{ row.lottery_type === 0 ? '付费' : row.lottery_type === 1 ? '赠送' : '-' }}
</ElTag>
</template>
<!-- tag -->
<!-- 是否中大 tag -->
<template #is_win="{ row }">
<ElTag size="small" :type="row.is_win === 1 ? 'success' : 'info'">
{{ row.is_win === 0 ? '无' : row.is_win === 1 ? '中奖' : '-' }}
{{ row.is_win === 0 ? '无' : row.is_win === 1 ? '中奖' : '-' }}
</ElTag>
</template>
<!-- 方向 tag -->
@@ -182,8 +182,10 @@
useSlot: true
},
{ prop: 'lottery_type', label: '抽奖类型', width: 100, useSlot: true },
{ prop: 'is_win', label: '奖', width: 80, useSlot: true },
{ prop: 'win_coin', label: '赢取平台币' },
{ prop: 'is_win', label: '是否中大奖', width: 100, useSlot: true },
{ prop: 'win_coin', label: '赢取平台币', width: 110 },
{ prop: 'super_win_coin', label: '中大奖平台币', width: 120 },
{ prop: 'reward_win_coin', label: '摇色子中奖平台币', width: 140 },
{ prop: 'direction', label: '方向', width: 90, useSlot: true },
{ prop: 'start_index', label: '起始索引', width: 90 },
{ prop: 'target_index', label: '终点索引', width: 90 },

View File

@@ -54,7 +54,7 @@
<el-option label="赠送" :value="1" />
</el-select>
</el-form-item>
<el-form-item label="奖" prop="is_win">
<el-form-item label="是否中大奖" prop="is_win">
<el-select
v-model="formData.is_win"
placeholder="请选择"
@@ -63,18 +63,38 @@
:disabled="dialogType === 'edit'"
>
<el-option label="无" :value="0" />
<el-option label="中奖" :value="1" />
<el-option label="中奖" :value="1" />
</el-select>
</el-form-item>
<el-form-item label="赢取平台币" prop="win_coin">
<el-input-number
v-model="formData.win_coin"
placeholder="请输入赢取平台币"
placeholder="= 中大奖 + 摇色子中奖"
:precision="2"
style="width: 100%"
:disabled="dialogType === 'edit'"
/>
</el-form-item>
<el-form-item label="中大奖平台币" prop="super_win_coin">
<el-input-number
v-model="formData.super_win_coin"
placeholder="豹子时发放"
:precision="2"
:min="0"
style="width: 100%"
:disabled="dialogType === 'edit'"
/>
</el-form-item>
<el-form-item label="摇色子中奖平台币" prop="reward_win_coin">
<el-input-number
v-model="formData.reward_win_coin"
placeholder="摇色子中奖"
:precision="2"
:min="0"
style="width: 100%"
:disabled="dialogType === 'edit'"
/>
</el-form-item>
<el-form-item label="方向" prop="direction">
<el-select
v-model="formData.direction"
@@ -186,7 +206,7 @@
player_id: [{ required: true, message: '请选择玩家', trigger: 'change' }],
lottery_config_id: [{ required: true, message: '请选择彩金池配置', trigger: 'change' }],
lottery_type: [{ required: true, message: '请选择抽奖类型', trigger: 'change' }],
is_win: [{ required: true, message: '请选择奖', trigger: 'change' }],
is_win: [{ required: true, message: '请选择是否中大奖', trigger: 'change' }],
win_coin: [{ required: true, message: '赢取平台币必填', trigger: 'blur' }],
rollArrayItems: [
{
@@ -219,6 +239,8 @@
lottery_type: null as number | null,
is_win: null as number | null,
win_coin: null as number | null,
super_win_coin: null as number | null,
reward_win_coin: null as number | null,
direction: null as number | null,
start_index: null as number | null,
target_index: null as number | null,
@@ -278,6 +300,8 @@
'lottery_type',
'is_win',
'win_coin',
'super_win_coin',
'reward_win_coin',
'direction',
'start_index',
'target_index',

View File

@@ -27,10 +27,10 @@
</el-form-item>
</el-col>
<el-col v-bind="setSpan(6)">
<el-form-item label="奖" prop="is_win">
<el-form-item label="是否中大奖" prop="is_win">
<el-select v-model="formData.is_win" placeholder="全部" clearable style="width: 100%">
<el-option label="无" :value="0" />
<el-option label="中奖" :value="1" />
<el-option label="中奖" :value="1" />
</el-select>
</el-form-item>
</el-col>

View File

@@ -112,7 +112,7 @@
phone: undefined,
status: undefined,
coin: undefined,
is_up: undefined
lottery_config_id: undefined
})
// 搜索处理
@@ -127,17 +127,9 @@
return cellValue != null && cellValue !== '' ? `${cellValue}%` : '-'
}
// 倍率列展示0=正常 1=强制杀猪 2=T1高倍率
const isUpFormatter = (row: any) => {
const cellValue = row.is_up
return cellValue === 0
? '正常'
: cellValue === 1
? '强制杀猪'
: cellValue === 2
? 'T1高倍率'
: '-'
}
// 彩金池配置列lottery_config_id 关联 DiceLotteryConfig显示 name
const lotteryConfigNameFormatter = (row: any) =>
row?.diceLotteryConfig?.name ?? (row?.lottery_config_id ? `#${row.lottery_config_id}` : '自定义')
// 表格配置
const {
@@ -176,52 +168,52 @@
useSlot: true
},
{
prop: 'is_up',
label: '倍率',
width: 80,
prop: 'lottery_config_id',
label: '彩金池配置',
width: 120,
align: 'center',
formatter: isUpFormatter
formatter: (row: any) => lotteryConfigNameFormatter(row)
},
{
prop: 't1_wight',
prop: 't1_weight',
label: 'T1池权重',
width: 80,
align: 'center',
formatter: weightFormatter('t1_wight')
formatter: weightFormatter('t1_weight')
},
{
prop: 't2_wight',
prop: 't2_weight',
label: 'T2池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t2_wight')
formatter: weightFormatter('t2_weight')
},
{
prop: 't3_wight',
prop: 't3_weight',
label: 'T3池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t3_wight')
formatter: weightFormatter('t3_weight')
},
{
prop: 't4_wight',
prop: 't4_weight',
label: 'T4池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t4_wight')
formatter: weightFormatter('t4_weight')
},
{
prop: 't5_wight',
prop: 't5_weight',
label: 'T5池权重',
width: 100,
align: 'center',
formatter: weightFormatter('t5_wight')
formatter: weightFormatter('t5_weight')
},
{ prop: 'total_ticket_count', label: '总抽奖次数', align: 'center' },
{ prop: 'paid_ticket_count', label: '购买抽奖次数', align: 'center' },
{ prop: 'free_ticket_count', label: '赠送抽奖次数', align: 'center' },
{ prop: 'created_at', label: '创建时间', align: 'center' },
{ prop: 'updated_at', label: '更新时间', align: 'center' },
{ prop: 'create_time', label: '创建时间', align: 'center' },
{ prop: 'update_time', label: '更新时间', align: 'center' },
{
prop: 'operation',
label: '操作',

View File

@@ -15,7 +15,13 @@
<el-input v-model="formData.name" placeholder="请输入昵称" />
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="formData.phone" placeholder="请输入手机号" clearable maxlength="20" show-word-limit />
<el-input
v-model="formData.phone"
placeholder="请输入手机号"
clearable
maxlength="20"
show-word-limit
/>
</el-form-item>
<el-form-item label="密码" prop="password" :rules="passwordRules">
<el-input
@@ -38,29 +44,39 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item label="倍率" prop="is_up">
<el-select v-model="formData.is_up" placeholder="请选择倍率" clearable style="width: 100%">
<el-option label="正常" :value="0" />
<el-option label="强制杀猪" :value="1" />
<el-option label="T1高倍率" :value="2" />
<el-form-item label="彩金池配置" prop="lottery_config_id">
<el-select
v-model="formData.lottery_config_id"
placeholder="不选则使用下方自定义权重"
clearable
style="width: 100%"
@change="onLotteryConfigChange"
>
<el-option label="自定义权重" :value="0" />
<el-option
v-for="item in lotteryConfigOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="T1池权重(%)" prop="t1_wight">
<el-slider v-model="formData.t1_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item v-if="!formData.lottery_config_id" label="T1池权重(%)" prop="t1_weight">
<el-slider v-model="formData.t1_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T2池权重(%)" prop="t2_wight">
<el-slider v-model="formData.t2_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item v-if="!formData.lottery_config_id" label="T2池权重(%)" prop="t2_weight">
<el-slider v-model="formData.t2_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T3池权重(%)" prop="t3_wight">
<el-slider v-model="formData.t3_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item v-if="!formData.lottery_config_id" label="T3池权重(%)" prop="t3_weight">
<el-slider v-model="formData.t3_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T4池权重(%)" prop="t4_wight">
<el-slider v-model="formData.t4_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item v-if="!formData.lottery_config_id" label="T4池权重(%)" prop="t4_weight">
<el-slider v-model="formData.t4_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item label="T5池权重(%)" prop="t5_wight">
<el-slider v-model="formData.t5_wight" :min="0" :max="100" :step="0.01" show-input />
<el-form-item v-if="!formData.lottery_config_id" label="T5池权重(%)" prop="t5_weight">
<el-slider v-model="formData.t5_weight" :min="0" :max="100" :step="0.01" show-input />
</el-form-item>
<el-form-item>
<el-form-item v-if="!formData.lottery_config_id">
<div class="text-gray-500 text-sm">
五个池权重总和<span :class="Math.abs(weightsSum - 100) > 0.01 ? 'text-red-500' : ''">{{
weightsSum
@@ -78,9 +94,12 @@
<script setup lang="ts">
import api from '../../../api/player/index'
import lotteryConfigApi from '../../../api/lottery_config/index'
import { ElMessage } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
const WEIGHT_FIELDS = ['t1_weight', 't2_weight', 't3_weight', 't4_weight', 't5_weight'] as const
interface Props {
modelValue: boolean
dialogType: string
@@ -107,9 +126,8 @@
set: (value) => emit('update:modelValue', value)
})
const WEIGHT_KEYS = ['t1_wight', 't2_wight', 't3_wight', 't4_wight', 't5_wight'] as const
const weightsSum = computed(() => {
return WEIGHT_KEYS.reduce((sum, key) => sum + Number(formData[key] ?? 0), 0)
return WEIGHT_FIELDS.reduce((sum, key) => sum + Number(formData[key] ?? 0), 0)
})
/** 新增时密码必填,编辑时选填 */
@@ -133,16 +151,19 @@
password: '',
status: 1 as number,
coin: 0 as number,
is_up: null as number | null,
t1_wight: 0 as number,
t2_wight: 0 as number,
t3_wight: 0 as number,
t4_wight: 0 as number,
t5_wight: 0 as number
lottery_config_id: null as number | null,
t1_weight: 0 as number,
t2_weight: 0 as number,
t3_weight: 0 as number,
t4_weight: 0 as number,
t5_weight: 0 as number
}
const formData = reactive({ ...initialFormData })
/** 彩金池配置下拉选项 */
const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([])
watch(
() => props.modelValue,
(newVal) => {
@@ -150,24 +171,50 @@
}
)
/** 选择彩金池配置时,拉取该配置的权重填入表单(仅展示/备份lottery_config_id 非空时后端以配置为准) */
async function onLotteryConfigChange(lotteryConfigId: number | null) {
if (!lotteryConfigId) return
try {
const res = await lotteryConfigApi.read(lotteryConfigId)
const row = (res as any)?.data
if (row) {
WEIGHT_FIELDS.forEach((key) => {
;(formData as any)[key] = Number(row[key] ?? 0)
})
}
} catch (err) {
console.warn('拉取彩金池配置权重失败', err)
}
}
const initPage = async () => {
Object.assign(formData, initialFormData)
await loadLotteryConfigOptions()
if (props.data) {
await nextTick()
initForm()
}
}
/** 从 DiceLotteryConfig 拉取彩金池配置下拉选项 */
async function loadLotteryConfigOptions() {
try {
lotteryConfigOptions.value = await lotteryConfigApi.getOptions()
} catch {
lotteryConfigOptions.value = []
}
}
const numKeys = [
'id',
'status',
'coin',
'is_up',
't1_wight',
't2_wight',
't3_wight',
't4_wight',
't5_wight'
'lottery_config_id',
't1_weight',
't2_weight',
't3_weight',
't4_weight',
't5_weight'
]
const initForm = () => {
@@ -197,7 +244,8 @@
if (!formRef.value) return
try {
await formRef.value.validate()
if (Math.abs(weightsSum.value - 100) > 0.01) {
const useCustomWeights = !formData.lottery_config_id
if (useCustomWeights && Math.abs(weightsSum.value - 100) > 0.01) {
ElMessage.warning('五个池权重总和必须为100%')
return
}

View File

@@ -44,11 +44,19 @@
</el-form-item>
</el-col>
<el-col v-bind="setSpan(6)">
<el-form-item label="倍率" prop="is_up">
<el-select v-model="formData.is_up" placeholder="全部" clearable style="width: 100%">
<el-option label="正常" :value="0" />
<el-option label="强制杀猪" :value="1" />
<el-option label="T1高倍率" :value="2" />
<el-form-item label="彩金池配置" prop="lottery_config_id">
<el-select
v-model="formData.lottery_config_id"
placeholder="全部"
clearable
style="width: 100%"
>
<el-option
v-for="item in lotteryConfigOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-col>
@@ -56,6 +64,8 @@
</template>
<script setup lang="ts">
import lotteryConfigApi from '../../../api/lottery_config/index'
interface Props {
modelValue: Record<string, any>
}
@@ -67,6 +77,16 @@
const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const isExpanded = ref<boolean>(false)
const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([])
/** 从 DiceLotteryConfig 拉取彩金池配置下拉选项,用于 lottery_config_id 筛选 */
onMounted(async () => {
try {
lotteryConfigOptions.value = await lotteryConfigApi.getOptions()
} catch {
lotteryConfigOptions.value = []
}
})
const searchBarRef = ref()
const formData = computed({

View File

@@ -137,7 +137,10 @@ class GameController extends OpenController
'player_id' => $userId,
'lottery_config_id' => 0,
'lottery_type' => 0,
'is_win' => 0,
'win_coin' => 0,
'super_win_coin' => 0,
'reward_win_coin' => 0,
'use_coins' => 0,
'direction' => $direction,
'reward_config_id' => 0,

View File

@@ -34,6 +34,8 @@ class PlayStartLogic
/** 开启对局最低余额 = |DiceRewardConfig 最小 real_ev + 100| */
private const MIN_COIN_EXTRA = 100;
/** 豹子号中大奖额外平台币(可从 dice_config 等配置读取) */
private const SUPER_WIN_BONUS = 500;
/**
* 执行一局游戏
@@ -120,13 +122,24 @@ class PlayStartLogic
$targetIndex
));
$realEv = (float) ($chosen['real_ev'] ?? 0);
$winCoin = 100 + $realEv; // 赢取平台币 = 100 + DiceRewardConfig.real_ev
$rewardWinCoin = 100 + $realEv; // 摇色子中奖平台币 = 100 + DiceRewardConfig.real_ev
$isSuperWin = DicePlayRecord::isSuperWin($rollArray);
// 豹子中大奖时从缓存查 tier=BIGWIN 且 grid_number=roll_number 的奖励配置,取 real_ev 计算中大奖平台币
$superWinCoin = 0;
if ($isSuperWin) {
$bigWinConfig = DiceRewardConfig::getCachedByTierAndGridNumber('BIGWIN', $rollNumber);
$superWinCoin = $bigWinConfig !== null
? 100 + (float) ($bigWinConfig['real_ev'] ?? 0)
: self::SUPER_WIN_BONUS;
}
$winCoin = $superWinCoin + $rewardWinCoin; // 赢取平台币 = 中大奖 + 摇色子中奖
$record = null;
$configId = (int) $config->id;
$rewardId = $chosenId;
$configName = (string) ($config->name ?? '');
$isTierT5 = (string) ($chosen['tier'] ?? '') === 'T5';
$isWin = $isSuperWin ? 1 : 0;
try {
Db::transaction(function () use (
$playerId,
@@ -135,6 +148,9 @@ class PlayStartLogic
$configName,
$ticketType,
$winCoin,
$superWinCoin,
$rewardWinCoin,
$isWin,
$realEv,
$direction,
$startIndex,
@@ -147,7 +163,10 @@ class PlayStartLogic
'player_id' => $playerId,
'lottery_config_id' => $configId,
'lottery_type' => $ticketType,
'is_win' => $isWin,
'win_coin' => $winCoin,
'super_win_coin' => $superWinCoin,
'reward_win_coin' => $rewardWinCoin,
'use_coins' => 0,
'direction' => $direction,
'reward_config_id' => $rewardId,
@@ -210,7 +229,10 @@ class PlayStartLogic
'player_id' => $playerId,
'lottery_config_id' => $configId ?? 0,
'lottery_type' => $ticketType,
'is_win' => 0,
'win_coin' => 0,
'super_win_coin' => 0,
'reward_win_coin' => 0,
'use_coins' => 0,
'direction' => $direction,
'reward_config_id' => 0,

View File

@@ -82,7 +82,7 @@ class UserLogic
$token = $tokenResult['access_token'];
UserCache::setSessionByUsername($username, $token);
$userArr = $player->hidden(['password'])->toArray();
$userArr = $player->hidden(['password', 'lottery_config_id', 't1_weight', 't2_weight', 't3_weight', 't4_weight', 't5_weight'])->toArray();
UserCache::setUser((int) $player->id, $userArr);
UserCache::setPlayerByUsername($username, $userArr);

View File

@@ -19,7 +19,7 @@ class LotteryService
private int $playerId;
private ?int $configType0Id = null;
private ?int $configType1Id = null;
/** @var array{t1_wight?:int,t2_wight?:int,t3_wight?:int,t4_wight?:int,t5_wight?:int} */
/** @var array{t1_weight?:int,t2_weight?:int,t3_weight?:int,t4_weight?:int,t5_weight?:int} */
private array $playerWeights = [];
public function __construct(int $playerId)
@@ -62,11 +62,11 @@ class LotteryService
$s->configType0Id = $config0 ? (int) $config0->id : null;
$s->configType1Id = $config1 ? (int) $config1->id : null;
$s->playerWeights = [
't1_wight' => (int) ($player->t1_wight ?? 0),
't2_wight' => (int) ($player->t2_wight ?? 0),
't3_wight' => (int) ($player->t3_wight ?? 0),
't4_wight' => (int) ($player->t4_wight ?? 0),
't5_wight' => (int) ($player->t5_wight ?? 0),
't1_weight' => (int) ($player->t1_weight ?? 0),
't2_weight' => (int) ($player->t2_weight ?? 0),
't3_weight' => (int) ($player->t3_weight ?? 0),
't4_weight' => (int) ($player->t4_weight ?? 0),
't5_weight' => (int) ($player->t5_weight ?? 0),
];
$s->save();
return $s;
@@ -83,33 +83,33 @@ class LotteryService
Cache::set($key, json_encode($data), self::EXPIRE);
}
/** 根据奖池配置的 t1_wight..t5_wight 权重随机抽取档位 T1-T5 */
/** 根据奖池配置的 t1_weight..t5_weight 权重随机抽取档位 T1-T5 */
public static function drawTierByWeights(DiceLotteryConfig $config): string
{
$tiers = ['T1', 'T2', 'T3', 'T4', 'T5'];
$weights = [
(int) ($config->t1_wight ?? 0),
(int) ($config->t2_wight ?? 0),
(int) ($config->t3_wight ?? 0),
(int) ($config->t4_wight ?? 0),
(int) ($config->t5_wight ?? 0),
(int) ($config->t1_weight ?? 0),
(int) ($config->t2_weight ?? 0),
(int) ($config->t3_weight ?? 0),
(int) ($config->t4_weight ?? 0),
(int) ($config->t5_weight ?? 0),
];
return self::drawTierByWeightArray($tiers, $weights);
}
/**
* 根据玩家 t1_wightt5_wight 权重随机抽取中奖档位 T1-T5
* t1_wight=T1, t2_wight=T2, t3_wight=T3, t4_wight=T4, t5_wight=T5
* 根据玩家 t1_weightt5_weight 权重随机抽取中奖档位 T1-T5
* t1_weight=T1, t2_weight=T2, t3_weight=T3, t4_weight=T4, t5_weight=T5
*/
public static function drawTierByPlayerWeights(DicePlayer $player): string
{
$tiers = ['T1', 'T2', 'T3', 'T4', 'T5'];
$weights = [
(int) ($player->t1_wight ?? 0),
(int) ($player->t2_wight ?? 0),
(int) ($player->t3_wight ?? 0),
(int) ($player->t4_wight ?? 0),
(int) ($player->t5_wight ?? 0),
(int) ($player->t1_weight ?? 0),
(int) ($player->t2_weight ?? 0),
(int) ($player->t3_weight ?? 0),
(int) ($player->t4_weight ?? 0),
(int) ($player->t5_weight ?? 0),
];
return self::drawTierByWeightArray($tiers, $weights);
}

View File

@@ -42,9 +42,10 @@ class DicePlayerController extends BaseController
['phone', ''],
['status', ''],
['coin', ''],
['is_up', ''],
['lottery_config_id', ''],
]);
$query = $this->logic->search($where);
$query->with(['diceLotteryConfig']);
$data = $this->logic->getList($query);
return $this->success($data);
}

View File

@@ -20,11 +20,11 @@ use plugin\saiadmin\basic\think\BaseModel;
* @property $safety_line 安全线
* @property $create_time 创建时间
* @property $update_time 修改时间
* @property $t1_wight T1池权重
* @property $t2_wight T2池权重
* @property $t3_wight T3池权重
* @property $t4_wight T4池权重
* @property $t5_wight T5池权重
* @property $t1_weight T1池权重
* @property $t2_weight T2池权重
* @property $t3_weight T3池权重
* @property $t4_weight T4池权重
* @property $t5_weight T5池权重
*/
class DiceLotteryConfig extends BaseModel
{
@@ -48,4 +48,13 @@ class DiceLotteryConfig extends BaseModel
$query->where('name', 'like', '%'.$value.'%');
}
/**
* 奖池类型 搜索type=0/1/2 等)
*/
public function searchTypeAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('type', '=', $value);
}
}
}

View File

@@ -21,8 +21,10 @@ use think\model\relation\BelongsTo;
* @property $player_id 玩家id
* @property $lottery_config_id 彩金池配置
* @property $lottery_type 抽奖类型
* @property $is_win 中奖
* @property $win_coin 赢取平台币
* @property $is_win 是否中大奖:豹子号[1,1,1,1,1]~[5,5,5,5,5]为1否则0
* @property $win_coin 赢取平台币= super_win_coin + reward_win_coin
* @property $super_win_coin 中大奖平台币(豹子时发放)
* @property $reward_win_coin 摇色子中奖平台币
* @property $direction 方向:0=顺时针,1=逆时针
* @property $reward_config_id 奖励配置id
* @property $lottery_id 奖池
@@ -111,7 +113,25 @@ class DicePlayRecord extends BaseModel
}
}
/** 中奖 */
/**
* 是否豹子号中大奖5 个点数相同且为 1~5 之一
* @param int[] $rollArray 摇取点数数组,如 [1,1,1,1,1]
* @return bool
*/
public static function isSuperWin(array $rollArray): bool
{
if (count($rollArray) !== 5) {
return false;
}
$unique = array_unique($rollArray);
if (count($unique) !== 1) {
return false;
}
$value = reset($unique);
return in_array($value, [1, 2, 3, 4, 5], true);
}
/** 是否中大奖 */
public function searchIsWinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
@@ -135,6 +155,38 @@ class DicePlayRecord extends BaseModel
}
}
/** 中大奖平台币下限 */
public function searchSuperWinCoinMinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('super_win_coin', '>=', $value);
}
}
/** 中大奖平台币上限 */
public function searchSuperWinCoinMaxAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('super_win_coin', '<=', $value);
}
}
/** 摇色子中奖平台币下限 */
public function searchRewardWinCoinMinAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('reward_win_coin', '>=', $value);
}
}
/** 摇色子中奖平台币上限 */
public function searchRewardWinCoinMaxAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('reward_win_coin', '<=', $value);
}
}
/** 按奖励配置前端显示文本模糊diceRewardConfig.ui_text */
public function searchRewardUiTextAttr($query, $value)
{

View File

@@ -22,18 +22,18 @@ use app\dice\model\lottery_config\DiceLotteryConfig;
* @property $password 密码
* @property $status 状态
* @property $coin 平台币
* @property $is_up 倍率
* @property $t1_wight T1池权重
* @property $t2_wight T2池权重
* @property $t3_wight T3池权重
* @property $t4_wight T4池权重
* @property $t5_wight T5池权重
* @property $lottery_config_id 彩金池配置ID0或null时使用自定义权重*_weight
* @property $t1_weight T1池权重
* @property $t2_weight T2池权重
* @property $t3_weight T3池权重
* @property $t4_weight T4池权重
* @property $t5_weight T5池权重
* @property $total_ticket_count 总抽奖次数
* @property $paid_ticket_count 购买抽奖次数
* @property $free_ticket_count 赠送抽奖次数
* @property $created_at 创建时间
* @property $updated_at 更新时间
* @property $deleted_at 删除时间
* @property $create_time 创建时间
* @property $update_time 更新时间
* @property $delete_time 删除时间
*/
class DicePlayer extends BaseModel
{
@@ -49,10 +49,9 @@ class DicePlayer extends BaseModel
*/
protected $table = 'dice_player';
/** 创建时间字段dice_player 表为 created_at */
protected $createTime = 'created_at';
/** 更新时间字段dice_player 表为 updated_at */
protected $updateTime = 'updated_at';
protected $createTime = 'create_time';
protected $updateTime = 'update_time';
/**
* 新增前:生成唯一 uid昵称 name 默认使用 uid
@@ -83,7 +82,7 @@ class DicePlayer extends BaseModel
}
/**
* 从 DiceLotteryConfig type=0 取 t1_wightt5_wight 作为玩家未设置时的默认值
* 从 DiceLotteryConfig type=0 取 t1_weightt5_weight 作为玩家未设置时的默认值
*/
protected static function setDefaultWeightsFromLotteryConfig(DicePlayer $model): void
{
@@ -91,7 +90,7 @@ class DicePlayer extends BaseModel
if (!$config) {
return;
}
$fields = ['t1_wight', 't2_wight', 't3_wight', 't4_wight', 't5_wight'];
$fields = ['t1_weight', 't2_weight', 't3_weight', 't4_weight', 't5_weight'];
foreach ($fields as $field) {
try {
$val = $model->getAttr($field);
@@ -163,13 +162,20 @@ class DicePlayer extends BaseModel
}
/**
* 倍率 搜索
* 彩金池配置ID 搜索
*/
public function searchIs_upAttr($query, $value)
public function searchLottery_config_idAttr($query, $value)
{
if ($value !== '' && $value !== null) {
$query->where('is_up', '=', $value);
$query->where('lottery_config_id', '=', $value);
}
}
/**
* 关联彩金池配置
*/
public function diceLotteryConfig()
{
return $this->belongsTo(DiceLotteryConfig::class, 'lottery_config_id', 'id');
}
}

View File

@@ -51,7 +51,7 @@ class DiceRewardConfig extends BaseModel
/**
* 获取彩金池实例(含 list / 索引),无则从库加载并写入缓存;同请求内复用
* @return array{list: array, by_tier: array, by_s_end_index: array, by_n_end_index: array, min_real_ev: float}
* @return array{list: array, by_tier: array, by_tier_grid: array, by_s_end_index: array, by_n_end_index: array, min_real_ev: float}
*/
public static function getCachedInstance(): array
{
@@ -86,6 +86,7 @@ class DiceRewardConfig extends BaseModel
{
$list = (new self())->order('id', 'asc')->select()->toArray();
$byTier = [];
$byTierGrid = [];
$bySEndIndex = [];
$byNEndIndex = [];
foreach ($list as $row) {
@@ -95,6 +96,13 @@ class DiceRewardConfig extends BaseModel
$byTier[$tier] = [];
}
$byTier[$tier][] = $row;
$gridNum = isset($row['grid_number']) ? (int) $row['grid_number'] : 0;
if (!isset($byTierGrid[$tier])) {
$byTierGrid[$tier] = [];
}
if (!isset($byTierGrid[$tier][$gridNum])) {
$byTierGrid[$tier][$gridNum] = $row;
}
}
$sEnd = isset($row['s_end_index']) ? (int) $row['s_end_index'] : 0;
if ($sEnd !== 0) {
@@ -115,6 +123,7 @@ class DiceRewardConfig extends BaseModel
self::$instance = [
'list' => $list,
'by_tier' => $byTier,
'by_tier_grid' => $byTierGrid,
'by_s_end_index' => $bySEndIndex,
'by_n_end_index' => $byNEndIndex,
'min_real_ev' => $minRealEv,
@@ -128,12 +137,28 @@ class DiceRewardConfig extends BaseModel
return [
'list' => [],
'by_tier' => [],
'by_tier_grid' => [],
'by_s_end_index' => [],
'by_n_end_index' => [],
'min_real_ev' => 0.0,
];
}
/**
* 从缓存按档位 + 色子点数取一条奖励配置(用于超级大奖 tier=BIGWIN + grid_number=roll_number
* @param string $tier 档位,如 BIGWIN
* @param int $gridNumber 色子点数(如摇出总和)
* @return array|null 配置行或 null
*/
public static function getCachedByTierAndGridNumber(string $tier, int $gridNumber): ?array
{
$inst = self::getCachedInstance();
$byTierGrid = $inst['by_tier_grid'] ?? [];
$tierData = $byTierGrid[$tier] ?? [];
$row = $tierData[$gridNumber] ?? null;
return is_array($row) ? $row : null;
}
/**
* 从缓存取最小 real_ev
*/

View File

@@ -19,11 +19,11 @@ class DiceLotteryConfigValidate extends BaseValidate
protected $rule = [
'name' => 'require',
'type' => 'require',
't1_wight' => 'require',
't2_wight' => 'require',
't3_wight' => 'require',
't4_wight' => 'require',
't5_wight' => 'require',
't1_weight' => 'require',
't2_weight' => 'require',
't3_weight' => 'require',
't4_weight' => 'require',
't5_weight' => 'require',
];
/**
@@ -32,11 +32,11 @@ class DiceLotteryConfigValidate extends BaseValidate
protected $message = [
'name' => '名称必须填写',
'type' => '奖池类型必须填写',
't1_wight' => 'T1池权重必须填写',
't2_wight' => 'T2池权重必须填写',
't3_wight' => 'T3池权重必须填写',
't4_wight' => 'T4池权重必须填写',
't5_wight' => 'T5池权重必须填写',
't1_weight' => 'T1池权重必须填写',
't2_weight' => 'T2池权重必须填写',
't3_weight' => 'T3池权重必须填写',
't4_weight' => 'T4池权重必须填写',
't5_weight' => 'T5池权重必须填写',
];
/**
@@ -46,20 +46,20 @@ class DiceLotteryConfigValidate extends BaseValidate
'save' => [
'name',
'type',
't1_wight',
't2_wight',
't3_wight',
't4_wight',
't5_wight',
't1_weight',
't2_weight',
't3_weight',
't4_weight',
't5_weight',
],
'update' => [
'name',
'type',
't1_wight',
't2_wight',
't3_wight',
't4_wight',
't5_wight',
't1_weight',
't2_weight',
't3_weight',
't4_weight',
't5_weight',
],
];