weaver-e10-builder 1.6.10 → 1.6.12

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 (289) hide show
  1. package/dist/commands/form-browser-definition.d.ts.map +1 -1
  2. package/dist/commands/form-browser-definition.js +108 -7
  3. package/dist/commands/form-browser-definition.js.map +1 -1
  4. package/dist/commands/form-browser-scope-rules.d.ts +27 -0
  5. package/dist/commands/form-browser-scope-rules.d.ts.map +1 -0
  6. package/dist/commands/form-browser-scope-rules.js +141 -0
  7. package/dist/commands/form-browser-scope-rules.js.map +1 -0
  8. package/dist/commands/form-browser-scope-tree.d.ts +14 -0
  9. package/dist/commands/form-browser-scope-tree.d.ts.map +1 -0
  10. package/dist/commands/form-browser-scope-tree.js +115 -0
  11. package/dist/commands/form-browser-scope-tree.js.map +1 -0
  12. package/dist/commands/matrix-maintainer.d.ts +3 -0
  13. package/dist/commands/matrix-maintainer.d.ts.map +1 -0
  14. package/dist/commands/matrix-maintainer.js +117 -0
  15. package/dist/commands/matrix-maintainer.js.map +1 -0
  16. package/dist/commands/matrix.d.ts.map +1 -1
  17. package/dist/commands/matrix.js +2 -0
  18. package/dist/commands/matrix.js.map +1 -1
  19. package/dist/commands/report-admin.d.ts.map +1 -1
  20. package/dist/commands/report-admin.js +378 -2
  21. package/dist/commands/report-admin.js.map +1 -1
  22. package/dist/commands/report-validate.d.ts.map +1 -1
  23. package/dist/commands/report-validate.js +1102 -3
  24. package/dist/commands/report-validate.js.map +1 -1
  25. package/dist/commands/report.d.ts.map +1 -1
  26. package/dist/commands/report.js +341 -3
  27. package/dist/commands/report.js.map +1 -1
  28. package/dist/commands/role.d.ts.map +1 -1
  29. package/dist/commands/role.js +354 -0
  30. package/dist/commands/role.js.map +1 -1
  31. package/dist/commands/special.d.ts.map +1 -1
  32. package/dist/commands/special.js +67 -31
  33. package/dist/commands/special.js.map +1 -1
  34. package/dist/commands/wf-form.d.ts.map +1 -1
  35. package/dist/commands/wf-form.js +1 -121
  36. package/dist/commands/wf-form.js.map +1 -1
  37. package/dist/commands/workflow-after-submit-comment.d.ts +3 -0
  38. package/dist/commands/workflow-after-submit-comment.d.ts.map +1 -0
  39. package/dist/commands/workflow-after-submit-comment.js +56 -0
  40. package/dist/commands/workflow-after-submit-comment.js.map +1 -0
  41. package/dist/commands/workflow-layout-components.d.ts +3 -0
  42. package/dist/commands/workflow-layout-components.d.ts.map +1 -0
  43. package/dist/commands/workflow-layout-components.js +36 -0
  44. package/dist/commands/workflow-layout-components.js.map +1 -0
  45. package/dist/commands/workflow-node-batch.d.ts +3 -0
  46. package/dist/commands/workflow-node-batch.d.ts.map +1 -0
  47. package/dist/commands/workflow-node-batch.js +136 -0
  48. package/dist/commands/workflow-node-batch.js.map +1 -0
  49. package/dist/commands/workflow-node-opinion.d.ts +3 -0
  50. package/dist/commands/workflow-node-opinion.d.ts.map +1 -0
  51. package/dist/commands/workflow-node-opinion.js +51 -0
  52. package/dist/commands/workflow-node-opinion.js.map +1 -0
  53. package/dist/commands/workflow-node-reject.js +1 -1
  54. package/dist/commands/workflow-node-reject.js.map +1 -1
  55. package/dist/commands/workflow-node.d.ts.map +1 -1
  56. package/dist/commands/workflow-node.js +4 -3
  57. package/dist/commands/workflow-node.js.map +1 -1
  58. package/dist/commands/workflow-setting.d.ts.map +1 -1
  59. package/dist/commands/workflow-setting.js +2 -67
  60. package/dist/commands/workflow-setting.js.map +1 -1
  61. package/dist/index.js +6 -2
  62. package/dist/index.js.map +1 -1
  63. package/dist/services/actionflow/components/send_message.d.ts.map +1 -1
  64. package/dist/services/actionflow/components/send_message.js +8 -3
  65. package/dist/services/actionflow/components/send_message.js.map +1 -1
  66. package/dist/services/actionflow/context_preflight.js +1 -1
  67. package/dist/services/actionflow/context_preflight.js.map +1 -1
  68. package/dist/services/actionflow/formula_service.d.ts +1 -0
  69. package/dist/services/actionflow/formula_service.d.ts.map +1 -1
  70. package/dist/services/actionflow/formula_service.js +107 -31
  71. package/dist/services/actionflow/formula_service.js.map +1 -1
  72. package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
  73. package/dist/services/actionflow/preflight_service.js +4 -1
  74. package/dist/services/actionflow/preflight_service.js.map +1 -1
  75. package/dist/services/form-layout-describe.d.ts.map +1 -1
  76. package/dist/services/form-layout-describe.js +3 -2
  77. package/dist/services/form-layout-describe.js.map +1 -1
  78. package/dist/services/form-layout-document.d.ts.map +1 -1
  79. package/dist/services/form-layout-document.js +2 -1
  80. package/dist/services/form-layout-document.js.map +1 -1
  81. package/dist/services/matrix-maintainer.d.ts +27 -0
  82. package/dist/services/matrix-maintainer.d.ts.map +1 -0
  83. package/dist/services/matrix-maintainer.js +142 -0
  84. package/dist/services/matrix-maintainer.js.map +1 -0
  85. package/dist/services/report/blueprint.d.ts +109 -0
  86. package/dist/services/report/blueprint.d.ts.map +1 -0
  87. package/dist/services/report/blueprint.js +322 -0
  88. package/dist/services/report/blueprint.js.map +1 -0
  89. package/dist/services/report/build.d.ts.map +1 -1
  90. package/dist/services/report/build.js +8 -3
  91. package/dist/services/report/build.js.map +1 -1
  92. package/dist/services/report/card.d.ts +65 -0
  93. package/dist/services/report/card.d.ts.map +1 -0
  94. package/dist/services/report/card.js +151 -0
  95. package/dist/services/report/card.js.map +1 -0
  96. package/dist/services/report/copy-health.d.ts +31 -0
  97. package/dist/services/report/copy-health.d.ts.map +1 -0
  98. package/dist/services/report/copy-health.js +87 -0
  99. package/dist/services/report/copy-health.js.map +1 -0
  100. package/dist/services/report/dataset-heal.d.ts +64 -0
  101. package/dist/services/report/dataset-heal.d.ts.map +1 -0
  102. package/dist/services/report/dataset-heal.js +89 -0
  103. package/dist/services/report/dataset-heal.js.map +1 -0
  104. package/dist/services/report/dataset-ids.d.ts +70 -0
  105. package/dist/services/report/dataset-ids.d.ts.map +1 -0
  106. package/dist/services/report/dataset-ids.js +149 -0
  107. package/dist/services/report/dataset-ids.js.map +1 -0
  108. package/dist/services/report/dataset.d.ts.map +1 -1
  109. package/dist/services/report/dataset.js +3 -1
  110. package/dist/services/report/dataset.js.map +1 -1
  111. package/dist/services/report/drill.d.ts +74 -0
  112. package/dist/services/report/drill.d.ts.map +1 -0
  113. package/dist/services/report/drill.js +259 -0
  114. package/dist/services/report/drill.js.map +1 -0
  115. package/dist/services/report/empty-dataset.d.ts +51 -0
  116. package/dist/services/report/empty-dataset.d.ts.map +1 -0
  117. package/dist/services/report/empty-dataset.js +213 -0
  118. package/dist/services/report/empty-dataset.js.map +1 -0
  119. package/dist/services/report/field-binding.d.ts +75 -0
  120. package/dist/services/report/field-binding.d.ts.map +1 -0
  121. package/dist/services/report/field-binding.js +160 -0
  122. package/dist/services/report/field-binding.js.map +1 -0
  123. package/dist/services/report/forms.d.ts +32 -0
  124. package/dist/services/report/forms.d.ts.map +1 -1
  125. package/dist/services/report/forms.js +90 -0
  126. package/dist/services/report/forms.js.map +1 -1
  127. package/dist/services/report/formula-parent.d.ts +25 -0
  128. package/dist/services/report/formula-parent.d.ts.map +1 -0
  129. package/dist/services/report/formula-parent.js +116 -0
  130. package/dist/services/report/formula-parent.js.map +1 -0
  131. package/dist/services/report/locate.d.ts +40 -0
  132. package/dist/services/report/locate.d.ts.map +1 -0
  133. package/dist/services/report/locate.js +122 -0
  134. package/dist/services/report/locate.js.map +1 -0
  135. package/dist/services/report/reports.d.ts +4 -0
  136. package/dist/services/report/reports.d.ts.map +1 -1
  137. package/dist/services/report/reports.js +4 -2
  138. package/dist/services/report/reports.js.map +1 -1
  139. package/dist/services/report/scene.d.ts +22 -0
  140. package/dist/services/report/scene.d.ts.map +1 -0
  141. package/dist/services/report/scene.js +145 -0
  142. package/dist/services/report/scene.js.map +1 -0
  143. package/dist/services/report/types.d.ts +28 -0
  144. package/dist/services/report/types.d.ts.map +1 -1
  145. package/dist/services/report/verify.d.ts +24 -0
  146. package/dist/services/report/verify.d.ts.map +1 -1
  147. package/dist/services/report/verify.js +115 -2
  148. package/dist/services/report/verify.js.map +1 -1
  149. package/dist/services/report/workbook.d.ts +12 -1
  150. package/dist/services/report/workbook.d.ts.map +1 -1
  151. package/dist/services/report/workbook.js +107 -8
  152. package/dist/services/report/workbook.js.map +1 -1
  153. package/dist/services/role-function-permission.d.ts +12 -0
  154. package/dist/services/role-function-permission.d.ts.map +1 -0
  155. package/dist/services/role-function-permission.js +46 -0
  156. package/dist/services/role-function-permission.js.map +1 -0
  157. package/dist/services/special-layout.d.ts +113 -0
  158. package/dist/services/special-layout.d.ts.map +1 -0
  159. package/dist/services/special-layout.js +178 -0
  160. package/dist/services/special-layout.js.map +1 -0
  161. package/dist/services/workflow-after-submit-comment.d.ts +20 -0
  162. package/dist/services/workflow-after-submit-comment.d.ts.map +1 -0
  163. package/dist/services/workflow-after-submit-comment.js +81 -0
  164. package/dist/services/workflow-after-submit-comment.js.map +1 -0
  165. package/dist/services/workflow-base-settings.d.ts +1 -10
  166. package/dist/services/workflow-base-settings.d.ts.map +1 -1
  167. package/dist/services/workflow-field-permission-route.d.ts +15 -41
  168. package/dist/services/workflow-field-permission-route.d.ts.map +1 -1
  169. package/dist/services/workflow-field-permission-route.js +23 -8
  170. package/dist/services/workflow-field-permission-route.js.map +1 -1
  171. package/dist/services/workflow-layout-components.d.ts +52 -0
  172. package/dist/services/workflow-layout-components.d.ts.map +1 -0
  173. package/dist/services/workflow-layout-components.js +66 -0
  174. package/dist/services/workflow-layout-components.js.map +1 -0
  175. package/dist/services/workflow-layout-draft.d.ts +49 -0
  176. package/dist/services/workflow-layout-draft.d.ts.map +1 -0
  177. package/dist/services/workflow-layout-draft.js +98 -0
  178. package/dist/services/workflow-layout-draft.js.map +1 -0
  179. package/dist/services/workflow-node-batch-spec.d.ts +122 -0
  180. package/dist/services/workflow-node-batch-spec.d.ts.map +1 -0
  181. package/dist/services/workflow-node-batch-spec.js +496 -0
  182. package/dist/services/workflow-node-batch-spec.js.map +1 -0
  183. package/dist/services/workflow-node-batch.d.ts +73 -0
  184. package/dist/services/workflow-node-batch.d.ts.map +1 -0
  185. package/dist/services/workflow-node-batch.js +328 -0
  186. package/dist/services/workflow-node-batch.js.map +1 -0
  187. package/dist/services/workflow-node-opinion-description.d.ts +12 -0
  188. package/dist/services/workflow-node-opinion-description.d.ts.map +1 -0
  189. package/dist/services/workflow-node-opinion-description.js +52 -0
  190. package/dist/services/workflow-node-opinion-description.js.map +1 -0
  191. package/dist/services/workflow-node-opinion-layout.d.ts +22 -0
  192. package/dist/services/workflow-node-opinion-layout.d.ts.map +1 -0
  193. package/dist/services/workflow-node-opinion-layout.js +113 -0
  194. package/dist/services/workflow-node-opinion-layout.js.map +1 -0
  195. package/dist/services/workflow-node-opinion-range.d.ts +21 -0
  196. package/dist/services/workflow-node-opinion-range.d.ts.map +1 -0
  197. package/dist/services/workflow-node-opinion-range.js +74 -0
  198. package/dist/services/workflow-node-opinion-range.js.map +1 -0
  199. package/dist/services/workflow-node-opinion.d.ts +43 -0
  200. package/dist/services/workflow-node-opinion.d.ts.map +1 -0
  201. package/dist/services/workflow-node-opinion.js +198 -0
  202. package/dist/services/workflow-node-opinion.js.map +1 -0
  203. package/dist/services/workflow-opinion-settings.d.ts +14 -0
  204. package/dist/services/workflow-opinion-settings.d.ts.map +1 -1
  205. package/dist/services/workflow-opinion-settings.js +18 -2
  206. package/dist/services/workflow-opinion-settings.js.map +1 -1
  207. package/ecodecmd/src/build.js +36 -12
  208. package/package.json +1 -1
  209. package/skill-docs/SKILL.md +164 -162
  210. package/skill-docs/_catalog.md +13 -3
  211. package/skill-docs/actionflows/references/components/message/SendMessage.md +32 -30
  212. package/skill-docs/references/coding/guide-page-code.md +95 -0
  213. package/skill-docs/references/common/guide-plan-template.md +4 -1
  214. package/skill-docs/references/common/map.md +28 -4
  215. package/skill-docs/references/common/ref-cli-commands.md +14 -4
  216. package/skill-docs/references/components/ref-component-common.md +98 -0
  217. package/skill-docs/references/form/guide-browser-definition.md +2 -219
  218. package/skill-docs/references/form/guide-browser-scope.md +285 -0
  219. package/skill-docs/references/form/guide-create-form.md +1 -1
  220. package/skill-docs/references/hrm/guide-matrix.md +276 -245
  221. package/skill-docs/references/hrm/guide-role.md +77 -0
  222. package/skill-docs/references/report/add-dataset-registration-guide.md +44 -22
  223. package/skill-docs/references/report/advanced-crosstab-tree-guide.md +82 -0
  224. package/skill-docs/references/report/ai-report-workflow.md +100 -100
  225. package/skill-docs/references/report/api-auth-headers.md +129 -0
  226. package/skill-docs/references/report/api-report-build-fast-path.md +274 -275
  227. package/skill-docs/references/report/app-datasource-lookup-guide.md +230 -230
  228. package/skill-docs/references/report/branch-scene-guide.md +293 -0
  229. package/skill-docs/references/report/build-resilience-guide.md +99 -0
  230. package/skill-docs/references/report/card-report-guide.md +110 -0
  231. package/skill-docs/references/report/cell-config-echo-guide.md +44 -9
  232. package/skill-docs/references/report/cell-transform-guide.md +9 -9
  233. package/skill-docs/references/report/column-split-report-guide.md +96 -0
  234. package/skill-docs/references/report/condition-format-guide.md +49 -24
  235. package/skill-docs/references/report/cross-dataset-filter-guide.md +180 -69
  236. package/skill-docs/references/report/crosstab-raw-workbook-guide.md +265 -0
  237. package/skill-docs/references/report/dataset-query-filter-guide.md +231 -235
  238. package/skill-docs/references/report/dataset-sidebar-ops-guide.md +75 -34
  239. package/skill-docs/references/report/dataset-table-field-contract-guide.md +196 -46
  240. package/skill-docs/references/report/datasource-metadata-guide.md +128 -119
  241. package/skill-docs/references/report/datasource-selection-and-parent-filter-guide.md +183 -148
  242. package/skill-docs/references/report/date-range-query-reference.md +97 -102
  243. package/skill-docs/references/report/default-header-style-guide.md +8 -8
  244. package/skill-docs/references/report/designer-blank-prevention-guide.md +8 -8
  245. package/skill-docs/references/report/dossier-report-guide.md +69 -0
  246. package/skill-docs/references/report/drilldown-report-guide.md +75 -0
  247. package/skill-docs/references/report/event-hreflink-guide.md +55 -47
  248. package/skill-docs/references/report/expansion-block-parent-config-guide.md +208 -0
  249. package/skill-docs/references/report/failure-cleanup-and-nonblocking-guide.md +183 -0
  250. package/skill-docs/references/report/field-bind-exact-match-guide.md +208 -208
  251. package/skill-docs/references/report/financial-stats-report-guide.md +89 -0
  252. package/skill-docs/references/report/formula-cell-api-guide.md +325 -258
  253. package/skill-docs/references/report/golden-case-summary-sheet.md +200 -0
  254. package/skill-docs/references/report/guide-report-build.md +6 -1
  255. package/skill-docs/references/report/hidden-row-and-header-merge-guide.md +10 -10
  256. package/skill-docs/references/report/layout-showlocation-freeze-guide.md +39 -10
  257. package/skill-docs/references/report/multi-report-crosstab-casebook.md +263 -0
  258. package/skill-docs/references/report/paged-group-report-guide.md +68 -0
  259. package/skill-docs/references/report/preaggregate-auto-disable-guide.md +24 -13
  260. package/skill-docs/references/report/query-condition-api-guide.md +174 -125
  261. package/skill-docs/references/report/ref-report-commands.md +41 -3
  262. package/skill-docs/references/report/report-baseinfo-defaults-guide.md +117 -117
  263. package/skill-docs/references/report/report-building-guide.md +52 -52
  264. package/skill-docs/references/report/report-case-prompts.md +104 -0
  265. package/skill-docs/references/report/report-config-schema.md +281 -281
  266. package/skill-docs/references/report/report-create-modes-guide.md +73 -35
  267. package/skill-docs/references/report/report-data-model.md +131 -131
  268. package/skill-docs/references/report/report-delivery-contract.md +23 -3
  269. package/skill-docs/references/report/report-designer-feature-map.md +30 -35
  270. package/skill-docs/references/report/report-help-guide.md +304 -0
  271. package/skill-docs/references/report/report-internal-error-guide.md +71 -0
  272. package/skill-docs/references/report/report-knowledge-base.md +27 -27
  273. package/skill-docs/references/report/report-lifecycle-api-guide.md +126 -94
  274. package/skill-docs/references/report/report-list-page-ops-guide.md +54 -8
  275. package/skill-docs/references/report/report-permission-guide.md +99 -102
  276. package/skill-docs/references/report/report-requirement-analysis-template.md +93 -29
  277. package/skill-docs/references/report/report-self-check-guide.md +164 -164
  278. package/skill-docs/references/report/report-verification-discipline-guide.md +203 -0
  279. package/skill-docs/references/report/safe-partial-save-guide.md +151 -151
  280. package/skill-docs/references/report/shard-freeze-report-guide.md +97 -0
  281. package/skill-docs/references/report/snowflake-id-precision-guide.md +84 -84
  282. package/skill-docs/references/report/spec-build-schema.md +71 -71
  283. package/skill-docs/references/report/targeted-fix-guide.md +155 -97
  284. package/skill-docs/references/report/user-request-scope-only-guide.md +23 -4
  285. package/skill-docs/references/workflow/guide-after-submit-comment.md +58 -0
  286. package/skill-docs/references/workflow/guide-layout-components.md +26 -0
  287. package/skill-docs/references/workflow/guide-node-opinion.md +58 -0
  288. package/skill-docs/references/workflow/guide-workflow.md +49 -0
  289. package/skill-docs/references/form/guide-ebuilder-scope.md +0 -82
