@guandata/guanvis 0.1.38 → 0.1.39
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 +8 -0
- package/README.md +10 -2
- package/bin/install-env.js +73 -0
- package/bin/postinstall.js +5 -2
- package/bin/run.js +6 -1
- package/binaries/guanvis-darwin-arm64 +0 -0
- package/binaries/guanvis-darwin-x64 +0 -0
- package/binaries/guanvis-linux-arm64 +0 -0
- package/binaries/guanvis-linux-x64 +0 -0
- package/binaries/guanvis-win32-x64.exe +0 -0
- package/package.json +1 -1
- package/skills/guanvis/SKILL.md +8 -27
- package/skills/guanvis/evals/custom_chart_sdk/card_01_level_nodes.js +19 -0
- package/skills/guanvis/evals/custom_chart_sdk/charts/level_nodes.css +51 -0
- package/skills/guanvis/evals/custom_chart_sdk/charts/level_nodes.html +1 -0
- package/skills/guanvis/evals/custom_chart_sdk/charts/level_nodes.js +28 -0
- package/skills/guanvis/evals/custom_chart_sdk/page.js +5 -0
- package/skills/guanvis/evals/custom_chart_sdk/schema.js +7 -0
- package/skills/guanvis/references/troubleshooting.md +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## @guandata/guanvis 0.1.39 - 2026-08-20
|
|
4
|
+
|
|
5
|
+
- 修复 `attachCard` 场景下计算字段的序列化问题,减少附加卡片发布/导出时字段配置异常的情况。
|
|
6
|
+
- 优化 `publish` 在 `profile` 模式下的输出反馈,发布后可直接看到页面 URL,便于确认结果和继续验收。
|
|
7
|
+
- 改进自定义图表的生成与接入体验,补充更直接的速查入口、最小 SDK 模板,并增加注册函数的类型校验护栏,降低接入出错成本。
|
|
8
|
+
- 澄清自定义图表视觉验收与 `screenshot` 使用规则的边界,完善相关操作指引。
|
|
9
|
+
- 提升 npm 安装与 Skill 自动安装体验,包括更明确的安装反馈、删除确认流程修复,以及 Windows CLI 兼容性改进。
|
|
10
|
+
|
|
3
11
|
## @guandata/guanvis 0.1.38 - 2026-08-13
|
|
4
12
|
|
|
5
13
|
- 新增 `live` 系列命令和完整实时项目工作流,可对线上仪表板执行受控、可回溯的创建与维护操作。
|
package/README.md
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install -g @guandata/guanvis
|
|
9
|
-
guanvis install-skill
|
|
8
|
+
npm install -g --foreground-scripts @guandata/guanvis
|
|
10
9
|
```
|
|
11
10
|
|
|
11
|
+
> 全局安装/升级时会通过 postinstall 自动执行一次 `guanvis install-skill` 刷新 AI skill。`--foreground-scripts` 用于显示明确的成功、失败或跳过结果;失败时按提示手动运行 `guanvis install-skill`。CI 等无需 skill 的环境可设 `GUAN_SKIP_INSTALL_SKILL=1` 跳过。
|
|
12
|
+
|
|
12
13
|
安装后即可在终端使用:
|
|
13
14
|
|
|
14
15
|
```bash
|
|
@@ -54,6 +55,13 @@ guanvis publish ./my_dashboard/ --allow-overwrite
|
|
|
54
55
|
|
|
55
56
|
## 版本更新
|
|
56
57
|
|
|
58
|
+
### @guandata/guanvis 0.1.39
|
|
59
|
+
|
|
60
|
+
- 修复 `attachCard` 计算字段序列化问题,减少附加卡片配置异常。
|
|
61
|
+
- `profile` 模式发布后会直接输出页面 URL,便于继续验收。
|
|
62
|
+
- 完善自定义图表速查入口、最小 SDK 模板和注册函数类型校验。
|
|
63
|
+
- 改进 Skill 自动安装反馈、删除确认和 Windows CLI 兼容性。
|
|
64
|
+
|
|
57
65
|
### @guandata/guanvis 0.1.38
|
|
58
66
|
|
|
59
67
|
- 新增 `live` 系列命令和完整实时项目工作流,可受控地创建与维护线上仪表板。
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
4
|
+
|
|
5
|
+
const SANITIZED_MARKER = "GUAN_INSTALL_ENV_SANITIZED";
|
|
6
|
+
const SAFE_DELETE_TARGET = String.raw`(?:"(?:[^"]*[\\/])?genie-safe-delete\.cjs"|'(?:[^']*[\\/])?genie-safe-delete\.cjs'|(?:[^\s"']*[\\/])?genie-safe-delete\.cjs)`;
|
|
7
|
+
|
|
8
|
+
function envKey(env, expected) {
|
|
9
|
+
return Object.keys(env).find((key) => key.toLowerCase() === expected.toLowerCase());
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function stripWorkBuddySafeDelete(nodeOptions) {
|
|
13
|
+
const pattern = new RegExp(
|
|
14
|
+
String.raw`(^|\s)(?:--require|-r)(?:=|\s+)${SAFE_DELETE_TARGET}(?=\s|$)(?:\s+|$)`,
|
|
15
|
+
"gi"
|
|
16
|
+
);
|
|
17
|
+
let removed = false;
|
|
18
|
+
const value = String(nodeOptions || "").replace(pattern, (_, prefix) => {
|
|
19
|
+
removed = true;
|
|
20
|
+
return prefix ? " " : "";
|
|
21
|
+
}).trim();
|
|
22
|
+
return { value, removed };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function hasWorkBuddySafeDelete(env = process.env) {
|
|
26
|
+
const key = envKey(env, "NODE_OPTIONS");
|
|
27
|
+
return Boolean(key && stripWorkBuddySafeDelete(env[key]).removed);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function createInstallChildEnv(env = process.env) {
|
|
31
|
+
const childEnv = { ...env };
|
|
32
|
+
for (const key of Object.keys(childEnv)) {
|
|
33
|
+
if (key.toLowerCase() === "npm_config_global") {
|
|
34
|
+
delete childEnv[key];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const nodeOptionsKey = envKey(childEnv, "NODE_OPTIONS");
|
|
39
|
+
if (nodeOptionsKey) {
|
|
40
|
+
const cleaned = stripWorkBuddySafeDelete(childEnv[nodeOptionsKey]);
|
|
41
|
+
if (cleaned.removed) {
|
|
42
|
+
if (cleaned.value) childEnv[nodeOptionsKey] = cleaned.value;
|
|
43
|
+
else delete childEnv[nodeOptionsKey];
|
|
44
|
+
childEnv[SANITIZED_MARKER] = "1";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return childEnv;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function reexecInstallCommand(scriptPath, args, options = {}) {
|
|
51
|
+
const env = options.env || process.env;
|
|
52
|
+
if (env[SANITIZED_MARKER] === "1" || !hasWorkBuddySafeDelete(env)) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const spawn = options.spawn || spawnSync;
|
|
57
|
+
const exit = options.exit || process.exit;
|
|
58
|
+
const nodePath = options.nodePath || process.execPath;
|
|
59
|
+
const result = spawn(nodePath, [scriptPath, ...args], {
|
|
60
|
+
stdio: "inherit",
|
|
61
|
+
env: createInstallChildEnv(env),
|
|
62
|
+
shell: false,
|
|
63
|
+
});
|
|
64
|
+
if (result.error) throw result.error;
|
|
65
|
+
exit(result.status == null ? 1 : result.status);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
createInstallChildEnv,
|
|
71
|
+
hasWorkBuddySafeDelete,
|
|
72
|
+
reexecInstallCommand,
|
|
73
|
+
};
|
package/bin/postinstall.js
CHANGED
|
@@ -41,18 +41,21 @@ function main() {
|
|
|
41
41
|
);
|
|
42
42
|
if (result.error || result.status !== 0) {
|
|
43
43
|
console.warn(
|
|
44
|
-
`[${CLI_NAME}] postinstall:
|
|
44
|
+
`[${CLI_NAME}] postinstall: AI skill update FAILED` +
|
|
45
45
|
(result.error ? ` (${result.error.message})` : ` (exit ${result.status})`) +
|
|
46
46
|
`; run \`${CLI_NAME} install-skill\` manually to refresh SKILL.md.`
|
|
47
47
|
);
|
|
48
|
+
return;
|
|
48
49
|
}
|
|
50
|
+
console.log(`[${CLI_NAME}] postinstall: AI skill updated successfully.`);
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
try {
|
|
52
54
|
main();
|
|
53
55
|
} catch (err) {
|
|
54
56
|
console.warn(
|
|
55
|
-
`[${CLI_NAME}] postinstall: ${err.message};
|
|
57
|
+
`[${CLI_NAME}] postinstall: AI skill update FAILED (${err.message}); ` +
|
|
58
|
+
`run \`${CLI_NAME} install-skill\` manually.`
|
|
56
59
|
);
|
|
57
60
|
}
|
|
58
61
|
process.exit(0);
|
package/bin/run.js
CHANGED
|
@@ -6,6 +6,7 @@ const { execFileSync, execSync, spawnSync } = require("child_process");
|
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const fs = require("fs");
|
|
8
8
|
const os = require("os");
|
|
9
|
+
const { createInstallChildEnv, reexecInstallCommand } = require("./install-env");
|
|
9
10
|
|
|
10
11
|
const PLATFORM_MAP = {
|
|
11
12
|
"darwin-arm64": "guanvis-darwin-arm64",
|
|
@@ -111,6 +112,7 @@ function resolveNpxInvocation() {
|
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
if (process.argv[2] === "install-skill") {
|
|
115
|
+
reexecInstallCommand(__filename, process.argv.slice(2));
|
|
114
116
|
const pkgRoot = path.join(__dirname, "..");
|
|
115
117
|
const extraArgs = process.argv.slice(3);
|
|
116
118
|
const args = [
|
|
@@ -128,8 +130,11 @@ if (process.argv[2] === "install-skill") {
|
|
|
128
130
|
console.log("Installing guanvis to AI coding assistants...");
|
|
129
131
|
const npxInvocation = resolveNpxInvocation();
|
|
130
132
|
const result = spawnSync(npxInvocation.command, [...npxInvocation.argsPrefix, ...args], {
|
|
133
|
+
// Avoid leaking project-only Agent markers (for example PromptScript) from
|
|
134
|
+
// the caller's cwd into this global installation.
|
|
135
|
+
cwd: pkgRoot,
|
|
131
136
|
stdio: "inherit",
|
|
132
|
-
env: process.env,
|
|
137
|
+
env: createInstallChildEnv(process.env),
|
|
133
138
|
shell: false,
|
|
134
139
|
});
|
|
135
140
|
if (result.error) throw result.error;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/skills/guanvis/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: guanvis
|
|
3
3
|
description: 当用户要新建、修改、组装观远 BI / Guandata 的 Card(图表/报表卡片)、复杂报表 Pro(COMPLEX_REPORT_PRO)、用指标平台指标创建的指标卡片、文本卡片、图片卡片、筛选器(selector,含日历/时间宏/区间/离散值)或仪表板(Page),或给出 Card ID、数据集 ID、指标 ID、card.js/page.js、图表类型关键词(柱状/折线/饼/KPI/表格/漏斗/地图/散点等 30+ 种)时,优先使用这个 skill。即使用户只说"做个销售仪表板""创建一个复杂报表 Pro""用这个指标做张卡片""加个 KPI 卡片""新建一个区域筛选器联动所有图""帮我改一下这个图的图例""把这几个 card 拼成一个 page""加一个本月/近 7 天的快捷日期筛选",也要主动使用。它通过 AI 编写简洁的 JS 脚本(card_*.js / selector_*.js / page.js)定义卡片、筛选器和页面布局,再 pack/publish 上传到目标 BI。认证复用 guancli 共享配置。只想查现有 Card/Page 内容走 guancli。旧版复杂报表不支持创建或编辑。
|
|
4
|
-
compatibility: "Requires Node.js 14+. Install via npm link (local) or npm install -g @guandata/guanvis (from internal Nexus registry). CLI command: guanvis."
|
|
4
|
+
compatibility: "Requires Node.js 14+. Install via npm link --foreground-scripts (local) or npm install -g --foreground-scripts @guandata/guanvis (from internal Nexus registry) so the AI skill refresh result is visible. CLI command: guanvis."
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# guanvis
|
|
@@ -30,29 +30,7 @@ compatibility: "Requires Node.js 14+. Install via npm link (local) or npm instal
|
|
|
30
30
|
- 先 `preview` 做本地结构验证,再 `publish`(publish 自带构建打包上传,**发布前不需要单独 `pack`**;`pack` 只用于生成离线 ZIP 走 `upload`)。仅修复描述用 `card/page set-description` 并同步 JS 中的 `.setDescription(...)`;改看板内容按「线上仪表板更新红线」处理。
|
|
31
31
|
- **编辑红线(编辑 ≠ 删除重建)**:修改/改名已发布 Page 或 Card 必须保留原 pgId/cdId 原地覆盖发布。本地源工程还在且线上未被网页端改动 → 直接改本地 JS 同 ID 重新 publish;否则 → `checkout` 后编辑,且**不得**把 `attachCard` 改写成 `createCard()`(绕过 base JSON 会丢线上配置)。**禁止**用"新建 + 删除旧的"模拟编辑——资源 ID 变化会让收藏、分享、订阅、门户引用和页面权限全部失效且无法迁移;"保留旧页面出新版本"用 `guanvis page save-as`。全局参数同理只能 `parameter update <dpId>` 原地更新,禁止 delete 后重建同名参数(dpId 断链)。分流决策见 `references/checkout-editing.md` §4。
|
|
32
32
|
- **资源包安全红线**:Agent 只编辑 DSL 源文件;资源包 ZIP 是 `guanvis pack/publish` 的派生产物,不手工生成、解包修改或重打包。`guanvis upload` 只允许上传 `guanvis pack` 原样生成的 ZIP。若用户要求批量重绑资源、迁移已有页面或复用线上页面结构,先停下来说明风险并确认方案,不要直接改 ZIP。
|
|
33
|
-
- 发布后优先用 `guancli page get/card get` 回读结构与配置;`guanvis screenshot` 仅在明确需要视觉质量判断且模型支持图像理解时使用(额外消耗 token
|
|
34
|
-
|
|
35
|
-
### 桌面端对话式实时构建
|
|
36
|
-
|
|
37
|
-
桌面安全 Runtime 同时提供 `connected.guancli`、`connected.guanvis` 与右侧可见的 `browser` 时,使用 `guanvis live` 做无需持久化本地工程的对话式构建:
|
|
38
|
-
|
|
39
|
-
1. 用 `connected.guancli` 查询数据集、页面与卡片,真实取数走 `card preview`;不要向用户索取 Token。
|
|
40
|
-
2. 正式交付或需要任一完整能力时,把与普通工程完全相同的 `schema.js`、`card_*.js`、`selector_*.js`、`page.js`、主题/设计规则及二进制资产组成 version=1 JSON 内存工程,先调 `live project validate`,再把同一份 stdin 交给 `live project publish`。文本文件用 `content`;直接调用 CLI 时二进制用 `base64`,桌面安全 Runtime 中上传的图片或 xlsx 必须通过 `reference.list` 取得 ID,再用 `asset_refs:[{"reference_id":<id>,"path":"<工程内路径>"}]` 交给 Host 注入,模型不要读取或生成大段 base64。路径必须在工程内且大小写不能冲突。
|
|
41
|
-
3. 只有需求严格落在 KPI、基础/分组/堆叠柱、基础折线、明细表且强调最低延迟时,才用 `live page/card` 批量建卡并一次 apply;不得用 P0 命令降级模拟筛选器、文本、图片、地图、自定义图表或复杂报表。
|
|
42
|
-
4. publish/page create 返回页面 URL 后用 `browser.open` 在右侧打开;每次 publish/apply/patch/remove/delete 后 `browser.navigate(reload)`,再用 snapshot/screenshot 回读,并以 `guancli page get/card preview` 验证结构和真实数据。
|
|
43
|
-
5. `live project` 复用普通 GuanVis 的完整 DSL、主题、设计规则、校验和 transfer 发布引擎;不允许宿主文件参数、绝对路径、`..` 或文件 URI。新建资源必须显式 setId,覆盖同 ID Page 仍需用户明确确认后使用 `--allow-overwrite`。
|
|
44
|
-
6. `live card delete` 与 `live page remove-card` 仅在用户明确要求删除/移除时调用;前者删除实体,后者只移出布局。
|
|
45
|
-
|
|
46
|
-
完整内存工程最小契约:
|
|
47
|
-
|
|
48
|
-
```json
|
|
49
|
-
{"version":1,"files":[
|
|
50
|
-
{"path":"schema.js","content":"defineDataset(...)"},
|
|
51
|
-
{"path":"card_01.js","content":"var card = createCard(...); registerCard(card.build());"},
|
|
52
|
-
{"path":"page.js","content":"var page = createPage(...); registerPage(page.build());"},
|
|
53
|
-
{"path":"assets/logo.png","base64":"..."}
|
|
54
|
-
]}
|
|
55
|
-
```
|
|
33
|
+
- 发布后优先用 `guancli page get/card get` 回读结构与配置;`guanvis screenshot` 仅在明确需要视觉质量判断且模型支持图像理解时使用(额外消耗 token),不作默认闭环步骤。**例外**:自定义图表的视觉验收按速查第 24 条执行。
|
|
56
34
|
|
|
57
35
|
## AI Quick Reference(速查,详细说明见按需参考资料)
|
|
58
36
|
|
|
@@ -63,7 +41,7 @@ compatibility: "Requires Node.js 14+. Install via npm link (local) or npm instal
|
|
|
63
41
|
**图表属性配置**:设置图表属性时,先读 `references/chart-properties.md`,按其中的方法和参数配置。
|
|
64
42
|
|
|
65
43
|
1. **工厂函数**:数据集图表 `createCard()`;复杂报表 Pro `createComplexReportPro()` + `createReportWorkbook()`;已有线上普通卡片 `attachCard(cardId, jsonPath)`;指标卡片 `createMetricChart()`;筛选器/文本/图片/杜邦/Tab/页面用对应工厂函数,不要 `new XxxBuilder()`。旧版复杂报表拒绝,Pro 父卡不能用泛化 `attachCard()`
|
|
66
|
-
2. **注册函数**:`registerCard` / `registerComplexReportPro` / `registerMetricChart` / `registerSelector` / `registerTextCard` / `registerImageCard` / `registerDuPontChart` / `registerPage`,入参一律 `xxx.build()`
|
|
44
|
+
2. **注册函数**:`registerCard` / `registerComplexReportPro` / `registerMetricChart` / `registerSelector` / `registerTextCard` / `registerImageCard` / `registerCustomChart` / `registerDuPontChart` / `registerPage`,入参一律 `xxx.build()`;注册函数与工厂函数必须配对(如 `createCustomChart` 只能 `registerCustomChart`),错配会在 preview 时直接报错并提示正确函数
|
|
67
45
|
3. **字段引用**:单数据集用 `f("字段名")`,多数据集用 `field(DS, "字段名")`
|
|
68
46
|
4. **zone maxCount**:`BASIC_COLUMN/BAR/LINE` metric=1;`GROUPED_*/STACKED_*` metric=∞;`KPI_CARD` metric=1;组合图 `*_WITH_LINE` row=1
|
|
69
47
|
5. **column vs colorBy**:column 放维度(按类别分组着色),colorBy 放度量(按值渐变着色)
|
|
@@ -85,7 +63,8 @@ compatibility: "Requires Node.js 14+. Install via npm link (local) or npm instal
|
|
|
85
63
|
21. **布局组件**:AreaTitle/CardGroup/SelGroup/Tab 只支持放画布根布局、不支持嵌套组合;SelGroup 内只能放 selector;详见 `references/builder-reference.md`
|
|
86
64
|
22. **资源包/checkout JSON 禁止手改**:只改 DSL 源文件,不改 ZIP 内部文件与 `.guanvis/**` JSON;批量重绑、迁移页面等需求先讨论方案,必要时扩展 DSL,不手工改生成物。
|
|
87
65
|
23. **动态字段**:用户明确需要字段切换时用 `.addDynamicRow()` / `.addDynamicMetric()` 等(普通卡动态维度/数值,指标卡动态维度/指标);细节见 `references/builder-reference.md`。
|
|
88
|
-
24.
|
|
66
|
+
24. **自定义图表(HTML/CSS/JS 自绘)**:内置图表满足不了的可视化才走 `createCustomChart()`。子类型选型:纯 ECharts 配置能画 → `CustomChartSubType.ECHARTS_LITE`(脚本给 `option` 赋值,禁用 `GDPlugin`);需要自定义 DOM/CSS 布局或第三方库(节点图、进度轴、Vega 等)→ `CustomChartSubType.SDK`(`charts/<name>.{html,css,js}` 三件套 + `loadContent("charts/<name>")`,js 里实现 `renderChart(data, clickFunc, config)` 并 `new GDPlugin().init(renderChart)`)。数据用 `.addDataView(createCard(ChartType.DATA_GRID, ...))` 传入。最小可运行工程直接抄 `evals/custom_chart_sdk/`(SDK)或 `evals/custom_chart_echarts/`(ECHARTS_LITE)。**视觉验收**:preview 只校验结构不渲染 HTML/CSS,本地 file:// 打开也不可靠——正确闭环是发布(可先发到测试目录)后 `guanvis screenshot <pgId>` 读图确认(这是总则"screenshot 不作默认闭环"的例外:自定义图表视觉由手写 HTML/CSS 决定,结构回读覆盖不到);模型不支持图像理解时,改为把 publish 成功后输出的 `Page URL` 交给用户人工确认。不要浪费时间做本地渲染验证。完整 API 见 `references/builder-reference.md` 的 CustomChartBuilder 章节。
|
|
67
|
+
25. **复杂报表 Pro**:非默认功能,需单独授权——只有用户明确点名"复杂报表 / 复杂报表 Pro"或被修改卡片已是 Pro 才选 Pro;用户只说"表格/报表/透视表"一律用原生卡片(DATA_GRID/PIVOT_TABLE 等),版式做不到时告知"Pro 可实现但需授权"由用户决定。动手前必读 `references/complex-report-pro-patterns.md`(§0 选型、§2 配方、§3 数据视图规则、§4 报错修复、§5 编辑闭环、§6 验证闭环),全部结构红线与修复表以该文件为准;工作流程见下文「复杂报表 Pro 工作方式」
|
|
89
68
|
|
|
90
69
|
## 何时使用
|
|
91
70
|
|
|
@@ -109,6 +88,7 @@ guancli auth status
|
|
|
109
88
|
|
|
110
89
|
```bash
|
|
111
90
|
guancli ds search <关键词> # 查找数据集 ID
|
|
91
|
+
guancli ds preview <dsId> # 先看几行真实数据再动笔:确认量纲与格式(如"比例"是 0~1 小数还是百分数)
|
|
112
92
|
guanvis init <dsId1> <dsId2> -d ./my_dashboard/ # 生成 schema.js(多数据集加 --alias 命名全局变量)
|
|
113
93
|
```
|
|
114
94
|
|
|
@@ -270,7 +250,8 @@ guanvis icon list --group default_line -f json
|
|
|
270
250
|
|------|------|------|
|
|
271
251
|
| 基础仪表板 | `evals/sales_dashboard/` | 普通卡片 + 筛选器 + 页面布局 |
|
|
272
252
|
| 拆分图 | `evals/split_charts/` | 图表按字段拆分 |
|
|
273
|
-
|
|
|
253
|
+
| 自定义图表(ECharts Lite) | `evals/custom_chart_echarts/` | 纯 ECharts `option`,`loadContent()` 文件模式 |
|
|
254
|
+
| 自定义图表(SDK/自定义 DOM) | `evals/custom_chart_sdk/` | HTML/CSS 节点进度图,`GDPlugin` + 连接线对齐布局范式 |
|
|
274
255
|
| 复杂报表 Pro | `evals/complex_report_pro/` | 最小 Workbook DSL 工程(结构配方以 patterns.md §2 为准) |
|
|
275
256
|
| Tab 布局 | `evals/tab_layout/` | 根布局指标卡 + panel 内卡片 + 筛选器 |
|
|
276
257
|
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// 自定义图表 SDK 模式最小示例:横向等级进度节点图(自定义 HTML/CSS + GDPlugin)。
|
|
2
|
+
// 适用场景:内置图表做不出来的自定义 DOM 布局(节点图/进度轴/卡片流等);
|
|
3
|
+
// 纯 ECharts 需求改用 CustomChartSubType.ECHARTS_LITE(见 evals/custom_chart_echarts/)。
|
|
4
|
+
var dataView = createCard(ChartType.DATA_GRID, "等级数据视图")
|
|
5
|
+
.setId("a000000000000000sdkchild")
|
|
6
|
+
.bindDataset(DS)
|
|
7
|
+
.addRow(f("等级"))
|
|
8
|
+
.addMetric(f("占比", { aggrType: AggrType.SUM }))
|
|
9
|
+
// 节点顺序必须显式排序,否则依赖查询返回顺序;数据集有序号字段时优先按序号排
|
|
10
|
+
.addSort(f("等级", { sortType: SortOrder.ASC }));
|
|
11
|
+
|
|
12
|
+
var chart = createCustomChart("等级进度节点图")
|
|
13
|
+
.setId("a000000000000000sdkchart")
|
|
14
|
+
.setSubType(CustomChartSubType.SDK)
|
|
15
|
+
.loadContent("charts/level_nodes")
|
|
16
|
+
.addDataView(dataView);
|
|
17
|
+
|
|
18
|
+
// 自定义图表必须用 registerCustomChart;registerCard 会在 preview 时报类型错配。
|
|
19
|
+
registerCustomChart(chart.build());
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* 横向节点+连接线布局范式:
|
|
2
|
+
* 圆点和连接线放进同一个固定高度的 .circle-area,连接线绝对定位、top 对准圆心。
|
|
3
|
+
* 把连接线做成与节点同级的独立 flex 项无法与圆心垂直对齐(客户实测踩坑)。 */
|
|
4
|
+
#container {
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: center;
|
|
10
|
+
font-family: -apple-system, "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
11
|
+
}
|
|
12
|
+
.node {
|
|
13
|
+
flex: 1;
|
|
14
|
+
max-width: 160px;
|
|
15
|
+
text-align: center;
|
|
16
|
+
}
|
|
17
|
+
.node .name {
|
|
18
|
+
font-size: 14px;
|
|
19
|
+
font-weight: 600;
|
|
20
|
+
margin-bottom: 8px;
|
|
21
|
+
}
|
|
22
|
+
.node .circle-area {
|
|
23
|
+
position: relative;
|
|
24
|
+
height: 16px; /* 与圆点直径一致,连接线以此垂直居中 */
|
|
25
|
+
}
|
|
26
|
+
.node .dot {
|
|
27
|
+
width: 16px;
|
|
28
|
+
height: 16px;
|
|
29
|
+
border-radius: 50%;
|
|
30
|
+
background: #4575b4;
|
|
31
|
+
margin: 0 auto;
|
|
32
|
+
position: relative;
|
|
33
|
+
z-index: 1;
|
|
34
|
+
}
|
|
35
|
+
/* 连接线:从本节点圆心向右延伸到下一节点圆心 */
|
|
36
|
+
.node .connector {
|
|
37
|
+
position: absolute;
|
|
38
|
+
top: 7px; /* (circle-area 高 16 - 线高 2) / 2 */
|
|
39
|
+
left: 50%;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 2px;
|
|
42
|
+
background: #c3d4e8;
|
|
43
|
+
}
|
|
44
|
+
.node:last-child .connector {
|
|
45
|
+
display: none;
|
|
46
|
+
}
|
|
47
|
+
.node .value {
|
|
48
|
+
font-size: 13px;
|
|
49
|
+
color: #666;
|
|
50
|
+
margin-top: 8px;
|
|
51
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<div id="container"></div>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// SDK 模式渲染代码:实现 renderChart 并用 new GDPlugin().init(renderChart) 挂载。
|
|
2
|
+
// data[i] 对应第 i 个数据视图的列数据: [{name:"字段名", data:[...]}, ...]
|
|
3
|
+
// config.colors 是主题色数组。联动回传(仅在 dataView 配置了 .linkTo() 时需要):
|
|
4
|
+
// clickFunc({ clickedItems: [{ idx: [viewIndex, columnIndex], colName: "列名", value: ["选中值"] }] })
|
|
5
|
+
function renderChart(data, clickFunc, config) {
|
|
6
|
+
var cols = data[0] || [];
|
|
7
|
+
var names = (cols[0] || {}).data || [];
|
|
8
|
+
var values = (cols[1] || {}).data || [];
|
|
9
|
+
var color = (config && config.colors && config.colors[0]) || "#4575b4";
|
|
10
|
+
|
|
11
|
+
var container = document.getElementById("container");
|
|
12
|
+
container.innerHTML = "";
|
|
13
|
+
for (var i = 0; i < names.length; i++) {
|
|
14
|
+
var node = document.createElement("div");
|
|
15
|
+
node.className = "node";
|
|
16
|
+
// 量纲以 guancli ds preview 看到的真实数据为准:0~1 小数才需要 ×100
|
|
17
|
+
var pct = (Number(values[i]) * 100).toFixed(1) + "%";
|
|
18
|
+
node.innerHTML =
|
|
19
|
+
'<div class="name"></div>' +
|
|
20
|
+
'<div class="circle-area"><div class="connector"></div><div class="dot"></div></div>' +
|
|
21
|
+
'<div class="value"></div>';
|
|
22
|
+
node.querySelector(".name").textContent = String(names[i]);
|
|
23
|
+
node.querySelector(".dot").style.background = color;
|
|
24
|
+
node.querySelector(".value").textContent = pct;
|
|
25
|
+
container.appendChild(node);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
new GDPlugin().init(renderChart);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Auto-generated by guanvis schema command
|
|
2
|
+
// DO NOT EDIT — regenerate with: guanvis schema <dsId>
|
|
3
|
+
|
|
4
|
+
defineDataset("s0000000000000000000demo", [
|
|
5
|
+
{ fdId: "f0000000000000000000lvl1", name: "等级", fdType: "STRING", metaType: "DIM" },
|
|
6
|
+
{ fdId: "f0000000000000000000rat2", name: "占比", fdType: "DOUBLE", metaType: "METRIC" }
|
|
7
|
+
], { displayType: "CSV" });
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
| `unknown chart type 'X'` | ChartType 枚举值错误 | 使用 `ChartType.XXX` 常量,不要手写字符串 |
|
|
12
12
|
| `auth: ...` / `401` | Token 过期或 profile 错误 | 运行 `guancli auth status`,必要时重新 `auth login` |
|
|
13
13
|
| `run scripts: ...ReferenceError` | JS 脚本中引用了未定义的变量 | 检查是否使用了 `new XxxBuilder()` 而非工厂函数 `createXxx()` |
|
|
14
|
+
| `registerXxx() received a 'yyy' build result — use registerYyy(...) instead` | 注册函数与工厂函数错配(最常见:自定义图表误用 `registerCard`) | 按提示换成配对的注册函数,如 `createCustomChart` → `registerCustomChart(chart.build())` |
|
|
15
|
+
| 自定义图表发布后渲染空白 | SDK 模式脚本没调 `new GDPlugin().init(renderChart)`;或 ECHARTS_LITE 脚本误用 `GDPlugin`/没给 `option` 赋值 | 对照 `evals/custom_chart_sdk/`(SDK)或 `evals/custom_chart_echarts/`(ECHARTS_LITE)模板检查渲染脚本入口 |
|
|
16
|
+
| 自定义图表数值显示 `0.86%` 而非 `86%` | 没确认字段量纲就写格式化逻辑 | 先 `guancli ds preview <dsId>` 看真实数据,0~1 小数才需要 ×100 |
|
|
14
17
|
| `placeCard index out of range` | placeCard 的 cardIndex 超出已注册卡片数量 | 检查 registerCard/registerTextCard 的调用顺序和总数 |
|
|
15
18
|
| `page has no cards` | page.js 中没有 placeCard | 确保 page.js 中为每个已注册的卡片调用了 placeCard |
|
|
16
19
|
| `selector not linked to any card` | selector 没有调用 linkTo/linkToAll | 添加 `.linkToAll()` 或 `.linkTo(cardIndex)` |
|