@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,408 @@
|
|
|
1
|
+
## API 参考
|
|
2
|
+
|
|
3
|
+
### 数据集与字段
|
|
4
|
+
|
|
5
|
+
| 函数 | 说明 |
|
|
6
|
+
|------|------|
|
|
7
|
+
| `defineDataset(dsId, columns, options?)` | 定义数据集 schema(由 init 命令生成)。第一个数据集自动暴露为 `global.DS`(dsId 字符串)。`options.displayType` 指定数据集类型(如 `"EXCEL"`, `"DATAFLOW"`),确保看板页面正确显示数据集图标 |
|
|
8
|
+
| `field(dsId, fieldName, overrides?)` | 从 schema 构造字段引用,`dsId` 是字符串。可叠加 aggrType/alias/numberFormat/sortType/granularity 等 |
|
|
9
|
+
| `f(fieldName, overrides?)` | `field(DS, fieldName, overrides)` 的简写,仅适用于**单数据集**场景 |
|
|
10
|
+
| `calcField(name, formula, opts?)` | 创建卡片级计算字段(公式中用 `[字段名]` 引用字段)。`opts`: `calculationType`/`fdType`/`numberFormat`/`advCalc`/`fieldFormat` 等 |
|
|
11
|
+
| `filterField(dsId, fieldName, filterType, filterValue?, opts?)` | 创建筛选字段(带 filterType/filterValue),传给 `.addFilter()` 使用 |
|
|
12
|
+
| `getDataset(dsId)` | 获取已定义的数据集对象(返回对象,**不要**传给 `field()` 和 `bindDataset()`) |
|
|
13
|
+
|
|
14
|
+
**`field()` vs `calcField()` vs `filterField()` 选择**:
|
|
15
|
+
- `field()` — 引用数据集中已有的字段,用于维度/指标/排序等;单字段聚合优先在这里设置 `aggrType`,如 `SUM`、`AVG`、`COUNT`、`COUNT_DISTINCT`、`MIN`、`MAX`
|
|
16
|
+
- `calcField()` — 创建公式计算字段(如利润率 = 利润/销售额),用于必须组合多个字段、多个聚合或数据库函数的指标
|
|
17
|
+
- `filterField()` — 创建筛选条件字段,专门用于 `.addFilter()`
|
|
18
|
+
|
|
19
|
+
三者都是字段工厂函数,输出都是字段对象。
|
|
20
|
+
|
|
21
|
+
**聚合字段优先级**:
|
|
22
|
+
|
|
23
|
+
- 单字段聚合必须优先使用原生聚合配置,例如 `.addMetric(f("销售额", { aggrType: AggrType.SUM }))`、`.addMetric(f("客户ID", { aggrType: AggrType.COUNT_DISTINCT }))`。
|
|
24
|
+
- 去重计数使用 `AggrType.COUNT_DISTINCT`;不要在 `calcField()` 里写 `COUNT_DISTINCT([字段])`,这不是通用 SQL 函数,数据库直连时可能下推失败。
|
|
25
|
+
- 只有复合指标才使用 `calcField()`,例如 `SUM([销售额]) / COUNT(DISTINCT [客户ID])`;这类公式必须按 `schema.js` 里的 `displayType` 对应数据库方言生成。
|
|
26
|
+
|
|
27
|
+
**多数据集场景**:当 `schema.js` 包含多个 `defineDataset()` 时,`DS` 指向第一个数据集的 dsId 字符串。其他数据集需要直接用 dsId 字符串:
|
|
28
|
+
|
|
29
|
+
```javascript
|
|
30
|
+
var DS_ORDER = "od8e9899dfcb14f689e1bf80"; // 直接写 dsId 字符串
|
|
31
|
+
var card = createCard(ChartType.BASIC_LINE, "趋势图")
|
|
32
|
+
.bindDataset(DS_ORDER)
|
|
33
|
+
.addRow(field(DS_ORDER, "订单日期", { granularity: Granularity.MONTH }))
|
|
34
|
+
.addMetric(field(DS_ORDER, "销售额", { aggrType: AggrType.SUM }));
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Number Format
|
|
38
|
+
|
|
39
|
+
| 工厂方法 | 参数 | 说明 |
|
|
40
|
+
|----------|------|------|
|
|
41
|
+
| `NumberFormat.number(decimals?, thousands?)` | int, bool | 数值格式(默认 0 位小数,有千分位) |
|
|
42
|
+
| `NumberFormat.currency(symbol?, decimals?)` | string, int | 货币格式(默认 ¥,2 位小数) |
|
|
43
|
+
| `NumberFormat.percentage(decimals?, divideBy?)` | int, int | 百分比格式(默认 1 位小数) |
|
|
44
|
+
| `NumberFormat.auto(unit?)` | string | 自动缩略单位(万/亿/K/M) |
|
|
45
|
+
| `NumberFormat.custom(opts)` | object | 自定义格式 |
|
|
46
|
+
|
|
47
|
+
### 日期粒度 (Granularity)
|
|
48
|
+
|
|
49
|
+
DATE 类型字段拖入维度区时可指定时间粒度:
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
f("订单日期", { granularity: Granularity.YEAR }) // 按年
|
|
53
|
+
f("订单日期", { granularity: Granularity.QUARTER }) // 按季度
|
|
54
|
+
f("订单日期", { granularity: Granularity.MONTH }) // 按月
|
|
55
|
+
f("订单日期", { granularity: Granularity.DAY }) // 按天
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
可用值:`NONE`, `YEAR`, `QUARTER`, `MONTH`, `WEEK`, `DAYOFWEEK`, `DAY`, `HOUR`, `MINUTE`, `SECOND`
|
|
59
|
+
|
|
60
|
+
### 卡片级计算字段
|
|
61
|
+
|
|
62
|
+
使用 `calcField()` 在卡片指标区创建公式计算字段(不依赖 ETL 预计算):
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
.addMetric(calcField("利润率", "sum([Profit])/sum([Sales])"))
|
|
66
|
+
.addMetric(calcField("客单价", "[Sales]/[Quantity]", { calculationType: "normal" }))
|
|
67
|
+
.addMetric(calcField("发货天数", "datediff([Ship Date],[Order Date])"))
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**公式语法**:formula 中用 `[字段名]` 引用数据集字段。公式本质上是 **SQL 表达式**,支持的函数取决于底层数据引擎:
|
|
71
|
+
- **上传的 Excel/CSV 或抽取数据集** → 使用 **Apache Spark 3.5 SQL** 语法(支持 `datediff`、`case when`、`if`、`concat`、窗口函数等)
|
|
72
|
+
- **数据库直连数据集** → 使用**目标数据库自身的 SQL** 语法(如 MySQL、PostgreSQL、ClickHouse 等)
|
|
73
|
+
|
|
74
|
+
> **重要**:`schema.js` 中的 `displayType` 是生成 `calcField()` 公式时的 SQL 方言事实源。数据库直连数据集会把公式下推到目标库执行,不能把平台聚合枚举或伪函数直接写进公式。例如 PostgreSQL 去重计数应写 `COUNT(DISTINCT [客户ID])`,不要写 `COUNT_DISTINCT([客户ID])`;如果只是单独统计去重人数,应改用 `f("客户ID", { aggrType: AggrType.COUNT_DISTINCT })`。
|
|
75
|
+
|
|
76
|
+
`calcField(name, formula, opts?)` 参数:
|
|
77
|
+
- `name`:字段显示名
|
|
78
|
+
- `formula`:SQL 表达式,用 `[字段名]` 引用数据集字段
|
|
79
|
+
- `opts.calculationType`:`"aggregation"`(默认), `"normal"`, `"window"`(窗口计算)
|
|
80
|
+
- `opts.fdType`:默认 `"DOUBLE"`,可改为 `"LONG"`、`"STRING"` 等
|
|
81
|
+
- `opts.numberFormat` / `opts.alias`:同 `field()` overrides
|
|
82
|
+
- `opts.advCalc` / `opts.fieldFormat` / `opts.aggrType`:需要还原同环比、占比、表格指标格式等高级 zoneData 时可显式传入,导出器会原样透传到 card meta
|
|
83
|
+
|
|
84
|
+
**calculationType 选择**:
|
|
85
|
+
- `"aggregation"`(默认)— 公式**必须**包含聚合函数(如 `SUM([Profit])/SUM([Sales])`),否则后端报 `MISSING_AGGREGATION` 错误
|
|
86
|
+
- `"normal"` — 明细级公式,不含聚合函数(如 `datediff([Ship Date],[Order Date])`),适用于明细表或作为其他聚合的输入
|
|
87
|
+
- `"window"` — 窗口计算公式(如 `sum([Sales]) over(partition by [Category])`),用于排名、累计等
|
|
88
|
+
|
|
89
|
+
> **明细表限制**:`DETAIL_TABLE` / `SCROLL_TABLE` 只支持逐行明细展示,卡片级 `calcField()` 必须显式使用 `{ calculationType: "normal" }`,且公式中不要写 `SUM`/`COUNT(DISTINCT ...)`/`GROUP_CONCAT`/`STRING_AGG` 等聚合或窗口计算。需要汇总时,改用非明细图表的原生指标 `aggrType`;复杂聚合用非明细图表的 `aggregation` calcField,或在 ETL / 数据集计算字段中预计算。本地校验只稳定拦截 `aggregation`/`window` 类型和明显 `OVER(...)` 窗口子句,不维护跨 SQL 方言聚合函数名单。
|
|
90
|
+
|
|
91
|
+
> **常见错误**:`calcField("利润率", "[利润]/[销售额]")` 使用默认 `calculationType: "aggregation"` 但公式中没有聚合函数,会导致 `MISSING_AGGREGATION` 错误。正确写法是 `calcField("利润率", "SUM([利润])/SUM([销售额])")` 或改为 `{ calculationType: "normal" }`。
|
|
92
|
+
|
|
93
|
+
### 同环比高级计算
|
|
94
|
+
|
|
95
|
+
优先使用 BI 原生高级计算 builder,不要用 `calcField()` 手拼同比/环比公式。当前锁定的 MVP 范围对应界面「高级计算 → 同比/环比」里的以下设置:
|
|
96
|
+
- 时间类型:日环比、周同比、月同比、季同比、年同比、年同比(按周)
|
|
97
|
+
- 期末值:上月末、上季度末、上年末
|
|
98
|
+
- 自定义:后移 1 个月
|
|
99
|
+
- 输出值:增长值、增长率、对比值
|
|
100
|
+
- 增长率类型:普通增长率、绝对增长率
|
|
101
|
+
|
|
102
|
+
默认规则:同比、环比、同环比、年同比、月环比等语义未指定输出值时默认生成增长率;未指定模式时默认生成日期筛选模式(`ComparativeMode.FILTER_BASED`),保证页面日期筛选器联动生效。需要普通模式时显式传 `{ mode: ComparativeMode.NORMAL }`;需要增长值或对比值时显式传 `ComparativeOutput.GROWTH_VALUE` / `ComparativeOutput.COMPARE_VALUE`。
|
|
103
|
+
|
|
104
|
+
示例:
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
var dateField = f("订单日期");
|
|
108
|
+
|
|
109
|
+
createCard(ChartType.PIVOT_TABLE, "销售同环比")
|
|
110
|
+
.bindDataset(DS)
|
|
111
|
+
.addRow(dateField)
|
|
112
|
+
.addMetric(f("销售额", {
|
|
113
|
+
alias: "年同比增长率",
|
|
114
|
+
aggrType: AggrType.SUM,
|
|
115
|
+
advCalc: comparative.yearOverYear(dateField)
|
|
116
|
+
}))
|
|
117
|
+
.addMetric(f("销售额", {
|
|
118
|
+
alias: "年同比绝对增长率",
|
|
119
|
+
aggrType: AggrType.SUM,
|
|
120
|
+
advCalc: comparative.yearOverYear(dateField, ComparativeOutput.GROWTH_RATE, {
|
|
121
|
+
growthRateType: GrowthRateType.ABS
|
|
122
|
+
})
|
|
123
|
+
}))
|
|
124
|
+
.addMetric(f("销售额", {
|
|
125
|
+
alias: "月同比对比值",
|
|
126
|
+
aggrType: AggrType.SUM,
|
|
127
|
+
advCalc: comparative.monthOverMonth(dateField, ComparativeOutput.COMPARE_VALUE)
|
|
128
|
+
}))
|
|
129
|
+
.addMetric(f("销售额", {
|
|
130
|
+
alias: "上月末增长值",
|
|
131
|
+
aggrType: AggrType.SUM,
|
|
132
|
+
advCalc: comparative.periodEnd(dateField, ComparativePeriodEnd.MONTH_END, ComparativeOutput.GROWTH_VALUE)
|
|
133
|
+
}))
|
|
134
|
+
.addMetric(f("销售额", {
|
|
135
|
+
alias: "月同比普通模式增长率",
|
|
136
|
+
aggrType: AggrType.SUM,
|
|
137
|
+
advCalc: comparative.monthOverMonth(dateField, {
|
|
138
|
+
mode: ComparativeMode.NORMAL
|
|
139
|
+
})
|
|
140
|
+
}));
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
KPI 指标卡的 compare 区也支持同环比高级计算:
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
var dateField = f("订单日期");
|
|
147
|
+
|
|
148
|
+
createCard(ChartType.KPI_CARD, "销售额 KPI")
|
|
149
|
+
.bindDataset(DS)
|
|
150
|
+
.addMetric(f("销售额", { aggrType: AggrType.SUM }))
|
|
151
|
+
.addCompare(f("销售额", {
|
|
152
|
+
alias: "年同比增长率",
|
|
153
|
+
aggrType: AggrType.SUM,
|
|
154
|
+
advCalc: comparative.yearOverYear(dateField)
|
|
155
|
+
}));
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
常用枚举:
|
|
159
|
+
- `ComparativeOutput.GROWTH_VALUE`:增长值
|
|
160
|
+
- `ComparativeOutput.GROWTH_RATE`:增长率
|
|
161
|
+
- `ComparativeOutput.COMPARE_VALUE`:对比值
|
|
162
|
+
- `GrowthRateType.NORMAL`:普通增长率,默认值
|
|
163
|
+
- `GrowthRateType.ABS`:绝对增长率
|
|
164
|
+
- `ComparativeMode.FILTER_BASED`:日期筛选模式,默认值,用于复现前端「对比」槽位 + 日期筛选的高级计算
|
|
165
|
+
- `ComparativeMode.NORMAL`:普通模式,只有明确不需要页面日期筛选器联动时使用
|
|
166
|
+
- `ComparativePeriodEnd.MONTH_END` / `QUARTER_END` / `YEAR_END`:期末值
|
|
167
|
+
|
|
168
|
+
### 累计高级计算
|
|
169
|
+
|
|
170
|
+
优先使用 BI 原生累计高级计算 builder,不要用 `calcField()` 手拼窗口累计公式。当前范围对应界面「高级计算 → 累计计算」,输出 `advType: "RUNNING_TOTAL"`。
|
|
171
|
+
|
|
172
|
+
示例:
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
var orderDate = f("订单日期");
|
|
176
|
+
var region = f("地区");
|
|
177
|
+
var province = f("省/自治区");
|
|
178
|
+
var category = f("类别");
|
|
179
|
+
|
|
180
|
+
createCard(ChartType.PIVOT_TABLE, "销售累计")
|
|
181
|
+
.bindDataset(DS)
|
|
182
|
+
.addRow(orderDate)
|
|
183
|
+
.addRow(region)
|
|
184
|
+
.addRow(province)
|
|
185
|
+
.addColumn(category)
|
|
186
|
+
.addMetric(f("销售额", {
|
|
187
|
+
alias: "按列累计",
|
|
188
|
+
aggrType: AggrType.SUM,
|
|
189
|
+
advCalc: runningTotal.byColumn()
|
|
190
|
+
}))
|
|
191
|
+
.addMetric(f("销售额", {
|
|
192
|
+
alias: "按行累计",
|
|
193
|
+
aggrType: AggrType.SUM,
|
|
194
|
+
advCalc: runningTotal.byRow()
|
|
195
|
+
}))
|
|
196
|
+
.addMetric(f("销售额", {
|
|
197
|
+
alias: "地区组内累计",
|
|
198
|
+
aggrType: AggrType.SUM,
|
|
199
|
+
advCalc: runningTotal.byField(region)
|
|
200
|
+
}))
|
|
201
|
+
.addMetric(f("销售额", {
|
|
202
|
+
alias: "订单日期月累计",
|
|
203
|
+
aggrType: AggrType.SUM,
|
|
204
|
+
advCalc: runningTotal.byDateField(orderDate, RunningTotalGranularity.MONTH)
|
|
205
|
+
}));
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
常用 API:
|
|
209
|
+
- `runningTotal.byColumn()`:按列累计,生成 `calcRangeType: "COLUMN"`
|
|
210
|
+
- `runningTotal.byRow()`:按行累计,生成 `calcRangeType: "ROW"`
|
|
211
|
+
- `runningTotal.byField(field)`:按非日期维度字段累计,`field` 必须已在行/列区域
|
|
212
|
+
- `runningTotal.byDateField(field, granularity)`:按日期字段累计,`field` 必须已在行/列区域且为 `DATE` / `TIMESTAMP` / `SUB_DATE`
|
|
213
|
+
|
|
214
|
+
常用枚举:
|
|
215
|
+
- `RunningTotalGranularity.DAY`:日累计
|
|
216
|
+
- `RunningTotalGranularity.WEEK`:周累计
|
|
217
|
+
- `RunningTotalGranularity.MONTH`:月累计
|
|
218
|
+
- `RunningTotalGranularity.QUARTER`:季度累计
|
|
219
|
+
- `RunningTotalGranularity.YEAR`:当年累计
|
|
220
|
+
- `RunningTotalGranularity.ALL_YEARS` / `RunningTotalGranularity.NONE`:历年累计
|
|
221
|
+
|
|
222
|
+
约束:
|
|
223
|
+
- 仅支持表格/透视表类图表,这是 guanvis MVP 限制,不是 BI 原生能力上限。
|
|
224
|
+
- 至少需要一个行/列维度;历史 BI payload 中存在无维度累计,但 guanvis 当前不新建。
|
|
225
|
+
- 日期累计必须用 `byDateField()`;`byField(dateField)` 会报错。
|
|
226
|
+
- 最后一个日期维度不能选择自身最细粒度。例如最后一个 `DAY` 日期不能选 `DAY`,最后一个 `MONTH` 子日期不能选 `MONTH`。如果该日期字段后面还有可选维度,则可以选择自身最细粒度。
|
|
227
|
+
- `advValue.aggrType` 固定输出 `SUM`。后端存在更底层能力,但原生累计菜单固定写 `SUM`。
|
|
228
|
+
- 指标自身 `aggrType` 也必须是 `AggrType.SUM`;当前 MVP 不生成“外层 AVG、累计内部 SUM”的混合 payload。
|
|
229
|
+
|
|
230
|
+
### 排名高级计算
|
|
231
|
+
|
|
232
|
+
优先使用 BI 原生排名高级计算 builder,不要用 `calcField()` 手拼窗口函数。当前范围对应界面「高级计算 → 排名」:
|
|
233
|
+
- 排名范围:按列、按行、维度组内、维度项
|
|
234
|
+
- 排名方式:`RANK`、`DENSE_RANK`、`ROW_NUMBER`
|
|
235
|
+
- 顺序:从高到低、从低到高
|
|
236
|
+
- Top N:全部数据、自定义条数;条数范围 1-100,当前只支持 `COUNT`
|
|
237
|
+
|
|
238
|
+
示例:
|
|
239
|
+
|
|
240
|
+
```javascript
|
|
241
|
+
var region = f("大区");
|
|
242
|
+
var year = f("年");
|
|
243
|
+
|
|
244
|
+
createCard(ChartType.PIVOT_TABLE, "销售排名")
|
|
245
|
+
.bindDataset(DS)
|
|
246
|
+
.addRow(region)
|
|
247
|
+
.addRow(f("省份"))
|
|
248
|
+
.addColumn(year)
|
|
249
|
+
.addMetric(f("销售额", {
|
|
250
|
+
alias: "按列排名",
|
|
251
|
+
aggrType: AggrType.SUM,
|
|
252
|
+
advCalc: rank.byColumn({
|
|
253
|
+
rankType: RankType.RANK,
|
|
254
|
+
order: SortOrder.DESC
|
|
255
|
+
})
|
|
256
|
+
}))
|
|
257
|
+
.addMetric(f("销售额", {
|
|
258
|
+
alias: "大区组内排名",
|
|
259
|
+
aggrType: AggrType.SUM,
|
|
260
|
+
advCalc: rank.byField(region, {
|
|
261
|
+
rankType: RankType.DENSE_RANK,
|
|
262
|
+
order: SortOrder.ASC
|
|
263
|
+
})
|
|
264
|
+
}))
|
|
265
|
+
.addMetric(f("销售额", {
|
|
266
|
+
alias: "年份维度项 Top5",
|
|
267
|
+
aggrType: AggrType.SUM,
|
|
268
|
+
advCalc: rank.byDimensionItem(year, {
|
|
269
|
+
rankType: RankType.ROW_NUMBER,
|
|
270
|
+
order: SortOrder.DESC,
|
|
271
|
+
topN: rank.topN(5, { applyToSubtotal: false })
|
|
272
|
+
})
|
|
273
|
+
}));
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
常用 API:
|
|
277
|
+
- `rank.byColumn(opts)`:按列排名,生成 `calDimension: "COLUMN"`
|
|
278
|
+
- `rank.byRow(opts)`:按行排名,生成 `calDimension: "ROW"`
|
|
279
|
+
- `rank.byField(field, opts)`:维度组内排名,`field` 必须已在行/列区域
|
|
280
|
+
- `rank.byDimensionItem(field, opts)`:维度项排名,`field` 必须已在行/列区域;行/列区域至少需要两个维度,否则 builder 会拒绝导出,避免 BI 降级为行/列排名
|
|
281
|
+
- `rank.topN(count, { applyToSubtotal })`:自定义 Top N,`count` 为 1-100 整数,`applyToSubtotal` 默认 true
|
|
282
|
+
- `rank.all()`:全部数据,等价于默认 TopN 配置
|
|
283
|
+
|
|
284
|
+
常用枚举:
|
|
285
|
+
- `RankType.RANK`:重复排名,后续名次跳号
|
|
286
|
+
- `RankType.DENSE_RANK`:重复排名,后续名次连续
|
|
287
|
+
- `RankType.ROW_NUMBER`:不并列,逐行连续编号
|
|
288
|
+
- `SortOrder.DESC` / `SortOrder.ASC`:从高到低 / 从低到高;builder 会写出 BI 需要的 `desc` / `asc`
|
|
289
|
+
|
|
290
|
+
### 占比高级计算
|
|
291
|
+
|
|
292
|
+
优先使用 BI 原生占比高级计算 builder,不要用 `calcField()` 手拼窗口函数。当前范围对应界面「高级计算 → 占比」:
|
|
293
|
+
- 按列:`measureOnDimRow: true`
|
|
294
|
+
- 按行:`measureOnDimRow: false`;真实 UI 只在存在列维度时展示该选项
|
|
295
|
+
- 指定维度:目标字段必须在行/列区域,且不能是该轴最后一个非 MPH 维度
|
|
296
|
+
- 支持表格行/列结构图表;`DETAIL_TABLE` 没有可用于占比上下文的行/列层级,不支持原生占比高级计算
|
|
297
|
+
- 默认数据格式:若未显式配置格式,builder 自动补百分比格式、保留 2 位小数
|
|
298
|
+
|
|
299
|
+
示例:
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
var region = f("大区");
|
|
303
|
+
var province = f("省份");
|
|
304
|
+
var category = f("类别");
|
|
305
|
+
var subcategory = f("子类别");
|
|
306
|
+
|
|
307
|
+
createCard(ChartType.PIVOT_TABLE, "销售占比")
|
|
308
|
+
.bindDataset(DS)
|
|
309
|
+
.addRow(region)
|
|
310
|
+
.addRow(province)
|
|
311
|
+
.addColumn(category)
|
|
312
|
+
.addColumn(subcategory)
|
|
313
|
+
.addMetric(f("销售额", {
|
|
314
|
+
alias: "按列占比",
|
|
315
|
+
aggrType: AggrType.SUM,
|
|
316
|
+
advCalc: percentage.byColumn()
|
|
317
|
+
}))
|
|
318
|
+
.addMetric(f("销售额", {
|
|
319
|
+
alias: "按行占比",
|
|
320
|
+
aggrType: AggrType.SUM,
|
|
321
|
+
advCalc: percentage.byRow()
|
|
322
|
+
}))
|
|
323
|
+
.addMetric(f("销售额", {
|
|
324
|
+
alias: "大区层级占比",
|
|
325
|
+
aggrType: AggrType.SUM,
|
|
326
|
+
advCalc: percentage.byField(region)
|
|
327
|
+
}))
|
|
328
|
+
.addMetric(f("销售额", {
|
|
329
|
+
alias: "类别层级占比",
|
|
330
|
+
aggrType: AggrType.SUM,
|
|
331
|
+
advCalc: percentage.byField(category)
|
|
332
|
+
}));
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
常用 API:
|
|
336
|
+
- `percentage.byColumn()`:按列占比,生成 `measureOnDimRow: true`
|
|
337
|
+
- `percentage.byRow()`:按行占比,生成 `measureOnDimRow: false`
|
|
338
|
+
- `percentage.byField(field, opts)`:按指定维度层级占比;builder 会在卡片 zone 上下文中根据字段属于 row/column 回填 `measureOnDimRow`
|
|
339
|
+
- 同一个字段同时出现在行、列区域时,用 `opts.axis: "row" | "column"` 显式指定轴向,例如 `percentage.byField(region, { axis: "column" })`
|
|
340
|
+
- 日期维度带粒度时直接传同一个 field 引用,例如 `var month = f("日期", { granularity: Granularity.MONTH })`,builder 会写出 BI zone 中的粒度字段 ID
|
|
341
|
+
|
|
342
|
+
支持聚合类型:`SUM`、`CNT`、`MAX`、`MIN`、`AVG`、`CNT_DISTINCT`、`NUL`。JS DSL 中 `NUL` 对应 `AggrType.FIRST_NOT_NULL`,没有 `AggrType.NUL` 这个枚举名;如果后端环境已移除 `NUL` 支持,以目标环境实际 `AggrType.percentSupportedTypes` 为准。
|
|
343
|
+
|
|
344
|
+
**常用 Spark SQL 函数示例**(适用于 Excel/CSV 数据集):
|
|
345
|
+
```javascript
|
|
346
|
+
// 日期差
|
|
347
|
+
calcField("发货天数", "datediff([Ship Date],[Order Date])")
|
|
348
|
+
// 条件判断
|
|
349
|
+
calcField("Ship Status", "case when datediff([Ship Date],[Order Date]) > 6 then 'Late' else 'On Time' end", { fdType: "STRING" })
|
|
350
|
+
// 字符串拼接
|
|
351
|
+
calcField("全名", "concat([First Name], ' ', [Last Name])", { fdType: "STRING" })
|
|
352
|
+
// 窗口函数
|
|
353
|
+
calcField("类别销售占比", "sum([Sales]) over(partition by [Category])", { calculationType: "window" })
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**高级 zoneData 透传**:当要还原精品应用里的同环比、自定义排序、特殊字段格式时,不要手工 patch zip,直接把这些字段放在 `field()` / `calcField()` 的 overrides 中:
|
|
357
|
+
|
|
358
|
+
```javascript
|
|
359
|
+
var yoyRate = calcField("同比", "SUM([销售额])", {
|
|
360
|
+
aggrType: AggrType.FIRST_NOT_NULL,
|
|
361
|
+
advCalc: {
|
|
362
|
+
advType: "COMPARATIVE",
|
|
363
|
+
advValue: {
|
|
364
|
+
advType: "COMPARATIVE",
|
|
365
|
+
dateFdId: "date_fd",
|
|
366
|
+
valueType: "RATE",
|
|
367
|
+
offset: 1,
|
|
368
|
+
offsetType: "YEAR",
|
|
369
|
+
granularity: "DAY",
|
|
370
|
+
mode: "FILTER_BASED"
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
fieldFormat: {
|
|
374
|
+
numberFormat: { formatType: "PERCENTAGE", decimalPlaces: 2 }
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
createCard(ChartType.PIVOT_TABLE, "品牌同比分析")
|
|
379
|
+
.bindDataset(DS)
|
|
380
|
+
.addRow(f("品牌"))
|
|
381
|
+
.addMetric(yoyRate)
|
|
382
|
+
.addSort(f("品牌", {
|
|
383
|
+
ordering: "ASC",
|
|
384
|
+
customSort: ["华东", "华南", "华北"]
|
|
385
|
+
}));
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### 卡片级筛选器 (Filters Zone)
|
|
389
|
+
|
|
390
|
+
通过 `.addFilter()` 在卡片上添加固定筛选条件,有三种写法:
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
// 写法1: filterField() 工厂函数(推荐,最简洁)
|
|
394
|
+
.addFilter(filterField(DS, "地区", FilterType.IN, ["华东", "华北"]))
|
|
395
|
+
.addFilter(filterField(DS, "销售额", FilterType.GT, ["10000"]))
|
|
396
|
+
|
|
397
|
+
// 写法2: addFilter 三参数快捷语法
|
|
398
|
+
.addFilter(field(DS, "地区"), FilterType.IN, ["华东", "华北"])
|
|
399
|
+
|
|
400
|
+
// 写法3: 对象语法(需要 filterLevel 时)
|
|
401
|
+
.addFilter(filterField(DS, "订单日期", FilterType.BT, ["2024-01-01", "2024-12-31"], { filterLevel: FilterLevel.AGGREGATION }))
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
`filterField(dsId, fieldName, filterType, filterValue?, opts?)` — 与 `field()` 和 `calcField()` 模式一致。
|
|
405
|
+
|
|
406
|
+
枚举 `FilterType`:`IN`, `NOT_IN`, `GT`, `GE`, `LT`, `LE`, `EQ`, `NE`, `BT`(区间), `CONTAINS`, `NOT_CONTAINS`, `STARTSWITH`, `ENDSWITH`, `IS_NULL`, `NOT_NULL`
|
|
407
|
+
|
|
408
|
+
枚举 `FilterLevel`:`DETAIL`(明细筛选,默认), `AGGREGATION`(聚合筛选), `RESULT`(结果筛选)
|