weaver-e10-builder 1.6.8 → 1.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/commands/form-attachment-setting.d.ts.map +1 -1
  2. package/dist/commands/form-attachment-setting.js +147 -50
  3. package/dist/commands/form-attachment-setting.js.map +1 -1
  4. package/dist/commands/form-code.d.ts.map +1 -1
  5. package/dist/commands/form-code.js +4 -1
  6. package/dist/commands/form-code.js.map +1 -1
  7. package/dist/commands/form-field-linkage.d.ts +2 -0
  8. package/dist/commands/form-field-linkage.d.ts.map +1 -1
  9. package/dist/commands/form-field-linkage.js +97 -41
  10. package/dist/commands/form-field-linkage.js.map +1 -1
  11. package/dist/commands/form-layout-code-reviewed.d.ts.map +1 -1
  12. package/dist/commands/form-layout-code-reviewed.js +5 -2
  13. package/dist/commands/form-layout-code-reviewed.js.map +1 -1
  14. package/dist/commands/form-layout.js +1 -1
  15. package/dist/commands/form-layout.js.map +1 -1
  16. package/dist/commands/menu.d.ts.map +1 -1
  17. package/dist/commands/menu.js +90 -1
  18. package/dist/commands/menu.js.map +1 -1
  19. package/dist/commands/wf-form.d.ts.map +1 -1
  20. package/dist/commands/wf-form.js +111 -39
  21. package/dist/commands/wf-form.js.map +1 -1
  22. package/dist/services/form-attachment-settings.d.ts +47 -20
  23. package/dist/services/form-attachment-settings.d.ts.map +1 -1
  24. package/dist/services/form-attachment-settings.js +148 -68
  25. package/dist/services/form-attachment-settings.js.map +1 -1
  26. package/dist/services/form-code.d.ts +1 -1
  27. package/dist/services/form-code.d.ts.map +1 -1
  28. package/dist/services/form-code.js +2 -2
  29. package/dist/services/form-code.js.map +1 -1
  30. package/dist/services/form-layout-code-reviewed.d.ts +2 -0
  31. package/dist/services/form-layout-code-reviewed.d.ts.map +1 -1
  32. package/dist/services/form-layout-code-reviewed.js +4 -3
  33. package/dist/services/form-layout-code-reviewed.js.map +1 -1
  34. package/dist/services/menu-catalog.d.ts +45 -0
  35. package/dist/services/menu-catalog.d.ts.map +1 -1
  36. package/dist/services/menu-catalog.js +76 -0
  37. package/dist/services/menu-catalog.js.map +1 -1
  38. package/dist/services/workflow-layout-init-reviewed.d.ts +2 -0
  39. package/dist/services/workflow-layout-init-reviewed.d.ts.map +1 -1
  40. package/dist/services/workflow-layout-init-reviewed.js +30 -2
  41. package/dist/services/workflow-layout-init-reviewed.js.map +1 -1
  42. package/dist/services/workflow-layout-structure.d.ts +3 -0
  43. package/dist/services/workflow-layout-structure.d.ts.map +1 -0
  44. package/dist/services/workflow-layout-structure.js +44 -0
  45. package/dist/services/workflow-layout-structure.js.map +1 -0
  46. package/package.json +1 -1
  47. package/skill-docs/SKILL.md +4 -4
  48. package/skill-docs/_catalog.md +1 -1
  49. package/skill-docs/references/common/capability-boundaries.md +6 -4
  50. package/skill-docs/references/common/ref-cli-commands.md +4 -3
  51. package/skill-docs/references/form/guide-field-linkage.md +9 -1
  52. package/skill-docs/references/form/guide-form-attachment-setting.md +31 -12
  53. package/skill-docs/references/form/guide-form-layout-planning.md +1 -1
  54. package/skill-docs/references/form/layout/code-block/code-block-guide.md +5 -5
  55. package/skill-docs/references/form/layout/code-block/layout-css.md +95 -15
  56. package/skill-docs/references/form/layout/template/advanced.md +2 -0
  57. package/skill-docs/references/form/layout/workflow-layout.md +10 -0
  58. package/skill-docs/references/menu/system-menus.md +21 -0
  59. package/skill-docs/references/code-block/guide-code-block.md +0 -141
  60. package/skill-docs/references/code-block/guide-layout-css.md +0 -107
  61. package/skill-docs/references/code-block/ref-controls.md +0 -60
  62. package/skill-docs/references/code-block/ref-coverage.md +0 -32
  63. package/skill-docs/references/code-block/ref-details.md +0 -57
  64. package/skill-docs/references/code-block/ref-events-validation.md +0 -42
  65. package/skill-docs/references/code-block/ref-foundations-fields.md +0 -56
  66. package/skill-docs/references/code-block/ref-recipes.md +0 -164
  67. package/skill-docs/references/code-block/ref-troubleshooting.md +0 -49
  68. package/skill-docs/references/code-block/ref-ui-global.md +0 -47
  69. package/skill-docs/references/form/form-template/style-templates-advanced-css-guide.md +0 -167
  70. package/skill-docs/references/form/form-template/style-templates-advanced.md +0 -315
  71. package/skill-docs/references/form/form-template/style-templates-easy.md +0 -55
  72. package/skill-docs/references/form/form-template/style-templates-flow.md +0 -27
  73. package/skill-docs/references/form/form-template/style-templates.md +0 -29