@@ -0,0 +1,96 @@
1
+ # 分栏报表四案例 · 场景 J(SKILL A0.19)
2
+
3
+ > 案例一「行分栏」:各分公司员工劳动关系详表——纵向扩展明细横向分 2 栏,标题行复制。
4
+ > 案例二「列分栏」:股票行情——横向扩展记录纵向分块(1-8 / 9-16 / 17-24),表头列复制。
5
+ > 案例三「卡片分栏」:条码卡 3 栏平铺(卡片版式 + 条码格)。
6
+ > 案例四「行分栏汇总统计」:多级行维度(集团→公司→厂)+ 合计行 + 红色百分比预警 + 横向分栏。
7
+
8
+ ---
9
+
10
+ ## 一、核心结论:分栏是渲染级配置,不是多带构造
11
+
12
+ 分栏入口 = 设计器「**页面 → 报表展示 → 分栏**」(help-guide §8.5:按行/列数分栏 / 按栏数分栏;
13
+ 模式:垂直 / 水平 / 卡片;复制标题或表头)。**设计 workbook 保持单数据带**,引擎按配置复制标题
14
+ 并重排实例 —— 与预聚合 / 分页同属 sheetConfig 级开关(knowledge-base §4.7)。
15
+
16
+ **落库通道(已固化)**:
17
+ - `build spec`:`layout.sheetConfig: { ... }` → 并入 `sheet.tag.sheetConfig`(A0.19 起,与 dataPreAgg 同通道)
18
+ - `card spec`:`spec.sheetConfig` 原本就透传
19
+
20
+ ⚠️ **分栏 sheetConfig 具体键名待确认**(类比 dataPreAgg 当年也是验证出来的)。
21
+ **验证捕获法**:设计器建一张分栏报表 → `getReportDevInfo` → 看 `sheetProps[0].sheetConfig`
22
+ (JSON 字符串)里的分栏键 → 回填本指南后即可在 spec 里写死。
23
+ 示例占位(**未验证**,仅示意形状):`{"splitConfig":{"mode":"row","count":20}}`。
24
+
25
+ ## 二、四案例解析
26
+
27
+ ### J-1 行分栏(案例一 · 纵向扩展数据横向分栏)
28
+
29
+ | 特性 | 设计 |
30
+ |---|---|
31
+ | 左维度「分公司名称」纵跨整栏 | 分公司 Field `Vertical+Group`、isActiveParent;明细左父格链到它 |
32
+ | 明细带(序号/姓名/劳动关系/学历) | 序号=`cellType:"seq"`;其余普通 Field 左父格链式 |
33
+ | 每栏复制标题行 | 分栏配置「复制标题行」= 表头 Const 行(引擎自动复制) |
34
+ | 分栏触发 | 按行数(每 N 行一栏)或按栏数 |
35
+
36
+ spec 骨架:普通分组明细表 `build spec` + `layout.sheetConfig`(分栏键)。
37
+
38
+ ### J-2 列分栏(案例二 · 横向扩展数据纵向分块)
39
+
40
+ | 特性 | 设计 |
41
+ |---|---|
42
+ | 字段为行标签(日期/成交量/…) | 字段名列 = 各 Field 竖排(不扩展),左父格链 |
43
+ | 记录横向扩展(序号 1-8) | 序号/日期行 = `Horizontal` 扩展格(日期 Group 或记录序),isActiveParent |
44
+ | 分块(1-8 / 9-16 / …) | 分栏配置「按列数」+「复制表头列」(序号+标签列) |
45
+ | 顶层标题合并 | 「某公司2~4月份股票行情」Const 跨全宽 |
46
+
47
+ 直构坐标模板(rebuild 路径):标签列 A(6 个 Field 竖排),B 列横向扩展锚点;分栏键在 sheetConfig。
48
+
49
+ ### J-3 卡片分栏(案例三 · 卡片版式 3 栏平铺 + 条码)
50
+
51
+ | 特性 | 设计 |
52
+ |---|---|
53
+ | 一条记录=一张卡片(姓名/编号ID/职务/出生日期/地址/邮编/联系方式) | **`card build` 通道**(cells 网格 label/value,同段落机制) |
54
+ | 3 栏平铺、行间复制 | 分栏模式=**卡片**(栏数 N + 复制单元=整体扩展单元首尾单元格,knowledge-base §4.7-5) |
55
+ | 编号ID 条码 | ✅ A0.19 起 card spec 单元格支持 **`qrcode`/`qrlink`** 透传(`qrcodeType/qrcodelink`);**条码枚举值待验证**(设计器 条码下拉:无/条码/二维码,具体字符串回填) |
56
+ | 姓名+条码图片位 | 姓名 Field;图片格=字段转换(图片 transType,见 cell-transform-guide)或 Const 占位 |
57
+
58
+ ### J-4 行分栏汇总统计(案例四 · 多级行维度 + 合计 + 预警 + 分栏)
59
+
60
+ | 特性 | 设计 |
61
+ |---|---|
62
+ | 三级行维度(集团→公司→厂) | 场景 H 多级行维度:子级左父格→上级格(rebuild 直构) |
63
+ | 各级「合计」行 | Formula 左父格=该级维度格(crosstab §4.2 ★禁默认链) |
64
+ | 值列组(全年计划/10月/累计/完成年计划比…) | 普通 Field + 完成率 Formula;红色百分比=conditionRule(超标红字) |
65
+ | 横向分栏 | 同 J-1 分栏配置;多级左维度树整棵随栏复制(引擎行为,已验证) |
66
+
67
+ ## 三、搭建提示语句
68
+
69
+ **J-1 行分栏**:
70
+ > 按行分栏格式搭一张员工劳动关系详表:列「分公司名称/序号/员工姓名/劳动关系/学历」,
71
+ > 分公司 Field 纵向分组扩展、明细跟随,序号用系统序号;数据源 `<sid>`(appId `<appId>`);
72
+ > 横向分栏每栏 N 行、复制标题行;用 `build spec` 落库 + `layout.sheetConfig` 写分栏配置
73
+ > (键名以设计器确认回填为准),落库后回读验收父格链。
74
+
75
+ **J-2 列分栏**:
76
+ > 按列分栏格式搭一张股票行情表:左侧标签列(日期/成交量/开盘/盘高/盘低/收盘)竖排,
77
+ > 记录横向扩展(序号行);纵向分块每块 N 列、复制表头列;数据源 `<sid>`(appId `<appId>`);
78
+ > 走 rebuild 直构(横向扩展 + 分栏 sheetConfig),回读验收扩展格与分栏配置。
79
+
80
+ **J-3 卡片分栏条码**:
81
+ > 按卡片分栏格式搭一张员工条码卡:卡片内 姓名+条码(编号ID 字段,qrcode 透传)+
82
+ > 职务/出生日期/地址/邮编/联系方式 label-value 网格;数据源 `<sid>`(appId `<appId>`);
83
+ > 用 `card build` 出版式,`spec.sheetConfig` 写卡片分栏(栏数 3,复制单元首尾);
84
+ > 条码枚举值与分栏键名以设计器确认回填为准,回读验收 qrcodeType 与锚点。
85
+
86
+ **J-4 行分栏汇总统计**:
87
+ > 按行分栏汇总格式搭一张生产产量完成情况表:行维度三级「集团→公司→厂」逐级缩进、
88
+ > 各级合计行、值列组(计划/实际/完成比),完成率超 100% 红字;
89
+ > 数据源 `<sid>`(appId `<appId>`);rebuild 直构(多级行维度+合计行)+
90
+ > `layout.sheetConfig` 横向分栏;回读验收合计行左父格与条件色。
91
+
92
+ ## 四、能力边界(如实)
93
+
94
+ 1. 分栏 sheetConfig 键名、条码 qrcodeType 枚举字符串 = **待确认**(通道已通,值待回填)。
95
+ 2. 分栏后跨栏的父格/合并表现(尤其多级行维度整棵复制)= 引擎渲染行为,设计器已验证。
96
+ 3. J-2/J-4 的多级结构超出 build spec 表达力 → rebuild 直构;J-1/J-3 单源可走 build spec / card build。
@@ -4,7 +4,7 @@
4
4
  > **UI**:设计器「开始 → 条件格式」
