@guandata/guanvis 0.1.16
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 +44 -0
- package/README.md +85 -0
- package/bin/run.js +87 -0
- 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 +41 -0
- package/skills/guanvis/SKILL.md +334 -0
- package/skills/guanvis/evals/china_map/card_01_basic_map.js +13 -0
- package/skills/guanvis/evals/china_map/card_02_world_map.js +10 -0
- package/skills/guanvis/evals/china_map/card_03_point_map.js +12 -0
- package/skills/guanvis/evals/china_map/page.js +10 -0
- package/skills/guanvis/evals/china_map/schema.js +10 -0
- package/skills/guanvis/evals/comparative_mvp_roundtrip/README.md +30 -0
- package/skills/guanvis/evals/comparative_mvp_roundtrip/card_01_comparative_mvp.js +72 -0
- package/skills/guanvis/evals/comparative_mvp_roundtrip/page.js +6 -0
- package/skills/guanvis/evals/comparative_mvp_roundtrip/schema.js +22 -0
- package/skills/guanvis/evals/comparative_mvp_roundtrip/verify_default_roundtrip.sh +92 -0
- package/skills/guanvis/evals/custom_chart_echarts/card_01_bar.js +13 -0
- package/skills/guanvis/evals/custom_chart_echarts/card_02_pie.js +13 -0
- package/skills/guanvis/evals/custom_chart_echarts/charts/bar.js +11 -0
- package/skills/guanvis/evals/custom_chart_echarts/charts/pie.js +15 -0
- package/skills/guanvis/evals/custom_chart_echarts/page.js +5 -0
- package/skills/guanvis/evals/custom_chart_echarts/schema.js +9 -0
- package/skills/guanvis/evals/percentage_advcalc_roundtrip/README.md +26 -0
- package/skills/guanvis/evals/percentage_advcalc_roundtrip/card_01_percentage_advcalc.js +44 -0
- package/skills/guanvis/evals/percentage_advcalc_roundtrip/card_02_scroll_percentage.js +12 -0
- package/skills/guanvis/evals/percentage_advcalc_roundtrip/page.js +6 -0
- package/skills/guanvis/evals/percentage_advcalc_roundtrip/schema.js +22 -0
- package/skills/guanvis/evals/rank_advcalc_roundtrip/README.md +28 -0
- package/skills/guanvis/evals/rank_advcalc_roundtrip/card_01_rank_advcalc.js +59 -0
- package/skills/guanvis/evals/rank_advcalc_roundtrip/page.js +6 -0
- package/skills/guanvis/evals/rank_advcalc_roundtrip/schema.js +22 -0
- package/skills/guanvis/evals/rank_advcalc_roundtrip/verify_default_roundtrip.sh +135 -0
- package/skills/guanvis/evals/running_total_advcalc_roundtrip/README.md +15 -0
- package/skills/guanvis/evals/running_total_advcalc_roundtrip/card_01_running_total_advcalc.js +74 -0
- package/skills/guanvis/evals/running_total_advcalc_roundtrip/page.js +6 -0
- package/skills/guanvis/evals/running_total_advcalc_roundtrip/schema.js +22 -0
- package/skills/guanvis/evals/sales_dashboard/card_01_revenue_column.js +10 -0
- package/skills/guanvis/evals/sales_dashboard/card_02_trend_line.js +9 -0
- package/skills/guanvis/evals/sales_dashboard/card_03_kpi.js +6 -0
- package/skills/guanvis/evals/sales_dashboard/card_04_pie.js +9 -0
- package/skills/guanvis/evals/sales_dashboard/card_05_calc_field_test.js +12 -0
- package/skills/guanvis/evals/sales_dashboard/page.js +11 -0
- package/skills/guanvis/evals/sales_dashboard/schema.js +14 -0
- package/skills/guanvis/evals/sales_dashboard/selector_01_region.js +10 -0
- package/skills/guanvis/references/api-reference.md +408 -0
- package/skills/guanvis/references/builder-reference.md +690 -0
- package/skills/guanvis/references/publish-and-constraints.md +46 -0
- package/skills/guanvis/references/tableau-migration.md +73 -0
- package/skills/guanvis/references/theme.md +115 -0
- package/skills/guanvis/references/troubleshooting.md +20 -0
- package/skills/guanvis/references/validation-and-chart-patterns.md +205 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Auto-generated by guanvis schema command
|
|
2
|
+
// This file defines dataset schemas for field() references in card scripts.
|
|
3
|
+
|
|
4
|
+
// Dataset: 各省销售数据 (example, 4 fields)
|
|
5
|
+
defineDataset("s1234567890abcdef12345678", [
|
|
6
|
+
{ fdId: "a1111111111111111111111", name: "省/自治区", fdType: "STRING", metaType: "DIM" },
|
|
7
|
+
{ fdId: "a2222222222222222222222", name: "销售额", fdType: "DOUBLE", metaType: "METRIC" },
|
|
8
|
+
{ fdId: "a3333333333333333333333", name: "利润率", fdType: "DOUBLE", metaType: "METRIC" },
|
|
9
|
+
{ fdId: "a4444444444444444444444", name: "订单数", fdType: "INT", metaType: "METRIC" }
|
|
10
|
+
]);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Comparative MVP Round-Trip
|
|
2
|
+
|
|
3
|
+
This eval verifies the L3 native BI `COMPARATIVE` advanced calculation MVP against a real `default` BI environment.
|
|
4
|
+
|
|
5
|
+
It intentionally uses BI menu-facing cases:
|
|
6
|
+
|
|
7
|
+
- 日环比: 增长值
|
|
8
|
+
- 周同比: 增长率
|
|
9
|
+
- 月同比: 对比值
|
|
10
|
+
- 季同比: 增长值
|
|
11
|
+
- 年同比: 默认增长率 + 默认日期筛选模式
|
|
12
|
+
- 年同比(按周): 对比值
|
|
13
|
+
- 期末值: 上月末增长率、上季度末增长值、上年末对比值
|
|
14
|
+
- 自定义: 后移 1 个月增长率
|
|
15
|
+
- 普通模式兼容性由 exporter 单测覆盖;round-trip eval 使用日期筛选上下文保证线上 preview 有可验证结果
|
|
16
|
+
|
|
17
|
+
Run from `guanvis/`:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
./evals/comparative_mvp_roundtrip/verify_default_roundtrip.sh
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The script publishes fixed resource IDs to `default`, then verifies:
|
|
24
|
+
|
|
25
|
+
- `advCalc` is preserved in `zoneData.metric[*].advCalc`.
|
|
26
|
+
- No metric silently degrades to a formula.
|
|
27
|
+
- `card preview` succeeds.
|
|
28
|
+
- Each target metric has at least one non-empty preview value.
|
|
29
|
+
|
|
30
|
+
Runtime outputs are written to `.roundtrip/` and ignored by git.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
var dateField = f("订单日期");
|
|
2
|
+
|
|
3
|
+
var normalCard = createCard(ChartType.PIVOT_TABLE, "L3 同环比 MVP 默认日期筛选模式")
|
|
4
|
+
.setId("p3bc51ab664e095ab2dff402")
|
|
5
|
+
.bindDataset(DS)
|
|
6
|
+
.addFilter(filterField(DS, "订单日期", FilterType.BT, ["2024-01-01", "2025-12-31"]))
|
|
7
|
+
.addFilter(filterField(DS, "订单日期", FilterType.BT, ["2025-01-01", "2025-12-31"]))
|
|
8
|
+
.addMetric(f("销售额", {
|
|
9
|
+
alias: "月同比对比值",
|
|
10
|
+
aggrType: AggrType.SUM,
|
|
11
|
+
advCalc: comparative.monthOverMonth(dateField, ComparativeOutput.COMPARE_VALUE)
|
|
12
|
+
}))
|
|
13
|
+
.addMetric(f("销售额", {
|
|
14
|
+
alias: "季同比增长值",
|
|
15
|
+
aggrType: AggrType.SUM,
|
|
16
|
+
advCalc: comparative.quarterOverQuarter(dateField, ComparativeOutput.GROWTH_VALUE, { replenishDimData: true })
|
|
17
|
+
}))
|
|
18
|
+
.addMetric(f("销售额", {
|
|
19
|
+
alias: "年同比增长率",
|
|
20
|
+
aggrType: AggrType.SUM,
|
|
21
|
+
advCalc: comparative.yearOverYear(dateField, { replenishDimData: true })
|
|
22
|
+
}))
|
|
23
|
+
.addMetric(f("销售额", {
|
|
24
|
+
alias: "上月末增长率",
|
|
25
|
+
aggrType: AggrType.SUM,
|
|
26
|
+
advCalc: comparative.periodEnd(dateField, ComparativePeriodEnd.MONTH_END, ComparativeOutput.GROWTH_RATE)
|
|
27
|
+
}))
|
|
28
|
+
.addMetric(f("销售额", {
|
|
29
|
+
alias: "上季度末增长值",
|
|
30
|
+
aggrType: AggrType.SUM,
|
|
31
|
+
advCalc: comparative.periodEnd(dateField, ComparativePeriodEnd.QUARTER_END, ComparativeOutput.GROWTH_VALUE)
|
|
32
|
+
}))
|
|
33
|
+
.addMetric(f("销售额", {
|
|
34
|
+
alias: "上年末对比值",
|
|
35
|
+
aggrType: AggrType.SUM,
|
|
36
|
+
advCalc: comparative.periodEnd(dateField, ComparativePeriodEnd.YEAR_END, ComparativeOutput.COMPARE_VALUE)
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
registerCard(normalCard.build());
|
|
40
|
+
|
|
41
|
+
var filterBasedCard = createCard(ChartType.PIVOT_TABLE, "L3 同环比 MVP 日期筛选模式")
|
|
42
|
+
.setId("o360e50afb73bcc998353c13")
|
|
43
|
+
.bindDataset(DS)
|
|
44
|
+
.addFilter(filterField(DS, "订单日期", FilterType.BT, ["2024-01-01", "2025-12-31"]))
|
|
45
|
+
.addFilter(filterField(DS, "订单日期", FilterType.BT, ["2025-01-01", "2025-12-31"]))
|
|
46
|
+
.addMetric(f("销售额", {
|
|
47
|
+
alias: "日环比增长值",
|
|
48
|
+
aggrType: AggrType.SUM,
|
|
49
|
+
advCalc: comparative.dayOverDay(dateField, ComparativeOutput.GROWTH_VALUE, { mode: ComparativeMode.FILTER_BASED })
|
|
50
|
+
}))
|
|
51
|
+
.addMetric(f("销售额", {
|
|
52
|
+
alias: "周同比增长率",
|
|
53
|
+
aggrType: AggrType.SUM,
|
|
54
|
+
advCalc: comparative.weekOverWeek(dateField, ComparativeOutput.GROWTH_RATE, { mode: ComparativeMode.FILTER_BASED })
|
|
55
|
+
}))
|
|
56
|
+
.addMetric(f("销售额", {
|
|
57
|
+
alias: "默认年同比增长率",
|
|
58
|
+
aggrType: AggrType.SUM,
|
|
59
|
+
advCalc: comparative.yearOverYear(dateField)
|
|
60
|
+
}))
|
|
61
|
+
.addMetric(f("销售额", {
|
|
62
|
+
alias: "年同比按周对比值",
|
|
63
|
+
aggrType: AggrType.SUM,
|
|
64
|
+
advCalc: comparative.yearOverYearByWeek(dateField, ComparativeOutput.COMPARE_VALUE, { mode: ComparativeMode.FILTER_BASED })
|
|
65
|
+
}))
|
|
66
|
+
.addMetric(f("销售额", {
|
|
67
|
+
alias: "自定义后移增长率",
|
|
68
|
+
aggrType: AggrType.SUM,
|
|
69
|
+
advCalc: comparative.customMonthShift(dateField, -1, ComparativeOutput.GROWTH_RATE)
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
registerCard(filterBasedCard.build());
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Dataset: 订单表 (default)
|
|
2
|
+
defineDataset("a184fe1b1c27941a9ac977bc", [
|
|
3
|
+
{ fdId: "o0f29e706bf1041d9ab0da11", name: "订单 ID", fdType: "STRING", metaType: "DIM" },
|
|
4
|
+
{ fdId: "r739b62cd3dab49ff9bb7134", name: "订单日期", fdType: "DATE", metaType: "DIM" },
|
|
5
|
+
{ fdId: "o82eaae89ecd046a4b531ce4", name: "发货日期", fdType: "DATE", metaType: "DIM" },
|
|
6
|
+
{ fdId: "k673939fff12744b786d8d44", name: "邮寄方式", fdType: "STRING", metaType: "DIM" },
|
|
7
|
+
{ fdId: "me4783b3bf8984906a32e5ce", name: "客户 ID", fdType: "STRING", metaType: "DIM" },
|
|
8
|
+
{ fdId: "v2a8590c1236e4e58882ee9c", name: "客户名称", fdType: "STRING", metaType: "DIM" },
|
|
9
|
+
{ fdId: "j81f7f09ab6c84168924f9aa", name: "细分", fdType: "STRING", metaType: "DIM" },
|
|
10
|
+
{ fdId: "s99bcae4ac5a045ebae87762", name: "城市", fdType: "STRING", metaType: "DIM" },
|
|
11
|
+
{ fdId: "ufe7632b5afa44dd7a79194e", name: "省/自治区", fdType: "STRING", metaType: "DIM" },
|
|
12
|
+
{ fdId: "e2a051c6ebda04917a10cc14", name: "国家", fdType: "STRING", metaType: "DIM" },
|
|
13
|
+
{ fdId: "xe01f39825ccc428eaf67911", name: "地区", fdType: "STRING", metaType: "DIM" },
|
|
14
|
+
{ fdId: "cd9b3a6c556ef4c53a08df16", name: "产品 ID", fdType: "STRING", metaType: "DIM" },
|
|
15
|
+
{ fdId: "cece9879e99f545449909a82", name: "类别", fdType: "STRING", metaType: "DIM" },
|
|
16
|
+
{ fdId: "k15359167149d4d02bbede2b", name: "子类别", fdType: "STRING", metaType: "DIM" },
|
|
17
|
+
{ fdId: "f247afa584af241dba64821d", name: "产品名称", fdType: "STRING", metaType: "DIM" },
|
|
18
|
+
{ fdId: "g4a34bd7bcb78425aa5485d1", name: "销售额", fdType: "DOUBLE", metaType: "METRIC" },
|
|
19
|
+
{ fdId: "xd21ba1d7fd19433ebc728b6", name: "数量", fdType: "LONG", metaType: "METRIC" },
|
|
20
|
+
{ fdId: "l0dbffcc612e047c9a6dae7b", name: "折扣", fdType: "DOUBLE", metaType: "METRIC" },
|
|
21
|
+
{ fdId: "s1c05aa5e4bdd4a54a60e811", name: "利润", fdType: "DOUBLE", metaType: "METRIC" }
|
|
22
|
+
], { displayType: "DATAFLOW" });
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
5
|
+
EVAL_DIR="$ROOT_DIR/evals/comparative_mvp_roundtrip"
|
|
6
|
+
OUT_DIR="$EVAL_DIR/.roundtrip"
|
|
7
|
+
|
|
8
|
+
mkdir -p "$OUT_DIR"
|
|
9
|
+
|
|
10
|
+
cd "$ROOT_DIR"
|
|
11
|
+
|
|
12
|
+
go run ./cmd/guanvis preview "$EVAL_DIR" > "$OUT_DIR/preview_payload.json"
|
|
13
|
+
go run ./cmd/guanvis publish "$EVAL_DIR" > "$OUT_DIR/publish.log"
|
|
14
|
+
|
|
15
|
+
guancli card get p3bc51ab664e095ab2dff402 --profile default --raw > "$OUT_DIR/raw_normal.json"
|
|
16
|
+
guancli card get o360e50afb73bcc998353c13 --profile default --raw > "$OUT_DIR/raw_filter_based.json"
|
|
17
|
+
guancli card preview p3bc51ab664e095ab2dff402 --profile default --limit 50 -f json > "$OUT_DIR/preview_normal.json"
|
|
18
|
+
guancli card preview o360e50afb73bcc998353c13 --profile default --limit 50 -f json > "$OUT_DIR/preview_filter_based.json"
|
|
19
|
+
|
|
20
|
+
python3 - "$OUT_DIR" <<'PY'
|
|
21
|
+
import json
|
|
22
|
+
import sys
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
out = Path(sys.argv[1])
|
|
26
|
+
|
|
27
|
+
cases = [
|
|
28
|
+
{
|
|
29
|
+
"kind": "normal",
|
|
30
|
+
"raw": out / "raw_normal.json",
|
|
31
|
+
"preview": out / "preview_normal.json",
|
|
32
|
+
"expected_aliases": [
|
|
33
|
+
"月同比对比值",
|
|
34
|
+
"季同比增长值",
|
|
35
|
+
"年同比增长率",
|
|
36
|
+
"上月末增长率",
|
|
37
|
+
"上季度末增长值",
|
|
38
|
+
"上年末对比值",
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"kind": "filter_based",
|
|
43
|
+
"raw": out / "raw_filter_based.json",
|
|
44
|
+
"preview": out / "preview_filter_based.json",
|
|
45
|
+
"expected_aliases": [
|
|
46
|
+
"日环比增长值",
|
|
47
|
+
"周同比增长率",
|
|
48
|
+
"默认年同比增长率",
|
|
49
|
+
"年同比按周对比值",
|
|
50
|
+
"自定义后移增长率",
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
summary = {"cards": []}
|
|
56
|
+
|
|
57
|
+
for case in cases:
|
|
58
|
+
raw_obj = json.loads(case["raw"].read_text())
|
|
59
|
+
response = raw_obj.get("response") or raw_obj.get("data") or raw_obj
|
|
60
|
+
zone_data = response["content"]["meta"]["chartMain"]["zoneData"]
|
|
61
|
+
metrics = zone_data.get("metric", [])
|
|
62
|
+
by_alias = {m.get("alias"): m for m in metrics if m.get("alias")}
|
|
63
|
+
rows = json.loads(case["preview"].read_text())
|
|
64
|
+
|
|
65
|
+
card_summary = {
|
|
66
|
+
"kind": case["kind"],
|
|
67
|
+
"cardId": response.get("cdId") or response.get("id"),
|
|
68
|
+
"name": response.get("name"),
|
|
69
|
+
"previewRows": len(rows),
|
|
70
|
+
"aliases": {},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
for alias in case["expected_aliases"]:
|
|
74
|
+
metric = by_alias.get(alias)
|
|
75
|
+
if metric is None:
|
|
76
|
+
raise SystemExit(f"{case['kind']}: missing metric alias {alias}")
|
|
77
|
+
if "formula" in metric:
|
|
78
|
+
raise SystemExit(f"{case['kind']}: {alias} degraded to formula")
|
|
79
|
+
adv_calc = metric.get("advCalc")
|
|
80
|
+
if not adv_calc:
|
|
81
|
+
raise SystemExit(f"{case['kind']}: {alias} missing advCalc")
|
|
82
|
+
if adv_calc.get("advType") != "COMPARATIVE":
|
|
83
|
+
raise SystemExit(f"{case['kind']}: {alias} advType is not COMPARATIVE")
|
|
84
|
+
if not any(isinstance(row, dict) and row.get(alias) not in ("", None) for row in rows):
|
|
85
|
+
raise SystemExit(f"{case['kind']}: {alias} has no non-empty preview value")
|
|
86
|
+
card_summary["aliases"][alias] = adv_calc["advValue"]
|
|
87
|
+
|
|
88
|
+
summary["cards"].append(card_summary)
|
|
89
|
+
|
|
90
|
+
(out / "summary.json").write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
91
|
+
print(json.dumps(summary, ensure_ascii=False, indent=2))
|
|
92
|
+
PY
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var dataView = createCard(ChartType.DATA_GRID, "区域营收数据")
|
|
2
|
+
.setId("a000000000000000000child")
|
|
3
|
+
.bindDataset(DS)
|
|
4
|
+
.addRow(f("区域"))
|
|
5
|
+
.addMetric(f("营收", { aggrType: AggrType.SUM }));
|
|
6
|
+
|
|
7
|
+
var chart = createCustomChart("区域营收柱状图")
|
|
8
|
+
.setId("a000000000000000000chart")
|
|
9
|
+
.setSubType(CustomChartSubType.ECHARTS_LITE)
|
|
10
|
+
.loadContent("charts/bar")
|
|
11
|
+
.addDataView(dataView);
|
|
12
|
+
|
|
13
|
+
registerCustomChart(chart.build());
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var dataView = createCard(ChartType.DATA_GRID, "产品成本数据")
|
|
2
|
+
.setId("b000000000000000000child")
|
|
3
|
+
.bindDataset(DS)
|
|
4
|
+
.addRow(f("产品"))
|
|
5
|
+
.addMetric(f("成本", { aggrType: AggrType.SUM }));
|
|
6
|
+
|
|
7
|
+
var chart = createCustomChart("产品成本饼图")
|
|
8
|
+
.setId("b000000000000000000chart")
|
|
9
|
+
.setSubType(CustomChartSubType.ECHARTS_LITE)
|
|
10
|
+
.loadContent("charts/pie")
|
|
11
|
+
.addDataView(dataView);
|
|
12
|
+
|
|
13
|
+
registerCustomChart(chart.build());
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var cols = data[0] || [];
|
|
2
|
+
var categories = (cols[0] || {}).data || [];
|
|
3
|
+
var values = (cols[1] || {}).data || [];
|
|
4
|
+
|
|
5
|
+
option = {
|
|
6
|
+
tooltip: { trigger: "axis" },
|
|
7
|
+
xAxis: { type: "category", data: categories },
|
|
8
|
+
yAxis: { type: "value" },
|
|
9
|
+
series: [{ type: "bar", data: values }],
|
|
10
|
+
color: config.colors
|
|
11
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
var cols = data[0] || [];
|
|
2
|
+
var names = (cols[0] || {}).data || [];
|
|
3
|
+
var values = (cols[1] || {}).data || [];
|
|
4
|
+
|
|
5
|
+
option = {
|
|
6
|
+
tooltip: { trigger: "item" },
|
|
7
|
+
legend: { bottom: 10 },
|
|
8
|
+
series: [{
|
|
9
|
+
type: "pie",
|
|
10
|
+
radius: ["30%", "60%"],
|
|
11
|
+
data: names.map(function(name, i) { return { name: name, value: values[i] }; }),
|
|
12
|
+
label: { formatter: "{b}: {d}%" }
|
|
13
|
+
}],
|
|
14
|
+
color: config.colors
|
|
15
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Auto-generated by guanvis schema command
|
|
2
|
+
// DO NOT EDIT — regenerate with: guanvis schema s9ded2338f43807b095fbb4f
|
|
3
|
+
|
|
4
|
+
defineDataset("s9ded2338f43807b095fbb4f", [
|
|
5
|
+
{ fdId: "jb16f22f6c1c21c3f6e8e293", name: "区域", fdType: "STRING", metaType: "DIM" },
|
|
6
|
+
{ fdId: "o7093aaf2b2f32c9e964c41a", name: "产品", fdType: "STRING", metaType: "DIM" },
|
|
7
|
+
{ fdId: "lb1c31b4dc86511a27049a98", name: "营收", fdType: "DOUBLE", metaType: "METRIC" },
|
|
8
|
+
{ fdId: "aece10cd6806966be56f52ff", name: "成本", fdType: "DOUBLE", metaType: "METRIC" }
|
|
9
|
+
]);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Percentage Advanced Calc Round-Trip
|
|
2
|
+
|
|
3
|
+
This eval verifies the L3 native BI `LEVEL_PERCENTAGE` advanced calculation builder against a real `default` BI environment.
|
|
4
|
+
|
|
5
|
+
It covers:
|
|
6
|
+
|
|
7
|
+
- 按列:`SUM`
|
|
8
|
+
- 按行:`SUM` with a column dimension, matching the UI-created path
|
|
9
|
+
- 指定行维度:`SUM`
|
|
10
|
+
- 指定列维度:`SUM`
|
|
11
|
+
- 去重计数:`CNT_DISTINCT`
|
|
12
|
+
- 平均值:`AVG`, covering the backend SUM/CNT auxiliary denominator path
|
|
13
|
+
|
|
14
|
+
Local payload preview from `guanvis/`:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
go run ./cmd/guanvis preview ./evals/percentage_advcalc_roundtrip
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Default-environment publish/readback commands intentionally live in the project golden-answer note rather than this PR, because they publish fixed resource IDs to the shared `default` environment. The manual verification checks:
|
|
21
|
+
|
|
22
|
+
- `advCalc` is preserved in `zoneData.metric[*].advCalc`.
|
|
23
|
+
- No metric silently degrades to a formula.
|
|
24
|
+
- Each expected `measureOnDimRow` / `tfdId` / `auto` field round-trips.
|
|
25
|
+
- Percentage number format is present with two decimal places.
|
|
26
|
+
- `card preview` succeeds and percentage aliases have non-empty values.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
var region = f("地区");
|
|
2
|
+
var province = f("省/自治区");
|
|
3
|
+
var category = f("类别");
|
|
4
|
+
var subcategory = f("子类别");
|
|
5
|
+
|
|
6
|
+
var percentageCard = createCard(ChartType.PIVOT_TABLE, "L3 占比高级计算")
|
|
7
|
+
.setId("pct01a02b03c04d05e06f07g")
|
|
8
|
+
.bindDataset(DS)
|
|
9
|
+
.addRow(region)
|
|
10
|
+
.addRow(province)
|
|
11
|
+
.addColumn(category)
|
|
12
|
+
.addColumn(subcategory)
|
|
13
|
+
.addMetric(f("销售额", {
|
|
14
|
+
alias: "按列SUM占比",
|
|
15
|
+
aggrType: AggrType.SUM,
|
|
16
|
+
advCalc: percentage.byColumn()
|
|
17
|
+
}))
|
|
18
|
+
.addMetric(f("销售额", {
|
|
19
|
+
alias: "按行SUM占比",
|
|
20
|
+
aggrType: AggrType.SUM,
|
|
21
|
+
advCalc: percentage.byRow()
|
|
22
|
+
}))
|
|
23
|
+
.addMetric(f("销售额", {
|
|
24
|
+
alias: "地区层级SUM占比",
|
|
25
|
+
aggrType: AggrType.SUM,
|
|
26
|
+
advCalc: percentage.byField(region)
|
|
27
|
+
}))
|
|
28
|
+
.addMetric(f("销售额", {
|
|
29
|
+
alias: "类别层级SUM占比",
|
|
30
|
+
aggrType: AggrType.SUM,
|
|
31
|
+
advCalc: percentage.byField(category)
|
|
32
|
+
}))
|
|
33
|
+
.addMetric(f("客户 ID", {
|
|
34
|
+
alias: "客户去重按列占比",
|
|
35
|
+
aggrType: AggrType.COUNT_DISTINCT,
|
|
36
|
+
advCalc: percentage.byColumn()
|
|
37
|
+
}))
|
|
38
|
+
.addMetric(f("折扣", {
|
|
39
|
+
alias: "折扣AVG地区占比",
|
|
40
|
+
aggrType: AggrType.AVG,
|
|
41
|
+
advCalc: percentage.byField(region)
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
registerCard(percentageCard.build());
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
var scrollRegion = f("地区");
|
|
2
|
+
|
|
3
|
+
var scrollPercentageCard = createCard(ChartType.SCROLL_TABLE, "L3 占比高级计算 Scroll")
|
|
4
|
+
.setId("pct02a02b03c04d05e06f07g")
|
|
5
|
+
.bindDataset(DS)
|
|
6
|
+
.addRow(scrollRegion)
|
|
7
|
+
.addMetric(f("销售额", {
|
|
8
|
+
alias: "滚动表默认聚合占比",
|
|
9
|
+
advCalc: percentage.byColumn()
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
registerCard(scrollPercentageCard.build());
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Dataset: 订单表 (default)
|
|
2
|
+
defineDataset("a184fe1b1c27941a9ac977bc", [
|
|
3
|
+
{ fdId: "o0f29e706bf1041d9ab0da11", name: "订单 ID", fdType: "STRING", metaType: "DIM" },
|
|
4
|
+
{ fdId: "r739b62cd3dab49ff9bb7134", name: "订单日期", fdType: "DATE", metaType: "DIM" },
|
|
5
|
+
{ fdId: "o82eaae89ecd046a4b531ce4", name: "发货日期", fdType: "DATE", metaType: "DIM" },
|
|
6
|
+
{ fdId: "k673939fff12744b786d8d44", name: "邮寄方式", fdType: "STRING", metaType: "DIM" },
|
|
7
|
+
{ fdId: "me4783b3bf8984906a32e5ce", name: "客户 ID", fdType: "STRING", metaType: "DIM" },
|
|
8
|
+
{ fdId: "v2a8590c1236e4e58882ee9c", name: "客户名称", fdType: "STRING", metaType: "DIM" },
|
|
9
|
+
{ fdId: "j81f7f09ab6c84168924f9aa", name: "细分", fdType: "STRING", metaType: "DIM" },
|
|
10
|
+
{ fdId: "s99bcae4ac5a045ebae87762", name: "城市", fdType: "STRING", metaType: "DIM" },
|
|
11
|
+
{ fdId: "ufe7632b5afa44dd7a79194e", name: "省/自治区", fdType: "STRING", metaType: "DIM" },
|
|
12
|
+
{ fdId: "e2a051c6ebda04917a10cc14", name: "国家", fdType: "STRING", metaType: "DIM" },
|
|
13
|
+
{ fdId: "xe01f39825ccc428eaf67911", name: "地区", fdType: "STRING", metaType: "DIM" },
|
|
14
|
+
{ fdId: "cd9b3a6c556ef4c53a08df16", name: "产品 ID", fdType: "STRING", metaType: "DIM" },
|
|
15
|
+
{ fdId: "cece9879e99f545449909a82", name: "类别", fdType: "STRING", metaType: "DIM" },
|
|
16
|
+
{ fdId: "k15359167149d4d02bbede2b", name: "子类别", fdType: "STRING", metaType: "DIM" },
|
|
17
|
+
{ fdId: "f247afa584af241dba64821d", name: "产品名称", fdType: "STRING", metaType: "DIM" },
|
|
18
|
+
{ fdId: "g4a34bd7bcb78425aa5485d1", name: "销售额", fdType: "DOUBLE", metaType: "METRIC" },
|
|
19
|
+
{ fdId: "xd21ba1d7fd19433ebc728b6", name: "数量", fdType: "LONG", metaType: "METRIC" },
|
|
20
|
+
{ fdId: "l0dbffcc612e047c9a6dae7b", name: "折扣", fdType: "DOUBLE", metaType: "METRIC" },
|
|
21
|
+
{ fdId: "s1c05aa5e4bdd4a54a60e811", name: "利润", fdType: "DOUBLE", metaType: "METRIC" }
|
|
22
|
+
], { displayType: "DATAFLOW" });
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Rank Advanced Calc Round-Trip
|
|
2
|
+
|
|
3
|
+
This eval verifies the L3 native BI `RANK` advanced calculation builder against a real `default` BI environment.
|
|
4
|
+
|
|
5
|
+
It covers:
|
|
6
|
+
|
|
7
|
+
- 按列:`RANK` + 从高到低
|
|
8
|
+
- 按行:`DENSE_RANK` + 从低到高
|
|
9
|
+
- 维度组内:`ROW_NUMBER` + 指定行维度
|
|
10
|
+
- 维度项:`RANK` + 指定列维度
|
|
11
|
+
- Top N:`CUSTOM_NUMBER` with `applyToSubtotal=true/false`
|
|
12
|
+
|
|
13
|
+
Run from `guanvis/`:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
./evals/rank_advcalc_roundtrip/verify_default_roundtrip.sh
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The script publishes fixed resource IDs to `default`, then verifies:
|
|
20
|
+
|
|
21
|
+
- `advCalc` is preserved in `zoneData.metric[*].advCalc`.
|
|
22
|
+
- No metric silently degrades to a formula.
|
|
23
|
+
- Each expected `calDimension` / `rankType` / `sorting` / `tfdId` / `topN` field round-trips.
|
|
24
|
+
- `card preview` succeeds and ranking aliases have non-empty values.
|
|
25
|
+
|
|
26
|
+
Runtime outputs are written to `.roundtrip/` and ignored by git.
|
|
27
|
+
|
|
28
|
+
The eval uses fixed resource IDs and `GUANCLI_PROFILE=default`; reruns overwrite the same test page/cards in the shared default environment.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
var region = f("地区");
|
|
2
|
+
var province = f("省/自治区");
|
|
3
|
+
var category = f("类别");
|
|
4
|
+
|
|
5
|
+
var rangeCard = createCard(ChartType.PIVOT_TABLE, "L3 排名高级计算 范围")
|
|
6
|
+
.setId("r3f01a02b03c04d05e06f07a")
|
|
7
|
+
.bindDataset(DS)
|
|
8
|
+
.addRow(region)
|
|
9
|
+
.addRow(province)
|
|
10
|
+
.addColumn(category)
|
|
11
|
+
.addMetric(f("销售额", {
|
|
12
|
+
alias: "按列RANK降序",
|
|
13
|
+
aggrType: AggrType.SUM,
|
|
14
|
+
advCalc: rank.byColumn({ rankType: RankType.RANK, order: SortOrder.DESC })
|
|
15
|
+
}))
|
|
16
|
+
.addMetric(f("销售额", {
|
|
17
|
+
alias: "按行DENSE升序",
|
|
18
|
+
aggrType: AggrType.SUM,
|
|
19
|
+
advCalc: rank.byRow({ rankType: RankType.DENSE_RANK, order: SortOrder.ASC })
|
|
20
|
+
}))
|
|
21
|
+
.addMetric(f("销售额", {
|
|
22
|
+
alias: "地区组内ROW_NUMBER降序",
|
|
23
|
+
aggrType: AggrType.SUM,
|
|
24
|
+
advCalc: rank.byField(region, { rankType: RankType.ROW_NUMBER, order: SortOrder.DESC })
|
|
25
|
+
}))
|
|
26
|
+
.addMetric(f("销售额", {
|
|
27
|
+
alias: "类别维度项RANK升序",
|
|
28
|
+
aggrType: AggrType.SUM,
|
|
29
|
+
advCalc: rank.byDimensionItem(category, { rankType: RankType.RANK, order: SortOrder.ASC })
|
|
30
|
+
}));
|
|
31
|
+
|
|
32
|
+
registerCard(rangeCard.build());
|
|
33
|
+
|
|
34
|
+
var topNCard = createCard(ChartType.PIVOT_TABLE, "L3 排名高级计算 TopN")
|
|
35
|
+
.setId("r4f01a02b03c04d05e06f08a")
|
|
36
|
+
.bindDataset(DS)
|
|
37
|
+
.addRow(region)
|
|
38
|
+
.addRow(province)
|
|
39
|
+
.addColumn(category)
|
|
40
|
+
.addMetric(f("利润", {
|
|
41
|
+
alias: "Top3适用小计",
|
|
42
|
+
aggrType: AggrType.SUM,
|
|
43
|
+
advCalc: rank.byColumn({
|
|
44
|
+
rankType: RankType.RANK,
|
|
45
|
+
order: SortOrder.DESC,
|
|
46
|
+
topN: rank.topN(3, { applyToSubtotal: true })
|
|
47
|
+
})
|
|
48
|
+
}))
|
|
49
|
+
.addMetric(f("利润", {
|
|
50
|
+
alias: "Top5不适用小计",
|
|
51
|
+
aggrType: AggrType.SUM,
|
|
52
|
+
advCalc: rank.byDimensionItem(region, {
|
|
53
|
+
rankType: RankType.DENSE_RANK,
|
|
54
|
+
order: SortOrder.DESC,
|
|
55
|
+
topN: rank.topN(5, { applyToSubtotal: false })
|
|
56
|
+
})
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
registerCard(topNCard.build());
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Dataset: 订单表 (default)
|
|
2
|
+
defineDataset("a184fe1b1c27941a9ac977bc", [
|
|
3
|
+
{ fdId: "o0f29e706bf1041d9ab0da11", name: "订单 ID", fdType: "STRING", metaType: "DIM" },
|
|
4
|
+
{ fdId: "r739b62cd3dab49ff9bb7134", name: "订单日期", fdType: "DATE", metaType: "DIM" },
|
|
5
|
+
{ fdId: "o82eaae89ecd046a4b531ce4", name: "发货日期", fdType: "DATE", metaType: "DIM" },
|
|
6
|
+
{ fdId: "k673939fff12744b786d8d44", name: "邮寄方式", fdType: "STRING", metaType: "DIM" },
|
|
7
|
+
{ fdId: "me4783b3bf8984906a32e5ce", name: "客户 ID", fdType: "STRING", metaType: "DIM" },
|
|
8
|
+
{ fdId: "v2a8590c1236e4e58882ee9c", name: "客户名称", fdType: "STRING", metaType: "DIM" },
|
|
9
|
+
{ fdId: "j81f7f09ab6c84168924f9aa", name: "细分", fdType: "STRING", metaType: "DIM" },
|
|
10
|
+
{ fdId: "s99bcae4ac5a045ebae87762", name: "城市", fdType: "STRING", metaType: "DIM" },
|
|
11
|
+
{ fdId: "ufe7632b5afa44dd7a79194e", name: "省/自治区", fdType: "STRING", metaType: "DIM" },
|
|
12
|
+
{ fdId: "e2a051c6ebda04917a10cc14", name: "国家", fdType: "STRING", metaType: "DIM" },
|
|
13
|
+
{ fdId: "xe01f39825ccc428eaf67911", name: "地区", fdType: "STRING", metaType: "DIM" },
|
|
14
|
+
{ fdId: "cd9b3a6c556ef4c53a08df16", name: "产品 ID", fdType: "STRING", metaType: "DIM" },
|
|
15
|
+
{ fdId: "cece9879e99f545449909a82", name: "类别", fdType: "STRING", metaType: "DIM" },
|
|
16
|
+
{ fdId: "k15359167149d4d02bbede2b", name: "子类别", fdType: "STRING", metaType: "DIM" },
|
|
17
|
+
{ fdId: "f247afa584af241dba64821d", name: "产品名称", fdType: "STRING", metaType: "DIM" },
|
|
18
|
+
{ fdId: "g4a34bd7bcb78425aa5485d1", name: "销售额", fdType: "DOUBLE", metaType: "METRIC" },
|
|
19
|
+
{ fdId: "xd21ba1d7fd19433ebc728b6", name: "数量", fdType: "LONG", metaType: "METRIC" },
|
|
20
|
+
{ fdId: "l0dbffcc612e047c9a6dae7b", name: "折扣", fdType: "DOUBLE", metaType: "METRIC" },
|
|
21
|
+
{ fdId: "s1c05aa5e4bdd4a54a60e811", name: "利润", fdType: "DOUBLE", metaType: "METRIC" }
|
|
22
|
+
], { displayType: "DATAFLOW" });
|