@guandata/guanvis 0.1.22 → 0.1.24

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## @guandata/guanvis 0.1.24 - 2026-06-09
4
+
5
+ - 新增 area title 和 card group 布局能力,支持在页面中组织分区标题和卡片分组。
6
+ - `gen-layout-id` 支持生成 area title 相关布局 ID,便于构建复杂页面布局。
7
+ - 增强布局 DSL、打包导出和页面布局校验,补充大量布局场景测试。
8
+
9
+ ## @guandata/guanvis 0.1.23 - 2026-06-04
10
+
11
+ - 新增指标卡片构建能力,支持基于指标配置生成图表卡片,并补充 `metric init` 和指标图表参考文档。
12
+ - 增强指标卡片 payload、联动、导出打包与发布前校验,提升指标图表构建稳定性。
13
+ - `publish --allow-overwrite` 覆盖线上 Card/Page 前会先创建资源迁移导出备份,备份失败或超时会中止覆盖。
14
+ - 补充资源包安全约束,强调只上传 `guanvis pack` 原样生成的资源包。
15
+
3
16
  ## @guandata/guanvis 0.1.22 - 2026-06-03
4
17
 
5
18
  - `install-skill` 增加 WorkBuddy skill 安装路径支持。
package/README.md CHANGED
@@ -18,6 +18,8 @@ guanvis genid 5
18
18
  # 生成布局组件 ID
19
19
  guanvis gen-layout-id tab
20
20
  guanvis gen-layout-id panel 3 --length 8
21
+ guanvis gen-layout-id areaTitle
22
+ guanvis gen-layout-id cardGroup
21
23
 
22
24
  # 初始化:从 BI 获取数据集结构
23
25
  guanvis init <dsId> -d ./my_dashboard/
@@ -31,17 +33,37 @@ guanvis pack ./my_dashboard/
31
33
  # 一步到位:构建并上传到 BI
32
34
  guanvis publish ./my_dashboard/
33
35
 
36
+ # 上传已有 ZIP;只上传 guanvis pack 原样生成的资源包
37
+ guanvis upload ./my_dashboard_package.zip
38
+
34
39
  # 只检查将要覆盖哪些线上资源,不上传
35
40
  guanvis publish ./my_dashboard/ --dry-run
36
41
 
37
- # 明确要覆盖同 ID 线上 Card/Page 时才加
42
+ # 明确要覆盖同 ID 线上 Card/Page 时才加;覆盖前会先导出备份记录,备份成功才继续
38
43
  guanvis publish ./my_dashboard/ --allow-overwrite