5
5
  > **落库唯一有效点**:`fields[].conditionRule` / workbook `style.cellType.conditionRule`
6
6
  > 结构:`{ highlightDatas, lineDatas, iconDatas }`(**不是** sheet 级 `conditionalFormats`,后者不持久化)
7
- > **禁黑盒**:禁止下载 SpreadJS / 设计器 chunk 循环试探;见 `session-build-performance-guide.md`
7
+ > **禁黑盒**:禁止下载 SpreadJS / 设计器 chunk 循环试探;见 `api-report-build-fast-path.md`
8
8
 
9
9
  ---
10
10
 
@@ -59,18 +59,18 @@
59
59
 
60
60
  ```json
61
61
  {
62
- "lineDatas": [
63
- {
64
- "index": 0,
65
- "leftType": "min",
66
- "leftValue": "",
67
- "rightType": "max",
68
- "rightValue": "",
69
- "gradient": "gradient",
70
- "color": "#6495ED",
71
- "negativeFillColor": "#FF0000"
72
- }
73
- ]
62
+ "lineDatas": [
63
+ {
64
+ "index": 0,
65
+ "leftType": "min",
66
+ "leftValue": "",
67
+ "rightType": "max",
68
+ "rightValue": "",
69
+ "gradient": "gradient",
70
+ "color": "#6495ED",
71
+ "negativeFillColor": "#FF0000"
72
+ }
73
+ ]
74
74
  }
75
75
  ```
