优化玩家DicePlayer权重输入方式

This commit is contained in:
2026-03-07 11:51:34 +08:00
parent 4b6bbab9d1
commit 282d73a203
6 changed files with 241 additions and 35 deletions

View File

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

View File

@@ -71,5 +71,17 @@ export default {
url: '/dice/player/DicePlayer/updateStatus', url: '/dice/player/DicePlayer/updateStatus',
data: params data: params
}) })
},
/**
* 获取彩金池配置选项DiceLotteryConfig.id、name供 lottery_config_id 下拉使用
* @returns [ { id, name } ]
*/
async getLotteryConfigOptions(): Promise<Array<{ id: number; name: string }>> {
const res = await request.get<any>({
url: '/dice/player/DicePlayer/getLotteryConfigOptions'
})
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 ?? '') }))
} }
} }

View File

@@ -44,39 +44,98 @@
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
<!-- lottery_config_id = 自定义权重否则 = DiceLotteryConfig.id选择后该配置的五个 weight 会写入下方 player.*_weight -->
<el-form-item label="彩金池配置" prop="lottery_config_id"> <el-form-item label="彩金池配置" prop="lottery_config_id">
<el-select <el-select
v-model="formData.lottery_config_id" v-model="formData.lottery_config_id"
placeholder="不选则使用下方自定义权重" placeholder="留空则使用下方自定义权重,或选择彩金池"
clearable clearable
filterable
style="width: 100%" style="width: 100%"
:loading="lotteryConfigLoading"
@change="onLotteryConfigChange" @change="onLotteryConfigChange"
> >
<el-option label="自定义权重" :value="0" />
<el-option <el-option
v-for="item in lotteryConfigOptions" v-for="item in lotteryConfigOptions"
:key="item.id" :key="item.id"
:label="item.name" :label="(item.name && String(item.name).trim()) || `#${item.id}`"
:value="item.id" :value="item.id"
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="!formData.lottery_config_id" label="T1池权重(%)" prop="t1_weight"> <!-- 当前选中的 DiceLotteryConfig 数据展示 -->
<el-slider v-model="formData.t1_weight" :min="0" :max="100" :step="0.01" show-input /> <el-form-item v-if="currentLotteryConfig" label="当前配置" class="current-config-block">
<div class="current-lottery-config">
<div class="config-row">
<span class="config-label">名称</span>
<span>{{ currentLotteryConfig.name ?? '-' }}</span>
</div>
<div class="config-row">
<span class="config-label">类型</span>
<span>{{ lotteryConfigTypeText(currentLotteryConfig.type) }}</span>
</div>
<div class="config-row">
<span class="config-label">T1T5 权重</span>
<span>{{ currentLotteryConfigWeightsText }}</span>
</div>
<div v-if="currentLotteryConfig.remark" class="config-row">
<span class="config-label">备注</span>
<span>{{ currentLotteryConfig.remark }}</span>
</div>
</div>
</el-form-item> </el-form-item>
<el-form-item v-if="!formData.lottery_config_id" label="T2池权重(%)" prop="t2_weight"> <!-- lottery_config_id 为空时自定义权重可编辑有值时来自所选 DiceLotteryConfig仅展示不可编辑 -->
<el-slider v-model="formData.t2_weight" :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
:disabled="!isLotteryConfigEmpty()"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="!formData.lottery_config_id" label="T3池权重(%)" prop="t3_weight"> <el-form-item label="T2池权重(%)" prop="t2_weight">
<el-slider v-model="formData.t3_weight" :min="0" :max="100" :step="0.01" show-input /> <el-slider
v-model="formData.t2_weight"
:min="0"
:max="100"
:step="0.01"
show-input
:disabled="!isLotteryConfigEmpty()"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="!formData.lottery_config_id" label="T4池权重(%)" prop="t4_weight"> <el-form-item label="T3池权重(%)" prop="t3_weight">
<el-slider v-model="formData.t4_weight" :min="0" :max="100" :step="0.01" show-input /> <el-slider
v-model="formData.t3_weight"
:min="0"
:max="100"
:step="0.01"
show-input
:disabled="!isLotteryConfigEmpty()"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="!formData.lottery_config_id" label="T5池权重(%)" prop="t5_weight"> <el-form-item label="T4池权重(%)" prop="t4_weight">
<el-slider v-model="formData.t5_weight" :min="0" :max="100" :step="0.01" show-input /> <el-slider
v-model="formData.t4_weight"
:min="0"
:max="100"
:step="0.01"
show-input
:disabled="!isLotteryConfigEmpty()"
/>
</el-form-item> </el-form-item>
<el-form-item v-if="!formData.lottery_config_id"> <el-form-item label="T5池权重(%)" prop="t5_weight">
<el-slider
v-model="formData.t5_weight"
:min="0"
:max="100"
:step="0.01"
show-input
:disabled="!isLotteryConfigEmpty()"
/>
</el-form-item>
<el-form-item v-if="isLotteryConfigEmpty()">
<div class="text-gray-500 text-sm"> <div class="text-gray-500 text-sm">
五个池权重总和<span :class="Math.abs(weightsSum - 100) > 0.01 ? 'text-red-500' : ''">{{ 五个池权重总和<span :class="Math.abs(weightsSum - 100) > 0.01 ? 'text-red-500' : ''">{{
weightsSum weightsSum
@@ -130,6 +189,18 @@
return WEIGHT_FIELDS.reduce((sum, key) => sum + Number(formData[key] ?? 0), 0) return WEIGHT_FIELDS.reduce((sum, key) => sum + Number(formData[key] ?? 0), 0)
}) })
/** 当前彩金池配置的 T1T5 权重展示文案 */
const currentLotteryConfigWeightsText = computed(() => {
const c = currentLotteryConfig.value
if (!c) return '-'
const t1 = c.t1_weight ?? 0
const t2 = c.t2_weight ?? 0
const t3 = c.t3_weight ?? 0
const t4 = c.t4_weight ?? 0
const t5 = c.t5_weight ?? 0
return `${t1}% / ${t2}% / ${t3}% / ${t4}% / ${t5}%`
})
/** 新增时密码必填,编辑时选填 */ /** 新增时密码必填,编辑时选填 */
const passwordRules = computed(() => const passwordRules = computed(() =>
props.dialogType === 'add' ? [{ required: true, message: '密码必需填写', trigger: 'blur' }] : [] props.dialogType === 'add' ? [{ required: true, message: '密码必需填写', trigger: 'blur' }] : []
@@ -151,6 +222,7 @@
password: '', password: '',
status: 1 as number, status: 1 as number,
coin: 0 as number, coin: 0 as number,
/** 彩金池配置 ID空 = 自定义权重,否则 = DiceLotteryConfig.id */
lottery_config_id: null as number | null, lottery_config_id: null as number | null,
t1_weight: 0 as number, t1_weight: 0 as number,
t2_weight: 0 as number, t2_weight: 0 as number,
@@ -161,8 +233,48 @@
const formData = reactive({ ...initialFormData }) const formData = reactive({ ...initialFormData })
/** 彩金池配置下拉选项 */ /** 彩金池配置下拉选项DiceLotteryConfig id、name */
const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([]) const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([])
/** 彩金池选项加载中 */
const lotteryConfigLoading = ref(false)
/** 当前选中的 DiceLotteryConfig 完整数据(用于展示) */
const currentLotteryConfig = ref<Record<string, any> | null>(null)
function lotteryConfigTypeText(type: unknown): string {
const t = Number(type)
if (t === 0) return '付费'
if (t === 1) return '赠送'
return t ? `类型${t}` : '-'
}
/** 是否为空/自定义权重(未选彩金池或选 0 */
function isLotteryConfigEmpty(): boolean {
const v = formData.lottery_config_id
return v == null || v === 0
}
/** 根据当前 lottery_config_id 加载 DiceLotteryConfig并将五个权重写入当前 player.*_weight */
async function loadCurrentLotteryConfig() {
const id = formData.lottery_config_id
if (id == null || id === 0) {
currentLotteryConfig.value = null
return
}
try {
const res = await lotteryConfigApi.read(id)
const row = (res as any)?.data ?? (res as any)
if (row && typeof row === 'object') {
currentLotteryConfig.value = row
WEIGHT_FIELDS.forEach((key) => {
;(formData as any)[key] = Number(row[key] ?? 0)
})
} else {
currentLotteryConfig.value = null
}
} catch {
currentLotteryConfig.value = null
}
}
watch( watch(
() => props.modelValue, () => props.modelValue,
@@ -171,37 +283,51 @@
} }
) )
/** 选择彩金池配置时,拉取该配置的权重填入表单(仅展示/备份lottery_config_id 非空时后端以配置为准) */ /** 选择彩金池,拉取该配置的五个权重并写入当前 player.*_weight并更新当前配置展示 */
async function onLotteryConfigChange(lotteryConfigId: number | null) { async function onLotteryConfigChange(lotteryConfigId: number | null | undefined) {
if (!lotteryConfigId) return if (lotteryConfigId == null || lotteryConfigId === 0) {
currentLotteryConfig.value = null
return
}
try { try {
const res = await lotteryConfigApi.read(lotteryConfigId) const res = await lotteryConfigApi.read(lotteryConfigId)
const row = (res as any)?.data const row = (res as any)?.data ?? (res as any)
if (row) { if (row && typeof row === 'object') {
WEIGHT_FIELDS.forEach((key) => { WEIGHT_FIELDS.forEach((key) => {
;(formData as any)[key] = Number(row[key] ?? 0) ;(formData as any)[key] = Number(row[key] ?? 0)
}) })
currentLotteryConfig.value = row
} else {
currentLotteryConfig.value = null
} }
} catch (err) { } catch (err) {
console.warn('拉取彩金池配置权重失败', err) console.warn('拉取彩金池配置失败', err)
currentLotteryConfig.value = null
} }
} }
const initPage = async () => { const initPage = async () => {
currentLotteryConfig.value = null
Object.assign(formData, initialFormData) Object.assign(formData, initialFormData)
await loadLotteryConfigOptions() await loadLotteryConfigOptions()
if (props.data) { if (props.data) {
await nextTick() await nextTick()
initForm() initForm()
if (!isLotteryConfigEmpty()) {
await loadCurrentLotteryConfig()
}
} }
} }
/** 从 DiceLotteryConfig 拉取彩金池配置下拉选项 */ /** 从玩家控制器获取 DiceLotteryConfig id/name 列表,供 lottery_config_id 下拉使用 */
async function loadLotteryConfigOptions() { async function loadLotteryConfigOptions() {
lotteryConfigLoading.value = true
try { try {
lotteryConfigOptions.value = await lotteryConfigApi.getOptions() lotteryConfigOptions.value = await api.getLotteryConfigOptions()
} catch { } catch {
lotteryConfigOptions.value = [] lotteryConfigOptions.value = []
} finally {
lotteryConfigLoading.value = false
} }
} }
@@ -227,8 +353,14 @@
} }
const val = props.data[key] const val = props.data[key]
if (numKeys.includes(key)) { if (numKeys.includes(key)) {
;(formData as any)[key] = if (key === 'id') {
key === 'id' ? (val != null ? Number(val) || null : null) : Number(val) || 0 ;(formData as any)[key] = val != null ? Number(val) || null : null
} else if (key === 'lottery_config_id') {
const num = Number(val)
;(formData as any)[key] = val != null && !Number.isNaN(num) && num !== 0 ? num : null
} else {
;(formData as any)[key] = Number(val) || 0
}
} else { } else {
;(formData as any)[key] = val ?? '' ;(formData as any)[key] = val ?? ''
} }
@@ -244,12 +376,15 @@
if (!formRef.value) return if (!formRef.value) return
try { try {
await formRef.value.validate() await formRef.value.validate()
const useCustomWeights = !formData.lottery_config_id const useCustomWeights = isLotteryConfigEmpty()
if (useCustomWeights && Math.abs(weightsSum.value - 100) > 0.01) { if (useCustomWeights && Math.abs(weightsSum.value - 100) > 0.01) {
ElMessage.warning('五个池权重总和必须为100%') ElMessage.warning('五个池权重总和必须为100%')
return return
} }
const payload = { ...formData } const payload = { ...formData }
if (isLotteryConfigEmpty()) {
;(payload as any).lottery_config_id = null
}
if (props.dialogType === 'edit' && !payload.password) { if (props.dialogType === 'edit' && !payload.password) {
delete (payload as any).password delete (payload as any).password
} }
@@ -267,3 +402,31 @@
} }
} }
</script> </script>
<style lang="scss" scoped>
.current-config-block {
margin-bottom: 12px;
}
.current-lottery-config {
padding: 10px 12px;
background: var(--el-fill-color-light);
border-radius: 6px;
font-size: 13px;
color: var(--el-text-color-regular);
.config-row {
margin-bottom: 6px;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
}
.config-label {
color: var(--el-text-color-secondary);
margin-right: 4px;
}
}
</style>

