fix(admin): 组别填了年龄后「保存全部」无反应(number 字段被当字符串处理)
Vue 3 对 <input type="number"> 的 v-model 会自动 parseFloat(空值仍为 ''), 所以填了年龄后 row.ageMin/ageMax 是 number,而校验里写的是 row.ageMin.trim(), 点击处理器抛 TypeError 直接中断 —— 界面毫无反应;留空时是 '',.trim() 正常,所以能保存。 - CategoriesSection:新增 toAge() 统一取值(String() 包一层,非法值返回 NaN 交给校验标红), validate 与 buildInputs 都改用它;CategoryRow 的数值字段类型如实标注为 string | number - AdjustmentsPage:调整分值的 formDelta.value.trim() 同样会崩,改为 String(...).trim() 自检:vue-tsc + pnpm build 通过,前端 node --test 26/26。
This commit is contained in:
1 parent
c2696e768e
commit
7531ea29e1
2 files changed
+24
-9
No files matched your search
@@ -15,11 +15,12 @@ const toast = useToastStore()
|
||||
interface CategoryRow {
|
||||
key: number
|
||||
name: string
|
||||
multiplier: string
|
||||
// type="number" 的 v-model 会被 Vue 自动转成 number(空值仍是 ''),这里如实标注
|
||||
multiplier: string | number
|
||||
gender: '' | Gender
|
||||
ageMin: string
|
||||
ageMax: string
|
||||
sortOrder: string
|
||||
ageMin: string | number
|
||||
ageMax: string | number
|
||||
sortOrder: string | number
|
||||
}
|
||||
|
||||
interface RowError {
|
||||
@@ -97,6 +98,20 @@ function moveRow(index: number, delta: number): void {
|
||||
rows.value = next
|
||||
}
|
||||
|
||||
/**
|
||||
* 年龄取值。
|
||||
*
|
||||
* `type="number"` 的 v-model 会被 Vue 自动转成 number(空值仍是 ''),所以不能直接 `.trim()`:
|
||||
* 填了数字后字段是 number,`.trim()` 抛 TypeError,点击处理器中断,表现为「点了没反应」。
|
||||
* 非法输入返回 NaN,交给 validate 标红。
|
||||
*/
|
||||
function toAge(value: string | number): number | null {
|
||||
const text = String(value).trim()
|
||||
if (text === '') return null
|
||||
const parsed = Number(text)
|
||||
return Number.isFinite(parsed) ? parsed : Number.NaN
|
||||
}
|
||||
|
||||
function validate(): boolean {
|
||||
const next: Record<number, RowError> = {}
|
||||
const seen = new Set<string>()
|
||||
@@ -112,8 +127,8 @@ function validate(): boolean {
|
||||
rowError.multiplier = '权重为 0–100 的正数'
|
||||
}
|
||||
|
||||
const ageMin = row.ageMin.trim() === '' ? null : Number(row.ageMin)
|
||||
const ageMax = row.ageMax.trim() === '' ? null : Number(row.ageMax)
|
||||
const ageMin = toAge(row.ageMin)
|
||||
const ageMax = toAge(row.ageMax)
|
||||
if (ageMin !== null && (!Number.isInteger(ageMin) || ageMin < 0 || ageMin > 120)) rowError.age = '年龄为 0–120 的整数'
|
||||
else if (ageMax !== null && (!Number.isInteger(ageMax) || ageMax < 0 || ageMax > 120)) rowError.age = '年龄为 0–120 的整数'
|
||||
else if (ageMin !== null && ageMax !== null && ageMin > ageMax) rowError.age = '起始年龄不能大于结束年龄'
|
||||
@@ -129,8 +144,8 @@ function buildInputs(): EventCategoryInput[] {
|
||||
name: row.name.trim(),
|
||||
multiplier: Number(row.multiplier),
|
||||
gender: row.gender === '' ? null : row.gender,
|
||||
ageMin: row.ageMin.trim() === '' ? null : Number(row.ageMin),
|
||||
ageMax: row.ageMax.trim() === '' ? null : Number(row.ageMax),
|
||||
ageMin: toAge(row.ageMin),
|
||||
ageMax: toAge(row.ageMax),
|
||||
sortOrder: Number(row.sortOrder) || index + 1,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ function openCreate(): void {
|
||||
function validate(): string | null {
|
||||
if (formTeamId.value === null) return '请选择单位'
|
||||
const delta = Number(formDelta.value)
|
||||
if (formDelta.value.trim() === '' || !Number.isFinite(delta)) return '请填写分值'
|
||||
if (String(formDelta.value).trim() === '' || !Number.isFinite(delta)) return '请填写分值'
|
||||
if (delta === 0) return '分值不能为 0'
|
||||
if (formReason.value.trim() === '') return '理由必填'
|
||||
return null
|
||||
|
||||
Reference in new issue
Block a user