76
76
 
@@ -90,16 +90,16 @@ CLI:`e10-cli report validate condition --map "数据条"` / `--map "实心数
90
90
 
91
91
  ```json
92
92
  {
93
- "iconDatas": [
94
- {
95
- "index": 0,
96
- "iconSetType": "0",
97
- "iconCriteria": [
98
- { "iconValue": "67", "isGreaterThanOrEqualTo": true, "iconValueType": 1 },
99
- { "iconValue": "33", "isGreaterThanOrEqualTo": true, "iconValueType": 1 }
100
- ]
101
- }
102
- ]
93
+ "iconDatas": [
94
+ {
95
+ "index": 0,
96
+ "iconSetType": "0",
97
+ "iconCriteria": [
98
+ { "iconValue": "67", "isGreaterThanOrEqualTo": true, "iconValueType": 1 },
99
+ { "iconValue": "33", "isGreaterThanOrEqualTo": true, "iconValueType": 1 }
100
+ ]
101
+ }
102
+ ]
103
103
  }
104
104
  ```
105
105
 
@@ -125,6 +125,31 @@ CLI:`e10-cli report validate condition --map "图标集"`
125
125
  2. save 成功 → **先交设计器 URL**
126
126
  3. 可选 `verify condition` 后置
127
127
 
128
+ ### ⚠️ 硬坑一:重建 workbook 会丢/清空 conditionRule(已修复)
129
+
130
+ `` 的 `fieldToCell()` 若**未把 `fields[].conditionRule` 透传进 workbook `style.cellType.conditionRule`**,则:
131
+ - 引擎读 workbook → **新写的条件格式不生效**;
132
+ - 重建时该 cell 的 style 丢掉 `conditionRule` → **保存后既有规则被清空**。
133
+
134
+ **当 `workbookProps.sheets` 为空(如 0 cell,本平台常见)时,`mergeWorkbookSafe` 必走 `buildWorkbookFromFields(fields)` 重建**,此坑必现。
135
+
136
+ → 已修复:`fieldToCell()` 末尾补
137
+ ```js
138
+ const cr = parseJsonMaybe(f.conditionRule, null);
139
+ if (cr && typeof cr === 'object' && Object.keys(cr).length > 0) {
140
+ if (!style.cellType || typeof style.cellType !== 'object') style.cellType = {};
141
+ style.cellType.conditionRule = cr;
142
+ }
143
+ ```
144
+ > 若条件格式「写了却不生效」或「保存后原有规则消失」,先查此处。
145
+
146
+ ### ⚠️ 硬坑二:单点修改纪律(强制)
147
+
148
+ - 用户只要求改 A,**禁止顺手改 B**(例如只要求改条件格式,绝不可顺带改公式/字段/布局);
149
+ - 参考 `user-request-scope-only-guide.md`:仅改用户点名项;
150
+ - 生产报表做单点修改前,**先抓 `getReportDevInfo` 全量快照存档**,改后 diff 校验改动范围;
151
+ - 保存后服务端会**强制规范化**一批等价空值(`subordination ["",""]→[]`、`refX/refY -1→0`、`hiddenContext "0"→删除`、`orderType "no"→删除`、`transSelectOptions "[]"→""`、`allNeedFields` 顺序),属正常,**不是内容丢失**,无法也无需通过接口还原。
152
+
128
153
  ---
129
154
 
130
155
  ## 七、CLI
@@ -137,4 +162,4 @@ e10-cli report validate condition --map "图标集"
137
162
  e10-cli report verify condition <reportId> [appId]
138
163
  ```
