weaver-e10-builder 1.6.10 → 1.6.11

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 (155) hide show
  1. package/dist/commands/report-admin.d.ts.map +1 -1
  2. package/dist/commands/report-admin.js +378 -2
  3. package/dist/commands/report-admin.js.map +1 -1
  4. package/dist/commands/report-validate.d.ts.map +1 -1
  5. package/dist/commands/report-validate.js +1066 -3
  6. package/dist/commands/report-validate.js.map +1 -1
  7. package/dist/commands/report.d.ts.map +1 -1
  8. package/dist/commands/report.js +341 -3
  9. package/dist/commands/report.js.map +1 -1
  10. package/dist/commands/workflow-after-submit-comment.d.ts +3 -0
  11. package/dist/commands/workflow-after-submit-comment.d.ts.map +1 -0
  12. package/dist/commands/workflow-after-submit-comment.js +56 -0
  13. package/dist/commands/workflow-after-submit-comment.js.map +1 -0
  14. package/dist/commands/workflow-setting.d.ts.map +1 -1
  15. package/dist/commands/workflow-setting.js +2 -67
  16. package/dist/commands/workflow-setting.js.map +1 -1
  17. package/dist/services/report/blueprint.d.ts +109 -0
  18. package/dist/services/report/blueprint.d.ts.map +1 -0
  19. package/dist/services/report/blueprint.js +322 -0
  20. package/dist/services/report/blueprint.js.map +1 -0
  21. package/dist/services/report/build.d.ts.map +1 -1
  22. package/dist/services/report/build.js +8 -3
  23. package/dist/services/report/build.js.map +1 -1
  24. package/dist/services/report/card.d.ts +65 -0
  25. package/dist/services/report/card.d.ts.map +1 -0
  26. package/dist/services/report/card.js +151 -0
  27. package/dist/services/report/card.js.map +1 -0
  28. package/dist/services/report/copy-health.d.ts +31 -0
  29. package/dist/services/report/copy-health.d.ts.map +1 -0
  30. package/dist/services/report/copy-health.js +87 -0
  31. package/dist/services/report/copy-health.js.map +1 -0
  32. package/dist/services/report/dataset-heal.d.ts +64 -0
  33. package/dist/services/report/dataset-heal.d.ts.map +1 -0
  34. package/dist/services/report/dataset-heal.js +89 -0
  35. package/dist/services/report/dataset-heal.js.map +1 -0
  36. package/dist/services/report/dataset-ids.d.ts +70 -0
  37. package/dist/services/report/dataset-ids.d.ts.map +1 -0
  38. package/dist/services/report/dataset-ids.js +149 -0
  39. package/dist/services/report/dataset-ids.js.map +1 -0
  40. package/dist/services/report/dataset.d.ts.map +1 -1
  41. package/dist/services/report/dataset.js +3 -1
  42. package/dist/services/report/dataset.js.map +1 -1
  43. package/dist/services/report/empty-dataset.d.ts +51 -0
  44. package/dist/services/report/empty-dataset.d.ts.map +1 -0
  45. package/dist/services/report/empty-dataset.js +213 -0
  46. package/dist/services/report/empty-dataset.js.map +1 -0
  47. package/dist/services/report/field-binding.d.ts +75 -0
  48. package/dist/services/report/field-binding.d.ts.map +1 -0
  49. package/dist/services/report/field-binding.js +160 -0
  50. package/dist/services/report/field-binding.js.map +1 -0
  51. package/dist/services/report/forms.d.ts +32 -0
  52. package/dist/services/report/forms.d.ts.map +1 -1
  53. package/dist/services/report/forms.js +90 -0
  54. package/dist/services/report/forms.js.map +1 -1
  55. package/dist/services/report/formula-parent.d.ts +25 -0
  56. package/dist/services/report/formula-parent.d.ts.map +1 -0
  57. package/dist/services/report/formula-parent.js +116 -0
  58. package/dist/services/report/formula-parent.js.map +1 -0
  59. package/dist/services/report/locate.d.ts +40 -0
  60. package/dist/services/report/locate.d.ts.map +1 -0
  61. package/dist/services/report/locate.js +122 -0
  62. package/dist/services/report/locate.js.map +1 -0
  63. package/dist/services/report/reports.d.ts +4 -0
  64. package/dist/services/report/reports.d.ts.map +1 -1
  65. package/dist/services/report/reports.js +4 -2
  66. package/dist/services/report/reports.js.map +1 -1
  67. package/dist/services/report/scene.d.ts +22 -0
  68. package/dist/services/report/scene.d.ts.map +1 -0
  69. package/dist/services/report/scene.js +145 -0
  70. package/dist/services/report/scene.js.map +1 -0
  71. package/dist/services/report/types.d.ts +28 -0
  72. package/dist/services/report/types.d.ts.map +1 -1
  73. package/dist/services/report/verify.d.ts +24 -0
  74. package/dist/services/report/verify.d.ts.map +1 -1
  75. package/dist/services/report/verify.js +115 -2
  76. package/dist/services/report/verify.js.map +1 -1
  77. package/dist/services/report/workbook.d.ts +12 -1
  78. package/dist/services/report/workbook.d.ts.map +1 -1
  79. package/dist/services/report/workbook.js +107 -8
  80. package/dist/services/report/workbook.js.map +1 -1
  81. package/dist/services/workflow-after-submit-comment.d.ts +20 -0
  82. package/dist/services/workflow-after-submit-comment.d.ts.map +1 -0
  83. package/dist/services/workflow-after-submit-comment.js +81 -0
  84. package/dist/services/workflow-after-submit-comment.js.map +1 -0
  85. package/ecodecmd/src/build.js +36 -12
  86. package/package.json +1 -1
  87. package/skill-docs/SKILL.md +4 -4
  88. package/skill-docs/_catalog.md +10 -1
  89. package/skill-docs/references/coding/guide-page-code.md +95 -0
  90. package/skill-docs/references/components/ref-component-common.md +98 -0
  91. package/skill-docs/references/report/add-dataset-registration-guide.md +44 -22
  92. package/skill-docs/references/report/advanced-crosstab-tree-guide.md +82 -0
  93. package/skill-docs/references/report/ai-report-workflow.md +100 -100
  94. package/skill-docs/references/report/api-auth-headers.md +129 -0
  95. package/skill-docs/references/report/api-report-build-fast-path.md +274 -275
  96. package/skill-docs/references/report/app-datasource-lookup-guide.md +230 -230
  97. package/skill-docs/references/report/branch-scene-guide.md +293 -0
  98. package/skill-docs/references/report/build-resilience-guide.md +99 -0
  99. package/skill-docs/references/report/card-report-guide.md +110 -0
  100. package/skill-docs/references/report/cell-config-echo-guide.md +44 -9
  101. package/skill-docs/references/report/cell-transform-guide.md +9 -9
  102. package/skill-docs/references/report/column-split-report-guide.md +96 -0
  103. package/skill-docs/references/report/condition-format-guide.md +49 -24
  104. package/skill-docs/references/report/cross-dataset-filter-guide.md +180 -69
  105. package/skill-docs/references/report/crosstab-raw-workbook-guide.md +265 -0
  106. package/skill-docs/references/report/dataset-query-filter-guide.md +231 -235
  107. package/skill-docs/references/report/dataset-sidebar-ops-guide.md +75 -34
  108. package/skill-docs/references/report/dataset-table-field-contract-guide.md +196 -46
  109. package/skill-docs/references/report/datasource-metadata-guide.md +128 -119
  110. package/skill-docs/references/report/datasource-selection-and-parent-filter-guide.md +183 -148
  111. package/skill-docs/references/report/date-range-query-reference.md +97 -102
  112. package/skill-docs/references/report/default-header-style-guide.md +8 -8
  113. package/skill-docs/references/report/designer-blank-prevention-guide.md +8 -8
  114. package/skill-docs/references/report/dossier-report-guide.md +69 -0
  115. package/skill-docs/references/report/drilldown-report-guide.md +59 -0
  116. package/skill-docs/references/report/event-hreflink-guide.md +53 -47
  117. package/skill-docs/references/report/expansion-block-parent-config-guide.md +208 -0
  118. package/skill-docs/references/report/failure-cleanup-and-nonblocking-guide.md +183 -0
  119. package/skill-docs/references/report/field-bind-exact-match-guide.md +208 -208
  120. package/skill-docs/references/report/financial-stats-report-guide.md +89 -0
  121. package/skill-docs/references/report/formula-cell-api-guide.md +325 -258
  122. package/skill-docs/references/report/golden-case-summary-sheet.md +200 -0
  123. package/skill-docs/references/report/guide-report-build.md +6 -1
  124. package/skill-docs/references/report/hidden-row-and-header-merge-guide.md +10 -10
  125. package/skill-docs/references/report/layout-showlocation-freeze-guide.md +39 -10
  126. package/skill-docs/references/report/multi-report-crosstab-casebook.md +263 -0
  127. package/skill-docs/references/report/paged-group-report-guide.md +68 -0
  128. package/skill-docs/references/report/preaggregate-auto-disable-guide.md +24 -13
  129. package/skill-docs/references/report/query-condition-api-guide.md +145 -125
  130. package/skill-docs/references/report/ref-report-commands.md +41 -3
  131. package/skill-docs/references/report/report-baseinfo-defaults-guide.md +117 -117
  132. package/skill-docs/references/report/report-building-guide.md +52 -52
  133. package/skill-docs/references/report/report-case-prompts.md +104 -0
  134. package/skill-docs/references/report/report-config-schema.md +281 -281
  135. package/skill-docs/references/report/report-create-modes-guide.md +73 -35
  136. package/skill-docs/references/report/report-data-model.md +131 -131
  137. package/skill-docs/references/report/report-delivery-contract.md +23 -3
  138. package/skill-docs/references/report/report-designer-feature-map.md +30 -35
  139. package/skill-docs/references/report/report-help-guide.md +304 -0
  140. package/skill-docs/references/report/report-internal-error-guide.md +71 -0
  141. package/skill-docs/references/report/report-knowledge-base.md +27 -27
  142. package/skill-docs/references/report/report-lifecycle-api-guide.md +126 -94
  143. package/skill-docs/references/report/report-list-page-ops-guide.md +54 -8
  144. package/skill-docs/references/report/report-permission-guide.md +99 -102
  145. package/skill-docs/references/report/report-requirement-analysis-template.md +93 -29
  146. package/skill-docs/references/report/report-self-check-guide.md +164 -164
  147. package/skill-docs/references/report/report-verification-discipline-guide.md +203 -0
  148. package/skill-docs/references/report/safe-partial-save-guide.md +151 -151
  149. package/skill-docs/references/report/shard-freeze-report-guide.md +97 -0
  150. package/skill-docs/references/report/snowflake-id-precision-guide.md +84 -84
  151. package/skill-docs/references/report/spec-build-schema.md +71 -71
  152. package/skill-docs/references/report/targeted-fix-guide.md +155 -97
  153. package/skill-docs/references/report/user-request-scope-only-guide.md +23 -4
  154. package/skill-docs/references/workflow/guide-after-submit-comment.md +58 -0
  155. package/skill-docs/references/workflow/guide-workflow.md +6 -0