39
44
  ```
40
45
 
41
46
  说明:npm 包名为 `@guandata/guanvis`,用户侧 CLI 命令统一为 `guanvis`。
42
47
 
48
+ `guanvis upload` 只是上传器,不是自定义资源包制作入口。资源包应由 DSL 源文件通过 `guanvis pack` / `guanvis publish` 生成;不要手工生成、解包修改或重打包 ZIP。需要批量重绑资源或迁移已有页面时,先确认方案,不要直接改 ZIP 上传。
49
+
50
+ 使用 `--allow-overwrite` 覆盖线上资源时,CLI 会先为冲突 Card/Page 创建资源迁移导出备份记录,并等待备份导出成功;备份失败或超时会中止覆盖。CLI 不自动下载备份包,会在输出中打印 packageId。需要回滚时,到 BI 资源迁移导出记录中下载该资源包后手动导入覆盖回去。
51
+
43
52
  ## 版本更新
44
53
 
54
+ ### @guandata/guanvis 0.1.24
55
+
56
+ - 新增 area title 和 card group 布局能力,支持在页面中组织分区标题和卡片分组。
57
+ - `gen-layout-id` 支持生成 area title 相关布局 ID,便于构建复杂页面布局。
58
+ - 增强布局 DSL、打包导出和页面布局校验,补充大量布局场景测试。
59
+
60
+ ### @guandata/guanvis 0.1.23
61
+
62
+ - 新增指标卡片构建能力,支持基于指标配置生成图表卡片,并补充 `metric init` 和指标图表参考文档。
63
+ - 增强指标卡片 payload、联动、导出打包与发布前校验,提升指标图表构建稳定性。
64
+ - `publish --allow-overwrite` 覆盖线上 Card/Page 前会先创建资源迁移导出备份,备份失败或超时会中止覆盖。
65
+ - 补充资源包安全约束,强调只上传 `guanvis pack` 原样生成的资源包。
66
+
45
67
  ### @guandata/guanvis 0.1.22
46
68
 
47
69
  - `install-skill` 增加 WorkBuddy skill 安装路径支持。
@@ -69,7 +91,7 @@ guanvis publish ./my_dashboard/ --allow-overwrite
69
91
  ### 0.1.18
70
92
 
71
93
  - 新增 Tab 布局能力,支持通过 `createTab()` / `addPanel()` 组织同页多组可切换内容。
72
- - 新增 `gen-layout-id` 命令,用于生成 tab/panel 等布局组件 ID。
94
+ - 新增 `gen-layout-id` 命令,用于生成布局组件 ID。
73
95
  - 增加 Tab 布局示例工程和文档说明,便于快速复用。
74
96
  - 增强筛选器默认值校验,提前发现不匹配的筛选值配置。
75
97
 
Binary file
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guandata/guanvis",
3
- "version": "0.1.22",
3
+ "version": "0.1.24",
4
4
  "description": "观远 BI Card/Page 生成工具 - 通过 JS DSL 创建图表和仪表板",
5
5
  "bin": {
6
6
  "guanvis": "bin/run.js"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: guanvis
3
- description: 当用户要新建、修改、组装观远 BI / Guandata 的 Card(图表/报表卡片)、文本卡片、图片卡片、筛选器(selector,含日历/时间宏/区间/离散值)或仪表板(Page),或给出 Card ID、数据集 ID、card.js/page.js、图表类型关键词(柱状/折线/饼/KPI/表格/漏斗/地图/散点等 30+ 种)时,优先使用这个 skill。即使用户只说"做个销售仪表板""加个 KPI 卡片""新建一个区域筛选器联动所有图""帮我改一下这个图的图例""把这几个 card 拼成一个 page""加一个本月/近 7 天的快捷日期筛选",也要主动使用。它通过 AI 编写简洁的 JS 脚本(card_*.js / selector_*.js / page.js)定义卡片、筛选器和页面布局,再 pack/publish 上传到目标 BI。认证复用 guancli 共享配置。只想查现有 Card/Page 内容走 guancli。
3
+ description: 当用户要新建、修改、组装观远 BI / Guandata 的 Card(图表/报表卡片)、用指标平台指标创建的指标卡片、文本卡片、图片卡片、筛选器(selector,含日历/时间宏/区间/离散值)或仪表板(Page),或给出 Card ID、数据集 ID、指标 ID、card.js/page.js、图表类型关键词(柱状/折线/饼/KPI/表格/漏斗/地图/散点等 30+ 种)时,优先使用这个 skill。即使用户只说"做个销售仪表板""用这个指标做张卡片""加个 KPI 卡片""新建一个区域筛选器联动所有图""帮我改一下这个图的图例""把这几个 card 拼成一个 page""加一个本月/近 7 天的快捷日期筛选",也要主动使用。它通过 AI 编写简洁的 JS 脚本(card_*.js / selector_*.js / page.js)定义卡片、筛选器和页面布局,再 pack/publish 上传到目标 BI。认证复用 guancli 共享配置。只想查现有 Card/Page 内容走 guancli。
4
4
  compatibility: "Requires Node.js 14+. Install via npm link (local) or npm install -g @guandata/guanvis (from internal Nexus registry). CLI command: guanvis."
5
5
  ---
6
6
 
@@ -9,7 +9,7 @@ compatibility: "Requires Node.js 14+. Install via npm link (local) or npm instal
9
9
  这是一个执行型 skill,用于通过 AI 生成的 JS 脚本创建 BI Card 和 Page 资源。
10
10
 
11
11
  - AI 生成 `card_*.js` 定义各个 Card 图表;`page.js` 将多个 Card 组装成仪表板。
12
- - `schema.js` 由 `init` 命令自动生成,定义数据集字段信息(不允许 AI 修改)。
12
+ - `schema.js` 由 `init` 命令自动生成,定义数据集字段信息(不允许 AI 修改);指标卡片使用 `metric-init` 生成 `metrics.js`。
13
13
  - 框架内置验证规则,在 pack/publish 时检查字段数量、zone 兼容性、必填字段等。
14
14
  - 认证通过 `guancli` 共享配置自动获取。
15
15
 
@@ -17,18 +17,19 @@ compatibility: "Requires Node.js 14+. Install via npm link (local) or npm instal
17
17
 
18
18
  把可视化生成当作源文件驱动的构建流程:本地 JS DSL 是可编辑事实源,payload、ZIP、线上 Card/Page 都是从源文件生成的派生产物。
19
19
 
20
- - `schema.js` 是由 `init` 生成的数据集事实快照,不手改;数据集字段变化时重新运行 `init`。
20
+ - `schema.js` 是由 `init` 生成的数据集事实快照,不手改;数据集字段变化时重新运行 `init`。`metrics.js` 是由 `metric-init` 生成的指标事实快照,不手改;指标口径、适用维度或格式变化时重新运行 `metric-init`。
21
21
  - `card_*.js`、`selector_*.js`、`page.js` 是可编辑源文件;`*_package.zip`、preview JSON、publish 后线上资源都是派生产物。
22
22
  - Card/Page 描述也是 JS 源文件的一部分:新建看板或改版时,在 `card_*.js` / `page.js` 中写 `.setDescription(...)`,再通过 `preview`/`pack`/`publish` 从 JS 源文件生成并发布资源。
23
23
  - 写脚本前先形成 dashboard contract:目标用户、业务问题、使用的数据集、核心指标、维度拆解、筛选器、页面结构和验证方式。
24
24
  - 每次生成都针对明确目录或明确子目录;不要把 unrelated 示例、旧包或临时 ZIP 混入同一个发布目标。
25
25
  - 先 `preview/pack` 做本地结构验证,再 `publish/upload`;修改已发布资源前先判断变更类型:仅修复 Card/Page 描述时应保留原资源 ID,使用 `card/page set-description` 并同步维护 JS 中的 `.setDescription(...)`;调整图表、布局、筛选器、字段等看板内容时,按线上仪表板更新策略处理。
26
+ - **资源包安全红线**:Agent 只编辑 DSL 源文件;资源包 ZIP 是 `guanvis pack/publish` 的派生产物,不手工生成、解包修改或重打包。`guanvis upload` 只允许上传 `guanvis pack` 原样生成的 ZIP。若用户要求批量重绑资源、迁移已有页面或复用线上页面结构,先停下来说明风险并确认方案,不要直接改 ZIP。
26
27
  - 发布后优先用 `guancli page get/card get` 回读结构与配置。只有在明确需要视觉质量判断、且当前大模型支持图像理解时,才使用 `guanvis screenshot <pageId>` 生成 PNG 并交给模型分析;不要把截图作为默认闭环步骤,因为图像理解会额外消耗 token/费用。
27
28
 
28
29
  ## AI Quick Reference(速查,详细说明见按需参考资料)
29
30
 
30
- 1. **工厂函数**:只用 `createCard()` / `createSelector()` / `createTextCard()` / `createDuPontChart()` / `createTab()` / `createPage()`,不要 `new XxxBuilder()`
31
- 2. **注册函数**:`registerCard(card.build())` / `registerSelector(sel.build())` / `registerTextCard(text.build())` / `registerDuPontChart(dupont.build())` / `registerPage(page.build())`
31
+ 1. **工厂函数**:数据集图表用 `createCard()`;指标平台指标卡片用 `createMetricChart()`;筛选器/文本/图片/杜邦/Tab/页面用 `createSelector()` / `createTextCard()` / `createImageCard()` / `createDuPontChart()` / `createAreaTitle()` / `createCardGroup()` / `createTab()` / `createPage()`,不要 `new XxxBuilder()`
32
+ 2. **注册函数**:`registerCard(card.build())` / `registerMetricChart(card.build())` / `registerSelector(sel.build())` / `registerTextCard(text.build())` / `registerImageCard(image.build())` / `registerDuPontChart(dupont.build())` / `registerPage(page.build())`
32
33
  3. **字段引用**:单数据集用 `f("字段名")`,多数据集用 `field(DS, "字段名")`
33
34
  4. **zone maxCount**:`BASIC_COLUMN/BAR/LINE` metric=1;`GROUPED_*/STACKED_*` metric=∞;`KPI_CARD` metric=1;组合图 `*_WITH_LINE` row=1
34
35
  5. **column vs colorBy**:column 放维度(按类别分组着色),colorBy 放度量(按值渐变着色)
@@ -39,21 +40,23 @@ compatibility: "Requires Node.js 14+. Install via npm link (local) or npm instal
39
40
  10. **联动/下钻**:筛选器联动必须调用 `.linkToAll()` 或 `.linkTo(cardIndex)`;普通图表卡片联动普通图表用 `card.linkTo(layoutCardIndex, { fields: [{ source, target }] })`;固定路径下钻用 `registerDrillPath(parentCardIndex, [child.build()], { position: DrillPathPosition.BOTTOM })`;详细规则见 `references/builder-reference.md`
40
41
  11. **selector 类型选择**:离散值(区域/类别)→ `DS_ELEMENTS`(默认);连续数值(利润率/金额)→ `.setSelectorType(SelectorType.DS_INTERVAL)`;日期 → `CALENDAR`;快捷日期区间(本月/近7天等)→ `.setTimeMacroOptions(options)`
41
42
  12. **同环比默认**:用户说同比/环比/同环比/年同比/月环比且未指定输出值时,默认用增长率;未指定模式时默认按日期筛选模式(`ComparativeMode.FILTER_BASED`),普通模式需显式指定 `ComparativeMode.NORMAL`
42
- 13. **placeCard 索引**:按 registerCard registerTextCard 调用顺序累加,文件按文件名排序加载。**registerSelector 不参与 card index 计数**
43
+ 13. **placeCard 索引**:按 `registerCard` / `registerMetricChart` / `registerTextCard` 的实际调用顺序累加,文件按文件名排序加载。**registerSelector 不参与 card index 计数**
43
44
  14. **publish 环境**:认证由底层 CLI 负责——guancli 需先 `guancli auth use <profile>`,guancli-lite 需设置环境变量
44
- 15. **更新线上仪表板**:已发布过或线上正在使用的仪表板,若调整图表、布局、筛选器、字段等看板内容,默认创建新版本仪表板,不覆盖原仪表板;新版本使用新的 Page/Card/Selector ID,名称追加版本号(如 `销售仪表板 v2` / `销售仪表板 20260430`),保留多个版本。只有用户明确要求覆盖时,才复用原 ID
45
+ 15. **更新线上仪表板**:已发布过或线上正在使用的仪表板,若调整图表、布局、筛选器、字段等看板内容,默认创建新版本仪表板,不覆盖原仪表板;新版本使用新的 Page/Card/Selector ID,名称追加版本号(如 `销售仪表板 v2` / `销售仪表板 20260430`),保留多个版本。只有用户明确要求覆盖时,才复用原 ID;遇到覆盖提示时,Agent 必须先向用户说明将覆盖哪些线上资源并取得明确确认,确认前不得自行加 `--allow-overwrite`
45
46
  16. **描述维护**:仅修复已发布 Card/Page 的描述时,保留原资源 ID,使用 `guanvis card/page set-description` 更新线上描述;如果本地有对应 JS 工程,也同步更新 `.setDescription(...)`,让源文件与线上描述一致
46
- 17. **主题切换**:用户描述风格(深色科技风/科技蓝/蓝色简约等)→ 在工程目录里 `guanvis theme preference --keywords "..." --sync`(`[dir]` 可省,默认当前目录);不要选择租户默认的“浅色”/“深色”主题,找不到合适主题时保持/清空偏好,让 preview/pack/publish 自动使用内置“简约”兜底。改版未提风格时 `.applied.json` 会自动继承上次主题,preview/pack/publish 不需要重复指定。**多子目录工程**:每个子目录是独立工程,主题要在子目录里配置 + preview/pack/publish 也必须 `cd` 进对应子目录运行(在根目录直接跑会被命令显式拒绝并给出 cd 提示);详见 `references/theme.md`
47
+ 17. **主题切换**:用户描述风格(深色科技风/科技蓝/蓝色简约等)→ 在工程目录里 `guanvis theme preference --keywords "..." --sync`(`[dir]` 可省,默认当前目录);不要选择租户默认的“浅色”/“深色”主题,找不到合适主题时保持/清空偏好,让 preview/pack/publish 自动使用内置“简约”兜底。普通数据集图表与指标平台 MetricChart 都会自动应用主题视觉配置;改版未提风格时 `.applied.json` 会自动继承上次主题,preview/pack/publish 不需要重复指定。**多子目录工程**:每个子目录是独立工程,主题要在子目录里配置 + preview/pack/publish 也必须 `cd` 进对应子目录运行(在根目录直接跑会被命令显式拒绝并给出 cd 提示);详见 `references/theme.md`
47
48
  18. **设计规则**:`preview`/`pack`/`publish` 会自动应用内置设计规则;需要自定义静态卡片默认规则或主题已开放配置时,在工程目录新建 `design-rule.json`,不要手改 `themes/<themeId>.json`;详见 `references/theme.md`
48
- 19. **图表选型**:创建指标卡时,若只有单指标优先用 `SINGLE_VALUE`;需展示对比指标时用 `KPI_CARD`,并调用 `.addCompare(...)`
49
+ 19. **图表选型**:用户说“指标卡片”时先区分语义:如果是数据集字段做单值/KPI,用 `SINGLE_VALUE` / `KPI_CARD`;如果是“用指标平台已有指标创建卡片”,必须先 `guanvis metric-init <metricId>`,再用 `createMetricChart()` + `metric()` / `metricDim()`,生成后端 `CARD_TYPE.METRIC_CHART`。复杂指标卡片参数先读 `references/metric-chart-reference.md`
49
50
  20. **杜邦分析图**:杜邦不是普通 `ChartType`,用 `createDuPontChart()` 创建 `LAYOUT` 卡片;节点通常放 `KPI_CARD` 子卡片,并通过 `.setRoot()` / `.addChild()` 组织树。页面布局只放杜邦父卡片,不单独放子卡片;筛选器 `linkToAll()` 会覆盖杜邦子卡片。
50
- 21. **tab 布局**:同一主题有多组互斥分析内容时可用 tab;少量卡片或需同时对照时优先平铺。用法见 `references/builder-reference.md`,示例见 `evals/tab_layout/`
51
+ 21. **布局组件**:支持了布局组件 `小标题(AreaTitle)`/ `卡片组(CardGroup)`/ `标签页(Tab)`, 目前布局组件只支持放在画布的根布局,不支持嵌套组合使用,用法见 `references/builder-reference.md`。
52
+ 22. **资源包禁止手改**:只改 DSL,不改 ZIP 内部文件;`upload` 只用于上传 `guanvis pack` 原样生成的包。批量重绑、迁移页面等需求先讨论方案。
51
53
 
52
54
  ## 何时使用
53
55
 
54
56
  遇到这些任务就用:
55
57
 
56
58
  - 新建观远 BI Card(柱形图、折线图、饼图、表格、KPI、散点图、漏斗、地图等 30+ 种)。
59
+ - 基于指标平台已有指标创建指标卡片(MetricChart,后端 `cdType=13`),支持指标自身格式和适用维度。
57
60
  - 创建文本卡片(含内嵌指标引用)或图片卡片(外链/本地图片)。
58
61
  - 创建筛选器并配置联动关系(选择筛选器、日历筛选器等)。
59
62
  - 组装多个 Card 和筛选器为一个仪表板/Page,含 grid layout 布局和筛选器面板。
@@ -92,6 +95,31 @@ defineDataset("s9ded2338f43807b095fbb4f", [
92
95
  ], { displayType: "EXCEL" });
93
96
  ```