139
164
 
140
- 脚本:`e10-cli report verify condition`。
165
+ 脚本:`e10-cli report validate condition`。
@@ -6,6 +6,23 @@
6
6
  >
7
7
  > **与「左侧数据集筛选」区分**:整表/行级预过滤走 **`queryInfoSave`**(`conditionData`),见 **`dataset-query-filter-guide.md`**。本文档面向 **subordination / leftFilterField / customFilterField / datasetFilter**(单元格与多实例副本级)。
8
8
 
9
+ ## 〇、前置门禁:跨源关联必须「先探后写」(强制 · A0.9)
10
+
11
+ > 血案:供应商绩效看板 `1315297716934582273` 的跨源列定位,因**未先读子表样本数据**,
12
+ > 靠「重建 → 渲染」试错跑了 **~9 轮**,是整次搭建最大的时间浪费。
13
+
14
+ **在配置任何跨源筛选(`subordination` / `leftFilterField`)之前,必须先完成两步「探」**:
15
+
16
+ 1. **读子表样本数据** —— 要的是**真实取值**,不是字段元数据:
17
+ 确认「子表哪一列真正指向主表记录」及其**取值形态**(记录 id?显示名?逗号串?)。
18
+ 2. **跑 `join suggest`** ——
19
+ `e10-cli report join suggest --app-id <appId> --parent-source <主表sourceId> --child-source <子表sourceId>`
20
+ 取平台建议的关联键,再据此配父格。
21
+
22
+ **禁止**:未读样本就靠「反复落库 + 渲染」猜关联键 / 猜 `Equals` 还是 `Contain` / 猜 `left` 指向。
23
+ 子列取值一旦不对,**先回读样本数据**定位,不要又重建一轮落库。
24
+ (关联键真口径见 **§2.3.1**;子表 1:N 汇总见 **§2.3.2**;禁令总纲见 `targeted-fix-guide.md` §〇 · `pitfalls BUILD-18`。)
25
+
9
26
  ## 一、核心结论(必读)
10
27
 
11
28
  设计器下拉框**按 `fieldKey` 匹配字段**,不是按显示名(`text`)或裸系统名(`field_xxx`)。
@@ -43,17 +60,22 @@
43
60
 
44
61
  两者字段引用**都必须使用 fieldKey**。
45
62
 
46
- ### 2.1.1 连续同源区域:只配入口格(强制)
63
+ ### 2.1.1 连续同源区域:筛选只配入口格 · 后续字段以入口格为父格(★★ 最高优先 · 强制)
47
64
 
48
- > 完整规则见 **`datasource-selection-and-parent-filter-guide.md` §二**(含 **§2.5 关联键:需求优先 · 推断须用户确认**)。
65
+ > 完整规则见 **`datasource-selection-and-parent-filter-guide.md` §二**(含 **§2.5 关联键:需求优先 · 推断须用户确认**、**§2.6 自检判据**)。
49
66
 
50
67
  若连续一片单元格**全部来自同一数据源**,且整体挂在另一数据源父格下:
51
68
 
52
- - **仅该区域第一个字段**:自定义父格指向异源父格 + 配置 `subordination` / `leftFilterField`
53
- - **同区域其余字段**:父格用**默认**,**不要**逐格再指异源父格、**不要**重复配父格筛选
54
- - **关联字段**:需求已写明则按需求;未写明则字段匹配推断后 **必须提示用户确认**(CLI:`e10-cli report join-suggest`)
69
+ - **入口格(区域第一个字段)**:自定义父格指向异源关联键格 + 配置 `subordination` / `leftFilterField`(**只有这一格配筛选**)
70
+ - **同区域其余同源字段**:左父格**必须显式指向「本区域入口格」坐标**;`subordination` / `leftFilterField` **必须为空**
71
+ - **禁止**:后续字段指异源格(**跨源却无筛选** → 数据串源);也禁止逐格重复配一遍父格筛选
72
+ - **关联字段**:需求已写明则按需求;未写明则字段匹配推断后 **必须提示用户确认**(CLI:`e10-cli report join suggest`)
55
73
 
56
- 禁止对连续同源列/行「每个字段都配一遍跨源父格筛选」。
74
+ **铁律**:父格筛选只配在区域「入口格」上;同区域后续字段只要是同一个数据集,一律以这个入口字段为父格。
75
+
76
+ > **⚠ 边界(A0.21 交叉区布局 · 2026-10-29 实证)**:本条「只配入口格」仅适用于**后续格以入口格为父格**的链式布局。
77
+ > 交叉扩展区(横向日期 × 纵向维度)里每个数据格的左父格都直指**行维度扩展根**(异源)而非入口格
78
+ > ⇒ 每个跨源 Field 数据格**各自**配 `subordination` + `leftFilterField`(细则 `crosstab-raw-workbook-guide.md §4.3.4`)。
57
79
 
