游戏-渠道管理-优化样式增强验证,新增关联删除

This commit is contained in:
2026-04-03 17:49:46 +08:00
parent 6b830f4e25
commit 28bd9f1a09
7 changed files with 578 additions and 26 deletions

View File

@@ -47,11 +47,11 @@
/>
<FormItem
:label="t('game.config.name')"
type="string"
type="select"
v-model="baTable.form.items!.name"
prop="name"
:input-attr="{ disabled: metaFieldsDisabled }"
:placeholder="t('Please input field', { field: t('game.config.name') })"
:input-attr="{ content: nameSelectContent, disabled: metaFieldsDisabled }"
:placeholder="t('Please select field', { field: t('game.config.name') })"
/>
<FormItem
:label="t('game.config.title')"
@@ -79,6 +79,7 @@
class="weight-val"
:placeholder="t('Please input field', { field: t('game.config.weight value') })"
clearable
:disabled="isDefaultBigwinWeight && isBigwinDiceLockedKey(row.key)"
@input="onWeightRowChange"
/>
<el-button v-if="canEditWeightStructure" type="danger" link @click="removeWeightRow(idx)">
@@ -86,6 +87,7 @@
</el-button>
</div>
<el-button v-if="canEditWeightStructure" type="primary" link @click="addWeightRow">{{ t('Add') }}</el-button>
<div v-if="isDefaultBigwinWeight" class="form-help">{{ t('game.config.default_bigwin_weight_help') }}</div>
</div>
</el-form-item>
<FormItem
@@ -137,6 +139,17 @@ import { useConfig } from '/@/stores/config'
import { useAdminInfo } from '/@/stores/adminInfo'
import type baTableClass from '/@/utils/baTable'
import { buildValidatorData } from '/@/utils/validate'
import {
fixedRowsFromKeys,
getFixedKeysForGameConfigName,
isBigwinDiceLockedKey,
jsonStringFromFixedKeys,
normalizeGameWeightConfigName,
parseWeightJsonToMap,
rowsToMap,
weightRowsMatchBigwinDiceKeys,
type WeightRow,
} from '/@/utils/gameWeightFixed'
const config = useConfig()
const formRef = useTemplateRef('formRef')
@@ -169,21 +182,56 @@ const groupSelectContentFiltered = computed(() => {
return groupSelectBase
})
/** game_weight编辑或非超管时键只读仅超管新增时可增删行、改键 */
/** default_tier_weight / default_bigwin_weight及 default_kill_score_weight键固定仅值可改可增删行 */
const isFixedGameWeightConfig = computed(() => getFixedKeysForGameConfigName(baTable.form.items?.name) !== null)
/** game_weight编辑或非超管时键只读仅超管新增非固定项时可增删行、改键 */
const weightKeyReadonly = computed(() => {
if (!isGameWeight.value) return false
if (isFixedGameWeightConfig.value) return true
if (baTable.form.operate === 'Edit') return true
return !isSuperAdmin.value
})
const canEditWeightStructure = computed(() => isGameWeight.value && baTable.form.operate === 'Add' && isSuperAdmin.value)
const canEditWeightStructure = computed(
() => isGameWeight.value && baTable.form.operate === 'Add' && isSuperAdmin.value && !isFixedGameWeightConfig.value
)
type WeightRow = { key: string; val: string }
/** 默认大奖权重:仅校验每项整数与 0100005/30 固定 10000不参与 tier/kill 的「和≤100」 */
const isDefaultBigwinWeight = computed(() => normalizeGameWeightConfigName(baTable.form.items?.name) === 'default_bigwin_weight')
const weightRows = ref<WeightRow[]>([{ key: '', val: '' }])
/** default_tier_weight / default_kill_score_weight每项≤100且权重之和必须=100 */
const WEIGHT_SUM100_NAMES = ['default_tier_weight', 'default_kill_score_weight']
/** 配置标识:按分组限定可选项;编辑时若库中旧值不在列表中则临时追加一条 */
const nameSelectContent = computed((): Record<string, string> => {
const g = baTable.form.items?.group
let base: Record<string, string> = {}
if (g === 'game_config') {
base = {
game_rule: t('game.config.name opt game_rule'),
game_rule_en: t('game.config.name opt game_rule_en'),
}
} else if (g === 'game_weight') {
base = {
default_tier_weight: t('game.config.name opt default_tier_weight'),
default_kill_score_weight: t('game.config.name opt default_kill_score_weight'),
default_bigwin_weight: t('game.config.name opt default_bigwin_weight'),
}
}
const n = baTable.form.items?.name
if (typeof n === 'string' && n.trim() !== '' && base[n] === undefined) {
const norm = normalizeGameWeightConfigName(n)
if (norm !== '' && base[norm] !== undefined) {
return { ...base, [n]: base[norm] }
}
return { ...base, [n]: n }
}
return base
})
const isGameWeight = computed(() => baTable.form.items?.group === 'game_weight')
function parseValueToWeightRows(raw: unknown): WeightRow[] {
@@ -236,11 +284,29 @@ function weightRowsToJsonString(rows: WeightRow[]): string {
function syncWeightRowsToFormValue() {
const items = baTable.form.items
if (!items) return
const fixedKeys = getFixedKeysForGameConfigName(items.name)
if (fixedKeys) {
const map = rowsToMap(weightRows.value)
items.value = jsonStringFromFixedKeys(fixedKeys, map)
return
}
items.value = weightRowsToJsonString(weightRows.value)
}
function enforceDefaultBigwinLockedValues() {
if (normalizeGameWeightConfigName(baTable.form.items?.name) !== 'default_bigwin_weight') {
return
}
for (const r of weightRows.value) {
if (isBigwinDiceLockedKey(r.key)) {
r.val = '10000'
}
}
}
function onWeightRowChange() {
if (isGameWeight.value) {
enforceDefaultBigwinLockedValues()
syncWeightRowsToFormValue()
}
}
@@ -263,6 +329,14 @@ function removeWeightRow(idx: number) {
function hydrateWeightRowsFromForm() {
if (!isGameWeight.value) return
const fixedKeys = getFixedKeysForGameConfigName(baTable.form.items?.name)
if (fixedKeys) {
const map = parseWeightJsonToMap(baTable.form.items?.value)
weightRows.value = fixedRowsFromKeys(fixedKeys, map)
enforceDefaultBigwinLockedValues()
syncWeightRowsToFormValue()
return
}
weightRows.value = parseValueToWeightRows(baTable.form.items?.value)
}
@@ -283,6 +357,27 @@ watch(
watch(
() => baTable.form.items?.group,
() => {
if (baTable.form.items?.group === 'game_weight') {
hydrateWeightRowsFromForm()
}
const items = baTable.form.items
if (!items || !isSuperAdmin.value) {
return
}
const c = nameSelectContent.value
const keys = Object.keys(c)
if (keys.length === 0) {
return
}
if (typeof items.name !== 'string' || items.name === '' || c[items.name] === undefined) {
items.name = keys[0]
}
}
)
watch(
() => baTable.form.items?.name,
() => {
if (baTable.form.items?.group === 'game_weight') {
hydrateWeightRowsFromForm()
@@ -294,28 +389,78 @@ function validateGameWeightRules(): string | undefined {
if (baTable.form.items?.group !== 'game_weight') {
return undefined
}
const name = baTable.form.items?.name ?? ''
const configName = normalizeGameWeightConfigName(baTable.form.items?.name)
const fixedKeys = getFixedKeysForGameConfigName(configName)
const nums: number[] = []
for (const r of weightRows.value) {
const k = r.key.trim()
if (k === '') continue
const vs = r.val.trim()
if (vs === '') {
return t('Please input field', { field: t('game.config.weight value') })
if (fixedKeys) {
const map = rowsToMap(weightRows.value)
if (configName === 'default_bigwin_weight') {
for (const k of fixedKeys) {
const vs = (map[k] ?? '').trim()
if (vs === '') {
return t('Please input field', { field: t('game.config.weight value') })
}
const n = Number(vs)
if (!Number.isFinite(n)) {
return t('game.config.weight value numeric')
}
if (isBigwinDiceLockedKey(k)) {
if (n !== 10000) {
return t('game.config.bigwin weight locked 5 30')
}
} else if (n < 0 || n > 10000) {
return t('game.config.bigwin weight each 0 10000')
}
nums.push(n)
}
} else {
for (const k of fixedKeys) {
const vs = (map[k] ?? '').trim()
if (vs === '') {
return t('Please input field', { field: t('game.config.weight value') })
}
const n = Number(vs)
if (!Number.isFinite(n)) {
return t('game.config.weight value numeric')
}
if (n > 100) {
return t('game.config.weight each max 100')
}
nums.push(n)
}
}
const n = Number(vs)
if (!Number.isFinite(n)) {
return t('game.config.weight value numeric')
} else {
// 非固定键名但行结构已是 530 骰子时,按大奖 010000 校验(避免 name 格式异常时误走每项≤10000
const treatAsBigwin = configName === 'default_bigwin_weight' || weightRowsMatchBigwinDiceKeys(weightRows.value)
for (const r of weightRows.value) {
const k = r.key.trim()
if (k === '') continue
const vs = r.val.trim()
if (vs === '') {
return t('Please input field', { field: t('game.config.weight value') })
}
const n = Number(vs)
if (!Number.isFinite(n)) {
return t('game.config.weight value numeric')
}
if (treatAsBigwin) {
if (isBigwinDiceLockedKey(k)) {
if (n !== 10000) {
return t('game.config.bigwin weight locked 5 30')
}
} else if (n < 0 || n > 10000) {
return t('game.config.bigwin weight each 0 10000')
}
} else if (n > 10000) {
return t('game.config.weight each max 10000')
}
nums.push(n)
}
if (n > 100) {
return t('game.config.weight each max 100')
if (nums.length === 0) {
return t('Please input field', { field: t('game.config.value') })
}
nums.push(n)
}
if (nums.length === 0) {
return t('Please input field', { field: t('game.config.value') })
}
if (WEIGHT_SUM100_NAMES.includes(name)) {
if (WEIGHT_SUM100_NAMES.includes(configName)) {
let sum = 0
for (const x of nums) {
sum += x
@@ -372,4 +517,10 @@ const rules: Partial<Record<string, FormItemRule[]>> = reactive({
flex-shrink: 0;
color: var(--el-text-color-secondary);
}
.form-help {
margin-top: 8px;
font-size: 12px;
line-height: 18px;
color: var(--el-text-color-secondary);
}
</style>