94
97
 
98
+ ### 2b. 生成 metrics.js(创建指标平台指标卡片时)
99
+
100
+ 当用户说“用指标创建卡片”“指标卡片”且给出的是指标平台 metric ID/指标名时,走这条链路,而不是把指标当作数据集字段:
101
+
102
+ ```bash
103
+ # 先用 guancli 查指标 ID(如果用户只给名称)
104
+ guancli metric search '<关键词>'
105
+
106
+ # 生成指标事实快照
107
+ guanvis metric-init <metricId1> <metricId2> -d ./my_dashboard/
108
+ ```
109
+
110
+ 生成后在 `card_*.js` 中使用:
111
+
112
+ ```javascript
113
+ var card = createMetricChart(ChartType.PIVOT_TABLE, "销售指标分析")
114
+ .setId("cardId24chars")
115
+ .addRow(metricDim("销售额", "区域"))
116
+ .addMetric(metric("销售额"));
117
+
118
+ registerMetricChart(card.build());
119
+ ```
120
+
121
+ `metrics.js` 必须在 `card_*.js` 前加载;目录模式会自动按 `schema.js` → `metrics.js` → `card_*.js` → `selector_*.js` → `page.js` 的顺序执行。
122
+
95
123
  ### 3. 设置仪表板主题(按需)
96
124
 
97
125
  如果用户**明确提到了视觉风格**("深色科技风"、"蓝色简约"、"科技蓝T004" 或具体 themeId 等),在编写 card/page 之前把意图落到 `.preference.json`。不要把租户默认的“浅色”/“深色”当作可选主题;如果候选里没有合适风格,跳过这一步或执行 `theme preference --clear`,让命令自动使用内置“简约”:
@@ -188,6 +216,8 @@ registerPage(page.build());
188
216
 
189
217
  **仪表板主题**:项目目录下没配 `themes/` 时,`preview`/`pack`/`publish` 自动使用 skill 自带的简约主题(embed 在二进制里的 `simple.json`,不依赖租户线上主题列表)。如需切换租户自定义主题或带明确风格的默认主题,请参考 `references/theme.md`,通过 `guanvis theme preference` 写入 `themes/.preference.json`;租户默认“浅色”/“深色”没有特殊样式,不作为可选主题。**JS DSL 不再提供主题相关接口**——任何 `setDashboardTheme(...)` 或 `page.setTheme(...)` 调用都会因函数未定义而报错。
190
218
 
219
+ 指标平台 MetricChart 也会在 `preview`/`pack`/`publish` 阶段自动应用主题视觉配置:透视表会补表格/合计样式,柱线饼等会补坐标轴、图例、数据标签和主题色。主题只写 `settings` 与 `meta.chartMain.props`,不改 `zoneData`、`dsInfo`、`defaultView` 等影响指标查询的字段。
220
+
191
221
  **多页面支持**:可以在同一个项目中注册多个 page(多次调用 `registerPage`)。两种组织方式:
192
222
 
193
223
  1. **单目录**:所有 card 和 page 在同一目录,page 通过 card index(注册顺序)引用
@@ -236,6 +266,8 @@ guanvis genid 5 # 生成 5 个
236
266
  # 生成布局组件 ID
237
267
  guanvis gen-layout-id tab # 生成 1 个 tab_ + 默认 6 位字母
238
268
  guanvis gen-layout-id panel 3 --length 8 # 生成 3 个 panel_ + 8 位字母;length 只计算下划线后的随机字母,超出 6~10 时自动收敛
269
+ guanvis gen-layout-id areaTitle # 生成 1 个 areaTitle_ + 默认 6 位字母
270
+ guanvis gen-layout-id cardGroup # 生成 1 个 cardGroup_ + 默认 6 位字母
239
271
 
240
272
  # 预览生成结果(JSON 输出到 stdout,含 payload 验证,用于调试)
241
273
  guanvis preview ./my_dashboard/
@@ -248,7 +280,7 @@ guanvis pack -o output.zip ./my_dashboard/
248
280
  guanvis publish ./my_dashboard/
249
281
  guanvis publish ./my_dashboard/ --page-parent-dir <dir_id> # 指定页面目录
250
282
 
251
- # 上传已有 ZIP 资源包
283
+ # 上传已有 ZIP 资源包;只允许上传 guanvis pack 原样生成的 ZIP
252
284
  guanvis upload output.zip
253
285
 
254
286
  # 修复已发布资源描述(保留原 Card/Page ID)
@@ -294,15 +326,18 @@ guanvis pack ./project
294
326
  - 需要 `raw-backend-response: TRUE` header 绕过前端代理层
295
327
  - 不需要目标系统开启"一键迁移"开关,所有环境通用
296
328
 