58
80
  ### 2.2 数据结构
59
81
 
@@ -61,18 +83,18 @@
61
83
 
62
84
  ```json
63
85
  {
64
- "subordination": [
65
- "1304979556231593994.1299763447342276611.field_1299763447342276617",
66
- "1304979560546713602.1299789221321891842.field_1299789221321891843"
67
- ],
68
- "leftFilterField": [
69
- {
70
- "parentField": "1304979556231593994.1299763447342276611.field_1299763447342276617",
71
- "currentField": "1304979560546713602.1299789221321891842.field_1299789221321891843",
72
- "type": "Equals",
73
- "id": "1304979560546713602.1299789221321891842.field_1299789221321891843"
74
- }
75
- ]
86
+ "subordination": [
87
+ "1304979556231593994.1299763447342276611.field_1299763447342276617",
88
+ "1304979560546713602.1299789221321891842.field_1299789221321891843"
89
+ ],
90
+ "leftFilterField": [
91
+ {
92
+ "index": 27,
93
+ "currentField": "1304979560546713602.1299789221321891842.field_1299789221321891843",
94
+ "type": "Equals",
95
+ "parentField": "1304979556231593994.1299763447342276611.field_1299763447342276617"
96
+ }
97
+ ]
76
98
  }
77
99
  ```
78
100
 
@@ -83,21 +105,32 @@
83
105
  | parentField | 同 subordination[0] |
84
106
  | currentField | 同 subordination[1] |
85
107
  | type | 匹配关系,跨数据集关联通常用 `Equals` |
86
- | id | **必须等于 currentField**(设计器回显关键) |
108
+ | index | **该条条件自身的唯一序号**(设计器原生形态)—— ⚠ 不是字段 fieldKey,见 §2.3 |
87
109
 
88
110
  **save 后 fields 表**(`getReportDevInfo`):`leftFilterField`、`subordination` 出现在字段记录顶层(JSON 字符串或数组),不在 `style` 内。
89
111
 
90
- ### 2.3 左父格筛选识别与写入(2026-09 eteams · 必遵)
112
+ ### 2.3 左父格筛选识别与写入(2026-09 eteams 验证 · 必遵)
91
113
 
92
114
  设计器 F2「左父格筛选」下拉按 **fieldKey 注册表** 解析标签;下列写法会导致回显 **`undefined`** 或下拉空白:
93
115
 
94
116
  | 错误写法 | 现象 | 正确写法 |
95
117
  |----------|------|----------|
96
118
  | `parentField: "...field_5"`(截断/臆造字段名) | 父格关联字段显示 undefined | 完整 `{dataSetId}.{sourceId}.field_4746632256695654785` |
97
- | `id: "c43a895a664140dc"`(随机 UUID) | 筛选行无法匹配字段 | **`id` 必须等于 `currentField`(完整 fieldKey)** |
119
+ | `id`/`index` 写成字段 fieldKey | 多格共用同一标识 → 设计器把 N 条当同一条:**改一条全变、删一条全删**(BUILD-115) | **每条条件各自唯一 `index` 序号**,与 currentField 无关 |
98
120
  | `subordination: ["",""]` | 从属关系丢失 | `[parentField, currentField]` 与 leftFilter 同步 |
99
121
  | 仅改 fields 表、workbook 内 `style.cellType` 未同步 | 保存后字段绑定丢失 | workbook + fields **双保存**(见 §4.1) |
100
122
 
123
+ > **🔴 条件标识语义更正(2026-10-30 用户两次点名,E6 金标准实证)**:本表旧版写「`id` 必须等于 `currentField`」是**错的**。
124
+ > ① 平台/设计器认的是 **`index`(序号)**,不是 `id`。条件应写成 `{index, currentField, type, parentField}`;
125
+ > 写 `id` 的条件在设计器里会退化成「按字段归并」,即使 id 全表唯一,UI 里**照样联动**。
126
+ > ② 标识写成 fieldKey ⇒ 同字段的多条条件共享一个标识 ⇒ 设计器当成同一条:
127
+ > **改一个条件另一个跟着变、点一个删除全都被删**(用户原话)。
128
+ > 正解:`index` 全表唯一递增(`normalizeFilterCondIds()` 构建期自动补/改写),门禁第 ⑦ 组 `FILTER_ID_DUP` 兜底。
129
+ >
130
+ > **🔴 指标格左父格口径(E6 金标准)**:Sheet0 指标格 `leftX/leftY` 必须指 **本行 C 列(真实 Field 格)**,
131
+ > 不能指 D 拼接公式列 —— Formula 格没有字段身份,`subordination`/`parentField` 找不到父字段 ⇒ **取数整列 0**。
132
+ > 判据:`(本行 x, 2)`;参考样板 `1331753785429704735` 与用户手调的 E6 完全一致。
133
+
101
134
  **父格坐标(leftX / leftY)**:须指向布局上**真实的左父格单元格**(0-based 列 x、行 y),不能机械套用 `leftY = col - 1`。
102
135
 
103
136
  **纵向堆叠多数据集示例**(进销存-供应商 + 采购进货单,同列 B):
@@ -112,10 +145,10 @@
112
145
  from scripts.left_filter_builder import build_cross_dataset_filter
113
146
 
114
147
  lf, sub = build_cross_dataset_filter(
115
- ds_supplier, src_supplier, "field_4746632256695654785",
116
- ds_purchase, src_purchase, "field_4746633026496455388",
148
+ ds_supplier, src_supplier, "field_4746632256695654785",
149
+ ds_purchase, src_purchase, "field_4746633026496455388",
117
150
  )
118
- # lf[0]["id"] == lf[0]["currentField"] # 必须
151
+ # lf[0]["id"] 是独立唯一雪花号,**不等于** currentField(BUILD-115)
119
152
  ```
120
153
 
121
154
  **保存后验证**(`getReportDevInfo` 抽检首个跨表格,如进货单编号 y=5):
@@ -124,7 +157,61 @@ lf, sub = build_cross_dataset_filter(
124
157
  # parentField / currentField 各含两个 '.' 段;subordination 与 leftFilterField 一致
125
158
  ```
126
159
 
