@linkaicli/linkai-cli 0.0.0-stage → 1.0.18
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/AGENTS.md +64 -0
- package/GUIDE.md +149 -0
- package/LICENSE +190 -0
- package/NOTICE +6 -0
- package/README.md +82 -2
- package/THIRD_PARTY_NOTICES.txt +318 -0
- package/cli-manifest.json +1850 -0
- package/clis/_shared/common.js +1 -0
- package/clis/_shared/site-auth.js +1 -0
- package/clis/linkai/build.js +1 -0
- package/clis/linkai/card-rules.js +1 -0
- package/clis/linkai/collab.js +1 -0
- package/clis/linkai/commands.js +4 -0
- package/clis/linkai/core.js +12 -0
- package/clis/linkai/deliverable.js +2 -0
- package/clis/linkai/dictionary.js +1 -0
- package/clis/linkai/fill-card.js +1 -0
- package/clis/linkai/oauth.js +8 -0
- package/clis/linkai/reuse.js +1 -0
- package/clis/linkai/templates.js +1 -0
- package/dist/bundle/browser-cdp.mjs +2 -0
- package/dist/bundle/browser-page.mjs +2 -0
- package/dist/bundle/browser-utils.mjs +2 -0
- package/dist/bundle/core.mjs +3448 -0
- package/dist/bundle/daemon.mjs +16 -0
- package/dist/bundle/download-article.mjs +2 -0
- package/dist/bundle/download-media.mjs +2 -0
- package/dist/bundle/download-progress.mjs +2 -0
- package/dist/bundle/download.mjs +2 -0
- package/dist/bundle/errors.mjs +2 -0
- package/dist/bundle/logger.mjs +2 -0
- package/dist/bundle/main.mjs +3 -0
- package/dist/bundle/oplog.mjs +2 -0
- package/dist/bundle/pipeline.mjs +2 -0
- package/dist/bundle/registry.mjs +2 -0
- package/dist/bundle/skills.mjs +2 -0
- package/dist/bundle/types.mjs +2 -0
- package/dist/bundle/utils.mjs +2 -0
- package/dist/bundle/vendor/readability/Readability-readerable.js +122 -0
- package/dist/bundle/vendor/readability/Readability.js +2786 -0
- package/knowledge/README.md +29 -0
- package/knowledge/browser/README.md +40 -0
- package/knowledge/data-dictionary/README.md +35 -0
- package/knowledge/data-dictionary/_templates/enum.md +7 -0
- package/knowledge/data-dictionary/_templates/metric.md +5 -0
- package/knowledge/data-dictionary/_templates/view.md +29 -0
- package/knowledge/data-dictionary/enums/.gitkeep +1 -0
- package/knowledge/data-dictionary/index.md +12 -0
- package/knowledge/data-dictionary/metrics/.gitkeep +1 -0
- package/knowledge/data-dictionary/views/.gitkeep +1 -0
- package/knowledge/report-builder/README.md +80 -0
- package/knowledge/report-builder/SOP.md +91 -0
- package/knowledge/report-builder/build-spec.md +79 -0
- package/knowledge/report-builder/references/api-catalog.md +106 -0
- package/knowledge/report-builder/references/api.md +148 -0
- package/knowledge/report-builder/references/auth-space.md +58 -0
- package/knowledge/report-builder/references/card.md +382 -0
- package/knowledge/report-builder/references/chart-config-schema.md +572 -0
- package/knowledge/report-builder/references/chart-types.md +167 -0
- package/knowledge/report-builder/references/dashboard-patterns.md +138 -0
- package/knowledge/report-builder/references/dataset.md +152 -0
- package/knowledge/report-builder/references/fill-import.md +95 -0
- package/knowledge/report-builder/references/filters.md +170 -0
- package/knowledge/report-builder/references/gantt.md +79 -0
- package/knowledge/report-builder/references/pitfalls.md +265 -0
- package/knowledge/report-builder/references/query-engine.md +177 -0
- package/knowledge/report-builder/references/report.md +249 -0
- package/llms.txt +37 -0
- package/package.json +108 -4
- package/skills/agent-prompt.md +37 -0
- package/skills/linkai-browser/SKILL.md +67 -0
- package/skills/linkai-collab/SKILL.md +65 -0
- package/skills/linkai-data-workflow/SKILL.md +49 -0
- package/skills/linkai-data-workflow/assets/import-run-template.json +22 -0
- package/skills/linkai-data-workflow/assets/solution-template.md +60 -0
- package/skills/linkai-data-workflow/references/excel-analysis-modeling.md +35 -0
- package/skills/linkai-data-workflow/references/fill-import.md +95 -0
- package/skills/linkai-data-workflow/references/solution-knowledge.md +35 -0
- package/skills/linkai-report-builder/SKILL.md +151 -0
- package/skills/linkai-usage/SKILL.md +67 -0
- package/templates/report-spec/cards/detail-table.json +12 -0
- package/templates/report-spec/filters.example.json +28 -0
- package/templates/report-spec/plan-knowledge.example.yaml +18 -0
- package/templates/report-spec/report.example.yaml +123 -0
- package/templates/report-spec/sql/channel.sql +7 -0
- package/templates/report-spec/sql/detail.sql +10 -0
- package/templates/report-spec/sql/kpi.sql +8 -0
- package/templates/report-spec/sql/trend.sql +9 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# 筛选器全模型
|
|
2
|
+
|
|
3
|
+
读这篇的时机:给看板/报表/卡片加筛选器、设默认值、做日期区间、排查「筛选器不过滤」「别人看不到我配的筛选器」。
|
|
4
|
+
`references/report.md` 里的看板/报表筛选器 body 是本篇的特例。
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## 1. 三个层级、四个存放位置
|
|
8
|
+
|
|
9
|
+
| 层级 | 存哪 | 谁能看到 | 怎么写 |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| **卡片源筛选器** | 卡片本身(`IndexBlockPreFilter`) | 所有用户,作为卡片/报表筛选器的**模板** | `update-new` 的 `filters` 数组(`IndexBlockFilterV2Req`) |
|
|
12
|
+
| **看板系统模板** | `UserPageCardFilter`,`IsTenantSystem=true` | 同租户所有用户,作为看板筛选器的模板 | `batch-add-or-update-filter` + `filterSourceType:4` + **`isTenantSystem:true`** |
|
|
13
|
+
| 卡片系统模板 | `UserPageCardFilter`,`IsTenantSystem=true`,按 pageCardId | 同租户所有用户 | 同上但 `filterSourceType:2`;前端从不这样写,**不推荐** |
|
|
14
|
+
| **用户个人副本** | `UserPageCardFilter`,`UserId=当前用户`,`IsTenantSystem=false` | 只有这个用户 | `isTenantSystem:false` 的 `batch-add-or-update-filter`;或首次打开时由模板自动复制 |
|
|
15
|
+
|
|
16
|
+
用户打开页面时(`isEdit=false`),后端为他补个人副本:
|
|
17
|
+
|
|
18
|
+
- 看板筛选器:从「看板系统模板」复制。
|
|
19
|
+
- 卡片/报表筛选器:先找「卡片系统模板」,没有就**从卡片源筛选器复制**(`EnsureUserCardFiltersAsync`)。
|
|
20
|
+
- 已经有个人副本就直接用,**不会自动跟着模板更新**——系统版本号变化后界面只会提示「筛选条件有更新」(`UserPageFilterVersion`)。
|
|
21
|
+
|
|
22
|
+
`reset-user-filter` = 删掉当前用户的个人副本、立刻按上面的规则重新复制:
|
|
23
|
+
|
|
24
|
+
```jsonc
|
|
25
|
+
{"userPageSettingId": "<planId>", "filterSourceType": 4} // 看板
|
|
26
|
+
{"userPageCardId": "<pageCardId 或报表的 userPageCardId>", "filterSourceType": 2} // 卡片/报表(2026-10 起支持)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 对搭建者意味着什么(照做)
|
|
30
|
+
|
|
31
|
+
| 场景 | 正确做法 |
|
|
32
|
+
|---|---|
|
|
33
|
+
| **看板全局筛选器** | `batch-add-or-update-filter`,`filterSourceType:4`,`isTenantSystem:true`(= 界面编辑模式保存),然后 `reset-user-filter` 让自己看到新版本。`linkai plan-filter` 就是这两步 |
|
|
34
|
+
| **报表筛选器 / 卡片局部筛选器** | 写进**卡片源筛选器**:`card-get` → 改 `filters` → `card-save`。这是所有用户的模板。然后对自己的报表 `reset-user-filter`(`filterSourceType:2`)看效果 |
|
|
35
|
+
| 只想临时给自己看 | `isTenantSystem:false` 写个人副本(旧版文档里报表筛选器的写法,**别人看不到**) |
|
|
36
|
+
|
|
37
|
+
> ⚠ 旧版文档(2026-09)让报表筛选器走 `batch-add-or-update-filter` + `isTenantSystem:false`。按 2026-10 的后端代码,
|
|
38
|
+
> 这只写进了**搭建者自己的个人副本**,其他用户打开报表时会从卡片源筛选器复制——如果卡片源筛选器是空的,他们**看不到筛选器**。
|
|
39
|
+
> 已经这样做过的报表:把同样的筛选器补进卡片 `filters`。【待实测】
|
|
40
|
+
|
|
41
|
+
## 2. 一条筛选器的字段
|
|
42
|
+
|
|
43
|
+
两个 DTO 字段基本一致:看板/卡片层用 `PageSettingFilterV2Req`,卡片源筛选器用 `IndexBlockFilterV2Req`(少了 `userPageSettingId`/`userPageCardId`/`bindUserPageCards`)。
|
|
44
|
+
|
|
45
|
+
| 字段 | 取值 | 说明 |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `labelName` | 文本 | 界面标签 |
|
|
48
|
+
| `filterType` | `1` 选择 · `2` 日期 · `3` 条件 · `4` 变量 | 控件种类(`Enums.FilterType`) |
|
|
49
|
+
| `filterOperationType` | 见下表 | 运算 |
|
|
50
|
+
| `filterProperty` | `0` 维度过滤 · `1` 结果集过滤 · `2` 参数变量 | 作用在哪一层,见 §4 |
|
|
51
|
+
| `fieldName` | 数据集列别名 | 维度过滤作用的列;也决定下拉候选值从哪列取 |
|
|
52
|
+
| `propertyName` | `waxisN`/`yaxisN` | 结果集过滤作用的卡片字段(报表/卡片局部筛选器就靠它) |
|
|
53
|
+
| `bindUserPageCards` | `[{pageCardId, dataSettingComment, dataSettingIds:[]}]` | 看板筛选器绑哪些卡片的哪个字段(`dataSettingComment` = 卡片 dtos 的 `comment`) |
|
|
54
|
+
| `indexBlockDataId` / `indexBlockDataSourceId` | 数据集 / 数据源 id | 下拉候选值来源 |
|
|
55
|
+
| `defaultValueType` | `0` 无 · `1` 固定值 · `2` 列表第一个 · `3` 用户属性 · `4` 动态值 | `Enums.FilterDefaultValueType`。【前端规则】选择(1)/ 日期(2)筛选必须选默认值类型,界面上没有「无」:不要默认值时用 `1` + `defaultValue:"\"\""` |
|
|
56
|
+
| `defaultValue` | **JSON 序列化后的字符串** | 单值 `"\"华东\""`;多选/区间 `"[\"a\",\"b\"]"`;动态日期 `"\"-7\""`;无默认 `"\"\""` |
|
|
57
|
+
| `isRequired` | bool | 必填 |
|
|
58
|
+
| `isDate` | bool | 日期型;`filterType:2` 时为 `false` 会把区间补成 `00:00:00`~`23:59:59` |
|
|
59
|
+
| `isShowAllOption` | bool | 下拉里出「全部」 |
|
|
60
|
+
| `inOuter` | bool | 显示在外层(不收进「更多」) |
|
|
61
|
+
| `isSelfadd` + `userPageCardFilterValueRes` | `"true"` + `[{name,value,sortNum}]` | 手工维护的选项,不从数据集取 |
|
|
62
|
+
| `optionsCode` | `[code]` | 用「配置选项」字典做候选值 |
|
|
63
|
+
| `sortField` | 同持久排序的 `SortField` | 候选值排序 |
|
|
64
|
+
| `variableIds` / `variableType` | JSON 数组字符串 / `0` 字符 `1` 日期 | 参数变量用 |
|
|
65
|
+
| `filterId` | 已有筛选器的 id | **更新时必带,新增时不传**;不在数组里的旧筛选器会被删除(全量覆盖) |
|
|
66
|
+
| `sortNum` | int | 顺序 |
|
|
67
|
+
|
|
68
|
+
### filterOperationType 与查询值格式
|
|
69
|
+
|
|
70
|
+
| 值 | 含义 | 生成的 SQL | 查询时 `value` 格式 |
|
|
71
|
+
|---|---|---|---|
|
|
72
|
+
| 1 | 单选 | `= 'v'` | `"v"` |
|
|
73
|
+
| 2 | 多选 | `IN (…)` | JSON 数组字符串 `"[\"a\",\"b\"]"` |
|
|
74
|
+
| 31/32/33/34 | > / ≥ / < / ≤ | `> 'v'` | `"v"` |
|
|
75
|
+
| 35 / 36 | 等于 / 不等于(单值) | `= 'v'` / `!= 'v'` | `"v"` |
|
|
76
|
+
| 37 | 区间 | `>= v0 AND <= v1` | JSON 数组字符串,两个元素 |
|
|
77
|
+
| 57 | 「等于」(界面叫等于,实为 IN) | `IN (…)` | **逗号分隔**字符串 `"a,b"` |
|
|
78
|
+
| 58 | 不等于(NOT IN) | `NOT IN (…)` | 逗号分隔 |
|
|
79
|
+
| 60 / 61 / 62 | 左包含 / 右包含 / 包含 | `LIKE 'v%'` / `'%v'` / `'%v%'`(不区分大小写) | `"v"` |
|
|
80
|
+
|
|
81
|
+
界面里各控件可选的运算:选择控件 1/2;日期控件 31-34、35、36、37;条件控件 57、58、31-34、60、61、62、37。
|
|
82
|
+
过滤值是**直接拼进 SQL 字符串**的(没有转义),值里别带单引号。
|
|
83
|
+
|
|
84
|
+
### 动态日期默认值(`defaultValueType:4`)
|
|
85
|
+
|
|
86
|
+
`defaultValue` 填下面的代码;区间(37)填两个代码的数组,如 `"[\"-30\",\"0\"]"`。前端打开页面时换算成 `YYYY-MM-DD`。
|
|
87
|
+
|
|
88
|
+
| 代码 | 含义 | 代码 | 含义 |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
| `-60` `-30` `-14` `-7` `-3` | N 天前 | `-1` | 昨天 |
|
|
91
|
+
| `0` | 今天 | `7` `14` | 未来 N 天 |
|
|
92
|
+
| `m1` | 本月第一天 | `m-1` | 本月最后一天 |
|
|
93
|
+
| `yfirst` | 本年第一天 | `y-1` | 本年最后一天 |
|
|
94
|
+
|
|
95
|
+
## 3. 看板筛选器 vs 报表/卡片筛选器
|
|
96
|
+
|
|
97
|
+
| | 看板全局 | 报表 / 卡片局部 |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `filterSourceType` | `4` | `2`(`5` = AG 表格列头快速筛选) |
|
|
100
|
+
| 归属键 | `userPageSettingId` = planId | `userPageCardId` = pageCardId(报表:`report-card` 拿到的 id) |
|
|
101
|
+
| 绑字段 | `filterProperty:1` + `bindUserPageCards[].dataSettingComment` | `filterProperty:1` + `propertyName:"waxisN"`,`bindUserPageCards:[]` |
|
|
102
|
+
| 系统层写法 | `batch-add-or-update-filter`,`isTenantSystem:true` | 卡片源筛选器(`update-new` 的 `filters`) |
|
|
103
|
+
|
|
104
|
+
看板筛选器也可以用 `filterProperty:0`(维度过滤):直接按 `fieldName` 过滤**所有卡片的数据集**——只适合整页卡片共用同一列名的情况。
|
|
105
|
+
|
|
106
|
+
## 4. 维度过滤 vs 结果集过滤
|
|
107
|
+
|
|
108
|
+
| `filterProperty` | 作用位置 | 按什么找列 | 适合 |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `0` 维度 | 内层 `WT.<fieldName>`,**聚合之前** | 数据集列别名 | 明细过滤、聚合前筛(“只算华东的销量”) |
|
|
111
|
+
| `1` 结果集 | 外层 `W.<comment>`,聚合之后 | `propertyName`(waxisN) → 卡片 dtos → comment | 报表/看板绑卡片字段的常规写法 |
|
|
112
|
+
| `2` 参数变量 | 替换**数据集 SQL** 里的 `$1~$Z` 和 `$N{{ }}` 条件块(也替换卡片自定义字段表达式) | `variableIds` | 【实测】gop 模板类数据集的标准传参方式,见下 §4.1 |
|
|
113
|
+
|
|
114
|
+
结果集过滤时 `propertyName` 在卡片字段里找不到 → **静默跳过**,不报错。
|
|
115
|
+
|
|
116
|
+
### 4.1 参数变量筛选器(`filterProperty:2`)实例【实测 2026-10-13】
|
|
117
|
+
|
|
118
|
+
```jsonc
|
|
119
|
+
// 日期区间 → $2/$3(动态默认:近 30 天到昨天)
|
|
120
|
+
{"labelName":"日期","filterType":2,"filterOperationType":37,"filterProperty":2,
|
|
121
|
+
"variableIds":"[\"<$2 id>\",\"<$3 id>\"]","variableType":0,"fieldName":"","indexBlockDataId":"<全0>",
|
|
122
|
+
"defaultValueType":4,"defaultValue":"[\"-30\",\"-1\"]","isRequired":true,"inOuter":true,
|
|
123
|
+
"bindUserPageCards":[{"pageCardId":"<卡片A>","dataSettingIds":[],"dataSettingComment":""}]}
|
|
124
|
+
// 单选 → $C,候选值来自字典数据集的「维度」列,默认「品类」
|
|
125
|
+
{"labelName":"维度","filterType":1,"filterOperationType":1,"filterProperty":2,
|
|
126
|
+
"variableIds":"[\"<$C id>\"]","fieldName":"维度","indexBlockDataId":"<维度字典 dsId>","indexBlockDataSourceId":"<数据源id>",
|
|
127
|
+
"defaultValueType":1,"defaultValue":"\"品类\"","isRequired":true,"inOuter":true,"isSelfadd":"false","bindUserPageCards":[…]}
|
|
128
|
+
// 手工选项 → $D
|
|
129
|
+
{"labelName":"对比", … ,"isSelfadd":"true","userPageCardFilterValueRes":[{"name":"对比","value":"全部","sortNum":0},…]}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
其余字段照抄一条现有筛选器即可;**不要带 `id`/`filterId`/`bindUserPageCardIds`**(新增时后端生成;`bindUserPageCardIds` 以 `bindUserPageCards` 为准)。
|
|
133
|
+
下拉只取 `fieldName` 列的去重值,没法按另一列过滤(如指标字典只想列「规模」指标),要么另建只含所需值的字典数据集,要么用手工选项。
|
|
134
|
+
|
|
135
|
+
## 5. 查询时的过滤值
|
|
136
|
+
|
|
137
|
+
前端把筛选器转成查询条件(`customFilterSearch.formatQueryValue`):带上 `name`、`value`、`valueType`,去掉
|
|
138
|
+
`defaultValue/defaultValueType`;值为空的整条丢掉;字符串值 `trim()`。看板筛选器 `filterProperty:1` 时
|
|
139
|
+
按当前卡片在 `bindUserPageCards` 里找 `dataSettingComment` → 卡片 dtos 同 `comment` 的 `field` → 填进 `propertyName`。
|
|
140
|
+
|
|
141
|
+
除筛选器外,同一个 `filters` 数组里还会拼进:下钻条件(drill)、联动条件(link)、固定条件(fixedFilters)、列头快速筛选(column)。
|
|
142
|
+
|
|
143
|
+
## 6. 筛选器「在、能选、不过滤」的五个原因
|
|
144
|
+
|
|
145
|
+
1. 看板:`bindUserPageCards[].pageCardId` 填成了 indexBlockId,或字段名写成 `userPageCardId`。
|
|
146
|
+
2. 看板:`dataSettingComment` 在目标卡片 dtos 里不存在(换了数据集列名)。
|
|
147
|
+
3. 报表/卡片:`propertyName` 不是该卡片现有的 `waxisN`。
|
|
148
|
+
4. 你看到的是**个人副本**,模板改了但副本没更新 → `reset-user-filter`。
|
|
149
|
+
5. 值格式不对:57/58 要逗号串,2/37 要 JSON 数组串。
|
|
150
|
+
|
|
151
|
+
## 7. 候选值与调试
|
|
152
|
+
|
|
153
|
+
- 候选值:`POST /index-block/get-filter-field-value-info {"indexBlockDataId":"…","fieldName":"<列别名>"}` → 去重值列表。
|
|
154
|
+
- 看系统模板:`plan-get`(`isEdit=true`,编辑模式直接读系统模板,不复制个人副本);看自己的副本:`get-new-page-plan/<id>?isEdit=false`。
|
|
155
|
+
- 用户在页面上选的值通过 `PUT /page-setting/filter-value` **改写他个人副本的 `defaultValue`**,所以刷新还在、
|
|
156
|
+
且会盖掉模板默认值;`reset-user-filter` 删副本重建后恢复模板默认值。
|
|
157
|
+
|
|
158
|
+
## 8. 保存前校验(与界面保存规则一致)【前端 2026-10-30】
|
|
159
|
+
|
|
160
|
+
CLI 在 `batch-add-or-update-filter`(看板 / 卡片筛选)和卡片保存(卡片自带筛选)前按领谋界面的表单规则校验,不通过报 `CONFIG_INVALID` 并列出全部问题:
|
|
161
|
+
|
|
162
|
+
- 每条筛选必须有 `filterOperationType`(类型选择)。
|
|
163
|
+
- 参数变量筛选(`filterProperty:2`)必须有 `variableIds`。
|
|
164
|
+
- 选择 / 日期筛选必须有 `defaultValueType`(非 0);`isRequired:true` 时必须有默认值。
|
|
165
|
+
- 日期筛选动态值(`defaultValueType:4`)必须有值;区间要两端都有。
|
|
166
|
+
- 选择筛选:`isSelfadd:"true"` 时 `userPageCardFilterValueRes` 至少一个有值的选项;否则必须有 `fieldName`。
|
|
167
|
+
- 卡片筛选:结果集过滤(`filterProperty:1`)必须有 `propertyName`,且必须是卡片已绘制的字段(`waxisN` 等);维度过滤(`filterProperty:0`)必须有 `fieldName`。
|
|
168
|
+
- 看板筛选:`bindUserPageCards[]` 每项必须有 `pageCardId`。
|
|
169
|
+
|
|
170
|
+
看板筛选是整组保存:同名筛选原来就有、这次没改动的问题只提示不拦(实测 2026-11-02:已有看板 53 个筛选中 9 个 `defaultValueType:0`),新加或改动的筛选必须合规。
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# 甘特图(table/gantt)
|
|
2
|
+
|
|
3
|
+
已实战踩通的全流程。骨架在 `clis/linkai/templates.js` 的 `table/gantt`;可调项见 `references/chart-config-schema.md`。
|
|
4
|
+
|
|
5
|
+
## 数据形状
|
|
6
|
+
|
|
7
|
+
**每行 = 一条最细粒度任务**(一款一根条就每款一行;要子层级才用长表 + dynamic)。
|
|
8
|
+
所有列全部 `waxis<N>`(argumentType=2,同 agtable),日期列直接输出
|
|
9
|
+
`DATE_FORMAT(x,'%Y-%m-%d')` 字符串即可 —— 前端 `moment()` 解析,
|
|
10
|
+
**空值输出 `'—'` 或空串都安全**(`parseDate` 对 `''`/`—`/`-`/1970 一律归 null)。
|
|
11
|
+
|
|
12
|
+
## config.ganttRenderConfig.style 字段映射(全填 waxisN)
|
|
13
|
+
|
|
14
|
+
| 键 | 对应界面 | 效果 |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `main` | 主字段 | 卡片标题(左栏每行的大字) |
|
|
17
|
+
| `assist` | 辅助字段 | 标题右侧小字 |
|
|
18
|
+
| `image` | 图片字段 | 左侧缩略图 |
|
|
19
|
+
| `status` | 任务状态 | ★ 值**只能是**:待启动/进行中/已完成/超时完成/预警/异常(决定条色与卡片状态签) |
|
|
20
|
+
| `tags[]` | 标签字段 | 药丸行(若干短文本列) |
|
|
21
|
+
| `desc[]` | 描述字段 | 灰色描述行 |
|
|
22
|
+
| `list[]` | 列表字段 | 数值网格;塞一个长文本列可当"汇总说明"行 |
|
|
23
|
+
| `progress` | 进度图字段 | 底部进度条,值 0-100 |
|
|
24
|
+
| `taskBar.textFields[]` | 任务条文本 | 印在甘特条上的字 |
|
|
25
|
+
| `fieldMap.startDate/endDate` | 实际开始/结束 | 实线条;**只有开始没结束 → 自动渐变半条**("进行中"效果) |
|
|
26
|
+
| `fieldMap.plannedStart/plannedEnd` | 计划开始/结束 | 虚线框浅底 |
|
|
27
|
+
|
|
28
|
+
状态色(系统固定):待启动 #9CA3AF / 进行中 #2563EB / 已完成 #16A34A /
|
|
29
|
+
超时完成 #F28E2C / 预警 #D97706 / 异常 #DC2626。
|
|
30
|
+
|
|
31
|
+
其余 config:`ganttGridTitle` 左栏标题、`ganttGridMinWidth`(452)、`projectRowHeight`(202)、
|
|
32
|
+
`defaultZoomLevel`('hour'|'day'|'week'|'month')。
|
|
33
|
+
|
|
34
|
+
## ⚠ 图表类型有两套注册表,别混
|
|
35
|
+
|
|
36
|
+
旧版类型清单 ≠ 当前实际注册的类型(以 `linkai kinds` 为准)。
|
|
37
|
+
**卡片保存不校验 chartType,选了 v2 没注册的类型 → 页面白屏「操作异常,请刷新重试」**,
|
|
38
|
+
接口层零报错,console 里是 `Cannot read properties of null (reading 'config')`。
|
|
39
|
+
|
|
40
|
+
已核实:`gantt` 只在 v2 有;`meter/count` 只在旧版清单里有(v2 建卡必崩);
|
|
41
|
+
`meter/commonMeter` v2 里 `disabled: true`。**单数字指标卡用 `meter/list`(趋势指标卡)**,
|
|
42
|
+
默认 config 抄 v2 `Meter/config.js`(group/content 两段),大数字样式改
|
|
43
|
+
`content.valueTextMain`(fontSize/fill),副标题改列的 `title`。
|
|
44
|
+
|
|
45
|
+
排查这类白屏:先 `linkai shot --url <url>` 看现象;React 边界吞掉的渲染错误不走网络,接口层查不到。
|
|
46
|
+
本仓库的 `linkai browser` 没有 console 抓取命令,定位到具体报错需要人工在该页面打开 DevTools Console;
|
|
47
|
+
预防为主——chartType 只从 `linkai kinds`(v2 注册表)里选。
|
|
48
|
+
|
|
49
|
+
## meter 的 title 可以当显示文案改
|
|
50
|
+
|
|
51
|
+
铁律「dtos 的 title 不能改」是 **agtable 实测**;meter/list 实测把 `title`
|
|
52
|
+
改成任意文案(comment 保持列别名)查询照常出数,label 显示的就是 title——
|
|
53
|
+
指标卡副标题就这么改。
|
|
54
|
+
|
|
55
|
+
## 演示/占位数据的两个技巧
|
|
56
|
+
|
|
57
|
+
- 没有真实数据先出效果时,用 `UNION ALL` 参数表直接在 SQL 里造行(不碰任何表,天然过防线)。
|
|
58
|
+
- 时间列用 `DATE_ADD(CURRENT_DATE(), INTERVAL n DAY)` 围绕今天铺开——甘特永远"活的",
|
|
59
|
+
今天线始终穿过任务条。
|
|
60
|
+
|
|
61
|
+
## 一把出:`linkai card-gantt --ds <dsId> --spec spec.json`
|
|
62
|
+
|
|
63
|
+
```jsonc
|
|
64
|
+
{
|
|
65
|
+
"name": "项目甘特",
|
|
66
|
+
"image": "图片", "main": "任务", "assist": "子标题", "status": "任务状态",
|
|
67
|
+
"tags": ["负责人", "优先级"],
|
|
68
|
+
"desc": ["备注"],
|
|
69
|
+
"list": ["计划量", "完成量", "汇总说明"],
|
|
70
|
+
"progress": "进度",
|
|
71
|
+
"taskBarText": ["当前阶段"],
|
|
72
|
+
"start": "实际开始", "end": "实际结束",
|
|
73
|
+
"plannedStart": "计划开始", "plannedEnd": "计划结束",
|
|
74
|
+
"title": "任务", "rowHeight": 202, "zoom": "day"
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
键是固定的,**值全部换成你数据集里的列别名**,生成器自动注册 waxis 并填
|
|
79
|
+
`ganttRenderConfig.style`。用不到的键(如 `image`)删掉即可。
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# 踩过的坑(79 条)
|
|
2
|
+
|
|
3
|
+
> 1–26 是线上实测踩到的;27–37 为规则确认(标【确认】的未在线上跑过);38 起为实测。
|
|
4
|
+
|
|
5
|
+
1. **筛选器有「用户个人层」,会整份盖掉看板配置**。手动改过/清空过筛选值之后,`isEdit=false` 返回的就是个人层——`defaultValue` 变空、`isRequired` 翻转,**甚至整条筛选条件消失**。解药:`POST /page-setting/reset-user-filter` `{"userPageSettingId":"<planId>","filterSourceType":4}`(4=全局 2=卡片局部)。排查时先比对 `isEdit=true` / `false` 两份 filters,别急着改配置。
|
|
6
|
+
2. **筛选器靠 `bindUserPageCards[].dataSettingComment` 找卡片字段,这个 comment 必须在卡片 `indexBlockDataSettingDtos` 里真实存在**,否则筛选器能选、下拉有值、就是一条都不过滤。换筛选字段要同步往卡片 dtos 补一条同 comment 的隐藏字段。
|
|
7
|
+
3. 报表侧选过的筛选值也会被记住(刷新还在)——用户选值会改写他**个人副本**的 `defaultValue`。
|
|
8
|
+
**2026-10 起 `reset-user-filter` 也支持报表/卡片**:`{"userPageCardId":"<报表 userPageCardId>","filterSourceType":2}`。
|
|
9
|
+
⚠ 报表筛选器配置要写进**卡片源筛选器**(`update-new` 的 `filters`)别人才看得到;`isTenantSystem:false`
|
|
10
|
+
的 `batch-add-or-update-filter` 只改你自己的副本。分层模型见 `references/filters.md` §1。
|
|
11
|
+
4. **`dataSettingDtos[].title` 和 `comment` 都别动**。`comment` 是字段映射键,改了立刻查不出数;
|
|
12
|
+
`title` 看着人畜无害,实测改完(哪怕同步把 `indexBlockShowOrderFields[].aliasName` 也改了)
|
|
13
|
+
前端会在构造查询前就挂掉——`get-new-index-block-data` 请求**根本发不出去**,页面只剩空白表格区,
|
|
14
|
+
没有任何报错。排查这种"转圈转完什么都没有"先想想是不是动过 title。
|
|
15
|
+
要改表头文字,见下一条。
|
|
16
|
+
5. **自定义渲染列的表头文字来自 `field[0]` 那个字段的 `title`,不是 `column.name`**。
|
|
17
|
+
`column.name` 只是配置里的标识,界面上根本不显示。所以表头想叫什么,就把那个名字的字段放 `field` 数组第一位,
|
|
18
|
+
或者干脆接受它——别去改 title(见上条)。
|
|
19
|
+
6. **列宽的 key 不是 colId**:前端取 `colDef.widthKey || field || colId`,自定义渲染列取 `field` 数组的第一个。`agColumnWidths: [{"key":"waxis1","width":660}]`。列宽总和要顶满 `.ag-body-viewport` 的宽度,不然右边会多出一条空白 filler 列。
|
|
20
|
+
7. **卡片高度**用网格格数,`实际px = 24 × 格数 − 8`,首卡顶部在 y=106px。**分页栏钉在卡片底部**,所以卡片一超过视口高度,分页栏就要滚到底才看得见——按最小目标视口算格数。
|
|
21
|
+
8. **删掉的卡片进回收站**(左下角入口,`POST /index-block/get-recycle-station-page-list`),可以恢复。但别指望页面上那个计数——它不会实时刷新,当场看可能还是 0。
|
|
22
|
+
9. **antd 数字输入框不能用 JS 赋值**(React state 不同步,一保存就丢),必须真实点击 + `Input.insertText`。普通 Input 用 native value setter + `input` 事件是可以的。
|
|
23
|
+
10. **react-beautiful-dnd 的拖拽只在短距离成功**;字段在视口外时先折叠左侧分组把目标顶上来,别靠滚动。改 Emulation 视口会让 rbd 的位置缓存失效,改完要刷新。
|
|
24
|
+
11. 表头的升降序按钮 `sortable:false` 硬编码,只能用领谋自己的列头菜单;自定义渲染列会直接提示「暂不支持列头操作」,排序靠把字段拖到「排序」区。
|
|
25
|
+
12. 筛选器下拉宽度写死 `150px`,塞不下「名称+长 ID」;下拉末尾那个**空 option 是前端无条件 concat 上去的**,去不掉,全平台每个筛选器都有。
|
|
26
|
+
13. 自定义渲染列**不会自动换行**,需要换行的长文本列就别开自定义渲染,用普通列。
|
|
27
|
+
14. **别用脚本导航到 `/login`** —— 登录页一加载就清空 localStorage,把调试浏览器的登录态冲掉
|
|
28
|
+
(影响 `shot`;adapter 本身走会话文件不受影响,`shot` 已拒绝 /login 地址)。别去访问那个页面。
|
|
29
|
+
15. **表格空白、转完圈什么都没有 → 去看查询接口的响应**,别瞎猜:
|
|
30
|
+
```bash
|
|
31
|
+
linkai query --card <卡片id> # 等同页面取数请求,返回 code/message/total/sql
|
|
32
|
+
```
|
|
33
|
+
响应里 `message` 是数据库的真实报错,`extendData.sql` 是实际执行的 SQL(含 `SET @tenant_code`,
|
|
34
|
+
顺便能确认落在哪个空间)。这条能省掉一整轮猜测。
|
|
35
|
+
16. **排序:卡片这边怎么配都不生效,只能在数据集 SQL 里解决**(2026-09-17 订正,
|
|
36
|
+
原来这里写「用显示列自己的 orderByType 最稳」是错的)。三条路实测:
|
|
37
|
+
|
|
38
|
+
| 做法 | 结果 |
|
|
39
|
+
|---|---|
|
|
40
|
+
| 显示列的 `orderByType` = 1/2 | **无效** |
|
|
41
|
+
| 新建 `order<N>` 字段(照生产卡片抄,`isAggregation:true`)| 报错 `must be an aggregate expression or appear in GROUP BY` |
|
|
42
|
+
| `order<N>` + `argumentType:0`(界面排序区就是这么给的)| 不报错,但**仍然不排序** |
|
|
43
|
+
| 数据集 SQL 末尾直接 `ORDER BY` | **被丢掉** |
|
|
44
|
+
|
|
45
|
+
⚠ **2026-10-13 复核修正**:上表结论是对的,但根因只说对了一半。查询引擎
|
|
46
|
+
实际有**三条**排序来源(优先级:请求 `sortFields` > 卡片持久排序
|
|
47
|
+
`UsedIndexBlockSortField` > `argumentType=0` 的 order 字段),上表试的都是第三条,它有
|
|
48
|
+
「全部 order 字段都要 orderByType≠0」「与 WT.* 撞名 ambiguous」「数值默认 Sum() 在明细里报 GROUP BY 错」三个坑。
|
|
49
|
+
**第二条——卡片右上角「排序」弹窗,`PUT /page-setting/page-card-index-block-sort-field`,`linkai card-sort`——
|
|
50
|
+
当年没发现**,它按 `waxisN` 生成外层 ORDER BY、在分页之前。详见 `references/query-engine.md` §4。
|
|
51
|
+
✅ **2026-10-13 已实测:`card-sort` 生效**(外层 `ORDER BY waxis1 ASC`、分页前),**排序首选 `card-sort`**;
|
|
52
|
+
数据集 SQL 自套排序作为备选。
|
|
53
|
+
|
|
54
|
+
✅ **已实测有效的办法:数据集 SQL 自己套一层带 LIMIT 的排序**,用 LIMIT 逼住优化器保留顺序:
|
|
55
|
+
|
|
56
|
+
```sql
|
|
57
|
+
SELECT x.* FROM (
|
|
58
|
+
...原来的 SELECT...
|
|
59
|
+
) x
|
|
60
|
+
ORDER BY x.`排序键` ASC
|
|
61
|
+
LIMIT 100000
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
排序键**必须是字符串**(数值列会被当度量),多级排序就在 SQL 里拼成一列:
|
|
65
|
+
`CONCAT(LPAD(优先级,2,'0'), '#', LPAD(999999 - 停留天数, 6, '0'))` ——
|
|
66
|
+
前段升序、后段用大数相减实现降序。
|
|
67
|
+
|
|
68
|
+
17. **想跑任意 SQL 看数据?借筛选器候选值接口**。领谋没有「执行 SQL 拿结果」的接口,
|
|
69
|
+
但 `POST /index-block/get-filter-field-value-info` `{"indexBlockDataId":"...","fieldName":"<列别名>"}`
|
|
70
|
+
会返回该列的**去重值列表**。把整个查询结果拼成一列文本,它就成了一条查询通道:
|
|
71
|
+
|
|
72
|
+
```sql
|
|
73
|
+
SELECT CONCAT('总览|行数=', CAST(COUNT(*) AS STRING)) AS `探查` FROM t
|
|
74
|
+
UNION ALL SELECT CONCAT('分布|', COALESCE(状态,'NULL'), '|', CAST(COUNT(*) AS STRING)) FROM t GROUP BY 状态
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
建个一列的临时数据集(名字统一加 `zz-` 前缀好清理)→ 取候选值 → 读完删掉。
|
|
78
|
+
建报表前先这么摸一遍数据,比配完卡片发现列全是 NULL 强得多。
|
|
79
|
+
18. `dataSourceId` 由服务端按数据集自己推导,payload 里传了也会被覆盖成它认的值,不用管它。
|
|
80
|
+
19. 摸不清某个操作调了什么接口时,别猜——先查 `references/api.md` 与 `references/api-catalog.md`;查不到就问用户或领谋支持。
|
|
81
|
+
|
|
82
|
+
20. **图表类卡片的字段配置三连坑**(每一条都会让图表空白且前端不报错):
|
|
83
|
+
没有 `xaxis`(维度也用 `waxis`);`argumentType` 按角色给固定值(数值 1 / 维度 2 / 系列 3 / 排序 0,
|
|
84
|
+
见 SKILL.md 铁律 4——**不是**照抄数据集字段);`yaxis` 必须带 `axis:"y1"`。
|
|
85
|
+
21. **卡片列表接口直接返回每张卡片的 `chartSetting`**——
|
|
86
|
+
`POST /index-block/get-index-block-folder-bussiness-info` `{"page":{"pageIndex":1,"pageSize":200}}`。
|
|
87
|
+
要某个类型的骨架,从同空间挑一张同类型的抄,比任何文档都准。
|
|
88
|
+
|
|
89
|
+
22. **删东西有依赖顺序**:数据集被卡片引用时删不掉(403「该数据集已被指标[xxx]使用」),
|
|
90
|
+
得**先删卡片再删数据集**。删除一律用列表返回的 `id`(folderBussinessId),
|
|
91
|
+
不是 `objId`(那是 indexBlockId / dsId)。
|
|
92
|
+
临时产物统一用 `zz-<任务名>-` 前缀,收尾一条命令按依赖序清干净(只接受 `zz-` 开头的前缀):
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
linkai clean --prefix zz-<任务名>-
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
23. **同一个路径 GET 是查、POST 是建**。领谋这套接口没有 REST 语义约定,路径名看不出读写。
|
|
99
|
+
**任何没在本文档里写明的接口**,先查 `references/api-catalog.md` 确认 `method`,别拿 POST 去试。
|
|
100
|
+
数据源、SQL、库表结构类接口不对外开放,透传调用会被拒绝。
|
|
101
|
+
|
|
102
|
+
24. **chartType 选了租户端没注册的类型 → 保存成功、页面白屏**「操作异常,请刷新重试」,
|
|
103
|
+
接口全 200。类型以 `linkai kinds` 为准,`meter/count` 就是典型
|
|
104
|
+
(旧版类型清单有、v2 没有)。人工打开 DevTools Console 可见
|
|
105
|
+
`Cannot read properties of null (reading 'config')` 即是此症。详见 `references/gantt.md`。
|
|
106
|
+
|
|
107
|
+
25. **登录接口自己也要带 `agentId` 请求头,否则登录成功但之后每个接口 406**
|
|
108
|
+
「当前已切换账号或租户信息」。前端 axios 拦截器给**所有**请求加 `agentId` 头,
|
|
109
|
+
登录请求也不例外(`ignoreToken` 只清 `Authorization`,不清 `agentId`),
|
|
110
|
+
服务端按**头**建会话,body 里那个 `agentId` 不作数。
|
|
111
|
+
|
|
112
|
+
症状极具误导性:`new-login` 返回 200、token 解出来 payload 完全正常(UserId/TenantId 都在、
|
|
113
|
+
未过期),但拿它调任何业务接口都 406,连 `switch-tenant` 也 406,像是"被别人顶号了"。
|
|
114
|
+
`linkai login` 已修正(头 + body 同时带)。
|
|
115
|
+
|
|
116
|
+
26. 查询 SQL 用 `linkai query`,返回完整 `extendData.sql`,没有截断。
|
|
117
|
+
|
|
118
|
+
27. 【确认】**全是 `waxis`、没有 `yaxis` 的 AG 明细表会被 `GROUP BY` 全部列**——后端规则「没有数值字段但有维度字段
|
|
119
|
+
→ 分组」。完全相同的两行会合并成一行,行数比数据集少还不报错。数据集里保留唯一键列(如 ID)并注册成隐藏列。
|
|
120
|
+
规则全文见 `references/query-engine.md` §3。
|
|
121
|
+
28. 【确认】**报表筛选器的「系统模板」是卡片自己的 `filters`**。用户第一次打开报表时,系统从卡片源筛选器
|
|
122
|
+
给他复制一份个人副本;之后他只看自己的副本。所以:①改报表筛选器要改卡片 `filters`;
|
|
123
|
+
②已经打开过的用户要 `reset-user-filter` 才看到新版(界面会提示「筛选条件有更新」)。见 `references/filters.md` §1。
|
|
124
|
+
29. 【确认】**看板筛选器保存要传 `isTenantSystem:true`**(界面编辑模式就是这么传的)——传 `false` 只写进
|
|
125
|
+
你自己的个人副本,其他人看不到。`linkai plan-filter` 不改你的 JSON,`isTenantSystem` 由 filters.json 顶层决定。
|
|
126
|
+
30. 【确认】**筛选值直接拼进 SQL 字符串、不转义**:值里带单引号会让整条查询语法错误。
|
|
127
|
+
`filterOperationType` 57/58(界面上的「等于/不等于」)值是**逗号分隔串**,2(多选)和 37(区间)是 **JSON 数组串**,
|
|
128
|
+
格式给错不报错、只是筛不出东西。见 `references/filters.md` §2。
|
|
129
|
+
31. 【确认】**ABP 路由的「secondary id」**:方法里恰好有一个以 `Id` 结尾的形参(如 `userPageSettingId`)时,
|
|
130
|
+
它被拼到动作名**后面**当路径段:`POST /page-setting/get-new-page-plan/{userPageSettingId}`;形参就叫 `id` 的
|
|
131
|
+
则拼在动作名**前面**:`POST /index-block/{id}/del-index-block-data-source`。`references/api-catalog.md` 已按此生成。
|
|
132
|
+
32. 【确认】**跨租户的卡片可能被静默换数据源**:取数时数据源不是 StarRocks 且不属于当前租户,后端会改用当前租户
|
|
133
|
+
名叫 `Cloud` 的数据源。从别的空间复制来的卡片数不对时先查这个。
|
|
134
|
+
|
|
135
|
+
33. **同一浏览器同一账号同时只能操作一个租户**(用户反馈 + 已确认):会话按
|
|
136
|
+
(用户, agentId, 租户) 校验,浏览器所有标签共用一个 agentId,切租户后其它标签的旧租户请求全部 406。
|
|
137
|
+
CLI 的 OAuth 会话与浏览器会话独立;CLI 使用当前授权在服务端切换有权限的租户,不复用浏览器令牌。
|
|
138
|
+
34. (本条已废弃)
|
|
139
|
+
|
|
140
|
+
35. (本条已废弃)
|
|
141
|
+
|
|
142
|
+
36. `0000`(全域)不是可用空间,取数不注入 `@tenant_code`,不是可用租户。
|
|
143
|
+
|
|
144
|
+
37. (本条已废弃)
|
|
145
|
+
|
|
146
|
+
38. 【实测】**数据集 SQL 结尾带分号会报 `Unexpected input ';'`**:领谋把数据集包成 `(… ) AS WT` 子查询。
|
|
147
|
+
现成 `rpt_gop_*` 模板以 `;` 结尾,直接贴会失败。`ds-create/update` 已自动去掉结尾分号。
|
|
148
|
+
39. **只认选表清单**:数据集 SQL 里的每张表都必须在 `ds-tables` 清单里,否则本地直接拒绝(本 CLI 不具备操作数据库的能力,
|
|
149
|
+
不会去线上查视图定义)。需要的视图不在清单里(例如部分 `ads_gop_*_view`),请用户联系领谋数据团队加进清单。
|
|
150
|
+
40. 【实测,已修】旧版防线把 `WITH p AS (…)` 的 CTE 名和注释里的 `FROM xx` 当成表名,带 CTE 的 SQL 全被误拒。
|
|
151
|
+
41. 【实测】**参数没配时是 `'0'`**:裸 `$X` 替换成 `'0'`、`$N{{}}` 整块删除。`rpt_gop_dim_scatter` 不配 `$G/$H/$I`
|
|
152
|
+
时三个轴全为 NULL、不报错。用到的参数在看板上都要配筛选器并给默认值,见 `query-engine.md` §2.1。
|
|
153
|
+
42. (本条已废弃)
|
|
154
|
+
|
|
155
|
+
43. 【实测】网络到 `bi-api.linkmore.com` 偶发 `Connect Timeout`。adapter 只在**连接未建立**时自动重试(请求没发出,写操作也安全);
|
|
156
|
+
其它失败不重试——写命令报错后先用只读命令回读状态再决定,见 SOP「失败和回滚」。
|
|
157
|
+
44. 【实测】**取数时 SQL 里的大括号会被全部删掉**(不分字符串内外):`'^[0-9]{1,4}$'` 变成 `'^[0-9]1,4$'`,
|
|
158
|
+
`CONCAT('{','x','}')` 变成 `'x'`。拼 JSON 用 `json_object()`,正则量词改写成不带大括号的形式。
|
|
159
|
+
45. 【实测】**数据集 SQL 太长保存失败**:5.2 万字符 OK,10.6 万字符报 `DbUpdateException`。
|
|
160
|
+
46. 【实测】**「趋势指标卡」不画迷你线、数值是所有行求和**;迷你线只有 AG 表格自定义渲染的 `chartLine` 能画。见 `dashboard-patterns.md`。
|
|
161
|
+
47. 【实测】区间型筛选器的标签前端自动加「(区间)」,标签写「日期(区间)」会显示成「日期(区间)(区间)」。
|
|
162
|
+
48. (本条已废弃)
|
|
163
|
+
|
|
164
|
+
49. 【实测】调试浏览器窗口高度只有几十像素时,看板卡片懒加载永远不触发(页面不发取数请求)、截图也超时。
|
|
165
|
+
这是本机窗口问题,不是看板问题;`linkai` 没有调窗口尺寸的命令,需要人工把窗口拉大。验证数据用 `query`。
|
|
166
|
+
50. 【实测】`linkai` 报 `No inspectable targets found` = 调试 Chrome 没有任何标签页(全被关了),先开一个标签页再操作。
|
|
167
|
+
51. 【实测】**卡片「数据条数」500 会截断不分页的图表**:日趋势 1588 行按日期排序后只画了前 500 行(前三分之一的日期)。
|
|
168
|
+
折线/饼图/气泡等图表卡设 `limitCount: 0`(不限);`card-chart` 生成器已改为默认 0。表格开分页时前端不提交 limitCount。
|
|
169
|
+
52. 【实测】**折线图 x 轴标签不套字段的日期格式**(只有 y 轴和悬浮提示套),要 MM-DD 只能数据集直接给(如 `月日` 列),排序见坑 57。
|
|
170
|
+
53. 【确认】**饼图/环图的数值格式**:扇区标签和悬浮提示套字段格式(`format:'number'` + `thousandSeparator:true` + `decimal:-1`
|
|
171
|
+
= 整数千分位),在卡片字段上设好即可;**只有环图中心的 TOTAL 数字不套**(G2Plot 只认 `meta.y1.formatter`,前端没设,JSON 配不进函数),显示原始数,金额先在 SQL 里取整。
|
|
172
|
+
54. 【实测】**隐藏看板卡片标题**:卡片 `dataScreenSetting` 设 `{"useCardConfig":true,"cardTitle":{"show":false}}`,
|
|
173
|
+
经 `update-page-card` 保存。⚠ 该接口会用请求值覆盖每张卡的 `dataScreenSetting` / `dataScreenChartSetting`,
|
|
174
|
+
且 `list` 里没有的卡会被移出——先 `plan-get` 把全部卡(含标题卡)原样带上,只改要改的。卡片筛选器在正文区,隐藏标题不影响。
|
|
175
|
+
55. 【实测】**测查询耗时别用 `linkai` 计时**:命令行本身启动就要数秒(`status` 约 10 秒)。直接用 Node 调 `core.js` 的 `api()`
|
|
176
|
+
计 HTTP 时间,并按页面方式请求(图表不分页、6 张并发)。参考 `/tmp` 下的计时脚本写法:`core.api('POST','/page-setting/get-new-index-block-data',{usedIndexBlockId,filters},{raw:true})`。
|
|
177
|
+
56. 【实测】**看板慢先看三处**:①通用大模板(如 `rpt_gop_dim_trend` 64 列含 TOP 分层/累计窗口)只用其中 3 列时,换精简模板
|
|
178
|
+
(日趋势 1.0~2.6 秒 → 0.2~0.5 秒);②下拉候选值别对销售宽表去重,用款档案等小视图;③条数被截断时看起来"快",其实是数据不全。
|
|
179
|
+
57. 【实测】**图表按「不显示的列」排序**(如 x 轴是 MM-DD 文本,要按真实日期排、跨年也对):
|
|
180
|
+
✗ 拖进「排序」槽(`argumentType:0`、`order1`)——SQL 数据集上后端生成 `SELECT null AS 日期序, WT.*`,
|
|
181
|
+
报 `Column '日期序' is ambiguous`;持久排序指向 `order1` 则报 `Column 'order1' cannot be resolved`(外层没选它)。
|
|
182
|
+
✓ 数据集出一个数值列(`CAST(DATE_FORMAT(日期,'%Y%m%d') AS INT) AS 日期序`),在卡片上加成**第二个维度** `waxis2`,
|
|
183
|
+
再 `card-sort --card <cardId> --spec 日期序:asc`。折线/柱图只取第一个维度 `x[0]` 当 x 轴,第二个维度不画;卡片不聚合时也不影响分组。
|
|
184
|
+
58. (本条已废弃)
|
|
185
|
+
|
|
186
|
+
59. 【实测】**日历 CTE 的 `DAYS_ADD(CAST($2 AS DATE), n)` 返回日期时间**,直接 `CAST(… AS VARCHAR)` 显示成 `2026-10-13 00:00:00`;
|
|
187
|
+
要日期文本用 `DATE_FORMAT(x, '%Y-%m-%d')`。
|
|
188
|
+
60. 【实测】**手工下拉选项显示的是 value**:`userPageCardFilterValueRes` 的 `name` 填的是筛选器标签,选项上看到的是 `value`。
|
|
189
|
+
想显示中文又传枚举做不到,只能让 SQL 认中文值。
|
|
190
|
+
61. 【实测】**AG 自定义渲染里的「值标记」是白字**:`conditionStyle.value` 命中后文字强制 `#fff`、底色 = 条件色、带圆角内边距。
|
|
191
|
+
用浅色当底色(如 #EEECE5)数字几乎看不见。要浅底深字的效果只能用 `fontColor`,不要用值标记。
|
|
192
|
+
62. 【实测】**看板慢先量底层视图**:建一个只对一列求和的临时数据集,比较 1 天 / 7 天 / 90 天的耗时。
|
|
193
|
+
和区间长短无关的固定开销 = 视图里有不随查询裁剪的关联或汇总(如 `ads_gop_sales_item_view` 每次汇总全租户售后,
|
|
194
|
+
固定 0.35 秒)。这类问题报表侧解决不了:把测量结果交给领谋数据团队评估是否提供精简视图。页面打开是多张卡并发,看总体要按并发测。
|
|
195
|
+
63. 【实测】**条件样式:依赖值为 0 时永远不命中 `== 0`**。前端取依赖值写的是 `rowData[depField] || ''`,
|
|
196
|
+
0 先变成空串;`==` / `!=` 按字符串比、其余运算符按数值比(`Number('')` = 0)。所以「行序 == 0」要写成 `<` 1。
|
|
197
|
+
运算符只有 JS 比较符(`==` `!=` `>` `>=` `<` `<=`),**没有 contains**——写了会在 eval 时报错、整条被忽略。
|
|
198
|
+
64. 【实测】**改标题卡(cardType 5)的文字用 `POST /page-setting/replace-page-card`**(`oldPageCardId` + 新 `contentText` + 原坐标)。
|
|
199
|
+
`update-page-card` 只改坐标宽高,传 `contentText` 不生效;反过来 `replace-page-card` 也不可靠地改高度,实测 body 传 2 格仍返回原 4 格。
|
|
200
|
+
编辑文字后要重新 `plan-get`,再用完整列表调 `update-page-card` 改布局。返回 id 本次实测保持原值,但不假设必然不变,以响应和回读为准。
|
|
201
|
+
65. 【实测】**`card-sort` 的字段必须已经在卡片上**(报「Card has no field」)。图表要按不画的列排序(渠道序、系列序)时,
|
|
202
|
+
把它们加成第 2、3 个维度(`card-chart … --dim '日期标签,日期,渠道序' --meas 值 --series 渠道`)——只有第一个维度当 x 轴,其余不画。
|
|
203
|
+
66. 【实测】**调试 Chrome 视口只有 1006×50**(窗口找不到、`Browser.setWindowBounds` 报 window not found)时:
|
|
204
|
+
`Emulation.setDeviceMetricsOverride` 设成 1440×900 后卡片懒加载能触发、DOM 能读到数据,但 `Page.captureScreenshot` 仍超时、
|
|
205
|
+
图表 canvas 不画。只能读 DOM 文字核对表格类卡片;图表靠 `query` 核数据。卡片懒加载只在视口内触发,滚太快会读到空卡。
|
|
206
|
+
隐藏卡片标题后标题文字仍在 DOM(`opacity:0`),`innerText` 照样读得到,不代表没隐藏。
|
|
207
|
+
67. 【实测】**对数前先确认数仓没在刷数**:测试租户 `ads_gop_sales_item_view` 同一款同一区间 20 分钟内从 221 件变成 578 件(ETL 正在回刷),
|
|
208
|
+
期间拿它和宽表比会得出错误结论。差异大时隔几分钟再查一次,两次一致再下结论。
|
|
209
|
+
68. 【实测】**一行指标卡取多行数据集的第一行**:卡片 `limitCount: 1` + `card-sort` 指定哪行在前(如分渠道表的合计行 行序 降序)。
|
|
210
|
+
数据集不用为指标卡单独拆一份。
|
|
211
|
+
69. 【确认】**列表指标卡(类型一、类型六)的对比箭头颜色写死**:↑ 红(#f46649)、↓ 绿,不跟条件颜色。销售额上涨配 ↑ 会显示成红色。
|
|
212
|
+
只在「上升是坏事」的指标(退货率)上用箭头,规模类只用文字颜色。类型四的标题写死为「今日实时 + 当天日期」,不能当普通指标条用。
|
|
213
|
+
70. 【实测】**往方案加新卡后,自己在页面上填过筛选值的用户看不到新卡的数**:个人筛选副本里没有新卡的绑定,新卡收不到参数、显示「暂无数据」。
|
|
214
|
+
`linkai reset-filter --plan <planId>` 只重置自己的副本;其他用户要自己点筛选栏的重置。新增卡片还要同步加进方案筛选器的 `bindUserPageCards`。
|
|
215
|
+
71. 【实测】**调试 Chrome 可能被别的会话同时使用**(如 DS 任务),自己开的标签页会被关掉。验收脚本自己 `PUT /json/new` 开页、做完立即 `/json/close/<id>`,
|
|
216
|
+
不要依赖上一次留下的标签页,也不要动别人的页面。
|
|
217
|
+
72. 【实测】**前端发版后调试浏览器白屏,报 `SyntaxError: Unexpected token '<'`**:浏览器缓存了旧 index.html,引用的旧 `umi.<hash>.js`
|
|
218
|
+
已下线,服务器退回 HTML。不是方案配置问题。验收脚本在自己的标签页 `Network.setCacheDisabled` 即可,不必清整个浏览器缓存。
|
|
219
|
+
判断新组件是否已上线:抓首页引用的 `umi.*.js`,按其中的分包表下载 `*.async.js`,搜组件 id(如 `meterTimeline`、`fitTableWidth`)。
|
|
220
|
+
73. 【实测】**卡片内容溢出时 AG 一行卡会出纵向滚动条**:上线前量 `.ag-body-viewport` 的 clientHeight 与 scrollHeight,不等就加卡片格数。
|
|
221
|
+
74. 【实测】**自定义渲染(AG 单元格 / 时间轴卡片)一行里的项会换行**:`.FieldRenderer_row` 是 `flex-wrap: wrap`,
|
|
222
|
+
两项 `fieldWidth` 加 `itemGap` 只要大于卡片内宽(时间轴卡 = cardWidth − 内边距 24 − 边框 4)就折成两行,卡片凭空高出一截。
|
|
223
|
+
做两列网格时列宽取 `(内宽 − 间距) ÷ 2 − 几像素`。标签在上、值在下且标签随行变化时,标签和值各占一行(`showLabel` 的标签只能取字段标题)。
|
|
224
|
+
75. 【实测】**量懒加载卡片的尺寸要等渲染完**:刚滚进视口时读到的可视高度可能偏小(读到 64px,实际 112px),同一张卡测两次一致再按它定格数。
|
|
225
|
+
76. 【实测】**分区标题卡(cardType 5)的 `subtitle` 渲染在主标题后方同一行,但固定是斜体衬线**
|
|
226
|
+
(`.component_TitleTemplateSection_emphasis` 写死 `font-style: italic`)。`subtitleStyle` 只认 fontSize / fontWeight / fill / lineHeight / fontFamily,去不掉斜体。
|
|
227
|
+
demo/用户要求同行时:把原说明移到 `subtitle`、清空 `description`、PC/手机高度用 2 格;要正体时:留空 `subtitle`,用下方 `description`,根据行数给 3–4 格。
|
|
228
|
+
不要横线就 `showDecorLine:false`。标题从 4 格压到 2 格后,每个下游 PC 卡片的 `y` 都要减 2;一次改多个标题时累加位移。
|
|
229
|
+
方案页面底色:方案 `dataScreenSetting.pageBackgroundColor`;单卡底色:卡位 `dataScreenSetting` `{useCardConfig:true, backgroundColor, cardTitle:{show}}`。
|
|
230
|
+
77. 【实测】**方案居中留白要改卡位网格,不是改卡内 padding**。24 列布局的 demo 配方是所有顶层满宽卡 `x:2,width:20`,
|
|
231
|
+
左右各 2 格;同行子卡也只能占 `[2,22]`。要再加留白就对称改为 `x:3,width:18` 等,别只缩一边。
|
|
232
|
+
`update-page-card` 要带完整卡片列表和方案元数据;只改 PC 留白时保留 `mobileX/mobileWidth`,写后检查卡片边界、id 集合和矩形重叠。
|
|
233
|
+
78. 【实测】**暖色画布要改方案顶层 `dataScreenSetting.pageBackgroundColor`,不是把所有卡片都染色**。款式画像 demo 用 `#F4F3EE`;
|
|
234
|
+
分区标题、统计指标卡(`meter/list`、`meter/meterList`)和时间轴指标卡(`meter/meterTimeline`)的方案卡位默认用
|
|
235
|
+
`transparent` 透出暖色,配置在 pageCard 的 `dataScreenSetting.backgroundColor`,不要改前端或图表内部配置;其它内容组件保留 `#FFFFFF` 白色层次。只改单卡会让卡间空隙/左右留白仍露旧色;
|
|
236
|
+
所有卡都改暖色又会失去层次。更新时合并原顶层 JSON,经 `update-page-card` 完整 body 带回,不要覆盖其它页面配置。
|
|
237
|
+
79. 【实测】**饼图/环图默认必须用卡片持久排序按数值降序**。模板 SQL 里的 `ORDER BY 排名` 在 BI 外层包装查询后不保证成为
|
|
238
|
+
图表输入顺序,结果会出现图例 30% 后接 7%、5%、3%、再回到 8% 的乱序。用
|
|
239
|
+
`card-sort --card <cardId> --spec "<数值字段>:desc"`,不要按维度名降序;写后回读 `indexBlock.sortField` 应是目标 `yaxisN desc`,
|
|
240
|
+
并确认实际查询 SQL 最外层含 `ORDER BY yaxisN DESC`。占比等于数值除以同一总量,所以按数值降序也就是按占比降序。
|
|
241
|
+
80. 【确认】**列表指标卡类型六已换配置模型**:旧 `titleField` / `mainField` / `assistantFields` /
|
|
242
|
+
`assistantColumns` / `mainText` / `cardMinWidth` 不再读取。新卡用 `cardRender.areas` + `cardWidth` + `cardColumns` +
|
|
243
|
+
`cardGap` + `cardRadius` + `showBorder`。`areas` 空时会兜底显示全部字段,不是空卡;所以迁移存量卡时必须重建 `areas`,不能只换字段名。
|
|
244
|
+
头部统计指标卡无论原来是 AG 表格还是 `meter/list`,都按最新规则迁移到 `meter/meterList` + `stepType:'type6'`,不保留旧组件兼容分支。
|
|
245
|
+
81. 【确认】**时间轴指标卡现在必定显示时间节点和轴线**:`showTimeline` 开关和 `conditionStyle.rowMark` 已删除,旧 JSON 里的值会被忽略。
|
|
246
|
+
时间轴只用于真正的时间分组;要无轴线的自适应卡片网格,用 `meter/meterList` 的 `stepType:'type6'`。
|
|
247
|
+
82. 【实测】**PC 并排卡不能在手机端复用同一个坐标**:两张 PC 同行卡若都保存成相同的 `mobileX/mobileY/mobileWidth/mobileHeight`,
|
|
248
|
+
手机端会完全重叠。按 PC 从左到右顺序改成纵向堆叠,后一张 `mobileY = 前一张 mobileY + mobileHeight`,并把其后全部区块按新增高度顺延;
|
|
249
|
+
写后对所有 pageCard 做手机端矩形碰撞检查,不能只看 PC 布局。
|
|
250
|
+
83. 【实测】**统计指标卡不要用时间轴指标卡**:`meter/meterTimeline` 必定显示时间节点和轴线、组间固定按时间降序,拿来摆一排指标卡
|
|
251
|
+
需要伪造「排序键」当时间字段,且画面多出轴线。统计指标卡一律用 `meter/meterList` 类型六;时间轴只给真正按时间点分组的数据(如采购事件)。
|
|
252
|
+
84. 【实测】**列表指标卡类型六的卡片顺序 = 数据行顺序**:用 `card-sort` 指定(如 `组序:asc,卡序:asc`)。同一长表出两组卡时,
|
|
253
|
+
两张卡分别 `limitCount` = 每组卡数,并用相反的组序排序取各自那组(坑 68 的同一招)。`showBorder:true` 的顶部 3px 色条颜色写死
|
|
254
|
+
`#1e3a8a`,不能按组换色;组别区分靠卡内标题颜色和组名行。条件样式写在 `stepTypeConfig.type6.conditionStyle`(value / arrow / fontColor,无 rowMark)。
|
|
255
|
+
85. 【实测】**AG 表出现纵向滚动条时,`fitTableWidth` 会横向溢出约 8px**(滚动条宽度):列宽在滚动条出现前按无滚动条的宽度拉伸。
|
|
256
|
+
配置层面消除不了,只能按常见行数给足卡片高度让纵向滚动条不出现;行数不定的长表需接受溢出或开分页。
|
|
257
|
+
86. 【实测】**有卡片自带筛选器的卡不能隐藏外层标题栏**:卡片级筛选器(如「指标」下拉)渲染在标题栏里,`cardTitle.show:false` 会把切换器一起藏掉。
|
|
258
|
+
这类卡保留标题栏;其余数据卡在有分区标题时隐藏标题栏。隐藏后标题栏仍占约 22px 高度、只是透明,排高度时要算进去。
|
|
259
|
+
87. 【实测 2026-10-18】数据集 SQL 里的参数条件块 `$I{{ AND … }}` 过不了 `sql-check`:服务端 `/index-block/get-field-info-by-data-set-sql`
|
|
260
|
+
报 `Getting syntax error … No viable statement for input`,同一份 SQL 删掉条件块立刻通过。所以「日期区间」这类参数变量筛选器在当前链路配不出来,
|
|
261
|
+
别按 `rpt_gop_*` 模板的写法硬套;要么放弃时间筛选(子标题写清数据周期),要么改用结果集/维度筛选器。
|
|
262
|
+
88. 【实测】`dim_productsku_info_d_view` 存在重复 SKU(6246 行 / 6062 个 SKU):直接 `LEFT JOIN` 会让采购明细行数、金额虚增(本例多 28 行)。
|
|
263
|
+
JOIN 前先 `SELECT sku, MAX(...) FROM dim_productsku_info_d_view GROUP BY sku` 去重;品类字段冲突时用 MAX 取值并回读确认。
|
|
264
|
+
89. 【实测】`POST /page-setting/replace-page-card` 只传 `oldPageCardId + contentText + 坐标` 会把该页卡的 `cardType` 重置为 0,分区标题卡随即失效。
|
|
265
|
+
body 顶层和 `pageCard` 对象里都要显式带 `cardType:5`;写后立刻 `plan-get` 回读 cardType/height/坐标。
|