View File

@@ -64,7 +64,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import lotteryConfigApi from '../../../api/lottery_config/index' import api from '../../../api/player/index'
interface Props { interface Props {
modelValue: Record<string, any> modelValue: Record<string, any>
@@ -79,10 +79,10 @@
const isExpanded = ref<boolean>(false) const isExpanded = ref<boolean>(false)
const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([]) const lotteryConfigOptions = ref<Array<{ id: number; name: string }>>([])
/** 从 DiceLotteryConfig 拉取彩金池配置下拉选项,用于 lottery_config_id 筛选 */ /** 从玩家控制器获取 DiceLotteryConfig id/name 列表,用于 lottery_config_id 筛选 */
onMounted(async () => { onMounted(async () => {
try { try {
lotteryConfigOptions.value = await lotteryConfigApi.getOptions() lotteryConfigOptions.value = await api.getLotteryConfigOptions()
} catch { } catch {
lotteryConfigOptions.value = [] lotteryConfigOptions.value = []
} }

View File

@@ -6,6 +6,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace app\dice\controller\lottery_config; namespace app\dice\controller\lottery_config;
use app\dice\model\lottery_config\DiceLotteryConfig;
use plugin\saiadmin\basic\BaseController; use plugin\saiadmin\basic\BaseController;
use app\dice\logic\lottery_config\DiceLotteryConfigLogic; use app\dice\logic\lottery_config\DiceLotteryConfigLogic;
use app\dice\validate\lottery_config\DiceLotteryConfigValidate; use app\dice\validate\lottery_config\DiceLotteryConfigValidate;
@@ -28,6 +29,21 @@ class DiceLotteryConfigController extends BaseController
parent::__construct(); parent::__construct();
} }
/**
* 获取 DiceLotteryConfig 列表数据,仅含 id、name用于 lottery_config_id 下拉(值为 id显示为 name
* @param Request $request
* @return Response 返回 [ ['id' => int, 'name' => string], ... ]
*/
#[Permission('色子奖池配置列表', 'dice:lottery_config:index:index')]
public function getOptions(Request $request): Response
{
$list = DiceLotteryConfig::field('id,name')->order('id', 'asc')->select();
$data = $list->map(function ($item) {
return ['id' => (int) $item['id'], 'name' => (string) ($item['name'] ?? '')];
})->toArray();
return $this->success($data);
}
/** /**
* 数据列表 * 数据列表
* @param Request $request * @param Request $request

View File

@@ -6,6 +6,7 @@
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
namespace app\dice\controller\player; namespace app\dice\controller\player;
use app\dice\model\lottery_config\DiceLotteryConfig;
use plugin\saiadmin\basic\BaseController; use plugin\saiadmin\basic\BaseController;
use app\dice\logic\player\DicePlayerLogic; use app\dice\logic\player\DicePlayerLogic;
use app\dice\validate\player\DicePlayerValidate; use app\dice\validate\player\DicePlayerValidate;
@@ -28,6 +29,21 @@ class DicePlayerController extends BaseController
parent::__construct(); parent::__construct();
} }
/**
* 获取彩金池配置选项DiceLotteryConfig.id、name供前端 lottery_config_id 下拉使用
* @param Request $request
* @return Response 返回 [ ['id' => int, 'name' => string], ... ]
*/
#[Permission('大富翁-玩家列表', 'dice:player:index:index')]
public function getLotteryConfigOptions(Request $request): Response
{
$list = DiceLotteryConfig::field('id,name')->order('id', 'asc')->select();
$data = $list->map(function ($item) {
return ['id' => (int) $item['id'], 'name' => (string) ($item['name'] ?? '')];
})->toArray();
return $this->success($data);
}
/** /**
* 数据列表 * 数据列表
* @param Request $request * @param Request $request