127
- 参考实现:`本地工作目录`、`restore_and_fix_left_filter.js`。
160
+ ### 2.3.1 🔴 关联键必须是「子表关联字段」,不是本列展示字段(2026-09 验证定论)
161
+
162
+ > **血案**:报表 `1315297716934582273`(供应商绩效看板)跨源列**整列为空**,反复换 `Equals`/`Contain`、
163
+ > 换 `left` 指向都无效。最后定位到 `currentField` 写错了字段。
164
+
165
+ | 写作 | 结果 |
166
+ |------|------|
167
+ | `currentField` = 本格要展示的字段(如 评级.现供应商等级 / 风险.风险等级) | ❌ 整列空(拿等级去 Equals 供应商名,永不匹配) |
168
+ | `currentField` = **子表侧参与关联的键字段**(评级.供应商名称 / 风险.关联供应商) | ✅ 正确 |
169
+
170
+ **判定「哪个是关联键字段」**:子表里「指向主表记录」的那个字段(常常是 **Ebuilder 关联表单**控件),
171
+ **不是**你要显示的那一列。入口格展示字段与关联键字段通常是**两个不同字段**。
172
+
173
+ **关联键取值口径(同样致命)**:
174
+
175
+ | 主表侧 parentField | 子表侧 currentField | 结果 |
176
+ |---|---|---|
177
+ | 主表.**数据ID**(Text,值=记录 id) | 子表.Ebuilder 关联字段(原始值=目标记录 id) | ✅ 命中 |
178
+ | 主表.名称(Text 显示名) | 子表.Ebuilder 关联字段 | ❌ 不匹配(id vs 名称) |
179
+
180
+ Ebuilder 关联字段的原始值是**目标记录 id**,所以父格必须拿「数据ID」去比。
181
+ **并且入口格的左父格要指向承载该 id 的那一格**(无该列时新增一个隐藏列放 `id`),
182
+ 不要指向放显示名称的那一列。
183
+
184
+ > ⚠️ 这个「隐藏列」的落库口径是 **列宽 = 0**(`columns[].size = 0`,Excel 隐藏列语义),
185
+ > **不是** `visible:false`、也不是 cell 顶层 `colVisible=0` —— 后两者会被服务端丢弃/归一化成 `"1"`,
186
+ > 结果是留下一条 1px 宽的**可见**细条。详见 ``ref-report-pitfalls.md``(BUILD-16)。
187
+
188
+ ```
189
+ 信息区:A3 供应商名称(根) … M3 数据ID(隐藏列,left→A3)
190
+ 评级入口格 I3:leftX/Y → (2,12)=M3 ← 承载关联 id 的格
191
+ parentField = 信息.数据ID
192
+ currentField = 评级.供应商名称(Ebuilder)
193
+ ```
194
+
195
+ **回读校验**:`subordination` 两段与 `leftFilterField` 的 `parentField`/`currentField` 一致;
196
+ `parentField` 指向主表 id 类字段、`currentField` 指向子表关联字段。
197
+
198
+ 可检索:``ref-report-pitfalls.md``(BUILD-12 / BUILD-13)。
199
+
200
+ ### 2.3.2 子表 1:N → 用「汇总格」收敛成一行(勿让它撑行)
201
+
202
+ 子表一个父记录对应多条时,明细格会**把整行撑开**(出现只有子列有值、主列空白的行)。看板类报表应改为汇总:
203
+
204
+ | 需求 | 配置 |
205
+ |------|------|
206
+ | 条数 | `displayType:"Count"` + `countType:"count"` |
207
+ | 取最大档(如风险等级) | `displayType:"Count"` + `countType:"max"` |
208
+ | 取明细单值 | 无需汇总,`expandType:"NoExpand"`(多值会逗号拼接) |
209
+
210
+ **汇总格三件套(缺一不可)**:`displayType:"Count"` + `expandType:"Vertical"` + `groupType:"none"`。
211
+ ⚠️ 服务端会把 `displayType=Count` **规范化回 `Group`**;用 `NoExpand` 配 Count 会被规范化掉、汇总失效
212
+ (BUILD-14)。汇总按父格分组计算,不会撑行。
213
+
214
+ ⚠️ 汇总后的 **Select 值是裸 optionId**,需补 `transType:"select"` + `transSelectOptions:[{selectValue:id,selectName:名称}]`(BUILD-15)。
128
215
 
129
216
  ### 2.4 业务映射示例(EBU 报表)
130
217
 
