前端已把 NoticeFront 的 wangEditor 与自绘「通知对象」控件 1:1 搬进助手表单,
后端补上这两个控件所需的契约:
- ToolParam / FormField 新增:
· pickerSources:选人弹窗的**数据源页签**(形如 {name, 模块内相对地址}),
由 AgentOrchestrator 拼上模块前缀后下发(沿用「只写相对路径」的铁律);
· richTextUploadPath / richTextPreviewPath:正文插图的上传与预览地址。
- AgentOrchestrator:把 resolveUploadPath 抽出通用形态 resolveModulePath(幂等、只接受
模块内相对路径);buildForm 为 widget=userpicker 下发 pickerSources;
optionCall 强制改写 widget 的白名单放行 userpicker(否则会被降级成 select)。
- NoticeTools:notify.publish 与 notify.editNotice 的 receiveList 改为 userpicker,
两个数据源为「基础平台」/api/base/GetSchoolAll 与「自定义组」
/api/contacts/GetGroupTree?type=1;content 走 richtext。
测试:NotifyIntentFormTest / IntentDirectFormTest 补 pickerSources 断言
(**只写相对路径**,不带前缀 —— 前缀拼错是本项目反复出过的坑),
ModuleFormParityTest 补 userpicker 取值口径断言(字符串原样透传,不得包成数组)。
mvn -o test:Tests run: 135, Failures: 0, Errors: 0,BUILD SUCCESS。
This commit is contained in:
@@ -228,9 +228,14 @@ class IntentDirectFormTest {
|
||||
assertEquals("/list/new", resp.getForm().getLandingPath());
|
||||
assertTrue(resp.getReply().contains("发布通知"), "引导语应说明这是发布通知,实际:" + resp.getReply());
|
||||
|
||||
// 标题(单行)+ 正文(多行)
|
||||
// 标题(单行)+ 正文(富文本,与模块页的 wangEditor 一致)
|
||||
assertEquals("text", field(resp, "title").getWidget());
|
||||
assertEquals("textarea", field(resp, "content").getWidget());
|
||||
FormField content = field(resp, "content");
|
||||
assertEquals("richtext", content.getWidget(), "正文用富文本编辑器(模块页 wangEditor)");
|
||||
assertEquals("/notice/api/file/UploadImage", content.getRichTextUploadPath(),
|
||||
"正文里插图片要打模块真实前缀 /notice(且不是附件的 FileUpload)");
|
||||
assertEquals("/notice/api/file/Preview?id={id}", content.getRichTextPreviewPath(),
|
||||
"图片预览地址模板同样要带前缀,{id} 留给前端替换");
|
||||
|
||||
// 来源部门:下拉 + 代取地址(带上模块前缀与固定字典种类)
|
||||
FormField deptId = field(resp, "deptId");
|
||||
@@ -241,11 +246,32 @@ class IntentDirectFormTest {
|
||||
assertEquals("k", deptId.getValueKey());
|
||||
assertEquals("v", deptId.getLabelKey());
|
||||
|
||||
// 通知对象:按用户多选(与校园公告的「推送范围」按班级完全不同)
|
||||
// 通知对象:模块页同款自绘控件(radio 全部用户/指定用户 + 选人弹窗)。
|
||||
// ★ 它也有 optionCall,必须确认**没有被降级成 select** ——
|
||||
// AgentOrchestrator 对「带 optionCall 的字段」会把控件改写成 select(防止取回字典后还是输入框),
|
||||
// userpicker 靠白名单豁免;漏了就变成普通下拉,正是这次要避免的。
|
||||
FormField receiveList = field(resp, "receiveList");
|
||||
assertEquals("multiselect", receiveList.getWidget());
|
||||
assertNotNull(receiveList.getOptionCall(), "通知对象应带上组织树代取地址");
|
||||
assertEquals("userpicker", receiveList.getWidget(),
|
||||
"通知对象应是自绘的「全部用户 / 指定用户」+ 选人弹窗,不能被降级成 select");
|
||||
assertNotNull(receiveList.getOptionCall(), "通知对象应带上组织树代取地址(弹窗里用它取原始树)");
|
||||
assertEquals("/notice/api/base/GetSchoolAll", receiveList.getOptionCall().getPathAndQuery());
|
||||
assertEquals("all", receiveList.getAllToken(), "「全部用户」哨兵值");
|
||||
|
||||
// ★ 选人弹窗有两个页签(模块页 UserCheckInput.vue 的 sources)——这里钉住**拼好前缀**的结果。
|
||||
// 与附件上传同一个坑:只写相对路径、前缀由 resolveModulePath 拼,漏了就线上 404。
|
||||
// 注意「自定义组」的路径里带 query,拼前缀时不能被吃掉。
|
||||
assertNotNull(receiveList.getPickerSources(), "选人弹窗的数据源页签要下发到前端");
|
||||
assertEquals(2, receiveList.getPickerSources().size());
|
||||
FormField.PickerSource tab0 = receiveList.getPickerSources().get(0);
|
||||
assertEquals("基础平台", tab0.getName());
|
||||
assertNotNull(tab0.getCall());
|
||||
assertEquals("GET", tab0.getCall().getMethod(), "取组织树是只读 GET");
|
||||
assertEquals("/notice/api/base/GetSchoolAll", tab0.getCall().getPathAndQuery(),
|
||||
"代取地址必须带模块前缀 /notice");
|
||||
FormField.PickerSource tab1 = receiveList.getPickerSources().get(1);
|
||||
assertEquals("自定义组", tab1.getName());
|
||||
assertEquals("/notice/api/contacts/GetGroupTree?type=1", tab1.getCall().getPathAndQuery(),
|
||||
"自定义组树同样要带前缀,且 type=1 要保留");
|
||||
|
||||
// 校园公告独有的字段绝不能串到通知公告的表单上
|
||||
for (String foreign : new String[]{"pushScopes", "publishType", "receiptFlag", "topmost", "type"}) {
|
||||
|
||||
Reference in New Issue
Block a user