[色子游戏]玩家购买抽奖记录-优化样式

This commit is contained in:
2026-03-03 15:28:13 +08:00
parent 1b62a4f3e0
commit c02d19b1fd
8 changed files with 424 additions and 42 deletions

View File

@@ -61,5 +61,14 @@ export default {
url: '/dice/player_coin_record/DicePlayerCoinRecord/destroy',
data: params
})
},
/**
* 获取玩家选项id、username用于下拉
*/
getPlayerOptions() {
return request.get<Api.Common.ApiData>({
url: '/dice/player_coin_record/DicePlayerCoinRecord/getPlayerOptions'
})
}
}

View File

@@ -79,12 +79,30 @@
// 搜索表单
const searchForm = ref({
const searchForm = ref<Record<string, unknown>>({
username: undefined,
use_coins_min: undefined,
use_coins_max: undefined,
total_draw_count_min: undefined,
total_draw_count_max: undefined,
paid_draw_count_min: undefined,
paid_draw_count_max: undefined,
free_draw_count_min: undefined,
free_draw_count_max: undefined,
create_time_min: undefined,
create_time_max: undefined,
create_time: undefined as [string, string] | undefined
})
// 搜索处理
// 搜索处理(将创建时间范围 create_time 转为 create_time_min / create_time_max
const handleSearch = (params: Record<string, any>) => {
Object.assign(searchParams, params)
const p = { ...params }
if (Array.isArray(p.create_time) && p.create_time.length === 2) {
p.create_time_min = p.create_time[0]
p.create_time_max = p.create_time[1]
}
delete p.create_time
Object.assign(searchParams, p)
getData()
}
@@ -105,15 +123,22 @@
} = useTable({
core: {
apiFn: api.list,
columnsFactory: () => [
{ type: 'selection' },
{ prop: 'player_id', label: '玩家id' },
{ prop: 'use_coins', label: '消耗硬币' },
{ prop: 'total_draw_count', label: '总抽奖次数' },
{ prop: 'paid_draw_count', label: '购买抽奖次数' },
{ prop: 'free_draw_count', label: '赠送抽奖次数' },
{ prop: 'operation', label: '操作', width: 100, fixed: 'right', useSlot: true }
]
columnsFactory: () => {
const usernameFormatter = (row: Record<string, any>) =>
row?.dicePlayer?.username ?? row?.player_id ?? '-'
return [
{ type: 'selection' },
{ prop: 'id', label: 'ID', width: 80 },
{ prop: 'player_id', label: '玩家用户名', formatter: (row: Record<string, any>) => usernameFormatter(row) },
{ prop: 'use_coins', label: '消耗硬币' },
{ prop: 'total_draw_count', label: '总抽奖次数' },
{ prop: 'paid_draw_count', label: '购买抽奖次数' },
{ prop: 'free_draw_count', label: '赠送抽奖次数' },
{ prop: 'remark', label: '备注', width: 100, showOverflowTooltip: true },
{ prop: 'create_time', label: '创建时间', width: 170 },
{ prop: 'operation', label: '操作', width: 100, fixed: 'right', useSlot: true }
]
}
}
})

View File

@@ -8,20 +8,59 @@
@close="handleClose"
>
<el-form ref="formRef" :model="formData" :rules="rules" label-width="120px">
<el-form-item label="玩家id" prop="player_id">
<el-cascader v-model="formData.player_id" :options="[]" placeholder="请选择玩家id" allow-clear />
<el-form-item label="玩家" prop="player_id">
<el-select
v-model="formData.player_id"
placeholder="请选择玩家(显示用户名)"
clearable
filterable
style="width: 100%"
:disabled="dialogType === 'edit'"
>
<el-option
v-for="item in playerOptions"
:key="item.id"
:label="item.username"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="消耗硬币" prop="use_coins">
<el-input-number v-model="formData.use_coins" placeholder="请输入消耗硬币" />
</el-form-item>
<el-form-item label="总抽奖次数" prop="total_draw_count">
<el-input-number v-model="formData.total_draw_count" placeholder="请输入总抽奖次数" />
<el-input-number v-model="formData.use_coins" placeholder="请输入消耗硬币" :min="0" />
</el-form-item>
<el-form-item label="购买抽奖次数" prop="paid_draw_count">
<el-input-number v-model="formData.paid_draw_count" placeholder="请输入购买抽奖次数" />
<el-input-number
v-model="formData.paid_draw_count"
placeholder="请输入购买抽奖次数"
:min="0"
@change="onDrawCountChange"
/>
</el-form-item>
<el-form-item label="赠送抽奖次数" prop="free_draw_count">
<el-input-number v-model="formData.free_draw_count" placeholder="请输入赠送抽奖次数" />
<el-input-number
v-model="formData.free_draw_count"
placeholder="请输入赠送抽奖次数"
:min="0"
@change="onDrawCountChange"
/>
</el-form-item>
<el-form-item label="总抽奖次数" prop="total_draw_count">
<el-input-number
:model-value="totalDrawCountComputed"
placeholder="自动求和"
:min="0"
disabled
/>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input
v-model="formData.remark"
type="textarea"
:rows="3"
placeholder="请输入备注(必填)"
maxlength="500"
show-word-limit
/>
</el-form-item>
</el-form>
<template #footer>
@@ -69,23 +108,38 @@
* 表单验证规则
*/
const rules = reactive<FormRules>({
player_id: [{ required: true, message: '玩家id必需填写', trigger: 'blur' }],
player_id: [{ required: true, message: '请选择玩家', trigger: 'change' }],
use_coins: [{ required: true, message: '消耗硬币必需填写', trigger: 'blur' }],
total_draw_count: [{ required: true, message: '总抽奖次数必需填写', trigger: 'blur' }],
paid_draw_count: [{ required: true, message: '购买抽奖次数必需填写', trigger: 'blur' }],
free_draw_count: [{ required: true, message: '赠送抽奖次数必需填写', trigger: 'blur' }],
remark: [{ required: true, message: '备注必需填写', trigger: 'blur' }]
})
/** 玩家下拉选项id、username */
const playerOptions = ref<Array<{ id: number; username: string }>>([])
/** 总抽奖次数 = 购买抽奖次数 + 赠送抽奖次数(只读展示) */
const totalDrawCountComputed = computed(() => {
const paid = Number(formData.paid_draw_count) || 0
const free = Number(formData.free_draw_count) || 0
return paid + free
})
function onDrawCountChange() {
formData.total_draw_count = totalDrawCountComputed.value
}
/**
* 初始数据
*/
const initialFormData = {
id: null,
player_id: null,
use_coins: '',
total_draw_count: null,
paid_draw_count: null,
free_draw_count: null,
use_coins: null as number | null,
total_draw_count: null as number | null,
paid_draw_count: null as number | null,
free_draw_count: null as number | null,
remark: ''
}
/**
@@ -94,24 +148,31 @@
const formData = reactive({ ...initialFormData })
/**
* 监听弹窗打开,初始化表单数据
* 监听弹窗打开,初始化表单并拉取玩家选项(与 player_wallet_record 一致)
*/
watch(
() => props.modelValue,
(newVal) => {
if (newVal) {
async (open) => {
if (open) {
initPage()
try {
const list = await api.getPlayerOptions()
const arr = Array.isArray(list) ? list : (list as any)?.data
playerOptions.value = Array.isArray(arr)
? (arr as Array<{ id: number; username: string }>)
: []
} catch {
playerOptions.value = []
}
}
}
)
/**
* 初始化页面数据
* 初始化页面数据(仅重置表单、回填编辑数据,不在此处请求玩家列表)
*/
const initPage = async () => {
// 先重置为初始值
Object.assign(formData, initialFormData)
// 如果有数据,则填充数据
Object.assign(formData, { ...initialFormData })
if (props.data) {
await nextTick()
initForm()
@@ -122,13 +183,22 @@
* 初始化表单数据
*/
const initForm = () => {
if (props.data) {
for (const key in formData) {
if (props.data[key] != null && props.data[key] != undefined) {
;(formData as any)[key] = props.data[key]
}
if (!props.data) return
const keys = [
'id',
'player_id',
'use_coins',
'total_draw_count',
'paid_draw_count',
'free_draw_count',
'remark'
]
keys.forEach((key) => {
const val = props.data![key]
if (val != null && val !== undefined) {
;(formData as Record<string, unknown>)[key] = val
}
}
})
}
/**
@@ -140,14 +210,17 @@
}
/**
* 提交表单
* 提交表单(总抽奖次数由购买+赠送自动求和,提交前写入)
*/
const handleSubmit = async () => {
if (!formRef.value) return
try {
formData.total_draw_count = totalDrawCountComputed.value
await formRef.value.validate()
if (props.dialogType === 'add') {
await api.save(formData)
const rest = { ...formData } as Record<string, unknown>
delete rest.id
await api.save(rest)
ElMessage.success('新增成功')
} else {
await api.update(formData)

View File

@@ -8,6 +8,109 @@
@search="handleSearch"
@expand="handleExpand"
>
<el-col v-bind="setSpan(6)">
<el-form-item label="玩家(用户名)" prop="username">
<el-input v-model="formData.username" placeholder="按用户名搜索" clearable />
</el-form-item>
</el-col>
<el-col v-bind="setSpan(6)">
<el-form-item label="消耗硬币" prop="use_coins_min">
<div class="range-wrap">
<el-input-number
v-model="formData.use_coins_min"
placeholder="最小"
:min="0"
controls-position="right"
class="range-input"
/>
<span class="range-sep"></span>
<el-input-number
v-model="formData.use_coins_max"
placeholder="最大"
:min="0"
controls-position="right"
class="range-input"
/>
</div>
</el-form-item>
</el-col>
<el-col v-bind="setSpan(6)">
<el-form-item label="总抽奖次数" prop="total_draw_count_min">
<div class="range-wrap">
<el-input-number
v-model="formData.total_draw_count_min"
placeholder="最小"
:min="0"
controls-position="right"
class="range-input"
/>
<span class="range-sep"></span>
<el-input-number
v-model="formData.total_draw_count_max"
placeholder="最大"
:min="0"
controls-position="right"
class="range-input"
/>
</div>
</el-form-item>
</el-col>
<el-col v-bind="setSpan(6)">
<el-form-item label="购买抽奖次数" prop="paid_draw_count_min">
<div class="range-wrap">
<el-input-number
v-model="formData.paid_draw_count_min"
placeholder="最小"
:min="0"
controls-position="right"
class="range-input"
/>
<span class="range-sep"></span>
<el-input-number
v-model="formData.paid_draw_count_max"
placeholder="最大"
:min="0"
controls-position="right"
class="range-input"
/>
</div>
</el-form-item>
</el-col>
<el-col v-bind="setSpan(6)">
<el-form-item label="赠送抽奖次数" prop="free_draw_count_min">
<div class="range-wrap">
<el-input-number
v-model="formData.free_draw_count_min"
placeholder="最小"
:min="0"
controls-position="right"
class="range-input"
/>
<span class="range-sep"></span>
<el-input-number
v-model="formData.free_draw_count_max"
placeholder="最大"
:min="0"
controls-position="right"
class="range-input"
/>
</div>
</el-form-item>
</el-col>
<el-col v-bind="setSpan(8)">
<el-form-item label="创建时间" prop="create_time_min">
<el-date-picker
v-model="formData.create_time"
type="datetimerange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
clearable
/>
</el-form-item>
</el-col>
</sa-search-bar>
</template>
@@ -60,3 +163,22 @@
}
}
</script>
<style lang="scss" scoped>
.range-wrap {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.range-input {
flex: 1;
min-width: 0;
}
.range-sep {
color: var(--el-text-color-secondary);
flex-shrink: 0;
}
</style>