297
- **线上仪表板更新策略**:为了保护已经发布过的仪表板和线上仪表板,默认不要复用原 Page/Card/Selector ID 做覆盖更新。需要调整线上看板时,应先生成一组新的 ID,复制并修改 DSL/JS,给 Page 名称追加版本号(例如 `v2`、`v20260430` 或业务约定版本),再 `publish` 到目标目录。旧版本保留用于回滚和对比。仅当用户明确要求“覆盖原仪表板/复用原 ID”时,才允许同 ID 发布,并且命令必须显式加 `--allow-overwrite`;发布前可用 `--dry-run` 查看会覆盖哪些线上 Card/Page
329
+ **资源包安全约束**:`upload` 只是上传器,不是制作自定义资源包的入口。除非用户明确批准,否则不得上传手工生成、解包修改、重打包或批量替换内部内容后的 ZIP。需要批量重绑数据集、字段、卡片或页面 ID 时,先讨论方案,不要直接改 ZIP
330
+
331
+ **线上仪表板更新策略**:为了保护已经发布过的仪表板和线上仪表板,默认不要复用原 Page/Card/Selector ID 做覆盖更新。需要调整线上看板时,应先生成一组新的 ID,复制并修改 DSL/JS,给 Page 名称追加版本号(例如 `v2`、`v20260430` 或业务约定版本),再 `publish` 到目标目录。旧版本保留用于回滚和对比。仅当用户明确要求“覆盖原仪表板/复用原 ID”时,才允许同 ID 发布,并且命令必须显式加 `--allow-overwrite`;发布前可用 `--dry-run` 查看会覆盖哪些线上 Card/Page。**Agent 禁止在未确认的情况下自行加 `--allow-overwrite`**:当 CLI 提示将覆盖线上资源时,必须先停止发布,向用户说明将覆盖的 Page/Card ID、名称和覆盖后可能替换原页面布局/卡片配置,等用户明确确认“覆盖”后才可以重跑并加 `--allow-overwrite`。使用 `--allow-overwrite` 时,CLI 会先为冲突资源发起资源包导出备份并等待导出成功;备份未成功则中止覆盖。CLI 只记录备份导出记录和 packageId,不自动下载资源包;需要回滚时,到 BI 资源迁移导出记录中手动下载该资源包后再导入覆盖回去。
298
332
 
299
333
  ## 文件结构约定
300
334
 
301
335
  目录模式下文件加载顺序:
302
336
  1. `schema.js` — 数据集定义(自动生成,不可修改)
303
- 2. `card_01_xxx.js` ~ `card_NN_xxx.js` Card 定义(按文件名排序)
304
- 3. `selector_01_xxx.js` ~ `selector_NN_xxx.js` — 筛选器定义(在 card 之后执行,因为联动需要引用 card 索引)
305
- 4. `page.js` — Page/仪表板组装
337
+ 2. `metrics.js` — 指标定义(仅指标卡片需要,自动生成,不可修改)
338
+ 3. `card_01_xxx.js` ~ `card_NN_xxx.js` — Card 定义(按文件名排序)
339
+ 4. `selector_01_xxx.js` ~ `selector_NN_xxx.js` 筛选器定义(在 card 之后执行,因为联动需要引用 card 索引)
340
+ 5. `page.js` — Page/仪表板组装
306
341
 
307
342
  自定义图表时,图表内容文件(如 ECharts 脚本)放在 **子目录**(如 `charts/`),避免被当作 card 脚本执行。
308
343
 
@@ -18,6 +18,39 @@
18
18
 
19
19
  三者都是字段工厂函数,输出都是字段对象。
20
20
 
21
+ ### 指标平台指标与维度
22
+
23
+ 当卡片基于指标平台已有指标创建时,先生成指标事实快照:
24
+
25
+ ```bash
26
+ guanvis metric-init <metricId1> <metricId2> -d ./my_dashboard/
27
+ ```
28
+
29
+ `metric-init` 会写入 `metrics.js`,内容通过 `defineMetric()` 保存指标 ID、名称、类型、数据格式、适用维度和时间维度。AI 不应手改 `metrics.js`;指标变化时重新运行命令。
30
+
31
+ | 函数 | 说明 |
32
+ |------|------|
33
+ | `defineMetric(metricDef)` | 定义指标事实快照,由 `metric-init` 自动生成 |
34
+ | `metric(metricIdOrName, overrides?)` | 引用指标平台指标,用于 `createMetricChart(...).addMetric(...)` |
35
+ | `metricDim(metricIdOrName, dimName, overrides?)` | 引用指定指标的适用维度,用于行/列/筛选/排序 |
36
+ | `metricDim(dimName, overrides?)` | 在所有已定义指标中按维度名查找;同名维度较多时不要使用 |
37
+ | `getMetric(metricIdOrName)` | 获取已定义指标对象 |
38
+
39
+ 指标搜索使用位置参数,例如 `guancli metric search '销售额'`。不要使用 `--name-like`。
40
+
41
+ 复杂指标卡片的 `zoneData`、`props`、`config`、`summary`、MPH 占位列和验证方式见 `references/metric-chart-reference.md`。
42
+
43
+ 示例:
44
+
45
+ ```javascript
46
+ var card = createMetricChart(ChartType.PIVOT_TABLE, "销售指标分析")
47
+ .setId("card12345678901234567890")
48
+ .addRow(metricDim("销售额", "区域"))
49
+ .addMetric(metric("销售额"));
50
+
51
+ registerMetricChart(card.build());
52
+ ```
53
+
21
54
  **聚合字段优先级**:
22
55
 
23
56
  - 单字段聚合必须优先使用原生聚合配置,例如 `.addMetric(f("销售额", { aggrType: AggrType.SUM }))`、`.addMetric(f("客户ID", { aggrType: AggrType.COUNT_DISTINCT }))`。
@@ -29,6 +29,55 @@
29
29
  | `.setRawSettings(key, value)` | 原始设置 |
30
30
  | `.build()` | 构建(触发验证) |
31
31
 
32
+ ### MetricChartBuilder(指标平台指标卡片)
33
+
34
+ 用于“用指标平台已有指标创建卡片”,生成后端 `CARD_TYPE.METRIC_CHART`(`cdType=13`)。不要用普通 `createCard()` 伪造,也不要把指标 ID 当作数据集字段。
35
+
36
+ 前置:先运行 `guanvis metric-init <metricId...> -d <dir>` 生成 `metrics.js`。目录模式会在 `card_*.js` 前自动加载。
37
+
38
+ | 函数/方法 | 说明 |
39
+ |------|------|
40
+ | `defineMetric(metricDef)` | 定义指标事实快照,由 `metric-init` 生成;不要手写/手改 |
41
+ | `metric(metricIdOrName, overrides?)` | 引用指标,传指标 ID 或指标名;用于 `.addMetric(...)` |
42
+ | `metricDim(metricIdOrName, dimName, overrides?)` | 引用某个指标的适用维度;维度名、`fdId` 或 `publicDimensionId` 均可匹配 |
43
+ | `metricDim(dimName, overrides?)` | 在所有已定义指标的适用维度中查找;多指标同名维度时优先用上面的双参数写法 |
44
+ | `createMetricChart(chartType, name)` | 创建指标卡片,`chartType` 使用 `ChartType.XXX`,默认可用 `PIVOT_TABLE` |
45
+ | `.setId(cardId)` | 设置 24 位资源 ID,用于重复导入覆盖 |
46
+ | `.addRow(field)` / `.addColumn(field)` | 添加指标适用维度 |
47
+ | `.addMetric(metric)` | 添加指标平台指标;至少一个 |
48
+ | `.addFilter(field, filterType, filterValue)` / `.addSort(field)` | 添加筛选/排序 |
49
+ | `.setShowLegend()` / `.setDataLabel()` / `.setAxis()` / `.setTableSetting()` / `.setRawSettings()` | 常用图表设置,和普通 CardBuilder 一致 |
50
+ | `.setProps(obj)` / `.setRawProps(key, value)` | 设置指标卡片 `meta.chartMain.props` |
51
+ | `.setConfig(obj)` / `.setRawConfig(key, value)` | 设置指标卡片 `meta.chartMain.config` |
52
+ | `.setSummary(obj)` | 设置指标卡片 `meta.summary` |
53
+ | `.setColumns(columns)` | 设置指标卡片 `content.columns` / `dsInfo.columns` |
54
+ | `.addMetricAdditional()` / `.addColorBy()` / `.addSize()` / `.addTooltip()` / `.addSplit()` | 添加副轴、颜色、大小、提示、拆分区域字段 |
55
+ | `.build()` | 构建指标卡片 |
56
+
57
+ 完整参数表、MPH 占位列、自由钻取、条件格式、迷你图、业务限定、动态字段等见 `references/metric-chart-reference.md`。
58
+
59
+ ```javascript
60
+ var card = createMetricChart(ChartType.PIVOT_TABLE, "销售指标分析")
61
+ .setId("card12345678901234567890")
62
+ .addRow(metricDim("销售额", "区域"))
63
+ .addMetric(metric("销售额"))
64
+ .addSort(metric("销售额", { sortType: SortOrder.DESC }));
65
+
66
+ registerMetricChart(card.build());
67
+ ```
68
+
69
+ 多指标示例:
70
+
71
+ ```javascript
72
+ var card = createMetricChart(ChartType.GROUPED_COLUMN, "销售与利润")
73
+ .setId("metriccard12345678901234")
74
+ .addRow(metricDim("销售额", "月份", { granularity: Granularity.MONTH }))
75
+ .addMetric(metric("销售额"))
76
+ .addMetric(metric("利润"));
77
+
78
+ registerMetricChart(card.build());
79
+ ```
80
+
32
81
  #### 图表选型
