fix(回执表单): 日期类专属区字段按类型分派校验,修「填完仍提示必填」
build / build (push) Successful in 9m1s

家长端回执弹窗的专属区动态规则此前只写 required + trigger、没给 type。
async-validator 的 getValidationMethod 仅在规则「除掉 message 后只剩 required」
时才走 required 校验器;带上 trigger 后会回退到默认 string 校验器,而 DatePicker
的 v-model 给出的是 Date 对象,被判类型不符。真正的报错又在 cb() 里被自定义
message 顶掉,界面上只剩「请填写XX」——表现为字段明明填了却不让提交。

- ParentNotices.vue: 新增 ruleTypeOf() 统一映射规则类型
  (number -> type:"number",date/datetime -> type:"date",其余保持默认 string)。
  注意 async-validator 没有 datetime 类型,写上去会导致 validate 抛异常。
- ParentNotices.vue: 日期字段回填统一转 Date(本地时间语义,避免 new Date("yyyy-MM-dd")
  的 UTC 偏移),提交时序列化成 yyyy-MM-dd / yyyy-MM-dd HH:mm。
  这同时修掉一处数据污染:此前 String(Date) 会把
  "Tue Sep 22 2026 10:33:00 GMT+0800 (中国标准时间)" 这类 locale 脏串写进 fillData。
- NewNotice.vue: 定时发布时间弹窗的规则存在同类问题,补 type:"date"。
- 覆盖四类回执单:stay / visit / adjust 的日期字段曾坏,general 及公共区字段本就正常。

.gitignore 追加 .workbuddy/(本地 AI 工作目录,不入库)。
This commit is contained in:
lijing
2026-09-22 11:01:12 +08:00
parent 580b05a5eb
commit 7daf3502bd
4 changed files with 71 additions and 11 deletions
@@ -254,7 +254,12 @@
这些是模板项目已经踩过并写进注释的坑,本模块原样继承:
1. **`<FormItem required>` 必须配 `prop`** —— 否则字段名被解析成 `undefined`,model 取到 `undefined`,家长**填了值也照样报错**、表单永远提交不了。
2. **数字字段规则必须显式写 `type: "number"`** —— async-validator 只在规则「除掉 message 后只剩 required」时走 required 校验器;一旦带 `trigger`,会回退到 `type: "string"`,`InputNumber` 给出的数字被判类型不符,错误文案还被自定义 message 掩盖,极具误导性。
2. **非 string 取值的控件,规则里必须显式写 `type`** —— async-validator 只在规则「除掉 message 后只剩 required」时走 required 校验器;一旦带 `trigger`,会回退到 `default validators[type || 'string']`,再拿 `typeof value !== 'string'` 判类型不符,而**真实报错会被自定义 `message` 覆盖**,于是「明明填了值,红字仍显示『请填写XX』、表单交不上去」,极具误导性。
- `InputNumber` → `type: "number"`;
- `DatePicker` → **`type: "date"`**(v-model 给的是 `Date` 对象;async-validator **没有 `datetime` 这个类型**,写上去 `getType()` 直接抛 `Unknown rule type datetime`,整个 validate 崩掉,被 `.catch(() => false)` 吞成「提交失败」);
- `Select`/`Input`/`Textarea` → string,默认即可。
- 配套:日期字段在模型里统一存 `Date`、提交时再格式化成 `yyyy-MM-dd` / `yyyy-MM-dd HH:mm`(本地时间手工拼,别 `new Date("2026-09-23")` —— 按 UTC 解析会跑日期),否则 `String(Date)` 会提交成 `"Tue Sep 22 2026 10:33:00 GMT+0800 (中国标准时间)"`,回执名单与导出 CSV 全废。
- 30 秒定位法:在 node 里用项目自己的 `node_modules/async-validator` 复刻 `FormItem.validate()`(`descriptor[prop] = rules`、`model[prop] = fieldValue`、`{ firstFields: true }`),逐个类型跑一遍,比读代码猜快得多。
3. **表单模型是稳定的 `reactive` 对象,不能写成 `computed(() => ({...}))`** —— 每次依赖变化生成新对象,而 `FormItem` 校验读的是 `Form.model`,props 要等父组件重渲染才更新,同步 change 校验拿到的还是旧对象(「选了却红字不消失」)。
4. **`rules` 写成普通常量/`computed` 要分清场景** —— Form 内有 `watch: { rules () { this.validate() } }`,引用一变就全量重校验。
5. **存草稿只校验标题**,并用 `clearFieldState()` 清掉其它字段的残留红字。