feat(form): 发布表单与各模块「新建发布」页逐字段对齐(含审批流与作业两步发布)
build / build-push (push) Successful in 1m2s

把 5 个模块「新建/发布」页的字段与提交体逐个核对后,补齐此前缺失或形态不符的部分:

- 部门名镜像:公告/宿舍/活动三处在模块页是「字典 id + 反查名称」一起提交。
  新增 mirrorLabelOf 机制 —— 该字段不渲染控件、不进模型 schema,提交时按源字段
  选中项的显示名填充(deptName)
- 公告审批流:新增 flow 控件(widget=flow)+ 教师组织树字典 notice.teaTree,
  提交 flow:[{name,vote,approverTeaIds}];publishType 值域修正为 direct/approve;
  存草稿改用模块自己的独立接口 notice.saveDraft(POST /api/notice/SaveDraft)
- 活动分类:category 提交的是**分类名称**(模块页 :value="String(c.v)"),
  optionsKeys 由 ("k","v") 改为 ("v","v")
- 请假附件:fileIds 在 HomeLeave 是 number[](JSON 数组),去掉逗号串拼接;
  连续请假按 continuousLeaveNum 逐天展开成 continuousLeaveTime[](服务端/浏览器同源)
- 作业发布(整块新增):homework.publish / schedule / published / drafts /
  teachingSubjects / classTree。模块没有一步发布的接口,用 ToolDef.then 声明两步提交
  (Create 落草稿 → Publish | Schedule);附件是对象数组
  attachments:[{fileId,fileUrl,fileType,fileName,sort}],上传走 file 域
  /coursehomework/api/file/Upload
- 执行器:新增 followUp 两步提交(浏览器侧同源)、数组参数给标量时包成单元素数组、
  首步响应 data 取资源 id(对象形态取 .id,避免拼出 /homeworks/{"id":1}/publish)
- 新增 ModuleFormParityTest(13 项)逐条锁住上述契约

回归:mvn clean package → Tests run: 103, Failures: 0, Errors: 0, BUILD SUCCESS
真机:headless Chrome 走「表单 → 浏览器代执行 → 模块接口」,50 项断言全绿
This commit is contained in:
lijing
2026-10-13 11:29:03 +08:00
parent 322d589b3e
commit c16356db6e
14 changed files with 1318 additions and 52 deletions
@@ -57,6 +57,35 @@ public class FormField {
*/
private Integer scopeType;
/**
* 「镜像字段」:本字段不由用户填写({@code hidden}),提交时自动填入同一表单中
* {@code mirrorOf} 指定字段**选中项的显示名**。
*
* <p>★ 用途:公告/宿舍/活动三个模块页在提交时会用字典把部门 id 反查成名称一并发出
* ({@code deptId} + {@code deptName},后端字典缺失时回退该名称)。助手只有下拉选中的 id,
* 但前端手里就有选项的 label —— 由它顺手镜像过去,提交体才和模块页一模一样。
*/
private String mirrorOf;
/**
* 「连续请假」展开说明:{@code {count: 天数字段, start: 开始时间字段, end: 结束时间字段}}。
*
* <p>作用在请假工具上:当本字段({@code continuousLeave})取 1 时,前端按
* {@code continuousLeaveNum} 天把 {@code startDate}/{@code endDate} 复制成逐天时间段,
* 生成模块要的 {@code continuousLeaveTime}({@code [{startDate,endDate}]})——
* 与模块页 {@code LeaveTimeSection.regenerate()} 的口径一致。
*/
private Map<String, String> dailyExpand;
/**
* {@code widget=file} 且为 true 时,提交的不是 fileId 数组,而是模块要的**附件对象数组**。
*
* <p>作业模块(coursehomework V2)的 {@code attachments} 形如
* {@code [{fileId,fileUrl,fileType,fileName,sort}]},与其余模块的 {@code fileIds="1,2"} 不同,
* 故由前端按上传结果组装成对象。
*/
private boolean fileAsObject;
private boolean required;
/** 说明(来自工具定义,写清格式与含义) */