[色子游戏]玩家抽奖记录-新增字段保存中奖详情记录信息
This commit is contained in:
@@ -62,6 +62,18 @@
|
|||||||
{{ row.is_win === 0 ? '无' : row.is_win === 1 ? '中奖' : '-' }}
|
{{ row.is_win === 0 ? '无' : row.is_win === 1 ? '中奖' : '-' }}
|
||||||
</ElTag>
|
</ElTag>
|
||||||
</template>
|
</template>
|
||||||
|
<!-- 方向 tag -->
|
||||||
|
<template #direction="{ row }">
|
||||||
|
<ElTag size="small" :type="row.direction === 0 ? 'primary' : 'warning'">
|
||||||
|
{{ row.direction === 0 ? '顺时针' : row.direction === 1 ? '逆时针' : '-' }}
|
||||||
|
</ElTag>
|
||||||
|
</template>
|
||||||
|
<!-- 摇取点数 tag -->
|
||||||
|
<template #roll_array="{ row }">
|
||||||
|
<ElTag size="small">
|
||||||
|
{{ formatRollArray(row.roll_array) }}
|
||||||
|
</ElTag>
|
||||||
|
</template>
|
||||||
<!-- 操作列 -->
|
<!-- 操作列 -->
|
||||||
<template #operation="{ row }">
|
<template #operation="{ row }">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
@@ -106,7 +118,8 @@
|
|||||||
win_coin_min: undefined,
|
win_coin_min: undefined,
|
||||||
win_coin_max: undefined,
|
win_coin_max: undefined,
|
||||||
reward_ui_text: undefined,
|
reward_ui_text: undefined,
|
||||||
reward_tier: undefined
|
reward_tier: undefined,
|
||||||
|
direction: undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
// 搜索处理
|
// 搜索处理
|
||||||
@@ -122,6 +135,21 @@
|
|||||||
const rewardTierFormatter = (row: Record<string, any>) =>
|
const rewardTierFormatter = (row: Record<string, any>) =>
|
||||||
row?.diceRewardConfig?.tier ?? row?.reward_config_id ?? '-'
|
row?.diceRewardConfig?.tier ?? row?.reward_config_id ?? '-'
|
||||||
|
|
||||||
|
/** 摇取点数格式化为 1,3,4,5,6,6 */
|
||||||
|
function formatRollArray(val: unknown): string {
|
||||||
|
if (val == null || val === '') return '-'
|
||||||
|
if (Array.isArray(val)) return val.join(',')
|
||||||
|
if (typeof val === 'string') {
|
||||||
|
try {
|
||||||
|
const arr = JSON.parse(val)
|
||||||
|
return Array.isArray(arr) ? arr.join(',') : val
|
||||||
|
} catch {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String(val)
|
||||||
|
}
|
||||||
|
|
||||||
// 表格配置
|
// 表格配置
|
||||||
const {
|
const {
|
||||||
columns,
|
columns,
|
||||||
@@ -156,6 +184,10 @@
|
|||||||
{ prop: 'lottery_type', label: '抽奖类型', width: 100, useSlot: true },
|
{ prop: 'lottery_type', label: '抽奖类型', width: 100, useSlot: true },
|
||||||
{ prop: 'is_win', label: '中奖', width: 80, useSlot: true },
|
{ prop: 'is_win', label: '中奖', width: 80, useSlot: true },
|
||||||
{ prop: 'win_coin', label: '赢取平台币' },
|
{ prop: 'win_coin', label: '赢取平台币' },
|
||||||
|
{ prop: 'direction', label: '方向', width: 90, useSlot: true },
|
||||||
|
{ prop: 'start_index', label: '起始索引', width: 90 },
|
||||||
|
{ prop: 'target_index', label: '终点索引', width: 90 },
|
||||||
|
{ prop: 'roll_array', label: '摇取点数', width: 140, useSlot: true },
|
||||||
{
|
{
|
||||||
prop: 'reward_config_id',
|
prop: 'reward_config_id',
|
||||||
label: '奖励配置',
|
label: '奖励配置',
|
||||||
|
|||||||
@@ -75,6 +75,53 @@
|
|||||||
:disabled="dialogType === 'edit'"
|
:disabled="dialogType === 'edit'"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="方向" prop="direction">
|
||||||
|
<el-select
|
||||||
|
v-model="formData.direction"
|
||||||
|
placeholder="请选择方向"
|
||||||
|
clearable
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="dialogType === 'edit'"
|
||||||
|
>
|
||||||
|
<el-option label="顺时针" :value="0" />
|
||||||
|
<el-option label="逆时针" :value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="起始索引" prop="start_index">
|
||||||
|
<el-input-number
|
||||||
|
v-model="formData.start_index"
|
||||||
|
placeholder="起始索引"
|
||||||
|
:min="0"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="dialogType === 'edit'"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="终点索引" prop="target_index">
|
||||||
|
<el-input-number
|
||||||
|
v-model="formData.target_index"
|
||||||
|
placeholder="终点索引"
|
||||||
|
:min="0"
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="dialogType === 'edit'"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="摇取点数" prop="rollArrayItems">
|
||||||
|
<div class="roll-array-wrap">
|
||||||
|
<el-input-number
|
||||||
|
v-for="(_, i) in 6"
|
||||||
|
:key="i"
|
||||||
|
v-model="formData.rollArrayItems[i]"
|
||||||
|
:min="1"
|
||||||
|
:max="6"
|
||||||
|
:precision="0"
|
||||||
|
controls-position="right"
|
||||||
|
placeholder=""
|
||||||
|
class="roll-array-input"
|
||||||
|
:disabled="dialogType === 'edit'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="roll-array-hint">固定 6 个数,每个 1~6</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="奖励配置" prop="reward_config_id">
|
<el-form-item label="奖励配置" prop="reward_config_id">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="formData.reward_config_id"
|
v-model="formData.reward_config_id"
|
||||||
@@ -141,6 +188,23 @@
|
|||||||
lottery_type: [{ 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' }],
|
win_coin: [{ required: true, message: '赢取平台币必填', trigger: 'blur' }],
|
||||||
|
rollArrayItems: [
|
||||||
|
{
|
||||||
|
validator: (_rule: any, value: (number | null)[], callback: (e?: Error) => void) => {
|
||||||
|
if (!value || value.length !== 6) {
|
||||||
|
callback(new Error('摇取点数必须为 6 个数'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const ok = value.every((n) => n != null && n >= 1 && n <= 6)
|
||||||
|
if (!ok) {
|
||||||
|
callback(new Error('摇取点数必须填写 6 个数,每个 1~6'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
],
|
||||||
reward_config_id: [{ required: true, message: '请选择奖励配置', trigger: 'change' }]
|
reward_config_id: [{ required: true, message: '请选择奖励配置', trigger: 'change' }]
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -155,10 +219,20 @@
|
|||||||
lottery_type: null as number | null,
|
lottery_type: null as number | null,
|
||||||
is_win: null as number | null,
|
is_win: null as number | null,
|
||||||
win_coin: null as number | null,
|
win_coin: null as number | null,
|
||||||
|
direction: null as number | null,
|
||||||
|
start_index: null as number | null,
|
||||||
|
target_index: null as number | null,
|
||||||
|
roll_array: null as string | number[] | null,
|
||||||
reward_config_id: null as number | null
|
reward_config_id: null as number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = reactive({ ...initialFormData })
|
/** 摇取点数固定 6 位 [n0..n5],每项 1~6 */
|
||||||
|
const rollArrayItemsDefault = (): (number | null)[] => [null, null, null, null, null, null]
|
||||||
|
|
||||||
|
const formData = reactive({
|
||||||
|
...initialFormData,
|
||||||
|
rollArrayItems: rollArrayItemsDefault() as (number | null)[]
|
||||||
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
@@ -188,7 +262,7 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
const initPage = async () => {
|
const initPage = async () => {
|
||||||
Object.assign(formData, { ...initialFormData })
|
Object.assign(formData, { ...initialFormData, rollArrayItems: rollArrayItemsDefault() })
|
||||||
if (props.data) {
|
if (props.data) {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
initForm()
|
initForm()
|
||||||
@@ -204,16 +278,47 @@
|
|||||||
'lottery_type',
|
'lottery_type',
|
||||||
'is_win',
|
'is_win',
|
||||||
'win_coin',
|
'win_coin',
|
||||||
|
'direction',
|
||||||
|
'start_index',
|
||||||
|
'target_index',
|
||||||
|
'roll_array',
|
||||||
'reward_config_id'
|
'reward_config_id'
|
||||||
]
|
]
|
||||||
keys.forEach((key) => {
|
keys.forEach((key) => {
|
||||||
const val = props.data![key]
|
const val = props.data![key]
|
||||||
if (val != null && val !== undefined) {
|
if (val != null && val !== undefined) {
|
||||||
;(formData as Record<string, unknown>)[key] = val
|
if (key === 'roll_array') {
|
||||||
|
formData.roll_array = val
|
||||||
|
formData.rollArrayItems = parseRollArrayToItems(val)
|
||||||
|
} else {
|
||||||
|
;(formData as Record<string, unknown>)[key] = val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 将接口的 roll_array 转为固定 6 项数组,不足补 null */
|
||||||
|
function parseRollArrayToItems(val: unknown): (number | null)[] {
|
||||||
|
let arr: number[] = []
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
arr = val.map((n) => (typeof n === 'number' && !Number.isNaN(n) ? n : 0)).slice(0, 6)
|
||||||
|
} else if (typeof val === 'string') {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(val)
|
||||||
|
arr = Array.isArray(parsed) ? parsed.slice(0, 6).map((n: any) => Number(n) || 0) : []
|
||||||
|
} catch {
|
||||||
|
arr = val
|
||||||
|
.split(',')
|
||||||
|
.map((n) => parseInt(n, 10))
|
||||||
|
.filter((n) => !Number.isNaN(n))
|
||||||
|
.slice(0, 6)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const items: (number | null)[] = [...arr]
|
||||||
|
while (items.length < 6) items.push(null)
|
||||||
|
return items.slice(0, 6)
|
||||||
|
}
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
visible.value = false
|
visible.value = false
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
@@ -223,19 +328,56 @@
|
|||||||
if (!formRef.value) return
|
if (!formRef.value) return
|
||||||
try {
|
try {
|
||||||
await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
|
const payload = { ...formData } as Record<string, unknown>
|
||||||
|
// 将 6 个输入值拼成 [1,2,3,4,5,6] 格式,确保每项为 1~6 的整数
|
||||||
|
const items = formData.rollArrayItems
|
||||||
|
payload.roll_array = items.map((n) => {
|
||||||
|
const v = n != null ? Number(n) : 1
|
||||||
|
return Math.min(6, Math.max(1, Number.isNaN(v) ? 1 : Math.floor(v)))
|
||||||
|
})
|
||||||
|
delete payload.rollArrayItems
|
||||||
if (props.dialogType === 'add') {
|
if (props.dialogType === 'add') {
|
||||||
const rest = { ...formData } as Record<string, unknown>
|
delete payload.id
|
||||||
delete rest.id
|
await api.save(payload)
|
||||||
await api.save(rest)
|
|
||||||
ElMessage.success('新增成功')
|
ElMessage.success('新增成功')
|
||||||
} else {
|
} else {
|
||||||
await api.update(formData)
|
await api.update(payload)
|
||||||
ElMessage.success('修改成功')
|
ElMessage.success('修改成功')
|
||||||
}
|
}
|
||||||
emit('success')
|
emit('success')
|
||||||
handleClose()
|
handleClose()
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.log('表单验证失败:', error)
|
let msg = '表单验证失败,请检查必填项与格式'
|
||||||
|
if (error?.message) {
|
||||||
|
msg = error.message
|
||||||
|
} else if (typeof error === 'string') {
|
||||||
|
msg = error
|
||||||
|
} else if (error && typeof error === 'object') {
|
||||||
|
const first = Object.values(error).find((v: any) => v?.[0]?.message)
|
||||||
|
if (first && Array.isArray(first)) {
|
||||||
|
msg = (first[0] as any).message || msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ElMessage.warning(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.roll-array-wrap {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-array-input {
|
||||||
|
width: 72px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-array-hint {
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--el-text-color-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -34,6 +34,14 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col v-bind="setSpan(6)">
|
||||||
|
<el-form-item label="方向" prop="direction">
|
||||||
|
<el-select v-model="formData.direction" placeholder="全部" clearable style="width: 100%">
|
||||||
|
<el-option label="顺时针" :value="0" />
|
||||||
|
<el-option label="逆时针" :value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col v-bind="setSpan(6)">
|
<el-col v-bind="setSpan(6)">
|
||||||
<el-form-item label="赢取平台币" prop="win_coin_min">
|
<el-form-item label="赢取平台币" prop="win_coin_min">
|
||||||
<div class="range-wrap">
|
<div class="range-wrap">
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ class DicePlayRecordController extends BaseController
|
|||||||
['win_coin_max', ''],
|
['win_coin_max', ''],
|
||||||
['reward_ui_text', ''],
|
['reward_ui_text', ''],
|
||||||
['reward_tier', ''],
|
['reward_tier', ''],
|
||||||
|
['direction', ''],
|
||||||
]);
|
]);
|
||||||
$query = $this->logic->search($where);
|
$query = $this->logic->search($where);
|
||||||
$query->with([
|
$query->with([
|
||||||
|
|||||||
@@ -24,4 +24,36 @@ class DicePlayRecordLogic extends BaseLogic
|
|||||||
$this->model = new DicePlayRecord();
|
$this->model = new DicePlayRecord();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加前:roll_array 转为 JSON 字符串(数据库为 string 类型)
|
||||||
|
*/
|
||||||
|
public function add(array $data): mixed
|
||||||
|
{
|
||||||
|
$data = $this->normalizeRollArray($data);
|
||||||
|
return parent::add($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改前:roll_array 转为 JSON 字符串(数据库为 string 类型)
|
||||||
|
*/
|
||||||
|
public function edit($id, array $data): mixed
|
||||||
|
{
|
||||||
|
$data = $this->normalizeRollArray($data);
|
||||||
|
return parent::edit($id, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 roll_array 从数组转为 JSON 字符串
|
||||||
|
*/
|
||||||
|
private function normalizeRollArray(array $data): array
|
||||||
|
{
|
||||||
|
if (!array_key_exists('roll_array', $data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
$val = $data['roll_array'];
|
||||||
|
if (is_array($val)) {
|
||||||
|
$data['roll_array'] = json_encode($val, JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,12 @@ use think\model\relation\BelongsTo;
|
|||||||
* @property $lottery_type 抽奖类型
|
* @property $lottery_type 抽奖类型
|
||||||
* @property $is_win 中奖
|
* @property $is_win 中奖
|
||||||
* @property $win_coin 赢取平台币
|
* @property $win_coin 赢取平台币
|
||||||
|
* @property $direction 方向:0=顺时针,1=逆时针
|
||||||
* @property $reward_config_id 奖励配置id
|
* @property $reward_config_id 奖励配置id
|
||||||
* @property $lottery_id 奖池
|
* @property $lottery_id 奖池
|
||||||
|
* @property $start_index 起始索引
|
||||||
|
* @property $target_index 结束索引
|
||||||
|
* @property $roll_array 摇取点数,格式:[1,2,3,4,5,6]
|
||||||
* @property $lottery_name 奖池名
|
* @property $lottery_name 奖池名
|
||||||
* @property $create_time 创建时间
|
* @property $create_time 创建时间
|
||||||
* @property $update_time 修改时间
|
* @property $update_time 修改时间
|
||||||
@@ -157,4 +161,12 @@ class DicePlayRecord extends BaseModel
|
|||||||
$query->whereRaw('1=0');
|
$query->whereRaw('1=0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 方向 0=顺时针 1=逆时针 */
|
||||||
|
public function searchDirectionAttr($query, $value)
|
||||||
|
{
|
||||||
|
if ($value !== '' && $value !== null) {
|
||||||
|
$query->where('direction', '=', $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class DicePlayRecordValidate extends BaseValidate
|
|||||||
'is_win' => 'require',
|
'is_win' => 'require',
|
||||||
'win_coin' => 'require',
|
'win_coin' => 'require',
|
||||||
'reward_config_id' => 'require',
|
'reward_config_id' => 'require',
|
||||||
|
'roll_array' => 'require|checkRollArray',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +36,7 @@ class DicePlayRecordValidate extends BaseValidate
|
|||||||
'is_win' => '中奖必须填写',
|
'is_win' => '中奖必须填写',
|
||||||
'win_coin' => '赢取平台币必须填写',
|
'win_coin' => '赢取平台币必须填写',
|
||||||
'reward_config_id' => '奖励配置必须填写',
|
'reward_config_id' => '奖励配置必须填写',
|
||||||
|
'roll_array.require' => '摇取点数必须填写',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,6 +50,7 @@ class DicePlayRecordValidate extends BaseValidate
|
|||||||
'is_win',
|
'is_win',
|
||||||
'win_coin',
|
'win_coin',
|
||||||
'reward_config_id',
|
'reward_config_id',
|
||||||
|
'roll_array',
|
||||||
],
|
],
|
||||||
'update' => [
|
'update' => [
|
||||||
'player_id',
|
'player_id',
|
||||||
@@ -56,7 +59,36 @@ class DicePlayRecordValidate extends BaseValidate
|
|||||||
'is_win',
|
'is_win',
|
||||||
'win_coin',
|
'win_coin',
|
||||||
'reward_config_id',
|
'reward_config_id',
|
||||||
|
'roll_array',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证 roll_array:必须为 6 个元素,每个值在 1~6 之间
|
||||||
|
* @param mixed $value
|
||||||
|
* @param mixed $rule
|
||||||
|
* @param array $data
|
||||||
|
* @param string $field
|
||||||
|
* @return bool|string
|
||||||
|
*/
|
||||||
|
protected function checkRollArray($value, $rule = '', array $data = [], string $field = '')
|
||||||
|
{
|
||||||
|
if (is_string($value)) {
|
||||||
|
$decoded = json_decode($value, true);
|
||||||
|
$value = is_array($decoded) ? $decoded : [];
|
||||||
|
}
|
||||||
|
if (!is_array($value)) {
|
||||||
|
return '摇取点数必须为数组';
|
||||||
|
}
|
||||||
|
if (count($value) !== 6) {
|
||||||
|
return '摇取点数必须为 6 个数';
|
||||||
|
}
|
||||||
|
foreach ($value as $i => $n) {
|
||||||
|
$v = is_numeric($n) ? (int) $n : null;
|
||||||
|
if ($v === null || $v < 1 || $v > 6) {
|
||||||
|
return '摇取点数第' . ($i + 1) . '个值必须在 1~6 之间';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user