@@ -1,164 +1,164 @@
1
- # 报表落库自检(强制)
2
-
3
- > **适用**:API/脚本保存布局后、交付设计器链接前(可后台跑,但**不得跳过**)。
4
- > **目标**:尽早发现字段丢失、伪父格、绑定失败、超链接被冲掉,避免「设计器看着有格、取数/父格全错」。
5
-
6
- ---
7
-
8
- ## 一、父格坐标语义(勿混)
9
-
10
- | API `leftX/leftY` 或 `topX/topY` | 设计器含义 | 说明 |
11
- |----------------------------------|------------|------|
12
- | **`-1, -1`** | **默认** 或 **无** | 普通 Const / 单数据集 Field 的常见正确态 |
13
- | **`0, 0`** | **自定义 → 原点 (0,0)** | **不是默认**;写成 0,0 会显示父格「不对」 |
14
- | **其它 `x,y`** | **自定义** 指向该坐标 | 多数据集入口、交叉、**超链接占位依赖**等 |
15
-
16
- ---
17
-
18
- ## 二、按单元格类型的父格规则
19
-
20
- ### 2.1 普通 Const(表头 / 标题 / 无链接)
21
-
22
- | 项 | 规则 |
23
- |----|------|
24
- | 左父格 | **`-1,-1`** |
25
- | 上父格 | **`-1,-1`** |
26
- | 禁止 | `(0,0)`;勿把「默认」误写成原点 |
27
-
28
- ### 2.2 超链接 Const(`pcHreflink` / `h5Hreflink`,URL 含 `{L4}` `{C4}` 等)
29
-
30
- > **事故**:把「左父格默认」套到「点击查看」上 → 设计器左/上显示不对,且 `{L4}` 无法解析;或重建 workbook 时丢掉 `ConstCellType.cellText` → 保存后 `cellText` 变空、`pcHreflink` 丢失。
31
-
32
- | 项 | 规则 | 例(供应商表 M4) |
33
- |----|------|-------------------|
34
- | **上父格** | 无横向扩展时必须 **`topX=topY=-1`**(不需要上父格) | `(-1,-1)` |
35
- | **左父格** | **禁止**一律改成默认;须指向占位符依赖的数据格 | `{L4}` → 左父格 **`(3,11)`**(同行「数据ID」) |
36
- | **链接元数据** | 须进 **workbook `ConstCellType`**(`pcHreflink`/`openType`/`cellText`/`left*`/`top*`);仅写 `fields[]` **不够** | `/sp/ebdfpage/card/0/{sourceId}/{L4}` |
37
- | **workbook** | `ConstCellType` 必须含:`cellText`、`leftX/leftY/topX/topY`、有链接时还要 `pcHreflink` | 服务端 `saveReportDevInfo` **从 cellType 回写 fields**;缺 `leftX` → Java int **0** → 伪 `(0,0)`;缺 `pcHreflink` → 链接丢失 |
38
- | **禁止** | 只塞 `{typeName,cellText}` 的残 ConstCellType;禁止左=`(0,0)`;禁止有 `{Ln}` 却左=`-1,-1` |
39
-
40
- **占位符 → 左父格**(自检算法):
41
-
42
- 1. 从 `pcHreflink`/`h5Hreflink` 提取 `{L4}` / `{C4}` / `{Ln}` 等。
43
- 2. `{L4}`:同行纵向扩展语境下,左父格应指向同列(或约定列)上提供 ID 的 Field(本需求为 `(3,11)`)。
44
- 3. 若 URL 含占位而 `leftX/leftY === -1` → **FAIL**(不是「默认正确」)。
45
- 4. 若 `topX/topY !== -1` 且无横向交叉需求 → **FAIL**。
46
-
47
- ### 2.3 Field(单数据集、无指定计算)
48
-
49
- | 场景 | 左父格 |
50
- |------|--------|
51
- | **新建**报表 | 优先 **`-1,-1`(默认)** |
52
- | **已有**报表 | **禁止**用户未点名时批量改父格 |
53
-
54
- ---
55
-
56
- ## 三、保存门禁(每次 `saveReportDevInfo`)
57
-
58
- ### 保存前
59
-
60
- 1. `fields` 中 `cellType=Field` 数量 ≥ 保存前(或与预期列数一致)。
61
- 2. workbook `dataTable` 内 `FieldCellType` 数量 ≥ Field 数。
62
- 3. 每个 **Const**:workbook `ConstCellType` 须含 `cellText`(有文案时)以及显式 **`leftX/leftY/topX/topY`(常用 -1,禁止省略)**。
63
- 4. 每个 **超链接 Const**:`ConstCellType` 须含非空 `pcHreflink`、`openType`,且父格与 `fields` 一致(服务端以 workbook 为准回写)。
64
- 5. 每个 Field:`name` ∈ `fieldsAndOriginFields.fieldsKey[].name`(须带 `field_`;禁止裸雪花 ID)。
65
- - 拉 fieldsKey 参数名用 **`datasetId`**(不是 `dataSetId`)。
66
-
67
- ### 保存后立刻回读
68
-
69
- | 检查项 | 失败标准 |
70
- |--------|----------|
71
- | Field 数量 | 比保存前减少 → **立即失败**,禁止再改,优先恢复 |
72
- | Field.`name` | 裸 ID 或不在 fieldsKey → FAIL(`e10-cli report verify bind`) |
73
- | 普通 Const 父格 | `left=top=(0,0)` → FAIL(伪自定义 A1) |
74
- | 超链接 Const | 缺 `pcHreflink` / `cellText` 空 / `top≠-1` / 含 `{L*}` 但 `left=-1` 或 `left=(0,0)` → FAIL |
75
- | 同数据集 leftFilterField | Field 上仍有跨源 leftFilter → WARN/FAIL |
76
-
77
- ```bash
78
- e10-cli report verify bind <reportId> [appId] # 字段绑定
79
- e10-cli report verify self <reportId> [appId] # 父格/超链接自检
80
- e10-cli report verify all <reportId> [appId] # 自检 + 绑定(推荐)
81
- ```
82
-
83
- ---
84
-
85
- ## 四、Agent 自检脚本逻辑(摘要)
86
-
87
- ```javascript
88
- function assertParents(fields) {
89
- for (const f of fields) {
90
- if (f.cellType !== 'Const') continue;
91
- const origin =
92
- f.leftX === 0 && f.leftY === 0 && f.topX === 0 && f.topY === 0;
93
- const href = f.pcHreflink || f.h5Hreflink || '';
94
- if (origin && !href) {
95
- throw new Error(`Const(${f.x},${f.y}) 父格(0,0)=伪自定义A1,应为-1,-1`);
96
- }
97
- if (!href) continue;
98
- // 超链接:上父格默认无
99
- if (f.topX !== -1 || f.topY !== -1) {
100
- throw new Error(`链接格(${f.x},${f.y}) 不需要上父格,top 应为 -1,-1`);
101
- }
102
- if (!f.cellText) {
103
- throw new Error(`链接格(${f.x},${f.y}) cellText 为空(workbook 可能未写 ConstCellType)`);
104
- }
105
- // URL 占位依赖左父格,禁止「默认」
106
- if (/\{L\d+\}|\{C\d+\}/.test(href)) {
107
- if (f.leftX === -1 && f.leftY === -1) {
108
- throw new Error(`链接格(${f.x},${f.y}) 含占位符但左父格为默认,应指向依赖数据格`);
109
- }
110
- if (f.leftX === 0 && f.leftY === 0) {
111
- throw new Error(`链接格(${f.x},${f.y}) 左父格不能为(0,0)`);
112
- }
113
- }
114
- }
115
- }
116
-
117
- function assertWorkbookConstCellType(dataTable, fields) {
118
- for (const f of fields) {
119
- if (f.cellType !== 'Const') continue;
120
- const cell = dataTable?.[String(f.x)]?.[String(f.y)];
121
- const ct = cell?.style?.cellType;
122
- if (!ct || ct.typeName !== 'ConstCellType') {
123
- throw new Error(`workbook 缺 ConstCellType @(${f.x},${f.y})`);
124
- }
125
- if ((f.cellText || f.text) && !ct.cellText) {
126
- throw new Error(`workbook 缺 cellText @(${f.x},${f.y}),保存会冲掉文案`);
127
- }
128
- // 缺 leftX 时服务端写成 0 → 伪自定义 A1
129
- for (const k of ['leftX', 'leftY', 'topX', 'topY']) {
130
- if (ct[k] === undefined || ct[k] === null) {
131
- throw new Error(`workbook ConstCellType 缺 ${k} @(${f.x},${f.y}),会落成 0`);
132
- }
133
- }
134
- if (f.pcHreflink && ct.pcHreflink !== f.pcHreflink) {
135
- throw new Error(`workbook 缺/错 pcHreflink @(${f.x},${f.y})(服务端只认 cellType)`);
136
- }
137
- }
138
- }
139
-
140
- function assertFieldPreserved(before, after) {
141
- const n = (fs) => fs.filter((f) => f.cellType === 'Field').length;
142
- if (n(after) < n(before)) throw new Error('Field 被冲掉,禁止继续改');
143
- }
144
- ```
145
-
146
- ---
147
-
148
- ## 五、与交付节奏
149
-
150
- - 布局落库成功 → **先交设计器地址**(`report-delivery-contract.md` §〇)。
151
- - 本节自检可后台跑;**FAIL 必须补丁修复并告知**,不得假装完成。
152
- - **禁止**:为修一格 Const 父格而提交残缺 workbook(会导致 Field 全变 Const,或 Const 文案/超链接被冲掉)。修父格必须 **整表 Field + ConstCellType 完整写入 workbook**。
153
-
154
- ---
155
-
156
- ## 六、相关文档
157
-
158
- | 文档 | 关系 |
159
- |------|------|
160
- | `field-bind-exact-match-guide.md` | name ∈ fieldsKey |
161
- | `datasource-selection-and-parent-filter-guide.md` §〇 | 单数据集左父格默认;**勿**套用到超链接 Const;勿擅自改已有表 |
162
- | `safe-partial-save-guide.md` | 禁止空 workbook;须从 fields 重建 dataTable |
163
- | `e10-cli report verify bind` | 绑定门禁 |
164
- | `targeted-fix-guide.md` | 用户点名某处不对时禁止整表重扫 |
1
+ # 报表落库自检(强制)
2
+
3
+ > **适用**:API/脚本保存布局后、交付设计器链接前(可后台跑,但**不得跳过**)。
4
+ > **目标**:尽早发现字段丢失、伪父格、绑定失败、超链接被冲掉,避免「设计器看着有格、取数/父格全错」。
5
+
6
+ ---
7
+
8
+ ## 一、父格坐标语义(勿混)
9
+
10
+ | API `leftX/leftY` 或 `topX/topY` | 设计器含义 | 说明 |
11
+ |----------------------------------|------------|------|
12
+ | **`-1, -1`** | **默认** 或 **无** | 普通 Const / 单数据集 Field 的常见正确态 |
13
+ | **`0, 0`** | **自定义 → 原点 (0,0)** | **不是默认**;写成 0,0 会显示父格「不对」 |
14
+ | **其它 `x,y`** | **自定义** 指向该坐标 | 多数据集入口、交叉、**超链接占位依赖**等 |
15
+
16
+ ---
17
+
18
+ ## 二、按单元格类型的父格规则
19
+
20
+ ### 2.1 普通 Const(表头 / 标题 / 无链接)
21
+
22
+ | 项 | 规则 |
23
+ |----|------|
24
+ | 左父格 | **`-1,-1`** |
25
+ | 上父格 | **`-1,-1`** |
26
+ | 禁止 | `(0,0)`;勿把「默认」误写成原点 |
27
+
28
+ ### 2.2 超链接 Const(`pcHreflink` / `h5Hreflink`,URL 含 `{L4}` `{C4}` 等)
29
+
30
+ > **事故**:把「左父格默认」套到「点击查看」上 → 设计器左/上显示不对,且 `{L4}` 无法解析;或重建 workbook 时丢掉 `ConstCellType.cellText` → 保存后 `cellText` 变空、`pcHreflink` 丢失。
31
+
32
+ | 项 | 规则 | 例(供应商表 M4) |
33
+ |----|------|-------------------|
34
+ | **上父格** | 无横向扩展时必须 **`topX=topY=-1`**(不需要上父格) | `(-1,-1)` |
35
+ | **左父格** | **禁止**一律改成默认;须指向占位符依赖的数据格 | `{L4}` → 左父格 **`(3,11)`**(同行「数据ID」) |
36
+ | **链接元数据** | 须进 **workbook `ConstCellType`**(`pcHreflink`/`openType`/`cellText`/`left*`/`top*`);仅写 `fields[]` **不够** | `/sp/ebdfpage/card/0/{sourceId}/{L4}` |
37
+ | **workbook** | `ConstCellType` 必须含:`cellText`、`leftX/leftY/topX/topY`、有链接时还要 `pcHreflink` | 服务端 `saveReportDevInfo` **从 cellType 回写 fields**;缺 `leftX` → Java int **0** → 伪 `(0,0)`;缺 `pcHreflink` → 链接丢失 |
38
+ | **禁止** | 只塞 `{typeName,cellText}` 的残 ConstCellType;禁止左=`(0,0)`;禁止有 `{Ln}` 却左=`-1,-1` |
39
+
40
+ **占位符 → 左父格**(自检算法):
41
+
42
+ 1. 从 `pcHreflink`/`h5Hreflink` 提取 `{L4}` / `{C4}` / `{Ln}` 等。
43
+ 2. `{L4}`:同行纵向扩展语境下,左父格应指向同列(或约定列)上提供 ID 的 Field(本需求为 `(3,11)`)。
44
+ 3. 若 URL 含占位而 `leftX/leftY === -1` → **FAIL**(不是「默认正确」)。
45
+ 4. 若 `topX/topY !== -1` 且无横向交叉需求 → **FAIL**。
46
+
47
+ ### 2.3 Field(单数据集、无指定计算)
48
+
49
+ | 场景 | 左父格 |
50
+ |------|--------|
51
+ | **新建**报表 | 优先 **`-1,-1`(默认)** |
52
+ | **已有**报表 | **禁止**用户未点名时批量改父格 |
53
+
54
+ ---
55
+
56
+ ## 三、保存门禁(每次 `saveReportDevInfo`)
57
+
58
+ ### 保存前
59
+
60
+ 1. `fields` 中 `cellType=Field` 数量 ≥ 保存前(或与预期列数一致)。
61
+ 2. workbook `dataTable` 内 `FieldCellType` 数量 ≥ Field 数。
62
+ 3. 每个 **Const**:workbook `ConstCellType` 须含 `cellText`(有文案时)以及显式 **`leftX/leftY/topX/topY`(常用 -1,禁止省略)**。
63
+ 4. 每个 **超链接 Const**:`ConstCellType` 须含非空 `pcHreflink`、`openType`,且父格与 `fields` 一致(服务端以 workbook 为准回写)。
64
+ 5. 每个 Field:`name` ∈ `fieldsAndOriginFields.fieldsKey[].name`(须带 `field_`;禁止裸雪花 ID)。
65
+ - 拉 fieldsKey 参数名用 **`datasetId`**(不是 `dataSetId`)。
66
+
67
+ ### 保存后立刻回读
68
+
69
+ | 检查项 | 失败标准 |
70
+ |--------|----------|
71
+ | Field 数量 | 比保存前减少 → **立即失败**,禁止再改,优先恢复 |
72
+ | Field.`name` | 裸 ID 或不在 fieldsKey → FAIL(`e10-cli report verify bind`) |
73
+ | 普通 Const 父格 | `left=top=(0,0)` → FAIL(伪自定义 A1) |
74
+ | 超链接 Const | 缺 `pcHreflink` / `cellText` 空 / `top≠-1` / 含 `{L*}` 但 `left=-1` 或 `left=(0,0)` → FAIL |
75
+ | 同数据集 leftFilterField | Field 上仍有跨源 leftFilter → WARN/FAIL |
76
+
77
+ ```bash
78
+ e10-cli report verify bind <reportId> [appId] # 字段绑定
79
+ e10-cli report verify self <reportId> [appId] # 父格/超链接自检
80
+ e10-cli report verify all <reportId> [appId] # 自检 + 绑定(推荐)
81
+ ```
82
+
83
+ ---
84
+
85
+ ## 四、Agent 自检脚本逻辑(摘要)
86
+
87
+ ```javascript
88
+ function assertParents(fields) {
89
+ for (const f of fields) {
90
+ if (f.cellType !== 'Const') continue;
91
+ const origin =
92
+ f.leftX === 0 && f.leftY === 0 && f.topX === 0 && f.topY === 0;
93
+ const href = f.pcHreflink || f.h5Hreflink || '';
94
+ if (origin && !href) {
95
+ throw new Error(`Const(${f.x},${f.y}) 父格(0,0)=伪自定义A1,应为-1,-1`);
96
+ }
97
+ if (!href) continue;
98
+ // 超链接:上父格默认无
99
+ if (f.topX !== -1 || f.topY !== -1) {
100
+ throw new Error(`链接格(${f.x},${f.y}) 不需要上父格,top 应为 -1,-1`);
101
+ }
102
+ if (!f.cellText) {
103
+ throw new Error(`链接格(${f.x},${f.y}) cellText 为空(workbook 可能未写 ConstCellType)`);
104
+ }
105
+ // URL 占位依赖左父格,禁止「默认」
106
+ if (/\{L\d+\}|\{C\d+\}/.test(href)) {
107
+ if (f.leftX === -1 && f.leftY === -1) {
108
+ throw new Error(`链接格(${f.x},${f.y}) 含占位符但左父格为默认,应指向依赖数据格`);
109
+ }
110
+ if (f.leftX === 0 && f.leftY === 0) {
111
+ throw new Error(`链接格(${f.x},${f.y}) 左父格不能为(0,0)`);
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ function assertWorkbookConstCellType(dataTable, fields) {
118
+ for (const f of fields) {
119
+ if (f.cellType !== 'Const') continue;
120
+ const cell = dataTable?.[String(f.x)]?.[String(f.y)];
121
+ const ct = cell?.style?.cellType;
122
+ if (!ct || ct.typeName !== 'ConstCellType') {
123
+ throw new Error(`workbook 缺 ConstCellType @(${f.x},${f.y})`);
124
+ }
125
+ if ((f.cellText || f.text) && !ct.cellText) {
126
+ throw new Error(`workbook 缺 cellText @(${f.x},${f.y}),保存会冲掉文案`);
127
+ }
128
+ // 缺 leftX 时服务端写成 0 → 伪自定义 A1
129
+ for (const k of ['leftX', 'leftY', 'topX', 'topY']) {
130
+ if (ct[k] === undefined || ct[k] === null) {
131
+ throw new Error(`workbook ConstCellType 缺 ${k} @(${f.x},${f.y}),会落成 0`);
132
+ }
133
+ }
134
+ if (f.pcHreflink && ct.pcHreflink !== f.pcHreflink) {
135
+ throw new Error(`workbook 缺/错 pcHreflink @(${f.x},${f.y})(服务端只认 cellType)`);
136
+ }
137
+ }
138
+ }
139
+
140
+ function assertFieldPreserved(before, after) {
141
+ const n = (fs) => fs.filter((f) => f.cellType === 'Field').length;
142
+ if (n(after) < n(before)) throw new Error('Field 被冲掉,禁止继续改');
143
+ }
144
+ ```
145
+
146
+ ---
147
+
148
+ ## 五、与交付节奏
149
+
150
+ - 布局落库成功 → **先交设计器地址**(`report-delivery-contract.md` §〇)。
151
+ - 本节自检可后台跑;**FAIL 必须补丁修复并告知**,不得假装完成。
152
+ - **禁止**:为修一格 Const 父格而提交残缺 workbook(会导致 Field 全变 Const,或 Const 文案/超链接被冲掉)。修父格必须 **整表 Field + ConstCellType 完整写入 workbook**。
153
+
154
+ ---
155
+
156
+ ## 六、相关文档
157
+
158
+ | 文档 | 关系 |
159
+ |------|------|
160
+ | `field-bind-exact-match-guide.md` | name ∈ fieldsKey |
161
+ | `datasource-selection-and-parent-filter-guide.md` §〇 | 单数据集左父格默认;**勿**套用到超链接 Const;勿擅自改已有表 |
162
+ | `safe-partial-save-guide.md` | 禁止空 workbook;须从 fields 重建 dataTable |
163
+ | `e10-cli report verify bind` | 绑定门禁 |
164
+ | `targeted-fix-guide.md` | 用户点名某处不对时禁止整表重扫 |
@@ -0,0 +1,203 @@
1
+ # 报表验证纪律指南 — 回读清单 / diff 键 / 字节安全 / 双端差异
2
+
3
+ > 来源:技能竞赛汇总报表 V1/V2 搭建与**四轮公式乱码**定位(2026-10-12)。
4
+ > 适用:所有 E10 e-Builder 报表的 API 搭建、克隆、修改与定位。
5
+ > 关联注意点:`BUILD-46`(refX/refY)· `BUILD-49`(subordination)· `BUILD-51`(保存判定)· `BUILD-52`(字节安全)· `BUILD-53`(本指南)· `BUILD-54`(克隆纪律)。
6
+
7
+ 本指南回答一个问题:**「落库返回 200」之后,凭什么说这张报表是对的?**
8
+
9
+ ---
10
+
11
+ ## 一、结构回读清单(每次落库后必做)
12
+
13
+ `getReportDevInfo` 回读,逐条勾稽:
14
+
15
+ | # | 检查项 | 通过判据 | 工具 |
16
+ |---|--------|---------|------|
17
+ | 1 | **格数一致** | 回读 fields 数 == 期望格数 | `e10-cli report verify diff` / 手动比对 |
18
+ | 2 | **cellType 分布** | Field / Const / Formula / SequenceNumber 各类计数与蓝图一致 | 同上 |
19
+ | 3 | **fieldKey 全自洽** | 每个 Field 格 `fieldKey` 首段 == 本格 `dataSetId` | 回读脚本逐条断言 |
20
+ | 4 | **0 残留旧 id** | workbook 内所有数据集 id ∈ 本报表白名单 | `e10-cli report check-ids --report-id <rid> --app-id <appId>`(exit 3 = 有外来 id) |
21
+ | 5 | **Field 有绑定** | 每个 Field 格 `fieldKey` 非空、`tableName` 带类型后缀 | `getReportDevInfo` 回读 |
22
+ | 6 | **父格链无循环依赖** | 无「左父格指向自身 / 已删格」 | `e10-cli report scene check` / `formula parent check` |
23
+ | 7 | **data 非空** | `save` 的 `json.data` 非空 | 见 §一.1 |
24
+
25
+ ### 一.1 「200 但 data 带告警」也算失败(★ 铁律)
26
+
27
+ `saveReportDevInfo` 返回 `code:200` **不等于**落库有效。父格**循环依赖**这类问题会
28
+ **返回 200、但 `data` 里带告警**。判定必须是:
29
+
30
+ ```js
31
+ // ★ BUILD-51:只看解析后的字段
32
+ const ok = saved.json.code === 200 && saved.json.fail !== true;
33
+ // 且进一步检查 data 非空 / 无告警
34
+ ```
35
+
36
+ **禁止**用 `String(raw).includes('fail')` 判失败 —— 响应体**恒带** `"fail":false` 键名,
37
+ 该写法会把**成功**误判成失败(历史误判源)。
38
+
39
+ 脚本层已统一:`spec_lib.saveResultOk(saved)`。
40
+
41
+ ---
42
+
43
+ ## 二、diff 键清单 —— 必须含 `subordination` 与 `style`(★ 血案)
44
+
45
+ 做「对照报表 / 克隆源 / 蓝图」的逐格 diff 时,**键清单漏项 = 误判等价**。
46
+
47
+ > 血案:两轮公式乱码定位中,diff 只比了 `leftX/leftY/refX/refY/cellText`,
48
+ > **漏了 `subordination` 和 `style`** → 结论「两端等价」,但真正的差异(`subordination:[]` vs `["",""]`、
49
+ > `style.formatter:"common"` vs `"General"`)恰在被漏掉的两个键里 → 白排两轮。
50
+
51
+ **必比键清单**:
52
+
53
+ ```
54
+ cellType · cellText · leftX/leftY · topX/topY · refX/refY · expandType
55
+ subordination ← ★ 必比(BUILD-49)
56
+ style.formatter ← ★ 必比(BUILD-47 同族)
57
+ style.formatterType / cell.tag.formatterType
58
+ countType · groupType · displayType · isActiveParent
59
+ fieldKey / dataSetId / tableName / allNeedFields
60
+ ```
61
+
62
+ 对照工具:`e10-cli report formula parent check`(公式格父格与被引用字段一致性);
63
+ 需要整表 diff 时用 `dump cells` 两侧各导一份再逐键比。
64
+
65
+ ---
66
+
67
+ ## 三、字节安全读取(BUILD-52)
68
+
69
+ **问题**:HTTP 响应按 chunk 返回。若用
70
+
71
+ ```js
72
+ let d = '';
73
+ res.on('data', (c) => (d += c)); // ❌ Buffer → string 的隐式转换是**按块**做的
74
+ ```
75
+
76
+ 一个汉字占 3 字节,若恰好被 chunk 边界切开 → 每块各自 `toString('utf8')` → 变成 U+FFFD
77
+ (`�`)→ **假乱码**。这类乱码与格内容无关,纯属读取姿势错误,极易误导成「报表明细乱码」。
78
+
79
+ **两种正确写法**(任选其一):
80
+
81
+ ```js
82
+ // ① 指定编码,交给 StringDecoder 跨块缓冲(Node 内部处理不完整多字节序列)
83
+ res.setEncoding('utf8');
84
+ res.on('data', (c) => (d += c));
85
+
86
+ // ② Buffer 累积,最后一次转字符串(本技能主通道 spec_lib.request 用的就是这种)
87
+ const chunks = [];
88
+ res.on('data', (c) => chunks.push(Buffer.isBuffer(c) ? c : Buffer.from(c)));
89
+ res.on('end', () => { const d = Buffer.concat(chunks).toString('utf8'); /* … */ });
90
+ ```
91
+
92
+ 体检: → `✅ 所有读 body 的脚本都字节安全`(`bytesafe` 检查项)。
93
+ (2026-10-15 已批量修复 22 个脚本 / 24 处读取。)
94
+
95
+ ---
96
+
97
+ ## 四、服务端正确 ≠ 浏览器端正确(★ 公式乱码的核心认知)
98
+
99
+ 下列三条**都不能**证明浏览器端 SpreadJS 重算正确:
100
+
101
+ | 服务端证据 | 它能证明什么 | 不能证明什么 |
102
+ |-----------|-------------|-------------|
103
+ | `analysis` / `getJsonStr` 预计算值正确 | 服务端算得出结果 | 浏览器端重算是否命中同一依赖链 |
104
+ | 导出 Excel 缓存值正确 | 导出通道的值 | 预览页重算(走的是**另一条**路径) |
105
+ | `save` 返回 200 | 落库成功 | 渲染是否乱码 |
106
+
107
+ **公式类乱码必须看浏览器重算路径**:抓预览页渲染输出,用 p-token 正则扫
108
+
109
+ ```
110
+ /p\d+rc\d+/ # 例如 p1900rc1900nt —— 命中即「解析进了隐藏模板区」= 依赖链没建起来
111
+ ```
112
+
113
+ `p1900rc1900nt` 这类 token 是 `BUILD-49`(`subordination:[]`)的**典型指纹**:
114
+ 公式引用区间横跨另一个公式格时,`[]` 让展开引擎建不起引用依赖链,
115
+ 浏览器端只能把公式落到隐藏模板区,渲染出 `p<row>rc<col>nt` 字面量。
116
+
117
+ ---
118
+
119
+ ## 五、对照实验法(定位此类问题的最快路径)
120
+
121
+ **同报表内**取两个格做对照:
122
+
123
+ ```
124
+ A 格 = 设计器里手工写的(已渲染正常)
125
+ B 格 = API 构建的(渲染异常)
126
+ ```
127
+
128
+ 对 A / B **逐键 diff**(键清单见 §二)。差异键即根因候选。
129
+ 比「猜 + 改 + 重试」快一个数量级 —— 四轮乱码定位最终就是靠这一步定位到 `subordination`。
130
+
131
+ ### 五.1 离线自测(秒级回归,替代「会话内临时手写脚本」)
132
+
133
+ 改动**防御层 / 重建层**后,先跑一次离线自测(**无 IO,不连服务器**):
134
+
135
+ ```bash
136
+ e10-cli report # 期望:RESULT pass=N fail=0(当前 27 项)
137
+ ```
138
+
139
+ 覆盖 **BUILD-46/47/49/51/54** 的纯函数口径:Formula 四件套、Field 跨数据集 `subordination` 不被误改、
140
+ 防御层 R7/R8/R9 归一、`saveResultOk` 判定、`checkCloneDiscipline` 三条自检。
141
+ **不要**在会话里临时手写定位脚本(历史教训:会话末被清理 → 下次从零重写,见 PERF-6)。
142
+
143
+ ---
144
+
145
+ ## 六、克隆 / 移植前置自检(BUILD-54)
146
+
147
+ 新报表优先**克隆已验收状态**,而不是整表重建(BUILD-40)。克隆流程:
148
+
149
+ ```
150
+ dump fields(克隆源)→ 重映射 dataSetId / fieldKey / sourceId → 逐格 diff → save
151
+ ```
152
+
153
+ 重映射后**必须**同时满足三条,任一不过即**拒绝落库**:
154
+
155
+ | # | 检查 | 判据 |
156
+ |---|------|------|
157
+ | ① | **0 残留旧 id** | workbook 内 dataset id 全 ∈ 本报表白名单(`assertNoStaleDatasetIds`) |
158
+ | ② | **0 坐标冲突** | 无同一 `(x,y)` 出现两次(否则后写覆盖前写,静默丢格) |
159
+ | ③ | **META 键已清理** | 无 `id` / `createTime` / `updateTime` / `creator` 残留 |
160
+
161
+ 脚本层:`e10-cli report rebuild from-blueprint` 内的 `checkCloneDiscipline(fields, allowedIds)`
162
+ (不过即 `throw`,拒绝落库)。
163
+
164
+ **克隆纪律**:
165
+ - 克隆源必须是**用户确认的最新验收状态**;
166
+ - 克隆后逐格 diff(**含 `subordination` / `style`**)留证;
167
+ - 只改用户点名的 `reportId`(见 `user-request-scope-only-guide.md`)。
168
+
169
+ ---
170
+
171
+ ## 七、语义与范围纪律
172
+
173
+ 1. **比率 / 派生指标的正解是数据源侧预计算列**(表单加字段,或数据集 SQL 直出),
174
+ 报表**纯绑字段**。这样绕开平台级公式重映射缺陷 —— 比在报表里堆公式稳得多。
175
+ 2. 只改用户点名的 `reportId`;**「截图来自哪张表 ≠ 授权改哪张表」**。
176
+ 3. 用户手调 / 手复制的副本**未经点名不得碰**。
177
+
178
+ ---
179
+
180
+ ## 自检清单(落库前后各过一遍)
181
+
182
+ - [ ] 落库**前**:`initReportDev` 已 GET 设计器页(建壳顺序,BUILD-50)
183
+ - [ ] 落库**前**:`doctor scripts` 无 `bytesafe` / `port` / `env9` 告警
184
+ - [ ] 落库**后**:`saveResultOk` 通过 **且** `data` 非空、无告警(BUILD-51)
185
+ - [ ] 回读七项(§一表格)逐条勾稽
186
+ - [ ] 公式格:`refX/refY=-1` + `subordination=["",""]` + `expandType=NoExpand` + 左父格挂块入口格
187
+ - [ ] 若要判「乱码」:扫浏览器渲染输出 `p\d+rc\d+`,**不要**只看服务端预计算值
188
+ - [ ] diff 键清单**含** `subordination` / `style`
189
+ - [ ] 克隆场景:三条前置自检全过
190
+ - [ ] 改动防御层 / 重建层后:`e10-cli report` 全过(离线秒级,§五.1)
191
+
192
+ ## 八、设计器前端逻辑反编译定位法(2026-10-29 实证 · 弹窗回显类问题的终极手段)
193
+
194
+ API 行为与设计器表现矛盾、且注意点库/对照实验都无法解释时(如筛选 value 形态三轮都不回显,BUILD-98),
195
+ 直接反编译设计器前端 chunk 读源码——一次性终结猜测:
196
+
197
+ 1. **拿页面资源清单**:GET `https://<平台地址>/sp/edc/report/design/<reportId>`(HTML 里引用 `<静态资源CDN域名>/build/edc/static/js/main.js`);
198
+ 2. **定位 chunk 表**:main.js 里 `static/js/` 后有 webpack chunk 名/版本映射(设计器路由 = chunk 43 `route_ReportDesigner`);
199
+ 3. **下载目标 chunk**:`/build/edc/static/js/<chunk名>.js?v=<hash>`;共享组件可能在 11 `report_builder~route_DatasetList~route_ReportDesigner`、31 `report_builder` 等;
200
+ 4. **搜代码**:中文 UI 文案多以 **unicode 转义**存储(`\u7b5b\u9009`=筛选),或直接搜数据键名(`customFilterField` / `transSelectOptions`);
201
+ 5. **读关键函数**:找组件的 state 定义与写回函数(如弹窗行组件 `Ut(e,t,n)=r=>n({...t,[e]:r})` 原样存值),即可确定设计器的**原生数据形态**(例:多选筛选 value = optionId JSON 数组,BUILD-98 终版定案依据)。
202
+
203
+ 适用边界:仅定位读取,**禁止**把前端临时变量当接口契约;结论须回写注意点并附 chunk 证据。