@@ -1,107 +0,0 @@
1
- # 表单布局 CSS 编写指南
2
-
3
- 本篇用于**已创建的表单布局**:给指定布局的 PC 或移动端页面写 CSS。适用于表单引擎表单与流程表单的表格式、流式布局。表格式高级**模板**的 CSS 属于另一份配置,模板的网格和重复标记也不会由这里的 CSS 生成。
4
-
5
- ## 能设置什么
6
-
7
- | 目标 | CSS 可处理的内容 | 先确认的配置或结构 |
8
- | --- | --- | --- |
9
- | 页面主题 | 页面区域的背景与文字颜色、主题变量、按钮和选中状态颜色 | 页面根容器及变量是否被当前组件读取 |
10
- | 标题与分组 | 标题颜色、字重、底线,分组标题装饰、背景、内外间距 | 表格式的单元格样式或流式的分组结构 |
11
- | 字段组件 | 输入框、文本域、下拉、日期、浏览框的背景、边框、字体、内边距;提示语和焦点状态 | 各组件实际画边框的包裹层;保留图标和操作标记 |
12
- | 明细表 | 表头色、标题对齐、边框、隔行色、悬停与聚焦行色 | 是否存在相应明细表 DOM;固定表头是否另有一张表 |
13
- | 响应状态 | `:hover`、`:focus-within`、`:checked` 等状态,以及 `@media` 下的样式 | PC 与移动端分别检查,不能假定结构一致 |
14
-
15
- CSS 只改变已有元素的呈现。字段顺序、主表与明细表的迭代、合并单元格、字段组件类型和表单数据仍在布局或表单配置中处理。表格式布局的列宽、行高、单元格边框优先在网格中设置;流式布局的区域排列优先在布局设置中完成。
16
-
17
- ## 作用范围和写入
18
-
19
- 布局 CSS 按**布局 ID + 终端**保存。CSS 文件中写普通选择器,例如 `.ebpage`;CLI 会给普通规则加当前页面的 `#ebpage_<pageId>` 前缀。不要自己写这个页面 ID,也不要复制模板编译后的 `#widget_…`、`.cell_…` 等生成标识。`@media`、`@supports` 中的普通选择器同样会加作用域;`@keyframes` 保持原样。需要被这份 CSS 修饰的动态元素应放在布局页面容器内,挂在 `document.body` 下的弹层不在此作用域内。
20
-
21
- ```bash
22
- # 先读取当前 PC 布局代码,保存现有 CSS 供修改
23
- e10-cli form code layout read <表单objId> --app-id <应用ID> --layout-id <布局ID> --terminal PC
24
-
25
- # 将 CSS 文件写入该 PC 布局;JS 保持原状
26
- e10-cli form code layout set <表单objId> --app-id <应用ID> --layout-id <布局ID> --terminal PC --css <CSS文件>
27
-
28
- # 写入后回读
29
- e10-cli form code layout read <表单objId> --app-id <应用ID> --layout-id <布局ID> --terminal PC
30
- ```
31
-
32
- 流程表单对应 `e10-cli wf-form code layout read/set <formId> --layout-id <布局ID> --terminal PC|MOBILE [--css <CSS文件>]`,不需要 `--app-id`。移动端把 `--terminal` 改为 `MOBILE`,并针对该终端另写一份 CSS。`set --css` **整份替换**该布局、该终端原有 CSS;写入前先读出现有内容并合并到文件中。只传 `--css` 时已有 JS 保留。回读会核对源码和编译结果,随后仍需打开实际表单检查视觉效果。
33
-
34
- ## 通用写法
35
-
36
- ### 主题与选择状态
37
-
38
- 页面根节点存在 `.ebpage` 时,可集中设置主题变量;变量只对读取它的组件起作用。颜色和变量名称可参考表格式高级模板的 [CSS 指南](../form/form-template/style-templates-advanced-css-guide.md),但应在目标布局验证实际状态。
39
-
40
- ```css
41
- .ebpage {
42
- --primary: #347fcb;
43
- --btn-primary-hover-bg: #286daf;
44
- --checkbox-active-border-color: var(--primary);
45
- --checkbox-active-background-color: var(--primary);
46
- --radio-active-border-color: var(--primary);
47
- --radio-active-inner-background-color: var(--primary);
48
- --input-focus-border-color: var(--primary);
49
- }
50
- ```
51
-
52
- ### 字段输入区域
53
-
54
- 先看实际元素是输入框自身画线,还是其外层包裹层画线。以下是**表格式 PC 页面已识别的组件路径**,仅在目标布局存在相同 DOM 时复用;流式布局先检查对应组件结构再写选择器。
55
-
56
- ```css
57
- /* 文字输入:只清除控件边框,保留表格单元格边线。 */
58
- .weapp-form-widget__Text .weapp-form-input-style {
59
- border: none;
60
- background: transparent;
61
- }
62
-
63
- /* 浏览框的额外包裹层:目标页面确有此层时使用。 */
64
- .weapp-form-widget-content-container .ui-browser-types-select-wrap .ui-input-suffix-wrap {
65
- border: none;
66
- }
67
- ```
68
-
69
- 多行文本、日期、下拉、浏览框可能由 `textarea`、`.ui-input-wrap`、`.ui-select-input`、`.ui-browser` 或更外层绘制边框;逐个定位实际画线元素。避免对 `.ebpage input` 或 `.ebpage *` 一次性去边框,这会误伤选择标记、上传区和表格线。
70
-
71
- ### 表格式布局的明细表
72
-
73
- 以下规则针对已识别的表格式 PC 明细表结构。流式明细表只有在实际存在这些类和表格元素时才可复用。
74
-
75
- ```css
76
- .weapp-form-detail-table-wrapper .excelTableView-content-excel-table tbody tr[data-id]:nth-child(even) > td {
77
- background: #f7f9fc;
78
- }
79
-
80
- .weapp-form-detail-table-wrapper .excelTableView-content-excel-table tbody tr[data-id]:hover > td {
81
- background: #e9f2fc;
82
- }
83
-
84
- .weapp-form-detail-table-wrapper .excelTableView-content-excel-table tbody tr[data-id]:focus-within > td {
85
- background: #daebfa;
86
- }
87
- ```
88
-
89
- 明细表标题对齐与基础边框先用布局网格设置。需要 CSS 补充表头配色时,同时检查内容表与固定表头 `.excelTableView-content-excel-table-fixed-first-row`。把背景写到 `td` 上,是为了避免单元格自带背景遮住整行状态色。
90
-
91
- ## 表格式与流式如何选规则
92
-
93
- | 对象 | 表格式布局 | 流式布局 |
94
- | --- | --- | --- |
95
- | 页面主题变量 | 可从 `.ebpage` 开始,检查组件是否读取变量 | 同样从实际页面根节点检查 |
96
- | 字段控件 | 核对 `.weapp-form-widget__…` 与内部包裹层 | 核对实际组件路径;相同 DOM 才复用 |
97
- | 字段与分组位置 | 改网格、标记和单元格配置 | 改流式布局配置 |
98
- | `table`、`td`、明细表规则 | 仅用于真实存在的表格与明细表 | 不把表格式选择器直接套到流式区域 |
99
-
100
- ## 检查顺序
101
-
102
- 1. 读取目标布局和终端的原 CSS,确认页面上确有要修改的元素及类名。
103
- 2. 明确样式应落在页面、区域、网格单元格、组件包裹层还是输入元素;优先使用对应的布局配置,再写需要补充的 CSS。
104
- 3. 写入完整 CSS 文件,回读源码与编译结果;不要把编译后的页面 ID 写回源码。
105
- 4. 在实际表单中检查普通、只读、悬停、聚焦、选中及明细表滚动状态;移动端单独检查。
106
-
107
- 模板 CSS 指南提供更多 **PC 表格式**组件路径与状态写法;它们是选择器参考,并非流式布局的 DOM 保证。布局源码的其他规则见[表单代码块配置指南](guide-code-block.md)。
@@ -1,60 +0,0 @@
1
- # 浏览、选项、日期、附件与容器控件
2
-
3
- ## 浏览字段
4
-
5
- | 需求 | API 与处理方式 |
6
- |---|---|
7
- | 获取已选对象 ID/显示名 | `getBrowserOptionId(field, splitChar?)` / `getBrowserShowName(field, splitChar?)`;返回字符串,默认以逗号分隔 |
8
- | 获取完整选项对象 | `getBrowserOptionEntity(field)`;优先用它作为复制、合并和回填来源 |
9
- | 浏览弹窗取数增加请求参数 | `appendBrowserDataUrlParam(field, {参数名:值})`;只是向请求附加参数,数据源须识别这些参数 |
10
- | 回填浏览字段 | `changeFieldValue(field,{specialObj:[{id,name,data?}]})`;清空传空数组 |
11
-
12
- 浏览对象中的 `data` 对自定义浏览、附件等特殊来源很重要。不要把显示名称当 ID,也不要把添加请求参数误认为已在服务端实现数据过滤。运行时打开浏览弹窗检查实际可选记录。
13
-
14
- ## 选项字段
15
-
16
- `getSelectShowName(field, splitChar?)` 取显示名,默认以逗号分隔;`getBrowserOptionEntity(field)` 可取选项对象。固定选项可按 ID 用 `value` 回填,选项模板按 `specialObj` 回填。
17
-
18
- | 控制 | API |
19
- |---|---|
20
- | 从选项中移除 | `removeSelectOption(field, '选项ID1,选项ID2')` |
21
- | 控制可显示选项 | `controlSelectOption(field, '选项ID1,选项ID2')` |
22
- | 禁用/恢复选项 | `controlOptionDisable(field, '选项ID1,选项ID2', true/false)`;20250501 起,省略 flag 默认禁用 |
23
-
24
- 在表单 ready 后操作选项。移除、隐藏和禁用不是同义:分别验证弹窗/下拉是否显示、能否选中及已有值如何呈现。
25
-
26
- ## 日期
27
-
28
- `controlDateRange(field, start?, end?)` 限定可选择范围。边界可传日期字符串(如 `2023-08-20`)或相对今天的天数字符串;`'0'` 表示今天。在原 SDK 的示例中,开始端 `'5'` 表示当前日期前 5 天,结束端 `'3'` 表示当前日期后 3 天;省略一端表示不限制该端。明细字段不加行 ID 时作用于整列。根据需求同时核验边界日期和越界日期。
29
-
30
- ```js
31
- formSdk.controlDateRange(dateField, '2023-08-20', '2023-08-25');
32
- formSdk.controlDateRange(dateField, '5', '3');
33
- formSdk.controlDateRange(dateField, '0');
34
- formSdk.controlDateRange(dateField, undefined, '0');
35
- ```
36
-
37
- ## 附件与复杂值
38
-
39
- 附件回填需要 `specialObj` 中对象带实际附件 `data`,包括文件 ID、类型、预览/下载等权限与操作信息。最稳妥的来源是已有字段 `getFieldObj` 或附件模块正式返回;仅 `{id,name}` 不足以保证预览。多级选项、浏览对象的次级数据可在 `data.content` 或 `data.dataOptions`,应先读取同类字段实际对象后组装。
40
-
41
- ```js
42
- // data 应来自附件模块或现有附件字段,不在代码中凭空生成。
43
- formSdk.changeFieldValue(attachmentField, {
44
- specialObj: [{id: file.id, name: file.name, type: 'file', data: file}]
45
- });
46
- // 多级选项的第二级是文本时:
47
- formSdk.changeFieldValue(cascadeField, {
48
- specialObj: [{id: firstId, name: firstName, data: {content: secondText}}]
49
- });
50
- // 第二级是选项/浏览时,按已有控件对象构造 dataOptions:
51
- formSdk.changeFieldValue(cascadeField, {
52
- specialObj: [{id: firstId, name: firstName, data: {dataOptions: [{optionId: secondId, content: secondName}]}}]
53
- });
54
- ```
55
-
56
- 原附件案例中的 `data` 含 `fileid/name/size/extName/type/img/uploadUser/uploadUserName/uploadTime/doc/docId/loadlink/options/uploadType/ban/secretLevel/validity/folderId` 等字段。哪些必填、哪些操作可见由附件来源与权限决定;复制已有对象比手填这套结构可靠。
57
-
58
- ## 选项卡容器
59
-
60
- `switchTabItem(tabField, '序号')` 按从 1 开始的序号切换,或 `switchTabItem(tabField, tabId, 'id')` 按页签 ID 切换。`getFieldInfo(tabField).tabOptionTitle` 可检查页签信息,其中 `uid` 为 ID。20250501 及以后基线的 `changeTabItemAttr(tabField, '页签ID或序号, ...', attr)` 控制页签属性:`'1'` 禁用、`'2'` 可编辑、`'3'` 隐藏;一组调用中不要混用 ID 与序号。页签是布局容器,不当作普通选项字段写值。
@@ -1,32 +0,0 @@
1
- # JSSDK 原资料覆盖对照
2
-
3
- 本表用于维护指南的完整性;执行配置时按 [入口](guide-code-block.md) 路由,不需要再打开原始合并文档。核对范围是导出的 91 篇正文;同一原章的不同方法已按实际用途拆到专题。所谓“覆盖”指功能、必要调用契约和关键边界进入指南,不表示逐字保留原文全部示例数据或截图。
4
-
5
- | 原资料章节及篇数 | 在本目录中的落点 | 包含的功能 |
6
- |---|---|---|
7
- | 1 说明(3) | [基础与字段](ref-foundations-fields.md)、[排查](ref-troubleshooting.md) | SDK 实例、表单 ready、全局初始化 |
8
- | 2 表单事件注册(2) | [事件与校验](ref-events-validation.md) | 动作前拦截、动作后钩子 |
9
- | 3 字段基础操作(12) | [基础与字段](ref-foundations-fields.md) | Key 转标识、读值/对象/信息/属性、单个与批量赋值、属性、联动触发、组件引用 |
10
- | 4 字段事件与组件复写(7) | [事件与校验](ref-events-validation.md)、[组件与全局操作](ref-ui-global.md) | 主/明细字段事件、字段交互、属性事件、组件替换/追加/包装 |
11
- | 5 明细表操作(21) | [明细操作](ref-details.md) | 行增删查改、行 ID/序号转换、选中/禁选/显隐/排序、顶部操作、筛选、批量、复制末行 |
12
- | 6 表单全局操作(10) | [组件与全局操作](ref-ui-global.md) | 基本信息、移动端、消息、确认、自定义弹窗、刷新、提交参数、必填、加载、关闭提示 |
13
- | 7 特定字段类型(9) | [特定控件](ref-controls.md) | 浏览请求与值、选项显示/移除/禁用、日期范围 |
14
- | 8 容器字段(2) | [特定控件](ref-controls.md) | 页签切换、页签状态 |
15
- | 9 插件类型(3) | [组件与全局操作](ref-ui-global.md)、[排查](ref-troubleshooting.md) | 插件前提、读取、执行 |
16
- | 10 开发必看(1) | [基础与字段](ref-foundations-fields.md)、[排查](ref-troubleshooting.md) | 基线、实例获取和相关外部 SDK 边界 |
17
- | 11 常见问题(1) | [排查](ref-troubleshooting.md) | 时机、权限、超时、保存与提交区别 |
18
- | 12 案例分享(15) | [效果案例](ref-recipes.md)、各 API 专题 | 14 组业务效果;保存前汇总人员原文两篇重复,均已覆盖 |
19
- | 13 扩展说明(5) | [明细操作](ref-details.md)、[组件与全局操作](ref-ui-global.md)、[排查](ref-troubleshooting.md) | 嵌套明细、父子页面、调试屏蔽、事件刷新、不生效排查 |
20
-
21
- ## 核对后保留的边界与资料冲突
22
-
23
- | 项目 | 指南处理 |
24
- |---|---|
25
- | `formSdk` 闭包实例的最低基线 | 说明与开发必看主体写 250101;常见问题和开发必看一处又写 241201。指南按 250101 作为稳妥门槛,较早环境须实际检查。 |
26
- | 明细新增时使用末行数据 | 原文 5.17 列 `setDetailAddDefLast`,示例却调用 `setDetailAddUseCopy`;5.6 又单独列后者。两种 API 均保留,前者行为在目标环境核对。 |
27
- | `getFieldCom`、字段赋值及明细属性的示例笔误 | 在[排查文档](ref-troubleshooting.md)列出,专题示例采用修正后的调用形状。 |
28
- | 附件 `data`、插件具体方法、外部查询接口 | JSSDK 资料未给出完整提供方契约。指南说明如何接入和从现有数据读取,但不编造文件对象、插件方法或接口。 |
29
- | 审批节点提交拦截 | 表单 JSSDK `OPER_SAVE` 只覆盖表单数据保存;流程提交属于流程 SDK,本目录不宣称覆盖。 |
30
- | 页面组件 props 全局复写 | 原案例使用 `regOvProps`,是 ecode 层功能;与布局源码的字段局部渲染分别路由。 |
31
-
32
- 资料中所提工作流程 SDK、EB SDK、UI 组件和具体插件文档并不属于这 91 篇 JSSDK 资料;本目录只描述已给出的跨界入口,不臆造其完整方法。涉及这些外部契约时读取对应专题或说明尚缺契约。
@@ -1,57 +0,0 @@
1
- # 明细表与嵌套明细 JSSDK
2
-
3
- 先用 `convertFieldNameToId(明细表数据Key,'main')` 取明细标识,再以其为位置取得明细字段标识。`rowId` 是一行的运行时身份,不等于序号,也不是普通业务字段。`getDetailData(table)` 返回的每行含 `rowId` 以及以字段标识为键的 `{value}` 或 `{specialObj}` 对象;复制到另一明细表时去掉原 `rowId`,否则可能写错行。
4
-
5
- ## 行与数据操作
6
-
7
- | 目标 | API、关键参数 |
8
- |---|---|
9
- | 添加一行 | `addDetailRow(table, {[field]:{value:'文本'}, [browser]:{specialObj:[{id,name}]}})` |
10
- | 批量添加 | `addDetailData(table, [{[field]:{value:'A'}}, ...], config?)` |
11
- | 删除指定行/全部行 | `delDetailRow(table, rowId)` / `delDetailRow(table, 'all')` |
12
- | 更新多行 | `changeDetailData(table, [{rowId, [field]: {value:'新值'}}, ...], config?)`;250101 起,无 rowId 的项会新增行 |
13
- | 取全部行数据/某行 | `getDetailData(table, options?)` / `getDetailRowData(table, rowId)`;均至少 240601 基线 |
14
- | 取行 ID 串/行数 | `getDetailAllRowIndexStr(table)` 返回逗号分隔的 rowId;`getDetailRowCount(table)` 返回行数(原资料类型声明写 string、示例结果写 number,使用时以实际返回为准) |
15
- | 序号转行 ID/反向 | `getDetailRowIdByIndex(table, index)` / `getDetailIndexByRowId(table, rowId)`;index 从 1 起 |
16
- | 按行 ID 取显示序号 | `getDetailRowSerailNum(table, rowId)`(接口拼写为 Serail) |
17
- | 取明细字段 ID | `getDetailFieldIds(table, prefix?)`;240701 起,`prefix` 默认 `false`(不带 `field` 前缀),需要前缀时传 `true`;原示例以逗号分隔结果使用 |
18
-
19
- ```js
20
- const rows = formSdk.getDetailData(table) || [];
21
- const total = rows.reduce((n, row) => n + Number(row[detailAmount]?.value || 0), 0);
22
- formSdk.changeFieldValue(mainTotal, {value: String(total)});
23
- ```
24
-
25
- 上述汇总应在页面载入、金额变化、添加行、删除行后分别触发。金额换算用 `Number` 与明确的空值处理,不用拼接表达式再 `eval`。百分比要处理总额为 0 的情况。
26
-
27
- ## 行显示、选择与菜单
28
-
29
- | 目标 | API |
30
- |---|---|
31
- | 获取勾选行 | `getDetailCheckedRowIndexStr(table)`;返回行 ID 串 |
32
- | 勾选指定行/全部 | `checkDetailRow(table, 逗号分隔的rowId或'all', needClearBeforeChecked?)`;`checkDetailRow(table, '', true)` 清空已选 |
33
- | 禁止勾选 | `controlDetailRowDisableCheck(table, rowId或'all', true)`;`false` 恢复 |
34
- | 隐藏/显示行 | `controlDetailRowDisplay(table, 逗号分隔的rowId或'all', needHide)`;`true` 隐藏、`false` 显示 |
35
- | 排序显示行 | `setDetailSortRows(table, 逗号分隔的rowId, 'before'或'after')` |
36
- | 新增时复制末行 | `setDetailAddUseCopy(table, true/false)` |
37
- | 新增时默认使用末行数据 | `setDetailAddDefLast(table, true/false)`;至少 240701 基线,原文示例误写成 `setDetailAddUseCopy`,须区分两种设置的实际效果 |
38
- | 顶部自定义操作 | `setDetailTopAction(table, actions)`;每项有 `id/type/title/mode` 等,按目标组件允许的动作填写 |
39
- | 当前明细筛选条件 | `getDetailSearchCfg(table)`;可用于 `getDetailData(table,{searchValue: cfg})` |
40
-
41
- `addDetailData` 至少 241201 基线,传入数组每项以字段标识为键、值为 `{value}` 或 `{specialObj}`;第三参数可控制 `dataLinkage/viewLinkage/optionLinkage/jsApiChange`。`changeDetailData` 至少 250101 基线,结构相同但更新项需附 `rowId`;若传入项的 `rowId` 不存在,原资料说明会生成新行,配置时不要误用。动态行使用 `registerAction(ACTION_ADDROW + table, ...)` 与删除事件更新汇总或渲染;回调首参数是从 0 开始的行下标集合,不是 rowId。原资料同时列出 `setDetailAddDefLast` 与 `setDetailAddUseCopy`,但前者的示例错误调用了后者;保留两者各自契约,目标版本行为以实测为准。
42
-
43
- 顶部操作示例:`setDetailTopAction(table,[{id:'refresh',type:'refresh',title:'刷新',mode:'text'}])`;自定义渲染项可用 `{id:'custom',type:'custom',customRender:()=>React.createElement('div',{},'操作')}`,需保证当前代码入口有 React。`setDetailSortRows(table,'rowId1,rowId2','before'|'after')` 至少 241101 基线,默认 `before`。260401 及以后,`getDetailData(table,{searchValue:formSdk.getDetailSearchCfg(table)})` 可按当前明细筛选条件取行;不传第二参数则读取整表行。
44
-
45
- ## 父子明细
46
-
47
- 给某父行增加子行时,先确保父行已存在,再把子级行标识字段写为该父行的标识值;它是父子关系字段,不是新子行的 `rowId`。通常流程:取父 `rowId` → 读取父级行标识字段的值 → `addDetailRow(childTable,{[childRelationField]:{value: parentKey}, ...})`。按父行汇总时,筛选子表关系字段等于当前父行标识的行,再汇总回该父行字段。
48
-
49
- ```js
50
- const parentKey = formSdk.getFieldValue(`${parentRelation}_${parentRowId}`);
51
- formSdk.addDetailRow(childTable, {
52
- [childRelation]: {value: parentKey},
53
- [childAmount]: {value: '0'}
54
- });
55
- ```
56
-
57
- 不要把父表行 ID 直接当作子表行 ID。父子关系字段的实际值若为选项对象,先用 `getFieldObj` 检查结构,再按同类结构赋值。
@@ -1,42 +0,0 @@
1
- # 事件、校验与联动
2
-
3
- ## 动作前拦截与动作后钩子
4
-
5
- `registerCheckEvent(action, (successFn, failFn, data) => {...})` 在动作前执行。校验通过调用 `successFn()`;不通过调用 `failFn({msg:'原因'})` 由系统提示,或自行提示后调用 `failFn()`。异步逻辑必须在所有路径调用其中之一;超过约 25 秒未回调会超时。可多次注册,按注册顺序执行。`window.WeFormSDK` 提供动作常量:`OPER_SAVE`、`OPER_ADDROW`、`OPER_DELROW`、`OPER_BEFOREVERIFY`、`OPER_EDITDETAILROW`、`OPER_FD_LINKAGE`(240601 起)。针对某明细表的添加/删除动作在常量后拼接明细表标识。
6
-
7
- ```js
8
- formSdk.registerCheckEvent(window.WeFormSDK.OPER_SAVE, (ok, stop) => {
9
- const v = Number(formSdk.getFieldValue(amount) || 0);
10
- if (v > 0) ok();
11
- else stop({msg: '金额必须大于 0'});
12
- });
13
- ```
14
-
15
- `OPER_SAVE` 是表单数据保存动作,不等于工作流程节点的提交按钮校验。若需求是流程提交拦截,应选择流程相应能力及入口,不应把本例当作已覆盖。
16
-
17
- `OPER_EDITDETAILROW` 是移动端编辑明细的拦截事件。`OPER_FD_LINKAGE` 拦截字段联动执行,回调 `data` 可含 `actionType/triggerFields/triggerRowIds`;过滤指定触发字段后调用 `successFn` 或 `failFn`,字段 ID 要与真实返回类型一致。`OPER_BEFOREVERIFY` 在必填校验前触发。
18
-
19
- `registerAction(action, callback)` 是动作完成后的通知,可注册多个回调,按注册顺序执行。常量包括 `ACTION_ADDROW`、`ACTION_DELROW`(后拼明细标识)、`ACTION_FORM_SAVE`、`ACTION_DATA_LINKAGE`、`ACTION_DATA_RELATE`、`ACTION_VIEW_LINKAGE`。新增/删除明细行后的回调接收行下标集合和 `data`,下标从 0 开始,不可直接当 `rowId`;需要行身份时再查询。明细导入也可能触发添加行事件,`data.type` 可帮助区分。`ACTION_DATA_LINKAGE` 表示顶部字段联动/函数公式执行后,`data.runData` 可含 `actionType/resultFields/triggerFields/triggerRowIds`(240601 起);`ACTION_DATA_RELATE` 表示关联字段钻取、字段右侧函数或运算控件后,回调可含 `fieldIds/rowIds/tableId`。
20
-
21
- ## 字段变化与交互
22
-
23
- | API | 触发与用途 |
24
- |---|---|
25
- | `bindFieldChangeEvent('字段标识,字段标识', callback, options?)` | 主表或明细字段值变化;`data` 中可取 `rowId` |
26
- | `bindDetailFieldChangeEvent('明细字段标识', callback)` | 专门处理明细字段值变化 |
27
- | `bindFieldAttrChangeEvent('字段标识', callback)` | 字段读写属性变化 |
28
- | `bindFieldAction(type, '字段标识', callback)` | 字段区域交互;`onblur/onfocus/onclick/ondbclick/mouseover/mouseout` |
29
-
30
- 字段事件可指定 `scope` 区分用户修改与联动带出,常量为 `window.WeFormSDK.CHANGE_EVENT_SCOPE`(主表事件至少 250401;明细专用事件至少 250901)及 `window.WeFormSDK.CHANGE_EVENT_LINKAGE`。回调 `data` 可含 `id/value/rowId`;值变化不包括明细增删行,因此仍须注册行事件。联动修改不一定自动触发 JS 值变化事件,必要时通过赋值配置的 `jsApiChange` 或 `triggerFieldAllLinkage` 明确触发。251101 起可设置全局 `window.__FORM_JS_LINKAGE_EVENT_CHANGE__ = true` 扩展联动事件触发范围,可能使既有监听再次运行;只在确有需要时使用。
31
-
32
- ```js
33
- formSdk.bindFieldChangeEvent(detailAmount, ({rowId}) => {
34
- if (!rowId) return;
35
- const value = Number(formSdk.getFieldValue(`${detailAmount}_${rowId}`) || 0);
36
- formSdk.changeFieldValue(`${detailTax}_${rowId}`, {value: String(value * 0.13)});
37
- });
38
- formSdk.registerAction(`${window.WeFormSDK.ACTION_ADDROW}${table}`, () => recalculate());
39
- formSdk.registerAction(`${window.WeFormSDK.ACTION_DELROW}${table}`, () => recalculate());
40
- ```
41
-
42
- 编写校验时先定触发动作、允许/阻断条件、提示内容及异步失败路径;编写联动时同时覆盖载入、字段变化、明细增删,并防止监听目标再触发自身。保存后分别验证通过与不通过两条路径。
@@ -1,56 +0,0 @@
1
- # JSSDK 基础、字段定位与赋值
2
-
3
- ## 实例与时机
4
-
5
- - 布局源码和表单级 ecode(250101 及以后基线)使用当前作用域的 `formSdk`。旧方式 `window.WeFormSDK.getWeFormInstance()` 可能在多表单页面取错实例。
6
- - 早期基线可通过 `pageSdk.on('formReady', callback)` 等待表单加载,再调用 `window.WeFormSDK.getWeFormInstance(moduleKey?, formId?, dataId?)`;条件允许时传入更细的模块、表单、数据 ID,避免页面同时打开多份表单时取错。全局 ecode 用 `window.addEventListener('onFormReady', e => { const {formSdk, formId, module}=e.detail; ... })`,按 `formId/module` 限定作用范围;这个全局事件每打开一份表单都会触发,不放在单布局源码中重复监听。
7
- - 字段和明细行尚未渲染时不要操作其组件。注册事件通常在表单 ready 后进行,动态新增明细行须在添加行事件后处理。
8
-
9
- ## 字段标识与读取
10
-
11
- `formSdk.convertFieldNameToId(dataKey, location?, prefix?)` 将数据 Key 转为字段标识,`prefix` 默认 `true`,即返回带 `field` 前缀的标识;传 `false` 时返回纯数字 ID。主表用 `location='main'`;明细字段用明细表标识作为 location。260601 及以后也可用明细表数据 Key 作 location。字段数据 Key 在字段管理“数据 Key”列或设计器选中字段后的右侧查看;明细表 Key 在设计器选中明细表后查看,高级版可能要双击明细表。明细某行标识为 `${detailField}_${rowId}`,`rowId` 是运行时行 ID,不是显示序号。
12
-
13
- ```js
14
- const amount = formSdk.convertFieldNameToId('amount', 'main');
15
- const table = formSdk.convertFieldNameToId('payment_detail', 'main');
16
- const rate = formSdk.convertFieldNameToId('rate', table);
17
- const firstRowId = formSdk.getDetailRowIdByIndex(table, 1);
18
- const value = firstRowId ? formSdk.getFieldValue(`${rate}_${firstRowId}`) : undefined;
19
- ```
20
-
21
- | 读取 API | 用途 |
22
- |---|---|
23
- | `getFieldValue(fieldMark)` | 取单个字段简化值;文本返回内容,选项/浏览一般返回 ID,取显示名用控件专题方法 |
24
- | `getFieldObj(fieldMark)` | 取原始数据对象,可含 `value/specialObj/longitude/latitude/type/contentObj`;不确定控件结构时先看它;240701 起 |
25
- | `getFieldInfo(fieldMark)` | 字段元数据,可含 `fieldId/dataKey/name/componentKey/isSingle`;实际对象还可能有其他属性 |
26
- | `listFieldInfo()` | 当前表单所有字段信息,含 `readOnly/required` 等 |
27
- | `getFieldAttr(fieldMark)` | 当前读写属性,返回 1~5 的属性码 |
28
- | `getFieldCom(fieldMark)` | 字段组件信息,含 `id/type/config`;240701 起。原文示例误调用 `getFieldInfo` |
29
-
30
- ## 赋值结构
31
-
32
- `changeFieldValue(fieldMark, valueInfo, config?)` 修改字段值。普通文本、数字、日期传 `{value: '...'}`;浏览和动态选项传 `{specialObj:[{id,name,data?}]}`,清空浏览传 `{specialObj:[]}`。固定选项可传 `{value: optionId}`;选项模板使用 `specialObj`。日期区间的值可为 `开始日期,结束日期`。人员范围对象可带 `type`,如 `user/dept/subcompany/organization/group/role/position/all`。附件除 id/name 外还需要来自附件模块的完整 `data` 对象,不能凭文件名伪造可预览附件。地理位置可附 `latitude/longitude`;某些特殊字段还用 `type/contentObj`。
33
-
34
- ```js
35
- formSdk.changeFieldValue(amount, {value: '120.00'});
36
- formSdk.changeFieldValue(customer, {specialObj: [{id: customerId, name: customerName}]});
37
- formSdk.changeFieldValue(customer, {specialObj: []});
38
- formSdk.changeFieldValue(`${rate}_${firstRowId}`, {value: '0.13'});
39
- ```
40
-
41
- 第三参数可控制随赋值触发的处理:`dataLinkage`(字段联动、公式、钻取)、`viewLinkage`(显示联动)、`optionLinkage`、`dataValidate`、`jsApiChange`;对应值 `false` 表示不执行,默认按系统行为。该参数在 241001 及以后基线适用。需要在赋值后明确再次运行联动时,用 `triggerFieldAllLinkage(fieldMark)`,它会触发字段联动、函数公式、显示属性联动、数据钻取、选项联动等;明细字段须指定某行。250901 及以后可等待其 Promise。避免监听 A 又写 A 形成循环。
42
-
43
- ## 显示属性与批量修改
44
-
45
- `changeFieldAttr(fieldMark, viewAttr)` 的属性码:`1` 只读、`2` 可编辑、`3` 必填、`4` 隐藏、`5` 隐藏行。明细字段标识作用于整列,`${field}_${rowId}` 作用于指定行。流程节点或权限锁定的只读状态,不能依靠此 API 强行变为可编辑。EXCEL 布局隐藏明细列时还要留意冻结标题/列。
46
-
47
- `changeSingleField(fieldMark, valueInfo, {viewAttr})` 同时改值和属性。`changeMoreField(changeDatas, changeVariable?)` 批量修改,两参数都是以字段标识为键的对象:
48
-
49
- ```js
50
- formSdk.changeMoreField(
51
- {[amount]: {value: '120.00'}, [customer]: {specialObj: [{id: customerId, name: customerName}]}},
52
- {[amount]: {viewAttr: 1}}
53
- );
54
- ```
55
-
56
- 运行前检查标识非空、字段在当前布局可用、数据 Key 所在主/明细位置正确。读取 `getFieldObj` 对照实际值结构,再决定使用 `value` 还是 `specialObj`。
@@ -1,164 +0,0 @@
1
- # 按效果查代码模式
2
-
3
- 本页覆盖原案例中的独立做法。字段 Key、接口和字段对象均需替换为目标表单真实数据;示例中出现的模拟接口、固定附件对象和测试 ID 不能作为正式值。
4
-
5
- | 想要的效果 | 组合方法 | 关键检查 |
6
- |---|---|---|
7
- | 保存前汇总明细人员到主表并去重 | `registerCheckEvent(OPER_SAVE)` → `getDetailAllRowIndexStr` → 逐行 `getBrowserOptionEntity` → 按 id 去重 → `changeFieldValue(...,{specialObj})` → `successFn` | 空行、重复人员、失败回调;仅拦表单保存 |
8
- | 附件字段回填且可预览 | 从附件模块/现有字段取完整对象 → `changeFieldValue(...,{specialObj:[{id,name,data,type:'file'}]})` | 文件权限、预览/下载入口;不可只传 id/name |
9
- | 多级选项等复杂值赋值 | 先 `getFieldObj` 观察已有对象 → 按 `data.content` 或 `data.dataOptions` 等原结构写 `specialObj` | 选项模板、次级选项正确显示 |
10
- | 将明细富文本显示为按钮或链接 | `getDetailAllRowIndexStr` 遍历每行 → `proxyFieldComp` 替换该行内容;添加行事件补新行 | 点击跳转地址与作用范围 |
11
- | 按两个维度分类、累加到另一明细表 | `getDetailData` 建组合 Key → 对目标行更新/新增/删除 → 监听来源值变化和增删行 | 组合 Key 唯一、消失分组删除、重复事件 |
12
- | 全表单跨模块识别字段并回填外部数据 | 全局 ecode `onFormReady` 取当前实例并限制 module/formId → 字段事件 → 调受支持接口 → `changeMoreField` | 权限、数据范围、主表/明细位置、失败与清空逻辑 |
13
- | 明细数字合计并算各行占比 | 读取明细每行数值 → `reduce` 求和 → 主表回写 → 逐行占比赋值;监听值变化及增删行 | 空值、非数字、总额 0、精度 |
14
- | 联动带出后再汇总并触发后续联动 | 对带出字段监听联动 scope → 汇总 → 写主表 → 必要时 `triggerFieldAllLinkage` | 避免循环;确认事件是否实际触发 |
15
- | 合并多个主表浏览/选项字段 | 多字段 `getBrowserOptionEntity` → 合并或按 id 去重 → 主表 `specialObj` 赋值 | 是否保留重复项、空字段 |
16
- | 按同行条件选择明细人员合并到主表 | `getDetailData` → 判断同行选项值 → 取人员对象 → 去重 → `changeFieldValue` | 条件变化、增删行后重算 |
17
- | 子明细按父行汇总金额 | 父、子关系字段匹配 → 筛子表数据 → 合计 → 回写父表指定 `rowId` | 父标识唯一、子行归属、父行删除后的处理 |
18
- | 按显示序号生成明细值 | 明细行数组按显示顺序 `map((row,index)=>...)` → `changeDetailData`;监听增删行 | 排序后重新计算,避免把序号当 rowId |
19
- | 某字段为空时触发另一字段联动 | `getFieldValue` 判空 → `triggerFieldAllLinkage(target)`;载入与源字段变化均执行 | 空字符串、0 与未选择的判定 |
20
- | 自定义页面参数传递/组件换肤 | 全局 ecode `regOvProps` 或表单字段 `proxyFieldContentComp`,按生效范围选择 | 组件名/props 契约、编译入口 |
21
-
22
- 上述模式涉及的完整 API、参数与风险分别见 [事件](ref-events-validation.md)、[字段](ref-foundations-fields.md)、[明细](ref-details.md)、[控件](ref-controls.md) 和 [组件交互](ref-ui-global.md)。原案例存在重复与少量不完整代码:例如重复的“保存前汇总人员”,附件数据依赖文档模块,组件 props 示例有语法笔误,数字合计示例用 `eval`,全局回填示例包含模拟数据。这里保留其实现思路,代码应按专题中可运行的结构重新组装。
23
-
24
- ## 保存前汇总明细人员并去重
25
-
26
- 先定位明细、明细人员字段和主表目标字段;仅在表单数据保存前执行。需要流程“提交”时改用流程 SDK 的节点提交事件。
27
-
28
- ```js
29
- const table = formSdk.convertFieldNameToId('people_detail', 'main');
30
- const detailPerson = formSdk.convertFieldNameToId('person', table);
31
- const mainPeople = formSdk.convertFieldNameToId('all_people', 'main');
32
- formSdk.registerCheckEvent(window.WeFormSDK.OPER_SAVE, (ok, stop) => {
33
- try {
34
- const rowIds = (formSdk.getDetailAllRowIndexStr(table) || '').split(',').filter(Boolean);
35
- const unique = new Map();
36
- for (const rowId of rowIds) {
37
- for (const item of formSdk.getBrowserOptionEntity(`${detailPerson}_${rowId}`) || []) {
38
- if (item?.id) unique.set(String(item.id), item);
39
- }
40
- }
41
- formSdk.changeFieldValue(mainPeople, {specialObj: [...unique.values()]});
42
- ok();
43
- } catch (error) {
44
- stop({msg: '人员汇总失败,请检查明细数据'});
45
- }
46
- });
47
- ```
48
-
49
- ## 明细数值汇总并计算占比
50
-
51
- 值变化、增行、删行和初次载入都要重新计算;`getDetailData` 的每行包含 `rowId`。示例以数值 0 处理空值,业务若要求空值报错,应另作校验。
52
-
53
- ```js
54
- const table = formSdk.convertFieldNameToId('cost_detail', 'main');
55
- const detailAmount = formSdk.convertFieldNameToId('amount', table);
56
- const detailShare = formSdk.convertFieldNameToId('share', table);
57
- const mainTotal = formSdk.convertFieldNameToId('total', 'main');
58
- function recalculate() {
59
- const rows = formSdk.getDetailData(table) || [];
60
- const total = rows.reduce((sum, row) => sum + Number(row[detailAmount]?.value || 0), 0);
61
- formSdk.changeFieldValue(mainTotal, {value: String(total)}, {jsApiChange: false});
62
- for (const row of rows) {
63
- const amount = Number(row[detailAmount]?.value || 0);
64
- formSdk.changeFieldValue(`${detailShare}_${row.rowId}`, {value: String(total ? amount / total : 0)}, {jsApiChange: false});
65
- }
66
- }
67
- formSdk.bindFieldChangeEvent(detailAmount, recalculate);
68
- formSdk.registerAction(`${window.WeFormSDK.ACTION_ADDROW}${table}`, recalculate);
69
- formSdk.registerAction(`${window.WeFormSDK.ACTION_DELROW}${table}`, recalculate);
70
- recalculate();
71
- ```
72
-
73
- 如汇总源值本身来自字段联动,普通字段变化事件可能不触发;依目标基线使用 `scope: window.WeFormSDK.CHANGE_EVENT_LINKAGE` 或监听 `ACTION_DATA_LINKAGE`。占比输出为 0~1 还是 0~100,须按目标字段的百分比显示方式确定。不要直接打开全局联动事件开关而不检查既有监听是否形成循环。
74
-
75
- ## 父子明细按关系字段回写
76
-
77
- 父、子明细的关系字段值相同才能归属同一父行。先配置真实二级明细关系,再对每个父行筛选对应子行。这里的业务主键与 `rowId` 分开。
78
-
79
- ```js
80
- const parentTable = formSdk.convertFieldNameToId('parent_detail', 'main');
81
- const childTable = formSdk.convertFieldNameToId('child_detail', 'main');
82
- const parentKey = formSdk.convertFieldNameToId('parent_key', parentTable);
83
- const parentTotal = formSdk.convertFieldNameToId('parent_total', parentTable);
84
- const childKey = formSdk.convertFieldNameToId('child_parent_key', childTable);
85
- const childAmount = formSdk.convertFieldNameToId('child_amount', childTable);
86
- function recalculateParents() {
87
- const children = formSdk.getDetailData(childTable) || [];
88
- for (const parent of formSdk.getDetailData(parentTable) || []) {
89
- const key = parent[parentKey]?.value;
90
- const total = children.filter(row => row[childKey]?.value === key)
91
- .reduce((sum, row) => sum + Number(row[childAmount]?.value || 0), 0);
92
- formSdk.changeFieldValue(`${parentTotal}_${parent.rowId}`, {value: String(total)}, {jsApiChange: false});
93
- }
94
- }
95
- formSdk.bindFieldChangeEvent(childAmount, recalculateParents);
96
- formSdk.registerAction(`${window.WeFormSDK.ACTION_ADDROW}${childTable}`, recalculateParents);
97
- formSdk.registerAction(`${window.WeFormSDK.ACTION_DELROW}${childTable}`, recalculateParents);
98
- recalculateParents();
99
- ```
100
-
101
- 关系字段若为选项而非文本,按 `getFieldObj` 的 `specialObj` 比较 ID。父行标识必须唯一;删除父行后的子行处置应由业务规则明确。用 `getDetailData` 复制子行时不要复制旧 `rowId`。
102
-
103
- ## 来源明细按两列分组,同步到目标明细
104
-
105
- 来源中按“部门 ID + 类型 ID”分组求和;目标中已有分组更新、缺失分组新增、来源已消失的分组删除。监听来源的两列条件字段、数值字段与增删行事件。下面只展示同步函数,绑定方式同上方汇总案例。
106
-
107
- ```js
108
- function syncGroups(sourceTable, targetTable, sourceDept, sourceType, sourceAmount,
109
- targetDept, targetType, targetAmount) {
110
- const groups = new Map();
111
- for (const row of formSdk.getDetailData(sourceTable) || []) {
112
- const dept = row[sourceDept]?.specialObj?.[0];
113
- const type = row[sourceType]?.specialObj?.[0];
114
- if (!dept?.id || !type?.id) continue;
115
- const key = `${dept.id}:${type.id}`;
116
- const item = groups.get(key) || {dept, type, total: 0};
117
- item.total += Number(row[sourceAmount]?.value || 0);
118
- groups.set(key, item);
119
- }
120
- const existing = new Map();
121
- for (const row of formSdk.getDetailData(targetTable) || []) {
122
- const deptId = row[targetDept]?.specialObj?.[0]?.id;
123
- const typeId = row[targetType]?.specialObj?.[0]?.id;
124
- if (!deptId || !typeId || !groups.has(`${deptId}:${typeId}`)) {
125
- formSdk.delDetailRow(targetTable, row.rowId);
126
- } else {
127
- existing.set(`${deptId}:${typeId}`, row.rowId);
128
- }
129
- }
130
- for (const [key, item] of groups) {
131
- const rowId = existing.get(key);
132
- if (rowId) {
133
- formSdk.changeFieldValue(`${targetAmount}_${rowId}`, {value: String(item.total)}, {jsApiChange: false});
134
- } else {
135
- formSdk.addDetailRow(targetTable, {
136
- [targetDept]: {specialObj: [item.dept]},
137
- [targetType]: {specialObj: [item.type]},
138
- [targetAmount]: {value: String(item.total)}
139
- });
140
- }
141
- }
142
- }
143
- ```
144
-
145
- 这种同步会删除目标中无来源的行,只有目标表完全由来源派生时才适用;若允许用户手工维护目标行,应改为保留手工行并有明确的来源标识。跨字段 `id` 类型与数值精度须按实际表单处理。
146
-
147
- ## 根据明细同行条件筛人员,合并到主表
148
-
149
- 对每行读取条件选项,按不同条件分别取对应人员字段,再按人员 ID 去重并写入主表。初次载入、条件/人员字段变化、明细增删行均重新执行。
150
-
151
- ```js
152
- function syncPeople(table, conditionField, firstPeopleField, secondPeopleField, mainPeopleField) {
153
- const people = new Map();
154
- for (const row of formSdk.getDetailData(table) || []) {
155
- const choice = row[conditionField]?.specialObj?.[0]?.id;
156
- const selected = choice === '0' ? row[firstPeopleField]?.specialObj :
157
- choice === '1' ? row[secondPeopleField]?.specialObj : [];
158
- for (const person of selected || []) if (person?.id) people.set(String(person.id), person);
159
- }
160
- formSdk.changeFieldValue(mainPeopleField, {specialObj: [...people.values()]}, {jsApiChange: false});
161
- }
162
- ```
163
-
164
- 条件选项 ID `'0'/'1'` 是示例占位,须读取真实选项 ID。若人员字段由系统联动带出,还要按[事件指南](ref-events-validation.md)监听联动完成事件。
@@ -1,49 +0,0 @@
1
- # JSSDK 排查、版本与边界
2
-
3
- ## 代码不生效时
4
-
5
- 1. 确认保存的是目标表单的目标布局及目标终端,或正确的表单级/全局 ecode;JS 编译通过且代码已启用,CSS 单独保存。浏览器打开的是最新布局而非另一设备布局。
6
- 2. 确认 `formSdk` 取自当前表单实例;全局 ecode 用 `onFormReady` 的事件实例并限定 formId/module。较早基线的 `pageSdk.on('formReady')` 与新基线闭包方式不要混用到未支持的入口。
7
- 3. 用 `getBaseInfo`、`convertFieldNameToId`、`getFieldInfo` 检查当前表单和字段;数据 Key 不是字段名或物理表名。明细字段要指定明细表位置,行操作要取得真实 `rowId`。
8
- 4. 用 `getFieldObj` 对照目标类型的数据形状。文本/数字/日期常用 `{value}`;浏览/动态选项/附件常用 `{specialObj}`。附件预览还依赖完整 `data`。
9
- 5. 检查事件是否属于“表单保存”“流程提交”“用户改变”“联动改变”中的哪一种;必要时分开绑定。拦截回调必须调用通过或阻断函数;异步超时约 25 秒。
10
- 6. 检查权限和组件边界。流程节点默认只读或权限锁定的字段,不能仅靠 `changeFieldAttr(2)` 放开;JS 渲染也不改变后端权限。
11
-
12
- 开发调试时可按环境入口临时屏蔽不同层级二开:ecode 平台、全局初始化代码、布局源码对应不同入口。调试开关仅用于定位,不作为正式配置。对含多表单、父子页面、明细新行的场景,还要检查实例、`postMessage` 来源与渲染时机。
13
-
14
- ## 设计器源码面板为空 / ECode decode failed
15
-
16
- - **症状**:打开布局源码时控制台报 `ECode decode failed, SyntaxError: Expected ':' after property name in JSON at position 5`,源码面板为空,预览按钮失效。
17
- - **原因**:`sourceCode.ecode` 被 `encodeURIComponent` 写入。设计器用 `JSON.parse(decodeURI(ecode))` 读取,而 `decodeURI` 不还原 `%3A`(冒号),JSON 变成 `{"js"%3A...}`。
18
- - **处理**:用 `form code layout set` / `wf-form code layout set` 重新写入(CLI 已使用 `encodeURI`,并在写入前、回读后按设计器路径自检)。临时恢复可把 `sourceCode.ecode` 置为空字符串,再用空 JS/CSS 文件重写。
19
- - **手工调接口**:必须用 `encodeURI(JSON.stringify({js, css}))`,不要用 `encodeURIComponent`。
20
-
21
- ## 基线速查
22
-
23
- | 功能 | 原技术资料标注的最低基线 |
24
- |---|---|
25
- | `changeFieldValue` 的联动控制参数 | 241001 |
26
- | `valueInfo.type/contentObj` 特殊字段 | 241201 |
27
- | 字段联动拦截及联动动作的 `runData` | 240601 |
28
- | 字段变化事件的联动 `scope` | 250401;明细专用事件的扩展参数 250901 |
29
- | 明细批量添加 `addDetailData` | 241201 |
30
- | 布局/表单代码直接取得当前 `formSdk` | 主体说明标注 250101;另有一处写 241201,稳妥按 250101 判断 |
31
- | 明细批量更新 `changeDetailData` | 250101 |
32
- | `changeTabItemAttr` | 20250501 |
33
- | `controlOptionDisable` | 20250501 |
34
- | `convertFieldNameToId` 用明细表数据 Key 定位明细字段 | 260601 |
35
- | `getDetailData` 按当前明细筛选条件取数 | 260401 |
36
- | `triggerFieldAllLinkage(...).then(...)` | 250901 |
37
- | 联动赋值导致的明细行变化事件扩展 | 251101 |
38
- | `pluginGet/pluginExecute` | 260201 |
39
-
40
- 先确认目标环境版本和实际 API 可用性;未达到基线时不要假设同名功能可用。
41
-
42
- ## 原案例中需纠正的写法
43
-
44
- - 字段赋值示例声明 `textFieldMark` 后却调用 `fieldMark`,日期示例声明 `dateFieldMark` 后调用 `selectFieldMark`;按真正声明的目标字段写。
45
- - 字段属性示例的明细行模板字符串缺少引号闭合;正确形式为 `` `${detailField}_${rowId}` ``。
46
- - `getFieldCom` 章节示例调用了 `getFieldInfo`;两者用途不同,前者为组件引用,后者为字段信息。
47
- - 明细“默认使用末行”章节的示例实际调用 `setDetailAddUseCopy`;先确认所需是复制末行,而非仅控制默认光标或位置。
48
- - 案例中的 `eval(numbers.join('+'))`、测试 URL、固定附件元数据、模拟外部查询结果不能直接用于业务配置。数值合计用显式转换与 `reduce`,外部接口须有真实契约。
49
- - 全局 ecode 的 `import`、JSX、`regOvProps` 示例不要直接粘入布局源码;按目标编辑器支持的语法重写。布局源码中的局部字段组件复写则按其 API 单独处理。
@@ -1,47 +0,0 @@
1
- # 组件渲染、全局交互与扩展
2
-
3
- ## 当前表单与全局操作
4
-
5
- `formSdk.getBaseInfo()` 读取当前表单基本信息;`formSdk.isMobile()` 判断移动端。布局级代码优先使用当前作用域 `formSdk`;提示、弹窗由全局 `window.WeFormSDK` 提供。
6
-
7
- | 效果 | API 与要点 |
8
- |---|---|
9
- | 提示 | `window.WeFormSDK.showMessage(message, type?, duration?)`;type 为 `1` 警告、`2` 错误、`3` 成功;时长单位秒 |
10
- | 确认 | `window.WeFormSDK.showConfirm(content, onOk, onCancel?, {title,okText,cancelText}?)`;title 仅 PC 有效 |
11
- | 自定义弹窗 | `window.WeFormSDK.openCustomDialog({content,width,height,onOk,onCancel,footer?,...})`;返回对象可 `destroy()` |
12
- | 页面刷新 | `formSdk.reloadPage(params?)` |
13
- | 提交附加参数 | `formSdk.appendSubmitParam({customParam:{...}})`;接收端仍须能处理该参数 |
14
- | 主动做必填检查 | `formSdk.verifyFormRequired(mustAddDetail?,fieldRequired?)` |
15
- | 全局加载 | `window.WeFormSDK.getLoadingGlobal()` 取加载控件,调用 `start()`、`end()`、`destroy()` |
16
- | 关闭页面提示 | `formSdk.setFormTipCloseStatus(true/false)`;只控制提示状态,不执行保存 |
17
-
18
- 自定义 footer 使用 `@weapp/ui` 的 import/JSX 是 ecode 构建环境示例;布局源码只允许其编辑器可编译的语法和已暴露对象,不能直接套用 ecode 依赖。
19
-
20
- ## 字段区域事件和局部渲染
21
-
22
- `bindFieldAction(type, fields, handler)` 绑定失焦、聚焦、点击、双击、移入/移出;事件类型为 `onblur/onfocus/onclick/ondbclick/mouseover/mouseout`。
23
-
24
- | 需求 | API |
25
- |---|---|
26
- | 将当前字段内容替换为自定义内容 | `proxyFieldComp(fieldMark, reactNode或文本, range?)` |
27
- | 在字段后追加内容 | `afterFieldComp(fieldMark, reactNode或文本, range?)` |
28
- | 用函数包装原字段内容并利用 props 决定样式 | `proxyFieldContentComp(fieldMark, (props, componentFn) => React.createElement(..., componentFn()))` |
29
-
30
- `range` 省略时作用于全部读写状态;`'1'` 只读、`'2'` 可编辑、`'3'` 必填,多个值以逗号分隔。`proxyFieldContentComp` 的回调必须返回组件,第二参数 `componentFn` 可生成原字段内容。`React` 可用性和编译语法要以目标代码入口为准。明细字段不加行 ID 可作用于整列,指定行则加 `_rowId`;新添行的专门逻辑应在添加行事件后检查是否生效。此能力是当前表单字段的局部渲染,不等于发布平台级新组件,也不等于改写后端接口。
31
-
32
- ```js
33
- const field = formSdk.convertFieldNameToId('status', 'main');
34
- formSdk.proxyFieldContentComp(field, (props, original) =>
35
- React.createElement('div', {style: {backgroundColor: props?.widgetValue?.content === '1' ? '#e3f2fd' : ''}}, original())
36
- );
37
- ```
38
-
39
- ## 插件与页面间通信
40
-
41
- 260201 及以后基线提供 `formSdk.pluginGet(fieldMark, property)` 和 `formSdk.pluginExecute(fieldMark, method, ...args)`;只能操作该插件实际公开的属性/方法。具体 WPS 或其他插件须取得该插件契约,不能从 JSSDK 通用接口推断方法名。
42
-
43
- `window.open` 打开的子页面可通过 `window.opener` 访问父窗口;同源时可操作父页面的表单实例。跨源时用 `postMessage`,接收方检查 `event.origin` 和 `event.data.type`,发送方指定目标 origin;只发送必要数据,不传鉴权信息。
44
-
45
- 子表控件数据变化后,如需刷新相关显示,布局源码中可调用 `pageSdk.events.emit('field.change', '纯数字字段ID')`;ecode 中可调用 `window.ebuilderSDK.getPageSDK().events.emit('field.change', '纯数字字段ID')`。原资料还提到可附第三个字段数据参数:文本传文本,浏览型传以逗号分隔的 ID;按实际刷新需求决定是否传值。此处第二参数是纯数字字段 ID,不是带 `field` 前缀的标识。
46
-
47
- 全局 ecode 的 `regOvProps` 可复写特定组件 props,但其包名与目标组件名是项目级契约;它和布局内 `proxyFieldContentComp` 是不同层级。采用哪一层,应以所需生效范围为准。