lovife
|
5de9ccc100
|
feat(fill): 草稿保存(§9.3 / §9.4)
POST /mp/submissions 取草稿(幂等)+ PUT /mp/submissions/{id} 保存草稿。
学生填了一半能存下来,再打开还在。
四条守住的规则:
1) **填报单必须属于调用者** —— 这个条件写进 SQL 的 WHERE(selectMineById),
不是"查出来再判断"。后者一旦判断漏写就是越权。
2) **锁定字段服务端再拒一次**:前端已经渲染成只读,但请求可以伪造,
而「报考工种」被改错的后果是机构直接不受理。两层防护里只有服务端这层是真的。
3) **改动留痕**(changed_fields):老师填的值被学生改过要记下来 ——
审核时看到的是一个数字,无法判断该找谁(老师填错找老师,学生改错直接驳回)。
4) 已提交的填报单不能直接改,要先撤回。
本轮修掉的 4 个真问题(全是"不报错但结果错"的类型):
1) **changed_fields 是 jsonb,我当 varchar 用了**。存了逗号分隔字符串,
PostgreSQL 报 `invalid input syntax for type json`,而错误信息里的
"Token xxx is invalid" 完全指不到是这一列。已改为存 JSON 数组。
⚠️ 这已经是第三次被"列的真实类型与我的假设不符"咬到
(前两次:expected_count NOT NULL、min_long_side NOT NULL)。
教训:**写列之前查 information_schema 的实际类型,不要只读 DDL 文档。**
2) **changed_fields 把没动过的字段也标成"改过"**。原因是我拿"提交表的列值"
和"名册值"比,而锁定字段的列**永远不写初值**、姓名/证件号/电话**根本没有列** ——
全都读成 null,于是全被判成"改过"。留痕一旦充满噪音,真正的改动就没人看了。
已改为:排除锁定字段(按定义不可能被改)与没有列的字段。
3) **学生自己填的"非预填字段"根本没被读回来**。我的合并只遍历了"名册有的键",
于是在读学校填了、保存成功、再打开却没了。已改为按**表单字段全集**遍历,
并明确三种情形:动过的预填字段用草稿值(空也算,那是清空)、
自己填的用草稿值、其余用名册值。
4) **建草稿时没做初值,导致三种状态无法区分**(从没动过 / 改成了别的 / 清空了)——
列值都是 null。表现是改动判不出、清空会被名册值顶回来。
已在建草稿时把名册值写入"可改的预填字段"做初值,状态就自明了。
顺带修正一处**字段目录与 DDL 的真不一致**:
表单定义把「联系电话」标为可改(PRD 把它列在「预填可改」里),
但 collect_submission **没有 phone 列** —— 学生改了没地方存。
一期先设为**只读**,并在代码里写明要真正开放修改需要加一列。
不用"前端允许改、后端悄悄丢掉"糊过去 —— 那会让学生以为改成功了,
实际提交的还是老号码。
另一处实现选择修正:锁定字段(报考职业/工种/等级)**要写进提交单**。
它们恰恰是最重要的统计维度(按工种统计报名人数),不落列就统计不出来 ——
而架构约束正是"内置字段落列才可统计"。写进去还带来一个好处:
它是**提交时的快照**,老师之后改了名册,这份单子仍记得"他当时报的是四级"。
顺带修 E2E 的两条过时期望(回归抓到的):
· 写死了 127.0.0.1,而 H5 应用地址已改成穿透域名 → 改为从配置读期望值;
· fragment 改成 hash 路由格式后,token 解析没跟上。
验收:e2e-m3-draft 27/27、e2e-m3-gate 29/29、e2e-m3-h5-auth 23/23。
|
2026-09-29 11:41:40 +08:00 |
|