@@ -139,22 +226,20 @@ lf, sub = build_cross_dataset_filter(
139
226
 
140
227
  ```python
141
228
  def field_key_ref(ds_id, src_id, field):
142
- return f"{ds_id}.{src_id}.{field['name']}"
229
+ return f"{ds_id}.{src_id}.{field['name']}"
143
230
 
144
231
  def make_subordination(p_ds_id, p_src_id, p_field, c_ds_id, c_src_id, c_field):
145
- return [
146
- field_key_ref(p_ds_id, p_src_id, p_field),
147
- field_key_ref(c_ds_id, c_src_id, c_field),
148
- ]
232
+ return [
233
+ field_key_ref(p_ds_id, p_src_id, p_field),
234
+ field_key_ref(c_ds_id, c_src_id, c_field),
235
+ ]
149
236
 
150
237
  def make_left_filter(p_ds_id, p_src_id, p_field, c_ds_id, c_src_id, c_field):
151
- ck = field_key_ref(c_ds_id, c_src_id, c_field)
152
- pk = field_key_ref(p_ds_id, p_src_id, p_field)
153
- return [{"parentField": pk, "currentField": ck, "type": "Equals", "id": ck}]
238
+ ck = field_key_ref(c_ds_id, c_src_id, c_field)
239
+ pk = field_key_ref(p_ds_id, p_src_id, p_field)
240
+ return [{"parentField": pk, "currentField": ck, "type": "Equals", "id": ck}]
154
241
  ```
155
242
 
156
- 参考实现:`本地工作目录`。
157
-
158
243
  ---
159
244
 
160
245
  ## 三、单元格自定义筛选(customFilterField)
@@ -166,42 +251,66 @@ def make_left_filter(p_ds_id, p_src_id, p_field, c_ds_id, c_src_id, c_field):
166
251
  | **单元格 customFilterField** | `style.cellType.customFilterField` | 该单元格取数时的行级条件 |
167
252
  | **数据集 datasetFilter** | `saveReportWithCacheConfig` 的 `datasetFilter` 参数 | 整个数据集的基础过滤 |
168
253
 
169
- `currentField` 必须是 **fieldKey**;`id` 平台可接受但设计器回写**不带**(2026-10 抓包),所以
170
- 新写入以设计器形状为准:
254
+ 单元格自定义筛选同样必须使用 **fieldKey** 作为 `currentField`;每条条件配唯一 `index`(不是 `id`)。
255
+
256
+ ### 3.2 数据结构
171
257
 
172
258
  ```json
173
- [
174
- { "index": 1,
175
- "currentField": "{dataSetId}.{sourceId}.{fieldName}",
176
- "type": "Equals",
177
- "value": ["1"] }
178
- ]
259
+ {
260
+ "customFilterField": [
261
+ {
262
+ "index": 101,
263
+ "currentField": "1304979560546713602.1299789221321891842.field_1299789221321891843",
264
+ "type": "NotContain",
265
+ "value": "某核算机构"
266
+ },
267
+ {
268
+ "index": 102,
269
+ "currentField": "1304979560546713602.1299789221321891842.field_1299789221321891844",
270
+ "type": "Null",
271
+ "value": ""
272
+ }
273
+ ]
274
+ }
179
275
  ```
180
276
 
181
- **选项类字段**(Select / RadioBox / CheckBox / …)的 `value` 是**选项 valueKey 数组**;
182
- 文本/数字/日期写字符串。手工拼报文时容易只写选项显示名 —— 平台有时能按名称兜底,
183
- 但设计器回显会变成空,按 valueKey 写最稳。
184
-
185
- ### 3.2 用 CLI 写入(推荐)
277
+ ### 3.2.1 🔴 筛选 value 形态:按字段类型分流(★★ 全局规则 A0.20 · 2026-10-29 实证更正)
186
278
 
187
- ```bash
188
- # 自定义筛选:分类 等于 甲(选项名自动换成 valueKey)
189
- e10-cli report cell-filter set <reportId> --app-id <appId> \
190
- --cell 1,0 --op 等于 --value 甲
279
+ **触发条件**:`customFilterField` 绑定的字段为 select/文本类型,且 `type` ∈ {`Include`, `Equals`, `Contain`, `NotContain`}。所有报表生成任务统一生效。
191
280
 
192
- # 指定同一数据集里的其他字段,追加第二条条件
193
- e10-cli report cell-filter set ... --field 金额 --op 大于 --value 100 --append
281
+ **正确写法(唯一合法判据 = 字段元数据 `originFieldType`;多选一律 JSON 数组 · 2026-10-29 源码定案)**:
194
282
 
195
- # 结果筛选(前多少个 / 后多少个 / 奇数 / 偶数 / 特定)
196
- e10-cli report cell-filter set ... --cell 1,1 --kind result --op 前几个 --value 1
283
+ | 字段类型 | originFieldType | value 形态 | 例 |
284
+ |---|---|---|---|
285
+ | **真 select**(单选/多选/下拉) | `RadioBox` / `CheckBox` / `Select` 等 | **optionId 的 JSON 数组**(多值)/ 单 optionId 字符串(单值) | `value:["1330…621","1330…622"]` |
286
+ | **文本** | `String` / `Text` | **文本值逗号分隔**(即显示名形态) | `value:"优秀,合格"` |
197
287
 
198
- # 读回 / 清除
199
- e10-cli report cell-filter list <reportId> --app-id <appId>
200
- e10-cli report cell-filter remove <reportId> --app-id <appId> --cell 1,0
288
+ ```json
289
+ {
290
+ "customFilterField": [
291
+ {
292
+ "currentField": "{dataSetId}.{sourceId}.{字段名}",
293
+ "type": "Include",
294
+ "value": ["{optionId1}", "{optionId2}"],
295
+ "index": 103
296
+ }
297
+ ]
298
+ }
201
299
  ```
202
300
 
203
- 命令会改 `fields[]` + workbook `style.cellType`、双保存并回读比对;`designKey` 过期
204
- (code=200 + `data:"您当前的数据不是最新的…"`)会自动重读重写一次。
301
+ **为什么真 select 字段必须 optionId 数组(2026-10-29 源码级定案,route_ReportDesigner chunk 反编译实证)**:
302
+ 1. **数据行存的就是 optionId**(BUILD-15 实证)——筛选 value 写显示名**运行期一条都筛不出来**。
303
+ 2. **设计器弹窗写回函数**(`Ut`):`n({...t,[e]:r})` —— 多选 `Select multiple` 的 onChange 传**选项 id 数组**,**原样**写入 `value` ⇒ 设计器原生形态就是 optionId 数组。
304
+ 3. **弹窗回显匹配**:选项映射 `Y=L.map(e=>(ne===e.name&&(x(e.id),ne=e.id),{id:e.id,content:e.name}))` —— Select 按**数组中的 optionId** 勾选;仅「value 精确等于单个选项显示名」这一种历史字符串会被救成单 id。**逗号字符串既不是数组也不等于单个显示名** ⇒ 运行期引擎能切分逗号(预览生效)但弹窗值框永远「请选择」空白(三轮实证:显示名串 / optionId 逗号串均空白,仅数组形态回显)。
305
+
306
+ **⚠ 结论更正记录(勿回退)**:
307
+ - 2026-10-28 版「select 必须显示名」:金标准(员工培训参训情况汇总表 (2,8))实为 **Text 字段**(`originFieldType:String`),显示名只是 Text 形态。
308
+ - 2026-10-29 v1「select 必须逗号 optionId」:运行期正确、弹窗不回显——逗号串是**运行期容错形态**,非设计器原生形态。
309
+ - **终版:多选 = optionId JSON 数组;单值 = 单 optionId 字符串;Text = 文本逗号串。**
310
+
311
+ **金标准方法论(判定 value 形态的通用方法)**:写筛选前先取字段元数据(`fieldsBySource(srcId, appId).find(f=>f.name==='field_xxx')`),看 `originFieldType` / `config.type` / `config.options`:有 `options` 且类型为 RadioBox 族 → optionId 形态(选项 id 取 `config.options[].value`);String/Text → 文本形态。**人工配置样例必须先核字段类型再对照**。
312
+
313
+ **构建期检查(2026-10-29 降级)**:构建层 对 optionId 形态 value 默认**只告警不拦截**(构建期无法判定字段类型);`opts.enforceSelectFilterValues === true` 显式恢复拦截。`verify_self_check` 同步降为 warning。
205
314
 
206
315
  ### 3.3 type 枚举(平台值)
207
316
 
@@ -223,15 +332,15 @@ e10-cli report cell-filter remove <reportId> --app-id <appId> --cell 1,0
223
332
  需求 Excel 中常见写法 → API 配置:
224
333
 
225
334
  ```
226
- 核算机构 不包含 机构A,机构B → type: NotContain, value: 机构A(多条则多个 filter 项)
227
- 核算机构 为空 → type: Null, value: ""
228
- 年度={year} → type: Equals, value: "{year}"(系统参数原样保留)
335
+ 核算机构 不包含 机构A,机构B → type: NotContain, value: 机构A(多条则多个 filter 项)
336
+ 核算机构 为空 → type: Null, value: ""
337
+ 年度={year} → type: Equals, value: "{year}"(系统参数原样保留)
229
338
  ```
230
339
 
231
340
  ```python
232
341
  FILTER_TYPE_MAP = {
233
- "eq": "Equals", "uncontains": "NotContain",
234
- "empty": "Null", "nempty": "NotNull",
342
+ "eq": "Equals", "uncontains": "NotContain",
343
+ "empty": "Null", "nempty": "NotNull",
235
344
  }
236
345
  ```
237
346
 
@@ -253,12 +362,13 @@ FILTER_TYPE_MAP = {
253
362
  - [ ] `subordination` 为两段 fieldKey,非 `["",""]`
254
363
  - [ ] `leftFilterField` 非空,且 `parentField`/`currentField` 含两个 `.`
255
364
  - [ ] `customFilterField`(若有)的 `type` 为平台枚举
365
+ - [ ] **筛选 value 形态与字段类型匹配**:真 select(RadioBox 族)→ optionId 逗号分隔;Text/String → 文本值(A0.20 · 2026-10-29 更正 / §3.2.1)
256
366
  - [ ] 设计器打开后左父格筛选、自定义筛选下拉**有选中项**(非空白)
257
367
 
258
368
  ### 4.3 配置校验脚本
259
369
 
260
370
  ```bash
261
- python e10-cli report validate <配置文件路径>
371
+ e10-cli report py validate <配置文件路径>
262
372
  ```
263
373
 
264
374
  脚本会检查 fieldKey 格式、type 枚举、customFilterField 结构。
@@ -269,8 +379,9 @@ python e10-cli report validate <配置文件路径>
269
379
 
270
380
  ### 5.1 设计器筛选下拉空白
271
381
 
272
- 1. 确认 `parentField`/`currentField`/`id` 均为 `{dataSetId}.{sourceId}.{fieldName}`
382
+ 1. 确认 `parentField`/`currentField` 均为 `{dataSetId}.{sourceId}.{fieldName}`;`id` 为该条条件的**唯一雪花号**(不是 fieldKey,BUILD-115)
273
383
  2. 确认 `dataSetId` 是报表内数据集 ID,不是 appId / reportId
384
+ 3. **select 字段:确认 `value` 是选项显示名而非 optionId**(A0.20 / §3.2.1,注意点 BUILD-98)——这是本症状最高频根因
274
385
  3. 确认 `fieldName` 来自 `ds/fields` 接口的 `name` 字段
275
386
  4. 双保存后刷新设计器
276
387
 
@@ -292,7 +403,7 @@ python e10-cli report validate <配置文件路径>
292
403
  2. 对每个跨数据集列生成 `subordination` + `leftFilterField`(fieldKey + `id`)
293
404
  3. 对需求中的过滤条件生成 `customFilterField`(fieldKey + 平台 type)
294
405
  4. 含 Formula 单元格时遵守 `formula-cell-api-guide.md`(cellText 无前导 `=`)
295
- 5. 运行 `validate_report_config.py` 预检
406
+ 5. 运行 `e10-cli report py validate` 预检
296
407
  6. 若通过 API 保存,执行双保存并用 `getReportDevInfo` 验证
297
408
 
298
409
  ---