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 {
|
interface CategoryRow {
|
||||||
key: number
|
key: number
|
||||||
name: string
|
name: string
|
||||||
multiplier: string
|
// type="number" 的 v-model 会被 Vue 自动转成 number(空值仍是 ''),这里如实标注
|
||||||
|
multiplier: string | number
|
||||||
gender: '' | Gender
|
gender: '' | Gender
|
||||||
ageMin: string
|
ageMin: string | number
|
||||||
ageMax: string
|
ageMax: string | number
|
||||||
sortOrder: string
|
sortOrder: string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RowError {
|
interface RowError {
|
||||||
@@ -97,6 +98,20 @@ function moveRow(index: number, delta: number): void {
|
|||||||
rows.value = next
|
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 {
|
function validate(): boolean {
|
||||||
const next: Record<number, RowError> = {}
|
const next: Record<number, RowError> = {}
|
||||||
const seen = new Set<string>()
|
const seen = new Set<string>()
|
||||||
@@ -112,8 +127,8 @@ function validate(): boolean {
|
|||||||
rowError.multiplier = '权重为 0–100 的正数'
|
rowError.multiplier = '权重为 0–100 的正数'
|
||||||
}
|
}
|
||||||
|
|
||||||
const ageMin = row.ageMin.trim() === '' ? null : Number(row.ageMin)
|
const ageMin = toAge(row.ageMin)
|
||||||
const ageMax = row.ageMax.trim() === '' ? null : Number(row.ageMax)
|
const ageMax = toAge(row.ageMax)
|
||||||
if (ageMin !== null && (!Number.isInteger(ageMin) || ageMin < 0 || ageMin > 120)) rowError.age = '年龄为 0–120 的整数'
|
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 (ageMax !== null && (!Number.isInteger(ageMax) || ageMax < 0 || ageMax > 120)) rowError.age = '年龄为 0–120 的整数'
|
||||||
else if (ageMin !== null && ageMax !== null && ageMin > ageMax) rowError.age = '起始年龄不能大于结束年龄'
|
else if (ageMin !== null && ageMax !== null && ageMin > ageMax) rowError.age = '起始年龄不能大于结束年龄'
|
||||||
@@ -129,8 +144,8 @@ function buildInputs(): EventCategoryInput[] {
|
|||||||
name: row.name.trim(),
|
name: row.name.trim(),
|
||||||
multiplier: Number(row.multiplier),
|
multiplier: Number(row.multiplier),
|
||||||
gender: row.gender === '' ? null : row.gender,
|
gender: row.gender === '' ? null : row.gender,
|
||||||
ageMin: row.ageMin.trim() === '' ? null : Number(row.ageMin),
|
ageMin: toAge(row.ageMin),
|
||||||
ageMax: row.ageMax.trim() === '' ? null : Number(row.ageMax),
|
ageMax: toAge(row.ageMax),
|
||||||
sortOrder: Number(row.sortOrder) || index + 1,
|
sortOrder: Number(row.sortOrder) || index + 1,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ function openCreate(): void {
|
|||||||
function validate(): string | null {
|
function validate(): string | null {
|
||||||
if (formTeamId.value === null) return '请选择单位'
|
if (formTeamId.value === null) return '请选择单位'
|
||||||
const delta = Number(formDelta.value)
|
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 (delta === 0) return '分值不能为 0'
|
||||||
if (formReason.value.trim() === '') return '理由必填'
|
if (formReason.value.trim() === '') return '理由必填'
|
||||||
return null
|
return null
|
||||||
|
|||||||
Reference in new issue
Block a user