weaver-e10-builder 1.6.9 → 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.
- package/dist/commands/form-data.d.ts.map +1 -1
- package/dist/commands/form-data.js +4 -1
- package/dist/commands/form-data.js.map +1 -1
- package/dist/commands/report-admin.d.ts.map +1 -1
- package/dist/commands/report-admin.js +378 -2
- package/dist/commands/report-admin.js.map +1 -1
- package/dist/commands/report-validate.d.ts.map +1 -1
- package/dist/commands/report-validate.js +1066 -3
- package/dist/commands/report-validate.js.map +1 -1
- package/dist/commands/report.d.ts.map +1 -1
- package/dist/commands/report.js +341 -3
- package/dist/commands/report.js.map +1 -1
- package/dist/commands/workflow-after-submit-comment.d.ts +3 -0
- package/dist/commands/workflow-after-submit-comment.d.ts.map +1 -0
- package/dist/commands/workflow-after-submit-comment.js +56 -0
- package/dist/commands/workflow-after-submit-comment.js.map +1 -0
- package/dist/commands/workflow-setting.d.ts.map +1 -1
- package/dist/commands/workflow-setting.js +2 -67
- package/dist/commands/workflow-setting.js.map +1 -1
- package/dist/services/action-detail.d.ts.map +1 -1
- package/dist/services/action-detail.js +1 -17
- package/dist/services/action-detail.js.map +1 -1
- package/dist/services/actionflow/components/action_eb_update_compiler.d.ts.map +1 -1
- package/dist/services/actionflow/components/action_eb_update_compiler.js +6 -2
- package/dist/services/actionflow/components/action_eb_update_compiler.js.map +1 -1
- package/dist/services/actionflow/components/custom_trigger.js +1 -1
- package/dist/services/actionflow/components/custom_trigger.js.map +1 -1
- package/dist/services/actionflow/components/dml_execute.js +1 -1
- package/dist/services/actionflow/components/dml_execute.js.map +1 -1
- package/dist/services/actionflow/components/document_actions.js +1 -2
- package/dist/services/actionflow/components/document_actions.js.map +1 -1
- package/dist/services/actionflow/components/eb_get_data_by_id.d.ts.map +1 -1
- package/dist/services/actionflow/components/eb_get_data_by_id.js +2 -2
- package/dist/services/actionflow/components/eb_get_data_by_id.js.map +1 -1
- package/dist/services/actionflow/components/form_data_builder.d.ts.map +1 -1
- package/dist/services/actionflow/components/form_data_builder.js +18 -10
- package/dist/services/actionflow/components/form_data_builder.js.map +1 -1
- package/dist/services/actionflow/components/hrm_actions.js +0 -1
- package/dist/services/actionflow/components/hrm_actions.js.map +1 -1
- package/dist/services/actionflow/components/webhook_trigger.js +3 -3
- package/dist/services/actionflow/components/webhook_trigger.js.map +1 -1
- package/dist/services/actionflow/components/workflow_actions.js +3 -2
- package/dist/services/actionflow/components/workflow_actions.js.map +1 -1
- package/dist/services/actionflow/filter_rules.d.ts.map +1 -1
- package/dist/services/actionflow/filter_rules.js +15 -13
- package/dist/services/actionflow/filter_rules.js.map +1 -1
- package/dist/services/actionflow/form_source.d.ts.map +1 -1
- package/dist/services/actionflow/form_source.js +59 -11
- package/dist/services/actionflow/form_source.js.map +1 -1
- package/dist/services/actionflow/formula_service.d.ts.map +1 -1
- package/dist/services/actionflow/formula_service.js +4 -1
- package/dist/services/actionflow/formula_service.js.map +1 -1
- package/dist/services/actionflow/option_field_types.d.ts +5 -0
- package/dist/services/actionflow/option_field_types.d.ts.map +1 -0
- package/dist/services/actionflow/option_field_types.js +20 -0
- package/dist/services/actionflow/option_field_types.js.map +1 -0
- package/dist/services/actionflow/param_group_dto.d.ts.map +1 -1
- package/dist/services/actionflow/param_group_dto.js +7 -3
- package/dist/services/actionflow/param_group_dto.js.map +1 -1
- package/dist/services/actionflow/preflight_service.d.ts.map +1 -1
- package/dist/services/actionflow/preflight_service.js +42 -18
- package/dist/services/actionflow/preflight_service.js.map +1 -1
- package/dist/services/actionflow/webhook_source.d.ts.map +1 -1
- package/dist/services/actionflow/webhook_source.js +9 -4
- package/dist/services/actionflow/webhook_source.js.map +1 -1
- package/dist/services/actionflow/workflow_compiler.d.ts.map +1 -1
- package/dist/services/actionflow/workflow_compiler.js +11 -8
- package/dist/services/actionflow/workflow_compiler.js.map +1 -1
- package/dist/services/report/blueprint.d.ts +109 -0
- package/dist/services/report/blueprint.d.ts.map +1 -0
- package/dist/services/report/blueprint.js +322 -0
- package/dist/services/report/blueprint.js.map +1 -0
- package/dist/services/report/build.d.ts.map +1 -1
- package/dist/services/report/build.js +8 -3
- package/dist/services/report/build.js.map +1 -1
- package/dist/services/report/card.d.ts +65 -0
- package/dist/services/report/card.d.ts.map +1 -0
- package/dist/services/report/card.js +151 -0
- package/dist/services/report/card.js.map +1 -0
- package/dist/services/report/copy-health.d.ts +31 -0
- package/dist/services/report/copy-health.d.ts.map +1 -0
- package/dist/services/report/copy-health.js +87 -0
- package/dist/services/report/copy-health.js.map +1 -0
- package/dist/services/report/dataset-heal.d.ts +64 -0
- package/dist/services/report/dataset-heal.d.ts.map +1 -0
- package/dist/services/report/dataset-heal.js +89 -0
- package/dist/services/report/dataset-heal.js.map +1 -0
- package/dist/services/report/dataset-ids.d.ts +70 -0
- package/dist/services/report/dataset-ids.d.ts.map +1 -0
- package/dist/services/report/dataset-ids.js +149 -0
- package/dist/services/report/dataset-ids.js.map +1 -0
- package/dist/services/report/dataset.d.ts.map +1 -1
- package/dist/services/report/dataset.js +3 -1
- package/dist/services/report/dataset.js.map +1 -1
- package/dist/services/report/empty-dataset.d.ts +51 -0
- package/dist/services/report/empty-dataset.d.ts.map +1 -0
- package/dist/services/report/empty-dataset.js +213 -0
- package/dist/services/report/empty-dataset.js.map +1 -0
- package/dist/services/report/field-binding.d.ts +75 -0
- package/dist/services/report/field-binding.d.ts.map +1 -0
- package/dist/services/report/field-binding.js +160 -0
- package/dist/services/report/field-binding.js.map +1 -0
- package/dist/services/report/forms.d.ts +32 -0
- package/dist/services/report/forms.d.ts.map +1 -1
- package/dist/services/report/forms.js +90 -0
- package/dist/services/report/forms.js.map +1 -1
- package/dist/services/report/formula-parent.d.ts +25 -0
- package/dist/services/report/formula-parent.d.ts.map +1 -0
- package/dist/services/report/formula-parent.js +116 -0
- package/dist/services/report/formula-parent.js.map +1 -0
- package/dist/services/report/locate.d.ts +40 -0
- package/dist/services/report/locate.d.ts.map +1 -0
- package/dist/services/report/locate.js +122 -0
- package/dist/services/report/locate.js.map +1 -0
- package/dist/services/report/reports.d.ts +4 -0
- package/dist/services/report/reports.d.ts.map +1 -1
- package/dist/services/report/reports.js +4 -2
- package/dist/services/report/reports.js.map +1 -1
- package/dist/services/report/scene.d.ts +22 -0
- package/dist/services/report/scene.d.ts.map +1 -0
- package/dist/services/report/scene.js +145 -0
- package/dist/services/report/scene.js.map +1 -0
- package/dist/services/report/types.d.ts +28 -0
- package/dist/services/report/types.d.ts.map +1 -1
- package/dist/services/report/verify.d.ts +24 -0
- package/dist/services/report/verify.d.ts.map +1 -1
- package/dist/services/report/verify.js +115 -2
- package/dist/services/report/verify.js.map +1 -1
- package/dist/services/report/workbook.d.ts +12 -1
- package/dist/services/report/workbook.d.ts.map +1 -1
- package/dist/services/report/workbook.js +107 -8
- package/dist/services/report/workbook.js.map +1 -1
- package/dist/services/workflow-after-submit-comment.d.ts +20 -0
- package/dist/services/workflow-after-submit-comment.d.ts.map +1 -0
- package/dist/services/workflow-after-submit-comment.js +81 -0
- package/dist/services/workflow-after-submit-comment.js.map +1 -0
- package/ecodecmd/src/build.js +36 -12
- package/package.json +1 -1
- package/skill-docs/SKILL.md +4 -4
- package/skill-docs/_catalog.md +10 -1
- package/skill-docs/actionflows/SKILL.md +1 -0
- package/skill-docs/actionflows/references/components/ebuilder/EnquiryForm.md +2 -2
- package/skill-docs/actionflows/references/components/trigger/CustomTrigger.md +2 -0
- package/skill-docs/actionflows/references/components/trigger/WebHookTrigger.md +19 -1
- package/skill-docs/references/coding/guide-form-crud.md +2 -0
- package/skill-docs/references/coding/guide-page-code.md +108 -0
- package/skill-docs/references/components/ref-component-common.md +98 -0
- package/skill-docs/references/report/add-dataset-registration-guide.md +44 -22
- package/skill-docs/references/report/advanced-crosstab-tree-guide.md +82 -0
- package/skill-docs/references/report/ai-report-workflow.md +100 -100
- package/skill-docs/references/report/api-auth-headers.md +129 -0
- package/skill-docs/references/report/api-report-build-fast-path.md +274 -275
- package/skill-docs/references/report/app-datasource-lookup-guide.md +230 -230
- package/skill-docs/references/report/branch-scene-guide.md +293 -0
- package/skill-docs/references/report/build-resilience-guide.md +99 -0
- package/skill-docs/references/report/card-report-guide.md +110 -0
- package/skill-docs/references/report/cell-config-echo-guide.md +44 -9
- package/skill-docs/references/report/cell-transform-guide.md +9 -9
- package/skill-docs/references/report/column-split-report-guide.md +96 -0
- package/skill-docs/references/report/condition-format-guide.md +49 -24
- package/skill-docs/references/report/cross-dataset-filter-guide.md +180 -69
- package/skill-docs/references/report/crosstab-raw-workbook-guide.md +265 -0
- package/skill-docs/references/report/dataset-query-filter-guide.md +231 -235
- package/skill-docs/references/report/dataset-sidebar-ops-guide.md +75 -34
- package/skill-docs/references/report/dataset-table-field-contract-guide.md +196 -46
- package/skill-docs/references/report/datasource-metadata-guide.md +128 -119
- package/skill-docs/references/report/datasource-selection-and-parent-filter-guide.md +183 -148
- package/skill-docs/references/report/date-range-query-reference.md +97 -102
- package/skill-docs/references/report/default-header-style-guide.md +8 -8
- package/skill-docs/references/report/designer-blank-prevention-guide.md +8 -8
- package/skill-docs/references/report/dossier-report-guide.md +69 -0
- package/skill-docs/references/report/drilldown-report-guide.md +59 -0
- package/skill-docs/references/report/event-hreflink-guide.md +53 -47
- package/skill-docs/references/report/expansion-block-parent-config-guide.md +208 -0
- package/skill-docs/references/report/failure-cleanup-and-nonblocking-guide.md +183 -0
- package/skill-docs/references/report/field-bind-exact-match-guide.md +208 -208
- package/skill-docs/references/report/financial-stats-report-guide.md +89 -0
- package/skill-docs/references/report/formula-cell-api-guide.md +325 -258
- package/skill-docs/references/report/golden-case-summary-sheet.md +200 -0
- package/skill-docs/references/report/guide-report-build.md +6 -1
- package/skill-docs/references/report/hidden-row-and-header-merge-guide.md +10 -10
- package/skill-docs/references/report/layout-showlocation-freeze-guide.md +39 -10
- package/skill-docs/references/report/multi-report-crosstab-casebook.md +263 -0
- package/skill-docs/references/report/paged-group-report-guide.md +68 -0
- package/skill-docs/references/report/preaggregate-auto-disable-guide.md +24 -13
- package/skill-docs/references/report/query-condition-api-guide.md +145 -125
- package/skill-docs/references/report/ref-report-commands.md +41 -3
- package/skill-docs/references/report/report-baseinfo-defaults-guide.md +117 -117
- package/skill-docs/references/report/report-building-guide.md +52 -52
- package/skill-docs/references/report/report-case-prompts.md +104 -0
- package/skill-docs/references/report/report-config-schema.md +281 -281
- package/skill-docs/references/report/report-create-modes-guide.md +73 -35
- package/skill-docs/references/report/report-data-model.md +131 -131
- package/skill-docs/references/report/report-delivery-contract.md +23 -3
- package/skill-docs/references/report/report-designer-feature-map.md +30 -35
- package/skill-docs/references/report/report-help-guide.md +304 -0
- package/skill-docs/references/report/report-internal-error-guide.md +71 -0
- package/skill-docs/references/report/report-knowledge-base.md +27 -27
- package/skill-docs/references/report/report-lifecycle-api-guide.md +126 -94
- package/skill-docs/references/report/report-list-page-ops-guide.md +54 -8
- package/skill-docs/references/report/report-permission-guide.md +99 -102
- package/skill-docs/references/report/report-requirement-analysis-template.md +93 -29
- package/skill-docs/references/report/report-self-check-guide.md +164 -164
- package/skill-docs/references/report/report-verification-discipline-guide.md +203 -0
- package/skill-docs/references/report/safe-partial-save-guide.md +151 -151
- package/skill-docs/references/report/shard-freeze-report-guide.md +97 -0
- package/skill-docs/references/report/snowflake-id-precision-guide.md +84 -84
- package/skill-docs/references/report/spec-build-schema.md +71 -71
- package/skill-docs/references/report/targeted-fix-guide.md +155 -97
- package/skill-docs/references/report/user-request-scope-only-guide.md +23 -4
- package/skill-docs/references/workflow/guide-after-submit-comment.md +58 -0
- package/skill-docs/references/workflow/guide-workflow.md +6 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# 金标准案例 · 明细数据页 + 核心摘要页(业务专项统计报表)
|
|
2
|
+
|
|
3
|
+
> 来源:报表 `1332025742762827883`(app `878284317729439749`),需求文件《业务专项统计报表-需求描述-优化版.xlsx》。
|
|
4
|
+
> 用户 2026-10-30 明确认可「明细数据页配置完全正确」,本文件即该页的**逐格范式**,新建同类统计报表照此复刻。
|
|
5
|
+
> 配套注意点:BUILD-113 / BUILD-114 / BUILD-115 / BUILD-116 / BUILD-117。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 0. 页面命名铁律(BUILD-116)
|
|
10
|
+
|
|
11
|
+
**sheet 名必须与需求文件的 sheet 页名 1:1 一致,不得自造 `Sheet0 / Sheet1 / Sheet2`。**
|
|
12
|
+
|
|
13
|
+
| 场景 | 正确 | 错误 |
|
|
14
|
+
|------|------|------|
|
|
15
|
+
| 需求文件有「明细数据」「核心摘要」两页 | `sheets[i].name = '明细数据'` / `'核心摘要'` | `Sheet0` / `Sheet1` / `Sheet2` |
|
|
16
|
+
| 需求文件未给页名 | 用业务含义命名(「明细数据」「汇总」),仍不得用 Sheet+序号 | 按 idx 机械命名 |
|
|
17
|
+
|
|
18
|
+
蓝图里 `sheets[].name` 会被 `rebuild from-blueprint` 直写 `sheetProps[].name`,落库后用
|
|
19
|
+
`getReportDevInfo` 的 `sheetProps` 回读核对(`dump cells` 标题行也会打印 `sheetIndex=N <页名>`)。
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
// 一次性改多页命名
|
|
23
|
+
bp.sheets[0].name = '明细数据';
|
|
24
|
+
bp.sheets[1].name = '核心摘要';
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
> 已知事故:曾把第一页由 `Sheet1` 写成 `Sheet0`,用户当场指出「这种要莫就按照需求文件 sheet 页的名称命名,其他情况不要乱改」。
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 1. 明细数据页金标准(8 设计列 / 三模块 / 77 格)
|
|
32
|
+
|
|
33
|
+
### 1.1 列骨架
|
|
34
|
+
|
|
35
|
+
| 列 | 内容 | 类型 | 说明 |
|
|
36
|
+
|----|------|------|------|
|
|
37
|
+
| A | 专项负责人 | Field | `Vertical` 纵向根,`L(-1,-1)`,`top=本模块条` |
|
|
38
|
+
| B | 专项名称 | Field | `L(x,0)`,跟随 A |
|
|
39
|
+
| C | 所属大区/城市 | Field | `L(x,1)`,跟随 B |
|
|
40
|
+
| D | 负责人拼接串 | Formula | `A{rn}&"("&B{rn}&"/"&C{rn}&")"`,`L(x,0)`,`NoExpand` |
|
|
41
|
+
| E | 金额(年份锚) | Field `htzje` | `Horizontal` + `Group` + `groupType:'year'`,`top=本模块条` |
|
|
42
|
+
| F | 合计金额 | Const | `top=本模块条`(与 E 同 top,否则 CROSS_TOP_MISSING) |
|
|
43
|
+
| G | 数量(年份锚) | Field `id` | 同 E,第二组锚 |
|
|
44
|
+
| H | 合计数量 | Const | 同 F |
|
|
45
|
+
|
|
46
|
+
- 横向锚只占 **1 物理列**,按年份自动展开,**禁止**按年数预留空列(BUILD-66/67)。
|
|
47
|
+
- 指标格 `displayType:'Count'` + `countType:'sum'`(金额)/ `'count'`(数量)。
|
|
48
|
+
- 维度格 `displayType:'Group'` + `countType:'none'`。
|
|
49
|
+
- 拼接公式行号 = **Excel 行号 = x+1**(同行引用),不是上一行(BUILD-71)。
|
|
50
|
+
|
|
51
|
+
### 1.2 行骨架(每模块 4 行)
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
x=模块条行 【模块N】… Const,yCount=列数(横向合并)
|
|
55
|
+
x=表头行 负责人|专项名称|…|合计数量 Const ×8
|
|
56
|
+
x=数据行 A..H 八格 数据区只写 1 行,人数由 A 列 Vertical 自动展开
|
|
57
|
+
x=合计行 合计 | SUM(E{x})+… A 列 Const「合计」+ 各指标 SUM
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 1.3 模块1:两组维度行(关键)
|
|
61
|
+
|
|
62
|
+
「本区域」类指标必须**拆两组数据行**,因为 `所属大区/城市` 字段存两种粒度:
|
|
63
|
+
|
|
64
|
+
| 组 | A 格 `customFilterField` | 指标格左父格筛选 | 覆盖的人 |
|
|
65
|
+
|----|--------------------------|------------------|----------|
|
|
66
|
+
| 组1 | `isDq Equals "1"` | `jgs Equals ← C` + `cplx Include ← B` | 所属填大区名(陕西大区/上海大区) |
|
|
67
|
+
| 组2 | `isDq Equals "0"` | `dq Equals ← C` + `cplx Include ← B` | 所属填城市名(苏州/青岛) |
|
|
68
|
+
|
|
69
|
+
源数据实证(`专项区域业务` 表单):
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
令信通 | 王栋(西安) | 陕西大区 | isDq=是 → 需要 dq 匹配
|
|
73
|
+
业票通 | 邓果成 | 苏州 | isDq=否 → 需要 jgs 匹配
|
|
74
|
+
资管家 | 郭衍敏 | 青岛 | isDq=否 → 需要 jgs 匹配
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
⚠ 只配一组 ⇒ 另一半人金额恒 0(本次事故现象:摘要页「本区域纯专项金额」14 人里 12 人为 0)。
|
|
78
|
+
|
|
79
|
+
两组共用一个合计行:`SUM(E{a})+SUM(E{b})`。
|
|
80
|
+
|
|
81
|
+
### 1.4 模块2 / 模块3
|
|
82
|
+
|
|
83
|
+
| 模块 | 数据源 | 指标格筛选 |
|
|
84
|
+
|------|--------|-----------|
|
|
85
|
+
| 模块2 纯专项(全量) | SQL 视图 | 仅 `cplx Include ← B`(专项名称),全国全量,不带区域条件 |
|
|
86
|
+
| 模块3 混合合同(仅专项部分) | 专项方案表单 | `专项方案字段 Include ← B`,金额取 `专项方案金额` 字段 |
|
|
87
|
+
|
|
88
|
+
### 1.5 指标格左父格(BUILD-115 铁律)
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
指标格 leftX = 本行 x,leftY = 2 ← 指向 C 列「所属大区/城市」真实 Field 格
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**禁止指向 D 列拼接 Formula**:Formula 没有字段身份,`subordination[0]` / `filter.parentField` 解析不到父字段值 ⇒ **整列 0**。
|
|
95
|
+
|
|
96
|
+
`subordination` = `[第一条条件的 parentField, 本格字段 fieldKey]`;两条条件时取第一条(区域维度)。
|
|
97
|
+
|
|
98
|
+
### 1.5b 公式格左父格口径(BUILD-118,2026-10-30 用户截图点名)
|
|
99
|
+
|
|
100
|
+
**数据行里的 Formula 格(拼接串 / 金额 SUM / 占比)左父格也必须指「具体的表单字段格」,不能挂 Const 自定义文本,也不能跨行指父**:
|
|
101
|
+
|
|
102
|
+
| 公式格 | 左父格正确写法 | 用户截图实证 |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| D 列拼接 `A6&"("&B6&"/"&C6&")"` | 同行维度 Field(A 列负责人) | — |
|
|
105
|
+
| F 列金额 `SUM(E6)` | 本行维度 Field 或本列块字段锚 | 明细数据 → 本列块字段锚 |
|
|
106
|
+
| H/I 占比 `IFERROR(IF(G5=0,"-",F5/G5),"-")` | **分母字段格**(语义配对) | 核心摘要 H5 → G5 混合专项金额 |
|
|
107
|
+
|
|
108
|
+
- 禁止:数据行公式 left 挂行首 Const(「合计」等自定义文本)→ 关联关系取不到父字段。
|
|
109
|
+
- 禁止:跨行指父(如 H6 曾错指下一行 C7)→ 方向校验 `DIR_WRONG` 阻断 + 扩展上下文错乱。
|
|
110
|
+
- **例外放行**:合计/总计行(本行无 Field 格)左父格挂行首 Const 是平台验收形态(V10.7 同构),不改——
|
|
111
|
+
把合计行公式父格改指数据行 Field 有被卷进纵向扩展的风险。
|
|
112
|
+
- 门禁:`e10-cli report verify all` 第 ⑧ 组 `FORMULA_PARENT_CONST` / `FORMULA_PARENT_ROW_MISMATCH`(提示级 WARN)。
|
|
113
|
+
|
|
114
|
+
### 1.6 筛选条件写法
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
// leftFilterField
|
|
118
|
+
[
|
|
119
|
+
{"index":27,"currentField":"<DS_S>.<SRC_S>.jgs","type":"Equals","parentField":"<DS_R>.<SRC_R>.field_…6055"},
|
|
120
|
+
{"index":31,"currentField":"<DS_S>.<SRC_S>.cplx","type":"Include","parentField":"<DS_R>.<SRC_R>.field_…6053"}
|
|
121
|
+
]
|
|
122
|
+
// customFilterField(入口格分支条件)
|
|
123
|
+
[{"index":101,"currentField":"<DS_R>.<SRC_R>.field_…5939","type":"Equals","value":"1"}]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- `currentField` / `parentField` 三段式 `datasetId.nameIndex.field`(BUILD-94)。
|
|
127
|
+
- 条件标识用 **`index`(全表唯一递增)**,不要写 `id`(BUILD-115)。
|
|
128
|
+
- 文本包含匹配用 **`Include`**,不是 `Contain`。
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 2. 核心摘要页范式(6 可见列 + 3 零宽载体列)
|
|
133
|
+
|
|
134
|
+
需求只要 6 列,但「负责人」列要求是**三字段拼接串** ⇒ 拼接格不能同时承担字段身份。
|
|
135
|
+
解法:把三个维度字段放 **A/B/C 零宽列**,可见区从 D 开始。
|
|
136
|
+
|
|
137
|
+
| 列 | 内容 | 宽 | 说明 |
|
|
138
|
+
|----|------|----|------|
|
|
139
|
+
| A | 专项负责人 | **0** | Field Vertical 根,父格筛选锚 |
|
|
140
|
+
| B | 专项名称 | **0** | Field Vertical |
|
|
141
|
+
| C | 所属大区/城市 | **0** | Field Vertical,指标格左父格指它 |
|
|
142
|
+
| D | 负责人(拼接串) | 190 | `A{rn}&"("&B{rn}&"/"&C{rn}&")"` |
|
|
143
|
+
| E | 本区域纯专项金额 | 150 | `htzje` sum |
|
|
144
|
+
| F | 纯专项总金额 | 150 | `htzje` sum |
|
|
145
|
+
| G | 混合专项金额 | 150 | `专项方案金额` sum |
|
|
146
|
+
| H | 纯专项/混合占比 | 120 | `IFERROR(IF(G{rn}=0,"-",F{rn}/G{rn}),"-")` |
|
|
147
|
+
| I | 本区/总纯专项占比 | 130 | `IFERROR(IF(F{rn}=0,"-",E{rn}/F{rn}),"-")` |
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
// 隐藏列:cell.width = 0(BUILD-16,columns[].size=0)
|
|
151
|
+
{ x:4, y:0, width:0 } ...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 2.1 行骨架
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
x=0 标题 Const yCount=6,从 D 列起(y=3)
|
|
158
|
+
x=1 副标题 Const yCount=6
|
|
159
|
+
x=3 表头 Const ×6(A/B/C 也补表头,宽 0)
|
|
160
|
+
x=4 数据组1 isDq=1 → E 用 jgs Equals
|
|
161
|
+
x=5 数据组2 isDq=0 → E 用 dq Equals
|
|
162
|
+
x=6 总计 E=SUM(E5)+SUM(E6) … H/I 按总计行本行重算
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- 两组 root 格(A 列 `L(-1,-1)`)平台会**纵向串联成一段**,视觉上仍是一个连续人员清单。
|
|
166
|
+
- 占比格左父格 = D(拼接,逐人扩展),与 SUM 公式指拼接列同理(Formula 作**公式格**左父格合法)。
|
|
167
|
+
- 总计行「总计」标签放 D 列(可见首列),**不要**横向合并盖住 B/C/D(会丢指标)。
|
|
168
|
+
|
|
169
|
+
### 2.2 验收数值(本报表验证)
|
|
170
|
+
|
|
171
|
+
修复前后对比:
|
|
172
|
+
|
|
173
|
+
| 项 | 修复前 | 修复后 |
|
|
174
|
+
|----|--------|--------|
|
|
175
|
+
| 可见列 | 9 列(表头 6 个,指标错位到「占比」表头下) | 6 列(D..I 对齐表头) |
|
|
176
|
+
| 本区域纯专项金额 | 14 人里 12 人为 0 | 15 人全部有值 |
|
|
177
|
+
| 占比公式 | 引 C5/D5(维度文本) | 引 F/G、E/F |
|
|
178
|
+
| E5/F5 | 两格配置完全相同 | 口径分离(本区域 / 全量) |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 3. 门禁与验收
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
BP="E:/.../bp.json"
|
|
186
|
+
e10-cli report verify all --blueprint "$BP" # 含 DIR_WRONG / FILTER_ID_DUP / FILTER_SEGMENT
|
|
187
|
+
e10-cli report verify self --blueprint "$BP"
|
|
188
|
+
e10-cli report verify self --blueprint "$BP"
|
|
189
|
+
e10-cli report rebuild from-blueprint --blueprint "$BP" # dry-run
|
|
190
|
+
e10-cli report rebuild from-blueprint --blueprint "$BP" --apply
|
|
191
|
+
# 按页渲染取数(2026-10-30 新增 --sheet)
|
|
192
|
+
EB_ALLOW_RENDER=1 e10-cli report render values <reportId> <appId> 60 --sheet=1 --max-cols=10
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- `DIR_WRONG` 会拦「左父格在右方」——零宽载体列必须放**左侧**,不能放右侧。
|
|
196
|
+
- 渲染出来的 Formula 格 `value` 为 `null`、只带 `formula` 字符串属**正常**(服务端不算公式,前端 SpreadJS 计算);判读标准是 Field 格有没有值。
|
|
197
|
+
- Field 格全 0 ⇒ 先查左父格是否指到 Formula 列、筛选是否缺 `parentField`。
|
|
198
|
+
|
|
199
|
+
### 3.1 逐格体检脚本
|
|
200
|
+
|
|
@@ -42,7 +42,12 @@ e10-cli report build --spec spec.json --dry-run # 只看定源与字段绑定,
|
|
|
42
42
|
| `layout` | `{ title, freezeRows, showLocation }` |
|
|
43
43
|
| `style` / `titleStyle` / `headerStyle` / `bodyStyle` | 分层样式;不给就是默认表头样式 |
|
|
44
44
|
|
|
45
|
-
列的可选项:`width`、`format`(`货币`/`短日期`/`百分比`…,见 `cell-config-echo-guide.md`)、`formula`(公式列不参与字段绑定)、`groupType`(日期分组)、`rule`(条件格式,见 `condition-format-guide.md`)、`field` / `fieldName
|
|
45
|
+
列的可选项:`width`、`format`(`货币`/`短日期`/`百分比`…,见 `cell-config-echo-guide.md`)、`formula`(公式列不参与字段绑定)、`groupType`(日期分组)、`rule`(条件格式,见 `condition-format-guide.md`)、`field` / `fieldName`(显式指定字段)、`aggregate`(汇总方式,见下)、`display: "tree"`(折叠树形)、`sort`(`asc` / `desc`)。
|
|
46
|
+
|
|
47
|
+
**汇总列**:`"aggregate": "sum"`(或 `count`/`max`/`min`/`avg`)。同一行维度下聚合成一行,不会被子记录撑开。
|
|
48
|
+
汇总格的左父格会自动锚到**行维度入口列**(最左边那列普通字段),不需要手写父格。
|
|
49
|
+
配 `layout.totalRow: true` 追加合计行;合计列是 `SUM(整列)` 的公式格,行首是 Const「合计」。
|
|
50
|
+
回读时显示方式会被规范化成「分组」,属正常现象;`e10-cli report verify anchors` 可复检。
|
|
46
51
|
|
|
47
52
|
---
|
|
48
53
|
|
|
@@ -29,8 +29,8 @@ Excel 里 `ht="0" hidden="1"` 的行(常见用途:表头与数据之间的**
|
|
|
29
29
|
|
|
30
30
|
```js
|
|
31
31
|
spans = [
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
{ row: 2, col: 0, rowCount: 2, colCount: 1 }, // 固定列表头纵向合并(Excel B3:B4)
|
|
33
|
+
{ row: 2, col: 45, rowCount: 1, colCount: 3 }, // 日期区横向合并(Excel AU3:AW3)
|
|
34
34
|
]
|
|
35
35
|
```
|
|
36
36
|
|
|
@@ -44,7 +44,7 @@ spans = [
|
|
|
44
44
|
|
|
45
45
|
1. **`row`/`col` 是 0-based**,而 Excel 的 `mergeCells` 是 1-based → 换算 `row = excelRow - 1`、`col = excelColNum - 1`。
|
|
46
46
|
2. 日期/交叉维度区块本就必须 `colCount = 块宽`(本包默认日期块 3 列),**不要再叠加一次**,否则块宽翻倍。
|
|
47
|
-
3.
|
|
47
|
+
3. 验证:**只写 `spans` 即可生效**,可不写 cell 级 `rowCount`/`colCount`(服务端统一按 spans 回写 `xCount`/`yCount`)。
|
|
48
48
|
4. 合并区内的非左上角单元格**不要放内容**(Excel 同理),否则合并语义混乱。
|
|
49
49
|
|
|
50
50
|
### 从 Excel 提取 mergeCells(本环境 xlsx 常被 openpyxl 拒读)
|
|
@@ -56,7 +56,7 @@ import zipfile, xml.etree.ElementTree as ET
|
|
|
56
56
|
NS = "{http://schemas.openxmlformats.org/spreadsheetml/2006/main}"
|
|
57
57
|
sh = ET.fromstring(zipfile.ZipFile(path).read("xl/worksheets/sheet1.xml"))
|
|
58
58
|
mc = sh.find(f"{NS}mergeCells")
|
|
59
|
-
refs = [m.attrib["ref"] for m in mc.findall(f"{NS}mergeCell")]
|
|
59
|
+
refs = [m.attrib["ref"] for m in mc.findall(f"{NS}mergeCell")] # ["B3:B4", "AU3:AW3", ...]
|
|
60
60
|
```
|
|
61
61
|
|
|
62
62
|
映射规律(常见表头):
|
|
@@ -74,18 +74,18 @@ refs = [m.attrib["ref"] for m in mc.findall(f"{NS}mergeCell")] # ["B3:B4", "AU3:
|
|
|
74
74
|
只能看 `fields`(含 `xCount`/`yCount`)——**不能证明渲染效果**。要看用户到底看见什么,必须走渲染链:
|
|
75
75
|
|
|
76
76
|
```
|
|
77
|
-
POST /api/edc/report/view/analysis
|
|
78
|
-
|
|
79
|
-
GET
|
|
80
|
-
|
|
77
|
+
POST /api/edc/report/view/analysis (multipart;sheetId=reportId、pageFilter、pageNum…)
|
|
78
|
+
→ data.json[0] = sessionKey
|
|
79
|
+
GET /api/edc/report/view/getJsonStr?sessionKey=<key>
|
|
80
|
+
→ gunzip → workbook(含展开后的 dataTable / rows / spans)
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
判据:
|
|
84
84
|
|
|
85
85
|
- **无多余空行**:下一行(0-based = `数据行 index`)应已是非空数据行。
|
|
86
|
-
|
|
86
|
+
例:表头 r2、星期 r3 → r4 必须是数据(此前 r4 全空 = 事故)。
|
|
87
87
|
- **表头合并生效**:渲染 `spans` 中应存在 `{row:表头行, rowCount:2, colCount:1}` 共 N 条(N=固定列数)、
|
|
88
|
-
|
|
88
|
+
以及 `{row:表头行, col:日期起始列, colCount:块宽}`。
|
|
89
89
|
|
|
90
90
|
⚠️ 渲染有 **50000 单元格上限**(超限 `code:555`)。估算:`渲染行数 × 列数`。
|
|
91
91
|
本例 `1004 × 48 ≈ 48192` 勉强过关;列维度一展开就会超,需靠默认查询条件收敛。
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
## 一、报表显示位置 `showLocation`
|
|
9
9
|
|
|
10
|
-
### 1.1 UI →
|
|
10
|
+
### 1.1 UI → 存储枚举(前端验证)
|
|
11
11
|
|
|
12
12
|
设计器「页面 → 页面布局 → 报表显示位置」写入:
|
|
13
13
|
|
|
@@ -38,6 +38,35 @@
|
|
|
38
38
|
|
|
39
39
|
宽表(列宽×列数 ≥ 视口)时居左/居中视觉差可能不明显;仍须按枚举正确落库,不得因「看起来一样」改回错误值。
|
|
40
40
|
|
|
41
|
+
### 1.5 ⚠️⚠️ 血案:手写 workbook 漏 `tag` → 显示位置被静默改成居中(2026-09-14)
|
|
42
|
+
|
|
43
|
+
**症状**:修完 `tableName` 后用户反馈「报表上还是显示的不对」,定位 `fields[]`/`verify bind`/
|
|
44
|
+
`listWithPageReport` **全部正常**,最终定位 `sheetProps.showLocation` 从 `1` 变成了 `2`。
|
|
45
|
+
|
|
46
|
+
**根因**:用**手写临时脚本**构造 workbook 落库时,sheet 里**没有 `tag` 字段**(`tag: null`)。
|
|
47
|
+
按 §1.2:**tag 为 null 时服务端默认写 `2`** → 居左被静默改成居中。
|
|
48
|
+
|
|
49
|
+
**对比证据**:
|
|
50
|
+
|
|
51
|
+
| 构建方式 | sheet 键数 | `tag` | showLocation 结果 |
|
|
52
|
+
|---|---|---|---|
|
|
53
|
+
| CLI 正规路径(`e10-cli report fix table-name` → `buildWorkbook`) | **18** | 完整对象 | ✅ 保留原值 `1` |
|
|
54
|
+
| 手写临时脚本 | 7 | `null` | ❌ 被改成 `2` |
|
|
55
|
+
|
|
56
|
+
CLI 正规路径的 `tag` 含:
|
|
57
|
+
`childMerge` / `showLocation` / `filterSheet` / `tableNameSuffix` / `columnConfig` / `sheetConfig`;
|
|
58
|
+
sheet 还含 `theme` / `names` / `__rowColHeaderVisible` / `__gridline` / `__printLineVisible` /
|
|
59
|
+
`selections` / `colHeaderData` / `rowHeaderData` —— **这些都影响设计器渲染,一个都不能少**。
|
|
60
|
+
|
|
61
|
+
**★ 铁律:禁止用「手写临时 workbook」直接落库生产报表。**
|
|
62
|
+
服务端对缺失的非必填键**静默回落默认值**(不报错、不提示、无 diff 可查)。
|
|
63
|
+
必须走 CLI 正规构建路径。
|
|
64
|
+
|
|
65
|
+
**已加的护栏**:
|
|
66
|
+
- `e10-cli report fix table-name` 新增 `--show-location 1|2`(显式修正)
|
|
67
|
+
- dry-run 汇报打印 `显示位置 showLocation: live=X → 重建=Y (居左/居中)`
|
|
68
|
+
- 落库后回读校验 `showLocation`,不一致计入失败判定
|
|
69
|
+
|
|
41
70
|
---
|
|
42
71
|
|
|
43
72
|
## 二、冻结单元格 / 冻结表头
|
|
@@ -108,18 +137,18 @@
|
|
|
108
137
|
```java
|
|
109
138
|
Optional<AnalysisField> obj = this.fields.stream().filter(d -> d.getFixed() == 1).findFirst();
|
|
110
139
|
OffSet cell = obj.get().getMinCell();
|
|
111
|
-
setFrozenRowCount(cell.getX());
|
|
112
|
-
setFrozenColumnCount(cell.getY());
|
|
140
|
+
setFrozenRowCount(cell.getX()); // 冻结锚点上方各行
|
|
141
|
+
setFrozenColumnCount(cell.getY()); // 冻结锚点左侧各列
|
|
113
142
|
```
|
|
114
143
|
|
|
115
144
|
**推论(三条)**
|
|
116
145
|
|
|
117
146
|
1. **锚点格不必是空格**。设计器 `setFixedCellByTarget` 只在锚点格 `cellType.typeName` 为假(空格)时才补写
|
|
118
|
-
|
|
119
|
-
|
|
147
|
+
`cellText="fixed-cell-tag"` + 透明样式;**占用格(数据字段所在格)它什么都不写**,只更新内存里的 `tag.fixedCell`。
|
|
148
|
+
所以「用 API 把锚点设在数据格上」是**唯一可行**的做法 —— 只置 `tag.fixed` 即可,预览照样冻结。
|
|
120
149
|
2. **禁止**顺手给锚点格写 `cellText="fixed-cell-tag"`:服务端会据此把该格**边框 4 边 + 底色清空**
|
|
121
|
-
|
|
122
|
-
|
|
150
|
+
(`CustomEngine`/`SimpleListEngine` 的 `field.getFixed()==1 && "fixed-cell-tag".equals(cellText)` 分支),
|
|
151
|
+
属于改动未点名格的样式。
|
|
123
152
|
3. **`fixed=1` 的字段必须唯一**。`findFirst()` 取的是字段列表里第一个 `fixed==1`,多个会以第一个为准(顺序 = x 升序、同 x 按 y)→ 落库前先清掉所有旧 `fixed`。
|
|
124
153
|
|
|
125
154
|
**锚点坐标怎么选**
|
|
@@ -135,8 +164,8 @@ CLI:`e10-cli report fix freeze --report-id <id> --app-id <aid> --anchor 4,3 [-
|
|
|
135
164
|
|
|
136
165
|
1. **重建保真度不足**(除冻结点外与线上 `fields[]` 有差异)→ 拒绝,避免误伤;
|
|
137
166
|
2. **重复坐标**(同一 `(x,y)` 在 `fields[]` 里有 ≥2 条记录)→ 报 `exit 3` 并列出各条 `id/createTime`。
|
|
138
|
-
|
|
139
|
-
|
|
167
|
+
典型成因:**在设计器里把字段拖到某个表头格上**,旧 Const 未被清掉 → 该格"表头 + 字段"两条记录并存。
|
|
168
|
+
此时 workbook 一个坐标只能放一格,重建必然丢一条 → 必须先由用户确认取舍(或先去设计器清理)。
|
|
140
169
|
|
|
141
170
|
---
|
|
142
171
|
|
|
@@ -164,4 +193,4 @@ CLI:`e10-cli report fix freeze --report-id <id> --app-id <aid> --anchor 4,3 [-
|
|
|
164
193
|
| `targeted-fix-guide.md` | 定点范围;样式禁碰 |
|
|
165
194
|
| `report-designer-feature-map.md` §4.2 / §4.6 | UI 入口索引 |
|
|
166
195
|
| `safe-partial-save-guide.md` | 完整 workbook 写回 |
|
|
167
|
-
|
|
|
196
|
+
| `` → `fieldToCell` | 须把 `fixed` 写入 `cell.tag.fixed` |
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# 多报表交叉表搭建实战案例集(2026-10-29 ~ 10-30 · 业务专项统计报表)
|
|
2
|
+
|
|
3
|
+
> 本文件是**实战复盘 + 可复用蓝图模板**,配套 `SKILL.md` A0.13 / A0.13.1 强制规则。
|
|
4
|
+
> 案例报表:`1331872953607685192`「业务专项统计报表chl202610300310」(应用 `878284317729439749`)。
|
|
5
|
+
> 参考报表(已验收基准):`1331796692140359741`「chl测试专项业务202610292211」。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 一、本案例的结构画像
|
|
10
|
+
|
|
11
|
+
| 项 | 值 |
|
|
12
|
+
|---|---|
|
|
13
|
+
| sheet 数 | 2(`明细数据` / `核心摘要`) |
|
|
14
|
+
| 明细数据格数 | **79**(合并标题后从 163 降下来) |
|
|
15
|
+
| 核心摘要格数 | **30** |
|
|
16
|
+
| 报表块数 | 明细 3 块(模块1 / 模块2 / 模块3)+ 摘要 1 块 |
|
|
17
|
+
| 是否交叉表 | 是(4 个横向锚:`E4/G4`、`E10/G10`) |
|
|
18
|
+
| 列布局 | 8 列:`A 负责人 / B 专项名称 / C 所属大区城市 / D 拼接公式 / E 年份金额 / F 合计金额 / G 年份数量 / H 合计数量` |
|
|
19
|
+
| 数据集 | `xz=`专项区域业务(业务模块) `ht=`专项统计-直销合同-商务(数据加工) |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 二、★ 血案一:所有字段被绑到同一个数据集(最高频 · 必看)
|
|
24
|
+
|
|
25
|
+
### 症状
|
|
26
|
+
- 设计器右侧「数据集合」显示的是**同一个表**,跟字段实际该取的表不符;
|
|
27
|
+
- 字段回显空白 / 显示 `field_13xxxxxxxx` 原始 key;
|
|
28
|
+
- 报表预览取不到值,全 0 或全空。
|
|
29
|
+
|
|
30
|
+
### 根因(`e10-cli report rebuild from-blueprint` 第 236 行)
|
|
31
|
+
```js
|
|
32
|
+
const ds = idx.byKey[c.datasetKey || 'default'] || (c.datasetKey ? undefined : idx.all[0]);
|
|
33
|
+
```
|
|
34
|
+
**没写 `datasetKey` 的 Field 格 → 一律回退到 `idx.all[0]`(蓝图 `datasets[]` 的第一个)。**
|
|
35
|
+
而且 `buildCell()` 第 124-126 行会用解析出的 `ds` **重算覆盖** `dataSetId / nameIndex / fieldKey`:
|
|
36
|
+
```js
|
|
37
|
+
cell.dataSetId = String(ds.id);
|
|
38
|
+
cell.nameIndex = String(ds.nameIndex || '');
|
|
39
|
+
cell.fieldKey = `${ds.id}.${cell.nameIndex}.${bp.name}`;
|
|
40
|
+
```
|
|
41
|
+
→ 蓝图里 `dataSetId` 写得再对,**只要漏了 `datasetKey`,落库就是错的**,且回读校验「fieldKey 三段自洽」照样 PASS(因为它自洽地绑错了)。
|
|
42
|
+
|
|
43
|
+
### 铁律
|
|
44
|
+
**每个 Field 格必须同时给 4 个键,缺一不可**:
|
|
45
|
+
|
|
46
|
+
| 键 | 值 | 说明 |
|
|
47
|
+
|---|---|---|
|
|
48
|
+
| `datasetKey` | `'xz'` / `'ht'` | ★★ 落库脚本按它选数据集,漏了必错 |
|
|
49
|
+
| `dataSetId` | 数据集 id | 蓝图自检用 |
|
|
50
|
+
| `nameIndex` | 数据集 sourceId | 三段 key 的第二段 |
|
|
51
|
+
| `fieldKey` | `${id}.${sourceId}.${fieldName}` | 三段自洽 |
|
|
52
|
+
|
|
53
|
+
生成器里封装成工厂函数,并内置自检:
|
|
54
|
+
```js
|
|
55
|
+
function FD(x, y, fieldName, text, dsObj, opt = {}) {
|
|
56
|
+
const o = {
|
|
57
|
+
x, y, cellType: 'Field', sheetIndex: opt.sheetIndex || 0,
|
|
58
|
+
name: fieldName,
|
|
59
|
+
text: text || fieldName, // 数据显示名,设计器拿它当回显
|
|
60
|
+
tableName: TBL[opt.dsKey || 'xz'], // 面板显示名(带添加类型后缀)
|
|
61
|
+
datasetKey: opt.dsKey || 'xz', // ★★ 必须落进蓝图
|
|
62
|
+
dataSetId: dsObj.id,
|
|
63
|
+
nameIndex: dsObj.src,
|
|
64
|
+
fieldKey: `${dsObj.id}.${dsObj.src}.${fieldName}`,
|
|
65
|
+
...
|
|
66
|
+
};
|
|
67
|
+
cells.push(o); return o;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 自检:任一 Field 缺 datasetKey / text / fieldKey 即中止
|
|
71
|
+
const badField = cells.filter(c => c.cellType === 'Field' &&
|
|
72
|
+
(!c.text || !c.fieldKey || c.fieldKey.split('.')[0] !== c.dataSetId || !c.datasetKey));
|
|
73
|
+
if (badField.length) { console.error('!! Field 格不合规', badField.length); process.exit(1); }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 验伪方法(落库后必做)
|
|
77
|
+
```bash
|
|
78
|
+
# 看横向锚那一格:
|
|
79
|
+
# dataSetId / nameIndex / fieldKey / tableName 必须同时指向**正确的那张表**
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 三、★ 血案二:标题行没合并
|
|
85
|
+
|
|
86
|
+
### 症状
|
|
87
|
+
大标题 / 副标题 / 模块条文字挤在 A 列,右侧留白一大片,与参考报表不一致。
|
|
88
|
+
|
|
89
|
+
### 根因
|
|
90
|
+
上一版写成「1 个实格 + N-1 个空 `Const` 占位格」——视觉上**不是合并**。
|
|
91
|
+
参考报表的做法是**单格横向合并**:`xCount=1, yCount=列数`。
|
|
92
|
+
|
|
93
|
+
### 正确写法
|
|
94
|
+
```js
|
|
95
|
+
function BAR(x, text, si, st, n) {
|
|
96
|
+
guard(x, 0, si);
|
|
97
|
+
cells.push({
|
|
98
|
+
x, y: 0, cellType: 'Const', sheetIndex: si,
|
|
99
|
+
cellText: text,
|
|
100
|
+
xCount: 1, yCount: n || NCOL, // ★ 横向合并列数
|
|
101
|
+
topX: x === 0 ? -1 : 0, topY: x === 0 ? -1 : 0,
|
|
102
|
+
width: 150, style: st,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
参考报表验证(`1331796692140359741`):
|
|
107
|
+
```
|
|
108
|
+
x=0 y=0 Const xCount=1 yCount=8 "业务专项统计报表"
|
|
109
|
+
x=1 y=0 Const xCount=1 yCount=8 "统计周期 2023-2026 · 单位:元"
|
|
110
|
+
x=2 y=0 Const xCount=1 yCount=8 "本区域纯专项"
|
|
111
|
+
x=8 y=0 Const xCount=1 yCount=8 "纯专项(全量)"
|
|
112
|
+
```
|
|
113
|
+
**注意**:合并后不再需要那 N-1 个空格,格数会明显下降(本例 163 → 109),这是正常的。
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 四、★ 血案三:横向锚的上父格挂错(A0.13.1 的由来)
|
|
118
|
+
|
|
119
|
+
### 症状
|
|
120
|
+
- 年份列展开后,模块标题条不跟着撑宽,右侧留白;
|
|
121
|
+
- 或合计列(合计金额 / 合计数量)被横向锚带着逐列重复。
|
|
122
|
+
|
|
123
|
+
### 强制规则(A0.13.1)
|
|
124
|
+
多块 + 交叉表 + 有独立标题行的块内:
|
|
125
|
+
**横向扩展字段本身 + 它右侧所有单元格,上父格一律显式设为「本块标题行」,不写公共父格 `0,0`、不留 `-1,-1`。**
|
|
126
|
+
|
|
127
|
+
```js
|
|
128
|
+
// 模块块渲染:headX 是表头行,barX 是块标题条行
|
|
129
|
+
FD(headX, Y_AMT, 'qdnf', 'qdnf', DS.ht, {
|
|
130
|
+
dsKey: 'ht', sheetIndex: si, expandType: 'Horizontal', orderType: 'asc',
|
|
131
|
+
topX: barX, topY: 0, // ★★ 上父格 = 本块标题行(不是 0,0)
|
|
132
|
+
width: W[4], style: ST.head,
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 与之配套的判定宽容(否则死循环)
|
|
137
|
+
平台每次保存会把 `left=-1,-1` 归一成公共父格,所以 `scene check` 必须接受两跳链:
|
|
138
|
+
**表头格 `top=标题行` → 标题条 `top=公共父格`**,视为合规(`boundToPublicParentChained()`)。
|
|
139
|
+
详见 `SKILL.md` BUILD-60 / BUILD-62。
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 五、勾稽规则速查(父格该挂谁)
|
|
144
|
+
|
|
145
|
+
| 单元格类型 | 左父格(`leftX/leftY`) | 上父格(`topX/topY`) |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| 块标题条(合并 `yCount>1`) | `-1,-1` | 首块 `-1,-1`;非首块 `0,0` |
|
|
148
|
+
| 表头行 Const(行内非空 Const ≥2) | `-1,-1` | `0,0`(或经标题条两跳) |
|
|
149
|
+
| 行维入口格(首个 `Vertical` 字段) | `-1,-1` | `0,0` |
|
|
150
|
+
| 入口格右侧数据格 | `left=入口格坐标` | **`-1,-1`**(绑了 `top=0,0` 会判泛化禁令违规) |
|
|
151
|
+
| 横向扩展锚 | 跟随块内逻辑 | **本块标题行**(A0.13.1) |
|
|
152
|
+
| 横向锚右侧的合计列表头 | `-1,-1` | **本块标题行** |
|
|
153
|
+
| 数据行的合计列公式 | `left=同行入口格` | 本块标题行 |
|
|
154
|
+
| 合计行 | `left=合计行标签格` | 本块标题行 |
|
|
155
|
+
| 待接占位表头行(字段未接入) | `-1,-1` | `0,0`(整行都要归集) |
|
|
156
|
+
|
|
157
|
+
> `scene apply` **只补 `isActiveParent`,不修父格归属** —— 父格必须在蓝图里一次写对。
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 六、样式配色规范(8 种样式族 · 抄参考报表)
|
|
162
|
+
|
|
163
|
+
| 用途 | `backColor` | `foreColor` |
|
|
164
|
+
|---|---|---|
|
|
165
|
+
| 大标题 | `#2E5E9E` | `#FFFFFF` |
|
|
166
|
+
| 副标题 | `#EAF1F9` | `#44546A` |
|
|
167
|
+
| 模块条 | `#2E75B6` | `#FFFFFF` |
|
|
168
|
+
| 表头行 | `#E6E6E6` | `#333333` |
|
|
169
|
+
| 数据行 | `#fff` | `#333333` |
|
|
170
|
+
| 合计行 | `#FFF2CC` | `#333333` |
|
|
171
|
+
| 待接模块条 | `#7F7F7F` | `#FFFFFF` |
|
|
172
|
+
| 待接表头 | `#F2F2F2` | `#595959` |
|
|
173
|
+
|
|
174
|
+
```js
|
|
175
|
+
function style(bg, fg, opts = {}) {
|
|
176
|
+
return JSON.stringify({
|
|
177
|
+
backColor: bg, backgroundImageLayout: 0,
|
|
178
|
+
borderBottom: { color: '#999', style: 1 }, borderLeft: { color: '#999', style: 1 },
|
|
179
|
+
borderRight: { color: '#999', style: 1 }, borderTop: { color: '#999', style: 1 },
|
|
180
|
+
font: opts.font || '12px 微软雅黑', foreColor: fg,
|
|
181
|
+
formatter: '', // 「常规」= '' 或 'General',禁 'common'
|
|
182
|
+
hAlign: opts.hAlign === undefined ? 1 : opts.hAlign,
|
|
183
|
+
textDecoration: 0, textIndent: 0.0, themeColor: true, vAlign: 1, wordWrap: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## 七、跨表关联筛选标准写法
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
// 左边的 parentField 是本行维度字段,右边 currentField 是要取数的表的字段
|
|
194
|
+
const fFzr = { parentField: fk(DS.xz, 'field_…6054'), currentField: fk(DS.ht, 'zxfzr'), type: 'Equals', id: fk(DS.ht, 'zxfzr') };
|
|
195
|
+
const fCplx = { parentField: fk(DS.xz, 'field_…6053'), currentField: fk(DS.ht, 'cplx'), type: 'Contain', id: fk(DS.ht, 'cplx') };
|
|
196
|
+
const fDq = { parentField: fk(DS.xz, 'field_…6055'), currentField: fk(DS.ht, 'dq'), type: 'Equals', id: fk(DS.ht, 'dq') };
|
|
197
|
+
const fJgs = { parentField: fk(DS.xz, 'field_…6055'), currentField: fk(DS.ht, 'jgs'), type: 'Contain', id: fk(DS.ht, 'jgs') };
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**约定**:
|
|
201
|
+
- `id` **必须等于** `currentField`(否则设计器筛选项回显不出来);
|
|
202
|
+
- 同一个「所属大区城市」字段,在 A 模块用 `Equals dq`、在 B 模块用 `Contain jgs` ——
|
|
203
|
+
这就是「同一字段两套筛选」的标准表达,**写在不同的行**,各配各的 `customFilterField`;
|
|
204
|
+
- 本行自定义筛选(拆两行那种):
|
|
205
|
+
```js
|
|
206
|
+
[{ currentField: fk(DS.xz, 'field_…5939'), id: fk(DS.xz, 'field_…5939'), type: 'Equals', value: '1' }]
|
|
207
|
+
// 下拉字段 value 填 '1' / '0',不是「是」「否」文字
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## 八、命令速查(本案例全程用到的)
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
export EB_ETEAMSID="<取本机凭证>"
|
|
216
|
+
export EB_HOST="https://www.e-cology.com.cn"
|
|
217
|
+
|
|
218
|
+
# ★ 蓝图路径必须写盘符 E:/...,不能写 /e/...(会拼成 E:\e\...)
|
|
219
|
+
e10-cli report rebuild from-blueprint --blueprint "E:/.../bp-v14.json" --apply
|
|
220
|
+
|
|
221
|
+
# 场景校验 + 定点补丁
|
|
222
|
+
e10-cli report scene apply --report-id <rid> --app-id <appId> --scene A --apply
|
|
223
|
+
e10-cli report scene check --report-id <rid> --app-id <appId> --scene A
|
|
224
|
+
e10-cli report preflight --report-id <rid> --app-id <appId>
|
|
225
|
+
e10-cli report dataset id-check --report-id <rid> --app-id <appId>
|
|
226
|
+
|
|
227
|
+
# 回读验伪
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 九、本次会话注意清单(补充进 pitfalls 索引)
|
|
233
|
+
|
|
234
|
+
| 编号 | 坑 | 后果 | 规避 |
|
|
235
|
+
|---|---|---|---|
|
|
236
|
+
| **BUILD-65** | Field 格漏写 `datasetKey` | **全部字段被绑到 datasets[0]**,取不到值、回显空白 | FD 工厂强制 4 键 + 自检 |
|
|
237
|
+
| **BUILD-66** | 标题用「1 实格 + N-1 空格」 | 标题不合并,右侧留白 | 单格 `yCount=列数` |
|
|
238
|
+
| **BUILD-67** | 横向锚及其右侧上父格写 `0,0` | 标题不撑宽 / 合计列随锚复制 | A0.13.1:上父格 = 本块标题行 |
|
|
239
|
+
| **BUILD-68** | 数据格(入口右侧)写 `top=0,0` | `scene check` 判「泛化禁令」违规 | 数据格只 `left=入口格`,`top` 留 `-1,-1` |
|
|
240
|
+
| **BUILD-69** | 待接占位表头行 Const 留 `-1,-1` | 判「表头行未按方向统一到公共父格」 | 整行 Const 都写 `0,0` |
|
|
241
|
+
| **BUILD-70** | `--blueprint` 传 `/e/...` | `ENOENT E:\e\...` | 传 `E:/...` 盘符路径 |
|
|
242
|
+
| **BUILD-71** | 误以为 `scene apply` 能修父格 | 它只补 `isActiveParent`,白跑一轮 | 父格在蓝图里写对 |
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## 十、可复用蓝图骨架
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
const DS = {
|
|
250
|
+
xz: { id: '<dataset1>', src: '<sourceId1>', name: '表A' },
|
|
251
|
+
ht: { id: '<dataset2>', src: '<sourceId2>', name: '表B' },
|
|
252
|
+
};
|
|
253
|
+
const TBL = { xz: '表A(业务模块)', ht: '表B(数据加工)' };
|
|
254
|
+
|
|
255
|
+
// 块渲染:barX 标题条 / headX 表头行 / rows 数据行 / footX 合计行
|
|
256
|
+
function renderBlock(barX, headX, rows, footX, si, modes) {
|
|
257
|
+
// 表头:行维标题 Const → 写 top=0,0
|
|
258
|
+
// 横向锚 ×2:expandType=Horizontal, orderType=asc, topX=barX ← A0.13.1
|
|
259
|
+
// 横向锚右侧合计标题 Const:topX=barX, leftX=-1 ← A0.13.1 + 断左父格
|
|
260
|
+
// 数据行:入口格 top=0,0;右侧数据格 left=入口格 + top=-1,-1
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|