33
82
 
34
83
  - `SINGLE_VALUE`:只展示一个指标值,例如总销售额、订单数、门店数、平均客单价。
@@ -134,7 +183,7 @@ var card = createCard(ChartType.GROUPED_COLUMN, "区域销售")
134
183
  registerCard(card.build());
135
184
  ```
136
185
 
137
- `target` 为数字时,默认和页面布局中的 `card: n` 含义一致,按 `registerCard` / `registerTextCard` / `registerImageCard` / `registerCustomChart` / `registerDuPontChart` 等可布局资源的注册顺序解析;`registerSelector` 不参与该 index。注意它和 `SelectorBuilder.linkTo(cardIndex)` 不同,selector 的 index 仍是历史普通图表注册顺序。
186
+ `target` 为数字时,默认和页面布局中的 `card: n` 含义一致,按 `registerCard` / `registerMetricChart` / `registerTextCard` / `registerImageCard` / `registerCustomChart` / `registerDuPontChart` 等可布局资源的注册顺序解析;`registerSelector` 不参与该 index。CardBuilder 点击联动目前只支持普通图表卡片、下钻子卡和杜邦子卡作为目标,不支持 MetricChart、文本、图片和自定义图表。注意它和 `SelectorBuilder.linkTo(cardIndex)` 不同,selector 的 index 是过滤后的可联动目标序列:普通图表和 MetricChart 按注册/布局顺序进入序列,文本/图片/自定义图表等不可联动资源不占序号,杜邦子图追加在末尾。
138
187
 
139
188
  `target` 也可以是 cardId 字符串,用于引用不在布局 index 中的固定路径下钻子卡;字符串目标也可以指向普通 layout 图表卡。
140
189
 
@@ -144,7 +193,7 @@ registerCard(card.build());
144
193
 
145
194
  支持范围:
146
195
 
147
- - 普通图表卡片可以联动同页普通图表卡片,或其它下钻路径中的子卡。
196
+ - 普通图表卡片可以联动同页普通图表卡片,或其它下钻路径中的子卡;CardBuilder 点击联动暂不支持 MetricChart 作为 source 或 target。
148
197
  - 下钻子卡可以联动同页普通图表卡片。
149
198
  - 下钻路径内的父子卡、同路径子卡之间不建立联动;下钻子卡之间也不建立联动。
150
199
  - source 卡片不能跨 page 复用,也不能已有 `settings.asFilter`。
@@ -240,8 +289,10 @@ overview.linkTo("bbbbbbbbbbbbbbbbbbbbbbbb", {
240
289
 
241
290
  **布局单位**:
242
291
  1. 默认横向使用 12 列栅格;开启精细模式后使用 60 列栅格。
243
- 2. 推荐通过 `.setFineMode(true)` 设置为精细模式,且必须在任何 `addRow()` / `placeCard()` / `addTab()` 等布局方法之前调用。
292
+ 2. 推荐通过 `.setFineMode(true)` 设置为精细模式,且必须在任何 `addRow()` / `placeCard()` / `addTab()` / `addAreaTitle()` / `addCardGroup()` 等布局方法之前调用。
244
293
  3. `addRow()` 及其快捷方法的 `height` 省略或为 0 时使用默认行高(普通 6,精细 18)。
294
+ 4. 区域小标题用 `createAreaTitle(...).setId(...).build()` 定义,并通过 `page.addAreaTitle(title)` 放在 Page 根布局;不要放进 tab panel。
295
+ 5. 卡片组用 `createCardGroup(...).setId(...)` 定义,并通过 `page.addCardGroup(group)` 放在 Page 根布局。
245
296
 
246
297
  | 方法 | 说明 |
247
298
  |------|------|
@@ -255,6 +306,8 @@ overview.linkTo("bbbbbbbbbbbbbbbbbbbbbbbb", {
255
306
  | `.addQuarterWidthCards(ci1, ci2, ci3, ci4, height?)` | 四等分 |
256
307
  | `.placeCard(cardIndex, x, y, w, h)` | 精确放置 Card,`w/h` 必须大于 0, `x/y/w/h` 必须显式填写 |
257
308
  | `.addTab(tab, height?)` | 添加一个满宽 tab 容器;不传 height 时按第一个 panel 内容自动推导 |
309
+ | `.addAreaTitle(areaTitle, height?)` | 添加一个满宽区域小标题|
310
+ | `.addCardGroup(group, height?)` | 添加一个满宽卡片组;不传 height 时按标题和组内布局自动推导 |
258
311
  | `.setBackgroundColor(color)` | 页面背景色 |
259
312
  | `.setCardMargin(margin)` | 卡片间距 |
260
313
  | `.setFineMode(enabled)` | 开启/关闭精细模式 |
@@ -262,6 +315,66 @@ overview.linkTo("bbbbbbbbbbbbbbbbbbbbbbbb", {
262
315
  | `.setLayoutSetting(config)` | 原始 layout 配置 |
263
316
  | `.build()` | 构建 |
264
317
 
318
+ ### AreaTitleBuilder
319
+
320
+ `areaTitle` 是 Page 根布局里的区域小标题,不是 Card,不绑定数据集,也不会生成 page-card relation。ID 必须以 `areaTitle_` 开头,建议用 `guanvis gen-layout-id areaTitle` 生成。
321
+
322
+ | 方法 | 说明 |
323
+ |------|------|
324
+ | `createAreaTitle(name)` | 创建区域小标题,`name` 即为标题的内容,会被写入该组件的 style 中,必须要传 name |
325
+ | `.setId(areaTitleId)` | **必填**。设置区域小标题 ID,必须以 `areaTitle_` 开头 |
326
+ | `.setShowTitle(boolean)` | 是否显示标题 |
327
+ | `.setFontSize(number)` | 字号 |
328
+ | `.setColor(color)` | 字体颜色 |
329
+ | `.setBold(boolean)` | 是否加粗 |
330
+ | `.setTextAlign(alignment)` | 对齐方式, 支持 `left`, `center`, `right` |
331
+ | `.setBackgroundColor(color)` | 背景色 |
332
+ | `.setShowBgImage(boolean)` | 是否显示背景图 |
333
+ | `.setShowIcon(boolean)` | 是否显示图标 |
334
+ | `.build()` | 构建 areaTitle result |
335
+
336
+ ```javascript
337
+ var salesTitle = createAreaTitle("销售概览")
338
+ .setId("areaTitle_AbCdEf")
339
+ .setFontSize(20)
340
+ .setBold(true)
341
+ .setTextAlign("left")
342
+ .build();
343
+
344
+ var page = createPage("销售仪表板")
345
+ .setId("p184352b7a76776db5f534df")
346
+ .addAreaTitle(salesTitle)
347
+ .addFullWidthCard(0, 6);
348
+
349
+ registerPage(page.build());
350
+ ```
351
+
352
+ ### CardGroupBuilder
353
+
354
+ `cardGroup` 是一个布局容器,不是 Card,不绑定数据集,也不会生成独立 page-card relation。ID 必须以 `cardGroup_` 开头,建议用 `guanvis gen-layout-id cardGroup` 生成。卡片组目前只能放入根布局,暂不支持放入 tab panel、另一个卡片组或嵌套区域小标题。
355
+
356
+ | 方法 | 说明 |
357
+ |------|------|
358
+ | `createCardGroup(name)` | 创建卡片组,`name` 写入分组标题 |
359
+ | `.setId(cardGroupId)` | **必填**。设置卡片组 ID,必须以 `cardGroup_` 开头 |
360
+ | `.setShowTitle(boolean)` | 是否显示标题,默认 `true` |
361
+ | `.addRow(specs, height?)` | 在组内按行放置卡片,写法同 `PageBuilder.addRow()` |
362
+ | `.addFullWidthCard(cardIndex, height?)` | 在组内放一张满宽卡片 |
363
+ | `.placeCard(cardIndex, x, y, w, h)` | 在组内精确放置卡片 |
364
+
365
+ ```javascript
366
+ var salesGroup = createCardGroup("销售概览")
367
+ .setId("cardGroup_AbCdEf")
368
+ .addRow([{ card: 0 }, { card: 1 }])
369
+ .addFullWidthCard(2);
370
+
371
+ var page = createPage("销售仪表板")
372
+ .setId("p184352b7a76776db5f534df")
373
+ .addCardGroup(salesGroup);
374
+
375
+ registerPage(page.build());
376
+ ```
377
+
265
378
  #### 页面密度尺寸建议
266
379
 
267
380
  以下尺寸建议以非精细模式的 12 列布局单位为基准,用于生成页面时选择页面卡片间距和常见卡片高度。精细模式目前只定义横向 60 列栅格与显式 `x/y/w/h` 放置规则,暂不提供独立的密度尺寸换算规则。
@@ -280,9 +393,9 @@ overview.linkTo("bbbbbbbbbbbbbbbbbbbbbbbb", {
280
393
 
281
394
  注意:这里的高度建议是非精细模式下的页面生成建议,不覆盖 `addRow()` 在精细模式下省略高度时使用默认行高 `18` 的 API 行为。
282
395
 
283
- ### Tab 布局
396
+ ### Tab Builder
284
397
 
285
- tab 用于把页面中的卡片分到多个 panel。适合同一主题下多组互斥查看的分析内容;若卡片较少或需要同时对照,优先直接平铺。关键总览指标通常放在 tab 外,tab 内按实际分析主题组织 panel。支持通过 `page.addTab(tab)` 添加满宽 tab,暂不支持半宽 tab 或 tab 嵌套。
398
+ tab 用于把页面中的卡片分到多个 panel。适合同一主题下多组互斥查看的分析内容;若卡片较少或需要同时对照,优先直接平铺。关键总览指标通常放在 tab 外,tab 内按实际分析主题组织 panel。支持通过 `page.addTab(tab)` 添加满宽 tab,暂不支持半宽 tab 或 tab 嵌套。 示例可以参考 `evals/tab_layout/`。
286
399
 
287
400
  | 方法 | 说明 |
288
401
  |------|------|
@@ -353,8 +466,8 @@ registerPage(page.build());
353
466
  | `.setDisplayType(type)` | 展示类型(仅 `DS_ELEMENTS` 使用):`SelectorDisplay.SEARCH_LIST`(单选下拉)、`SEARCH_BOX`(多选下拉)、`CHECKBOX`(复选框)、`RADIO`(单选框)、`BUTTON_GROUP`(按钮组)。不设置时根据 multiSelect 自动选择。`DS_INTERVAL` 类型不需要此设置 |
354
467
  | `.setShowSelectAll(bool)` | 是否显示"全选"(默认 true) |
355
468
  | `.setCanClear(bool)` | 是否可清空(默认 true) |
356
- | `.linkTo(cardIndex, targetFieldName?)` | 联动指定卡片(cardIndex 为注册顺序),可指定目标字段名(默认同名匹配) |
357
- | `.linkToAll()` | 自动联动所有图表卡片(按同名字段匹配) |
469
+ | `.linkTo(cardIndex, targetFieldName?)` | 联动指定卡片(cardIndex 为过滤后的可联动目标序列:普通图表和 MetricChart 按注册/布局顺序,杜邦子图追加在末尾),可指定目标字段名(默认同名匹配) |
470
+ | `.linkToAll()` | 自动联动所有普通图表卡片、MetricChart 和杜邦子卡片(按同名字段匹配) |
358
471
  | `.build()` | 构建(触发验证) |
359
472
 
360
473
  **使用示例**:
@@ -428,7 +541,7 @@ registerSelector(sel);
428
541
  - **日期选择**(精确日期范围)→ `SelectorType.CALENDAR`,需要 `bindField` 绑定日期字段。默认会从联动目标卡片推断日期粒度;如需固定月/季度等粒度,可用 `.setGranularity(Granularity.MONTH)` 或 `.setGranularityOptions([...], default)`
429
542
  - **快捷日期区间**(本月/上月/近7天等预设区间)→ `.setTimeMacroOptions(options, default)`,不需要 `bindField`,自动匹配目标卡片日期字段联动。`default` 传 `null` 表示无默认值
430
543
 
431
- **联动机制**:筛选器通过 `settings.asFilter` 配置联动关系。`linkTo(cardIndex)` 会自动构建 `columnMappings`,将筛选器字段映射到目标卡片的同名字段。`linkToAll()` 会自动匹配所有普通图表卡片和杜邦子卡片中的同名字段。
544
+ **联动机制**:筛选器通过 `settings.asFilter` 配置联动关系。`linkTo(cardIndex)` 会自动构建 `columnMappings`,将筛选器字段映射到目标卡片的同名字段;cardIndex 只统计普通图表、MetricChart 和杜邦子卡片,文本/图片等不可联动资源不占序号。`linkToAll()` 会自动匹配所有普通图表卡片、MetricChart 和杜邦子卡片中的同名字段。
432
545
 
433
546
  **文件命名**:筛选器脚本建议命名为 `selector_NN_xxx.js`,会在 `card_*.js` 之后、`page.js` 之前执行。
434
547
 
@@ -0,0 +1,195 @@
1
+ # 指标平台指标卡片(MetricChart)创建指引
2
+
3
+ 本指引用于创建“用指标平台已有指标创建的卡片”,后端类型为 `CARD_TYPE.METRIC_CHART` / `cdType=13`。它不同于普通数据集字段的 `SINGLE_VALUE` / `KPI_CARD`。
4
+
5
+ ## 固定流程
6
+
7
+ 1. 查询指标 ID:
8
+
9
+ ```bash
10
+ guancli metric search '销售额年同比增长率'
11
+ ```
12
+
13
+ `guancli metric search --name-like ...` 不是当前 CLI 参数;搜索词用位置参数。
14
+
15
+ 2. 生成指标快照:
16
+
17
+ ```bash
18
+ guanvis metric-init <metricId1> <metricId2> -d ./my_dashboard/
19
+ ```
20
+
21
+ 3. 编写 `card_*.js`:
22
+
23
+ ```javascript
24
+ var card = createMetricChart(ChartType.PIVOT_TABLE, "销售指标分析")
25
+ .setId("card12345678901234567890")
26
+ .addRow(metricDim("销售额", "区域"))
27
+ .addMetric(metric("销售额"));
28
+
29
+ registerMetricChart(card.build());
30
+ ```
31
+
32
+ 4. 本地验证用 `guanvis preview/pack`。发布后若 `guancli card get/preview` 对 `METRIC_CHART` 报 `None.get`,不要据此判断卡片失败;优先使用指标卡编辑态数据接口或页面访问验证数据返回。
33
+
34
+ ## 兼容约束
35
+
36
+ - `MetricChartMeta.defaultView` 不要写 `"chart"`;后端 `ChartView` 不包含该值,导入后查询会报 `ChartView does not contain 'chart'`。
37
+ - `PIVOT_TABLE` 的 `column` 区域必须包含 `metaType: "MPH"` 的“度量名”占位列。guanvis 会在未显式添加 column 时自动补齐。
38
+ - `PIVOT_TABLE` 的 `metric` / `sorting` zoneInfo 需要 `needAggregation: true`;普通维度、筛选 zone 不聚合。
39
+ - 指标字段使用 `id` 表示 metric id;维度字段使用 `fdId` + `dsId` / `publicDimensionId`。不要把 metric id 当普通数据集 `fdId` 使用。
40
+ - `preview` / `pack` / `publish` 会像普通数据集卡片一样给 MetricChart 注入主题视觉配置,只写 `settings` 与 `meta.chartMain.props`,不会修改 `zoneData`、`dsInfo`、`defaultView`。显式通过 `.setProps()` / `.setTableSetting()` / `.setAxis()` 等写入的配置优先保留。
41
+
42
+ ## 顶层内容参数
43
+
44
+ | 路径 | 中文含义 | 说明 |
45
+ |---|---|---|
46
+ | `chartType` | 图表类型 | 使用 `ChartType.PIVOT_TABLE`、`BASIC_COLUMN`、`BASIC_LINE` 等枚举 |
47
+ | `metricIds` | 卡片引用的指标 ID 列表 | 由 `.addMetric(metric(...))` 自动收集;后端用它维护 card-metric 关系 |
48
+ | `metrics` | 指标详情列表 | 后端编辑态会补充;资源包创建通常不手写 |
49
+ | `columns` | 卡片级字段列表 | 指标卡片临时/动态字段可放这里;默认空数组 |
50
+ | `meta.chartMain.zoneInfo` | 区域规格 | 描述 row/column/metric/filter/sort 等区域的标题、数量限制、是否聚合 |
51
+ | `meta.chartMain.zoneData` | 区域字段 | 真实拖入的维度、指标、筛选、排序等字段 |
52
+ | `meta.chartMain.props` | 图表属性 | 透视表设置、图例、数据标签、坐标轴、主题色、辅助线等 |
53
+ | `meta.chartMain.config` | 图表配置 | 汇总阈值、自由钻取、KPI 趋势默认值等 |
54
+ | `meta.chartMain.dynamicZoneInfo` | 动态字段配置 | 动态维度/指标映射;复杂场景可通过 `.setRawConfig` / `.setProps` 透传 |
55
+ | `meta.summary` | 汇总配置 | 汇总字段、标签、位置和汇总类型 |
56
+ | `hasDrill` / `drillViews` | 钻取配置 | 是否有钻取与钻取路径;普通创建可先不写 |
57
+
58
+ ## zoneData 区域
59
+
60
+ | 区域 | 中文 | 可放字段 | 常见用途 |
61
+ |---|---|---|---|
62
+ | `row` | 维度/行 | 公共维度、适用维度、动态维度、MPH | 分组维度、X 轴、透视表行 |
63
+ | `column` | 对比/列 | 公共维度、适用维度、动态维度、MPH | 透视表列、系列拆分;透视表默认需要 MPH |
64
+ | `metric` | 数值 | 指标字段 | 主指标 |
65
+ | `metric_additional` | 副轴数值 | 指标字段 | 组合图副轴、双轴图 |
66
+ | `colorBy` | 颜色 | 指标字段 | 数值渐变着色 |
67
+ | `sizeBy` | 大小 | 指标字段 | 气泡大小 |
68
+ | `tooltip` | 更多提示 | 指标字段 | tooltip 附加指标 |
69
+ | `filters` | 筛选 | 维度或指标 | 明细筛选、聚合筛选、结果筛选 |
70
+ | `sorting` | 排序 | 维度或指标 | 升序/降序、自定义排序 |
71
+ | `split` | 拆分 | 公共维度 | 小多图拆分 |
72
+ | `ignoreFilters` | 忽略筛选 | 筛选字段 | 忽略外部联动筛选 |
73
+
74
+ ## 字段参数
75
+
76
+ ### 维度字段(DimensionZoneObj)
77
+
78
+ | 参数 | 中文含义 |
79
+ |---|---|
80
+ | `dsId` | 数据集 ID |
81
+ | `fdId` | 字段 ID |
82
+ | `name` / `alias` | 字段名 / 显示别名 |
83
+ | `fdType` | 字段类型,如 `STRING`、`DATE`、`LONG` |
84
+ | `metaType` | 元类型,维度为 `DIM`,度量名占位为 `MPH` |
85
+ | `granularity` / `parentFdName` | 日期粒度 / 原日期字段名 |
86
+ | `formula` | 卡片级字段公式 |
87
+ | `consolidation` | 公共维度归并信息 |
88
+ | `alignedDimension` | 指标 level 计算字段的对齐维度 |
89
+ | `baseFdType` / `timeFormat` | 技术字段类型 / 字符串时间解析格式 |
90
+ | `fieldFormat.numberFormat` | 数值格式 |
91
+ | `fieldFormat.headerFormat` | 表头格式 |
92
+ | `fieldFormat.conditionFormat` | 条件格式 |
93
+ | `fieldFormat.linkFormat` | 链接格式 |
94
+ | `hasSubTotal` | 是否显示小计 |
95
+ | `key` | 前端字段实例 key;guanvis 自动生成 |
96
+ | `subZoneId` / `dzId` | 子区域 ID / 动态字段 ID |
97
+ | `publicDimensionId` | 公共维度 ID |
98
+ | `isDrill` | 是否为自由钻取字段 |
99
+ | `annotation` | 字段释义 |
100
+ | `isHidden` | 是否隐藏 |
101
+
102
+ ### 指标字段(MetricZoneObj)
103
+
104
+ | 参数 | 中文含义 |
105
+ |---|---|
106
+ | `id` | 指标 ID |
107
+ | `name` / `alias` | 指标名 / 显示别名 |
108
+ | `fdType` | 值类型 |
109
+ | `metaType` | 固定为 `METRIC` |
110
+ | `fieldFormat.numberFormat` | 数据格式 |
111
+ | `fieldFormat.conditionFormat` | 条件格式 |
112
+ | `fieldFormat.headerFormat` | 表头格式 |
113
+ | `fieldFormat.itemSetting` | 颜色/项目设置,常用于 `colorBy` |
114
+ | `subtotalSetting.isDisplayed` | 小计/总计是否显示 |
115
+ | `subtotalSetting.isAggrDsBased` | 小计是否基于聚合数据集 |
116
+ | `subtotalSetting.aggrType` | 小计聚合方式 |
117
+ | `advCalc` | 高级计算,如排名、占比 |
118
+ | `filter` | 指标业务限定 |
119
+ | `miniChart` | 表格内迷你图 |
120
+ | `formula` / `formulaField` | 复合/原子拆分公式 |
121
+ | `parentFdName` / `granularity` | 日期派生字段信息 |
122
+ | `key` / `subZoneId` / `dzId` | 字段实例 key / 子区域 / 动态字段 |
123
+ | `isDrill` | 是否钻取字段 |
124
+ | `isHidden` | 是否隐藏 |
125
+
126
+ ### 筛选字段(FilterZoneObj)
127
+
128
+ | 参数 | 中文含义 |
129
+ |---|---|
130
+ | `id` | 指标 ID;当筛选指标时使用 |
131
+ | `dsId` / `fdId` | 数据集 ID / 字段 ID;当筛选维度时使用 |
132
+ | `filterType` | 筛选类型,如 `IN`、`NI`、`GT`、`GE`、`LT`、`LE`、`EQ`、`NE`、`BT` |
133
+ | `filterValue` | 筛选值数组;`BT` 需要两个值 |
134
+ | `filterLevel` | 筛选层级:`DETAIL` 明细、`AGGREGATION` 聚合、`RESULT` 结果 |
135
+ | `fieldFilterSettings` | 字段筛选器设置 |
136
+ | `compareColumn` | 是否对比列 |
137
+ | `advFilter` / `advFilterContent` | 高级筛选表达式及内容 |
138
+ | `refKey` | 关联来源 metric 字段 key,用于带业务限定指标筛选 |
139
+
140
+ ### 排序字段(SortingZoneObj)
141
+
142
+ | 参数 | 中文含义 |
143
+ |---|---|
144
+ | `id` | 指标 ID;指标排序时使用 |
145
+ | `dsId` / `fdId` | 维度字段来源 |
146
+ | `ordering` | 排序方向:`ASC` / `DESC` |
147
+ | `customSort.turnedOn` | 是否启用自定义排序 |
148
+ | `customSort.sortOrder` | 自定义排序值列表 |
149
+ | `isPinYinOrder` | 是否按拼音排序 |
150
+ | `associateFieldSorting` | 关联字段排序 |
151
+ | `advCalc` | 按高级计算结果排序 |
152
+ | `refKey` | 关联来源 metric 字段 key |
153
+
154
+ ## DSL 方法
155
+
156
+ | 方法 | 中文含义 |
157
+ |---|---|
158
+ | `createMetricChart(chartType, name)` | 创建指标卡片 |
159
+ | `.addMetric(metric(...))` | 添加主指标 |
160
+ | `.addMetricAdditional(metric(...))` | 添加副轴指标 |
161
+ | `.addRow(metricDim(...))` | 添加行/类目维度 |
162
+ | `.addColumn(metricDim(...))` | 添加列/对比维度 |
163
+ | `.addFilter(field, type, values)` | 添加筛选 |
164
+ | `.addSort(field)` | 添加排序 |
165
+ | `.addColorBy(metric(...))` | 添加颜色指标 |
166
+ | `.addSize(metric(...))` | 添加大小指标 |
167
+ | `.addTooltip(metric(...))` | 添加 tooltip 指标 |
168
+ | `.addSplit(metricDim(...))` | 添加拆分维度 |
169
+ | `.setProps(obj)` / `.setRawProps(key, value)` | 设置 `chartMain.props` |
170
+ | `.setConfig(obj)` / `.setRawConfig(key, value)` | 设置 `chartMain.config` |
171
+ | `.setSummary(obj)` | 设置 `meta.summary` |
172
+ | `.setColumns(columns)` | 设置 `content.columns` 与 dsInfo.columns |
173
+ | `.setTableSetting(obj)` | 设置 `props.miscPivotTableSetting` |
174
+ | `.setFreeDrill(enabled, position)` | 设置 `config.freeDrillConfig` |
175
+ | `.setRowThreshold(thresholds)` | 设置 `config.rowThreshold` |
176
+
177
+ 复杂配置可直接放到 `metric()` / `metricDim()` 的 overrides 中:
178
+
179
+ ```javascript
180
+ var card = createMetricChart(ChartType.PIVOT_TABLE, "复杂指标透视表")
181
+ .addRow(metricDim("销售额", "区域", {
182
+ hasSubTotal: true,
183
+ fieldFormat: { headerFormat: { alignment: "center" } }
184
+ }))
185
+ .addMetric(metric("销售额", {
186
+ alias: "销售额",
187
+ subtotalSetting: { isDisplayed: true, isAggrDsBased: true, aggrType: "SUM" },
188
+ fieldFormat: { numberFormat: NumberFormat.currency("¥", 0) }
189
+ }))
190
+ .addSort(metric("销售额", { ordering: SortOrder.DESC }))
191
+ .setTableSetting({ fixedHeaderInfo: { X: false }, isDefaultExpandedGroupedTable: true, defaultExpandCols: 0 })
192
+ .setConfig({ rowThreshold: [] });
193
+
194
+ registerMetricChart(card.build());
195
+ ```
@@ -5,10 +5,14 @@
5
5
  - **接口**:`POST /api/manual/template/transfer`(标准 multipart/form-data,表单字段名 `new-file`)
6
6
  - **认证**:随底层 `guancli fetch` 使用 `Cookie: uIdToken=...`
7
7
  - **关键 header**:`raw-backend-response: TRUE`(绕过前端代理层,直达后端)
8
- - **ID 策略**:`needIdMapping=false`,保持资源 ID 不变。同 ID 资源会被覆盖更新。`guanvis publish/upload` 默认会先探测目标环境已有 Card/Page ID,检测到覆盖风险时拒绝上传;只有明确加 `--allow-overwrite` 才允许覆盖。
8
+ - **ID 策略**:`needIdMapping=false`,保持资源 ID 不变。同 ID 资源会被覆盖更新。`guanvis publish/upload` 默认会先探测目标环境已有 Card/Page ID,检测到覆盖风险时拒绝上传;只有明确加 `--allow-overwrite` 才允许覆盖。加 `--allow-overwrite` 后,CLI 会先调用资源包导出为冲突资源生成备份记录,并等待导出成功;备份失败或超时则中止上传。
9
9
  - **通用性**:不需要目标系统开启"一键迁移"开关,所有客户环境可用
10
10
  - **异步执行**:上传成功后返回 `taskId`,后端异步完成导入
11
11
 
12
+ `upload` 只是上传器,不是自定义资源包制作入口。默认只允许上传由 `guanvis pack` 原样生成的 ZIP;禁止手工生成、解包修改或重打包资源包。
13
+
14
+ 若用户要求批量重绑资源、迁移已有页面或复用线上页面结构,先说明风险并确认方案;不要直接修改 ZIP 内部文件后上传。
15
+
12
16
  修改或重新发布已存在的仪表板资源时,默认按“新版本仪表板”处理:先从目标 BI 线上环境同步最新资源状态,再基于同步后的内容生成新的 Page/Card/Selector ID,并给仪表板名称追加版本号后发布。用户可能已经在 BI 上手工改过页面布局、卡片配置、筛选器或说明文本;如果只按本地旧文件 `publish`,同 ID 资源会被覆盖,导致线上改动丢失。只有用户明确要求覆盖原资源时,才允许保留原 ID 并同 ID 发布。
13
17
 
14
18
  ## 认证与 CLI 集成
@@ -21,6 +25,7 @@
21
25
 
22
26
  - `schema.js` 由 `init` 命令自动生成,不允许 AI 或人工修改。
23
27
  - card 脚本必须调用 `registerCard(card.build())`(目录模式)或返回 `card.build()`(单文件模式)。
28
+ - metric chart 脚本必须调用 `registerMetricChart(card.build())`。
24
29
  - text card 脚本必须调用 `registerTextCard(textCard.build())`。
25
30
  - image card 脚本必须调用 `registerImageCard(imageCard.build())`。
26
31
  - custom chart 脚本必须调用 `registerCustomChart(chart.build())`。
@@ -29,7 +34,8 @@
29
34
  - card 文件名建议 `card_NN_xxx.js` 控制执行顺序。
30
35
  - selector 文件名建议 `selector_NN_xxx.js`,在 card 之后执行。
31
36
  - page 文件必须命名为 `page.js`。
32
- - 筛选器的 `linkTo(cardIndex)` 中 cardIndex 基于 `registerCard()` 的调用顺序(0-based)。
37
+ - 筛选器的 `linkTo(cardIndex)` 中 cardIndex 基于过滤后的可联动目标序列(0-based):普通图表和 MetricChart 按注册/布局顺序,文本/图片等不可联动资源不占序号,杜邦子图追加在末尾。
38
+ - 资源包 ZIP 是派生产物,不是可编辑源文件;不要手工编辑或重打包 ZIP。
33
39
  - **文件访问边界**:只允许访问以下路径,不要主动探索或读取用户未明确授权的其他目录:
34
40
  - 当前工作目录(`-d` 指定的目录或 cwd)
35
41
  - `guancli` / `guanvis` CLI 工具的输出
@@ -44,4 +50,4 @@
44
50
  - **生成 ID**:先运行 `guanvis genid <数量>` 生成足够的 ID,在编写脚本时直接填入每个 card/selector/page 的 `.setId()` 调用中。
45
51
  - **线上更新默认策略**:已发布过或线上正在使用的仪表板,后续修改默认生成新的 Page/Card/Selector ID,并给 Page 名称追加版本号后发布,保留旧版本不覆盖。
46
52
  - **覆盖前检查**:发布前可先运行 `guanvis publish <dir> --dry-run` 或 `guanvis upload <zip> --dry-run`,只构建/解析资源并列出将被覆盖的线上 Card/Page,不提交 transfer 任务。
47
- - **显式覆盖场景**:只有用户明确要求覆盖原仪表板时,才保持 `.setId()` 不变,并在 `publish/upload` 时加 `--allow-overwrite`;多次同 ID 发布会覆盖资源(因为 transfer API 的 `needIdMapping=false`)。
53
+ - **显式覆盖场景**:只有用户明确要求覆盖原仪表板时,才保持 `.setId()` 不变,并在 `publish/upload` 时加 `--allow-overwrite`;多次同 ID 发布会覆盖资源(因为 transfer API 的 `needIdMapping=false`)。覆盖前备份只创建资源迁移导出记录并打印 packageId,不自动下载资源包;需要回滚时,用户应到 BI 资源迁移导出记录中下载该资源包,再手动导入覆盖回去。
@@ -16,6 +16,8 @@ AI 选择主题时不要把租户主题列表里的默认“浅色”/“深色
16
16
 
17
17
  每次执行命令时 stderr 会打印决策结果。命中线上主题时形如 `Theme: <name> [<id>] (source=preference|applied)`;落到自带兜底时形如 `Theme: 简约 (source=fallback, built-in simple.json)`,特意不打印 themeId 是因为那只是 skill 与 BI 默认值对齐的实现细节,不是租户主题列表里能查到的 ID。
18
18
 
19
+ 普通数据集图表和指标平台 MetricChart 都会应用主题视觉配置。MetricChart 只注入 `settings` 与 `meta.chartMain.props`:透视表补表格/合计样式,柱线饼等补坐标轴、图例、数据标签和主题色;不会修改 `zoneData`、`dsInfo`、`defaultView` 等查询相关字段。
20
+
19
21
  ### 何时主动操作
20
22
 
21
23
  > 所有 `theme *` 子命令的 **`[dir]` 可省**,缺省为当前工作目录;下面的示例假设你已经 `cd` 到 dashboard 工程目录。