markstar 1.0.0
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/README.md +33 -0
- package/bin/markstar.js +152 -0
- package/package.json +34 -0
- package/skills/data-to-chart/SKILL.md +157 -0
- package/skills/data-to-chart/reference/chart-mapping.md +187 -0
- package/skills/data-to-chart/reference/dashboard-guide.md +427 -0
- package/skills/data-to-chart/reference/data-processing.md +198 -0
- package/skills/data-to-chart/reference/echarts-templates.md +601 -0
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# MarkStar — AI 编程技能集合
|
|
2
|
+
|
|
3
|
+
一行命令安装 [Claude Code](https://claude.ai/code) 技能,开箱即用。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx markstar
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
技能会自动安装到 `~/.claude/skills/`,重启 Claude Code 即可使用。
|
|
12
|
+
|
|
13
|
+
## 技能列表
|
|
14
|
+
|
|
15
|
+
| 技能 | 命令 | 说明 |
|
|
16
|
+
|------|------|------|
|
|
17
|
+
| **data-to-chart** | `/data-to-chart` | 智能图表生成,自动选择 ECharts 图表类型并生成可交互 HTML。支持大屏/仪表盘模式。 |
|
|
18
|
+
|
|
19
|
+
## 卸载
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx markstar --uninstall
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 发布
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm publish
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 许可
|
|
32
|
+
|
|
33
|
+
MIT
|
package/bin/markstar.js
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MarkStar — AI 编程技能集合
|
|
5
|
+
*
|
|
6
|
+
* 用法:
|
|
7
|
+
* npx markstar 自动安装到 ~/.claude/skills/
|
|
8
|
+
* npx markstar --uninstall 卸载
|
|
9
|
+
* npx markstar --help 帮助
|
|
10
|
+
* npx markstar --version 版本号
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, copyFileSync, lstatSync, realpathSync, rmSync } from 'fs';
|
|
14
|
+
import { resolve, dirname, join } from 'path';
|
|
15
|
+
import { fileURLToPath } from 'url';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
|
|
18
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
|
+
const PKG = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf8'));
|
|
20
|
+
const SKILLS_SRC = resolve(__dirname, '..', 'skills');
|
|
21
|
+
|
|
22
|
+
function copyDirSync(src, dest) {
|
|
23
|
+
let realSrc = src;
|
|
24
|
+
try { realSrc = realpathSync(src); } catch {}
|
|
25
|
+
mkdirSync(dest, { recursive: true });
|
|
26
|
+
const entries = readdirSync(realSrc, { withFileTypes: true });
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
if (entry.name === '.DS_Store') continue;
|
|
29
|
+
const srcPath = join(realSrc, entry.name);
|
|
30
|
+
const destPath = join(dest, entry.name);
|
|
31
|
+
let stat;
|
|
32
|
+
try { stat = lstatSync(srcPath); } catch { continue; }
|
|
33
|
+
if (stat.isDirectory()) {
|
|
34
|
+
copyDirSync(srcPath, destPath);
|
|
35
|
+
} else if (stat.isFile()) {
|
|
36
|
+
copyFileSync(srcPath, destPath);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function countDirs(dir) {
|
|
42
|
+
if (!existsSync(dir)) return 0;
|
|
43
|
+
return readdirSync(dir, { withFileTypes: true }).filter(e => e.isDirectory()).length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function scanSkillEntries(dir) {
|
|
47
|
+
const entries = [];
|
|
48
|
+
if (!existsSync(dir)) return entries;
|
|
49
|
+
for (const name of readdirSync(dir, { withFileTypes: true })) {
|
|
50
|
+
if (!name.isDirectory()) continue;
|
|
51
|
+
const skillFile = resolve(dir, name.name, 'SKILL.md');
|
|
52
|
+
if (!existsSync(skillFile)) continue;
|
|
53
|
+
const content = readFileSync(skillFile, 'utf8');
|
|
54
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
55
|
+
if (!fmMatch) continue;
|
|
56
|
+
const nameMatch = fmMatch[1].match(/^name:\s*(.+)$/m);
|
|
57
|
+
const descMatch = fmMatch[1].match(/^description:\s*["']?(.+?)["']?\s*$/m);
|
|
58
|
+
if (nameMatch) {
|
|
59
|
+
entries.push({ name: nameMatch[1].trim(), desc: descMatch ? descMatch[1].trim() : '' });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return entries;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function install() {
|
|
66
|
+
console.log(`\n markstar v${PKG.version} — AI 编程技能集合\n`);
|
|
67
|
+
|
|
68
|
+
if (!existsSync(SKILLS_SRC)) {
|
|
69
|
+
console.error(' skills 源目录不存在,请重新安装 markstar。');
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const dest = resolve(homedir(), '.claude', 'skills');
|
|
74
|
+
mkdirSync(dest, { recursive: true });
|
|
75
|
+
|
|
76
|
+
const srcCount = countDirs(SKILLS_SRC);
|
|
77
|
+
console.log(` ${srcCount} 个技能 → ${dest}\n`);
|
|
78
|
+
|
|
79
|
+
copyDirSync(SKILLS_SRC, dest);
|
|
80
|
+
|
|
81
|
+
const skillEntries = scanSkillEntries(SKILLS_SRC);
|
|
82
|
+
for (const s of skillEntries) {
|
|
83
|
+
console.log(` ${s.name} — ${s.desc}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log('\n 安装完成!重启 Claude Code 即可使用。\n');
|
|
87
|
+
console.log(' 卸载:npx markstar --uninstall\n');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function uninstall() {
|
|
91
|
+
console.log(`\n markstar v${PKG.version} — 卸载\n`);
|
|
92
|
+
|
|
93
|
+
if (!existsSync(SKILLS_SRC)) {
|
|
94
|
+
console.error(' skills 源目录不存在,无法确定要卸载的技能。');
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const srcNames = new Set(
|
|
99
|
+
readdirSync(SKILLS_SRC, { withFileTypes: true }).filter(e => e.isDirectory()).map(e => e.name)
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const dest = resolve(homedir(), '.claude', 'skills');
|
|
103
|
+
if (!existsSync(dest)) {
|
|
104
|
+
console.log(' 未找到已安装的技能,无需卸载。\n');
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let removed = 0;
|
|
109
|
+
for (const name of readdirSync(dest, { withFileTypes: true })) {
|
|
110
|
+
if (name.isDirectory() && srcNames.has(name.name)) {
|
|
111
|
+
rmSync(resolve(dest, name.name), { recursive: true, force: true });
|
|
112
|
+
console.log(` 已删除: ${name.name}`);
|
|
113
|
+
removed++;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (removed === 0) {
|
|
118
|
+
console.log(' 未找到已安装的 markstar 技能,无需卸载。\n');
|
|
119
|
+
} else {
|
|
120
|
+
console.log(`\n 卸载完成,已移除 ${removed} 个技能。\n`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function showHelp() {
|
|
125
|
+
console.log(`
|
|
126
|
+
markstar v${PKG.version} — AI 编程技能集合
|
|
127
|
+
|
|
128
|
+
用法:
|
|
129
|
+
npx markstar 安装所有技能到 ~/.claude/skills/
|
|
130
|
+
npx markstar --uninstall 卸载
|
|
131
|
+
npx markstar --help 帮助
|
|
132
|
+
npx markstar --version 版本号
|
|
133
|
+
|
|
134
|
+
已收录技能:${countDirs(SKILLS_SRC)} 个
|
|
135
|
+
`);
|
|
136
|
+
const entries = scanSkillEntries(SKILLS_SRC);
|
|
137
|
+
for (const s of entries) {
|
|
138
|
+
console.log(` ${s.name} — ${s.desc}`);
|
|
139
|
+
}
|
|
140
|
+
console.log('');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const args = process.argv.slice(2);
|
|
144
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
145
|
+
showHelp();
|
|
146
|
+
} else if (args.includes('--version') || args.includes('-v')) {
|
|
147
|
+
console.log(PKG.version);
|
|
148
|
+
} else if (args.includes('--uninstall') || args.includes('-u')) {
|
|
149
|
+
uninstall();
|
|
150
|
+
} else {
|
|
151
|
+
install();
|
|
152
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "markstar",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=16.0.0"
|
|
6
|
+
},
|
|
7
|
+
"description": "MarkStar — AI 编程技能集合。智能图表生成(data-to-chart)等 Claude Code skills,一行 npx 安装",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"markstar": "bin/markstar.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/",
|
|
14
|
+
"skills/",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"claude-code",
|
|
19
|
+
"skill",
|
|
20
|
+
"echarts",
|
|
21
|
+
"chart",
|
|
22
|
+
"visualization",
|
|
23
|
+
"dashboard",
|
|
24
|
+
"data-to-chart",
|
|
25
|
+
"data-viz"
|
|
26
|
+
],
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/mjhgithub/markstar.git"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/mjhgithub/markstar#readme",
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT"
|
|
34
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: data-to-chart
|
|
3
|
+
description: Use when the user wants to create charts, graphs, or data visualizations, or uses Chinese keywords like 画图/图表/可视化/数据展示/生成图表. Also triggered by /data-to-chart command. Supports automatic chart type selection based on business scenario analysis with ECharts.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# data-to-chart — 智能图表生成
|
|
7
|
+
|
|
8
|
+
根据用户的分析意图和数据特征,自动选择 ECharts 图表类型并生成完整的可交互 HTML 文件。当检测到大屏/仪表盘场景时,自动切换为多图表 Dashboard 模式。
|
|
9
|
+
|
|
10
|
+
## 核心原则
|
|
11
|
+
|
|
12
|
+
**业务场景决定图表类型,数据结构辅助验证。冲突时业务优先。**
|
|
13
|
+
|
|
14
|
+
## 执行流程
|
|
15
|
+
|
|
16
|
+
严格按以下步骤执行。每步完成后进入下一步,不可跳过。
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
### Step 0: 大屏场景检测(前置)
|
|
21
|
+
|
|
22
|
+
检测用户输入是否含大屏关键词:「大屏、数据大屏、仪表盘、驾驶舱、概览、总览、看板」。
|
|
23
|
+
|
|
24
|
+
- **命中** → **必须先用 Read 工具加载 `reference/dashboard-guide.md`**,然后进入 Dashboard 流程(D1-D3),替代原有 Step 1-5
|
|
25
|
+
- **未命中** → 继续原有单图流程,进入 Step 1
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Dashboard 流程(命中大屏场景时)
|
|
30
|
+
|
|
31
|
+
### D1: 区域规划
|
|
32
|
+
|
|
33
|
+
分析用户描述,拆解为若干子图表 + KPI 卡片。每个子图按原 Step 1 场景分析确定图表类型。
|
|
34
|
+
|
|
35
|
+
根据图表数量,从 `dashboard-guide.md` 布局模式表中选择 Grid 布局:
|
|
36
|
+
|
|
37
|
+
| 图表数 | 布局 | Grid class |
|
|
38
|
+
|--------|------|------------|
|
|
39
|
+
| 1 | KPI 列 + 图表列 | `cols-2` |
|
|
40
|
+
| 2 | 2 列均分 | `cols-2` |
|
|
41
|
+
| 3 | 2列 + 下方跨整行 | `cols-2`,下方 `.span-full` |
|
|
42
|
+
| 4 | 2×2 | `cols-2 rows-2` |
|
|
43
|
+
| 5 | 上方跨行 + 2×2 | `.span-full` + `cols-2 rows-2` |
|
|
44
|
+
| 6 | 2×3 | `cols-3 rows-2` |
|
|
45
|
+
| ≥7 | 3×N | `cols-3` |
|
|
46
|
+
|
|
47
|
+
### D2: 数据获取与图表 Option 生成
|
|
48
|
+
|
|
49
|
+
对每个子图区域执行原 Step 2+3+4(数据获取 → 数据整理 → 双轴验证),记录每块图表的 option 对象。
|
|
50
|
+
|
|
51
|
+
**颜色统一**:所有图表使用 Theme B 调色板:`['#00DDFF','#37A2FF','#FF0087','#FFBF00','#00E396','#FEBE4A','#A78BFA','#34D399','#FF6B6B']`
|
|
52
|
+
|
|
53
|
+
**KPI 卡片数据**:从所有子图数据中提炼 2-4 个关键指标(总量、最高值、同比变化、合计占比等)。
|
|
54
|
+
|
|
55
|
+
### D3: 大屏 HTML 生成
|
|
56
|
+
|
|
57
|
+
使用 `dashboard-guide.md` 中的 Dashboard HTML 骨架,将各 option 嵌入。
|
|
58
|
+
|
|
59
|
+
输出格式:先输出 Dashoard 内容说明(各区域名称 + 图表类型 + 数据来源),再输出完整 HTML。
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Step 1: 场景分析 — 确定图表类型
|
|
64
|
+
|
|
65
|
+
**必须先用 Read 工具加载 `reference/chart-mapping.md`**,获取完整的图表类型映射表和优先级规则。
|
|
66
|
+
|
|
67
|
+
按优先级从用户输入中匹配业务关键词,确定图表类型:
|
|
68
|
+
|
|
69
|
+
| 优先级 | 关键词类别 | 推荐类型 |
|
|
70
|
+
|--------|-----------|---------|
|
|
71
|
+
| 1 | 趋势、变化、增长率、走势、时间线、历年 | `line` |
|
|
72
|
+
| 2 | 占比、份额、构成、分布、比例、百分比 | `pie` |
|
|
73
|
+
| 3 | 排名、对比、比较、TOP、排行 | `bar` |
|
|
74
|
+
| 4 | 时间+分类组合、堆积 | `bar`(stack) / `line`(areaStyle) |
|
|
75
|
+
| 5 | 关系、相关性、关联 | `scatter` |
|
|
76
|
+
| 6 | 地域、地区、省份、城市 | `map` |
|
|
77
|
+
| 7 | 流程、转化、漏斗、阶段 | `funnel` |
|
|
78
|
+
| 8 | 进度、完成率、KPI、达成 | `gauge` |
|
|
79
|
+
| 9 | 层级、树形、嵌套 | `sunburst` / `treemap` |
|
|
80
|
+
| 10 | 多维指标、综合评分 | `radar` |
|
|
81
|
+
| 11 | 分布、频次、密度 | `bar`(histogram) / `boxplot` |
|
|
82
|
+
| 12 | 波动、范围、区间 | `candlestick` |
|
|
83
|
+
|
|
84
|
+
**规则**:
|
|
85
|
+
- 多关键词匹配时取最高优先级
|
|
86
|
+
- 无法识别任何关键词时默认选择 `bar`
|
|
87
|
+
- 将选型结果记录在最终输出中(1-2 句话说明理由)
|
|
88
|
+
|
|
89
|
+
### Step 2: 数据获取
|
|
90
|
+
|
|
91
|
+
**必须先用 Read 工具加载 `reference/data-processing.md`**,获取完整的数据获取策略。
|
|
92
|
+
|
|
93
|
+
按优先级降级链执行,上一级获取不到数据时自动进入下一级:
|
|
94
|
+
|
|
95
|
+
1. **项目文件**:搜索当前项目目录下的 CSV/JSON/Excel 文件,读取并解析
|
|
96
|
+
2. **Web 搜索**:使用 web_search 工具搜索相关公开数据,必要时打开 1-2 个搜索结果页面提取详细数值
|
|
97
|
+
3. **示例数据**:使用合理模拟数据继续,并在输出中标注「⚠️ 已使用示例数据,非真实数据」
|
|
98
|
+
|
|
99
|
+
### Step 3: 数据整理
|
|
100
|
+
|
|
101
|
+
将获取的数据转换为 ECharts 可用格式。按数据结构选择格式:
|
|
102
|
+
|
|
103
|
+
- **时间序列** → `{ xAxis: { type: "category", data: ["2020", "2021", ...] }, series: [{ type: "line", data: [100, 120, ...] }] }`
|
|
104
|
+
- **分类对比** → `{ xAxis: { type: "category", data: ["分类A", "分类B", ...] }, series: [{ type: "bar", data: [100, 200, ...] }] }`
|
|
105
|
+
- **多系列** → `{ series: [{ name: "系列1", type: "line", data: [...] }, { name: "系列2", type: "line", data: [...] }] }`
|
|
106
|
+
- **饼图** → `{ series: [{ type: "pie", data: [{ name: "类别A", value: 100 }, { name: "类别B", value: 200 }] }] }`
|
|
107
|
+
- **散点图** → `{ series: [{ type: "scatter", data: [[x1, y1], [x2, y2], ...] }] }`
|
|
108
|
+
|
|
109
|
+
### Step 4: 双轴验证
|
|
110
|
+
|
|
111
|
+
对比分析业务选型与数据实际维度:
|
|
112
|
+
|
|
113
|
+
- 数据是时间序列但业务选饼图 → **以业务为准**,仍用时间序列方式展示
|
|
114
|
+
- 数据缺关键维度(如散点图需两个数值列但数据只有一个)→ **降级为柱状图**并在输出中说明降级原因
|
|
115
|
+
- 数据与业务一致 → 直接通过,进入 Step 5
|
|
116
|
+
|
|
117
|
+
### Step 5: 代码生成
|
|
118
|
+
|
|
119
|
+
**必须先用 Read 工具加载 `reference/echarts-templates.md`**,获取该图表类型的 ECharts option 结构参考。
|
|
120
|
+
|
|
121
|
+
参考模板但灵活适配实际数据的维度、系列数、值域。不可机械套用模板。
|
|
122
|
+
|
|
123
|
+
#### HTML 输出规范
|
|
124
|
+
|
|
125
|
+
**主题选择**:根据用户场景关键词自动匹配主题方案(参见 `reference/echarts-templates.md` 中的「主题配色方案」章节):
|
|
126
|
+
- 含「大屏、仪表盘、深色、暗色、科技」→ 方案 B:科技深色
|
|
127
|
+
- 含「论文、打印、学术、出版、无障碍」→ 方案 C:简约学术
|
|
128
|
+
- 其他(默认)→ 方案 A:专业商务
|
|
129
|
+
|
|
130
|
+
**代码生成**:
|
|
131
|
+
- 引入 CDN:`<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>`
|
|
132
|
+
- `.wrapper` 包裹容器:居中、最大宽度、圆角、阴影、内边距 — 与所选主题骨架一致
|
|
133
|
+
- 图表容器:`<div id="chart" style="width:100%; min-height:400px;"></div>`
|
|
134
|
+
- 文字区域:`<h1>` 标题 + `.subtitle` 数据来源 + `.note` 脚注,三件套缺一不可
|
|
135
|
+
- 初始化:`var chart = echarts.init(document.getElementById('chart')); chart.setOption(option);`
|
|
136
|
+
- 响应式:`window.addEventListener('resize', function() { chart.resize(); });`
|
|
137
|
+
- 默认启用:tooltip、legend(多系列时)、toolbox(saveAsImage)
|
|
138
|
+
- 字体:`font-family: "Microsoft YaHei", "PingFang SC", sans-serif;`
|
|
139
|
+
- 地图场景:额外引入中国地图 CDN JSON(`https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json`),通过 `echarts.registerMap('china', geoJson)` 注册后使用
|
|
140
|
+
|
|
141
|
+
#### 输出格式
|
|
142
|
+
|
|
143
|
+
1. 先输出文字说明:选型理由(1-2 句话)+ 数据来源(项目文件/Web 搜索/示例数据)
|
|
144
|
+
2. 再输出完整 HTML 代码块(````html ... ````)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 参考文件
|
|
149
|
+
|
|
150
|
+
执行时按需加载(使用 Read 工具):
|
|
151
|
+
|
|
152
|
+
| 文件 | 用途 | 触发条件 |
|
|
153
|
+
|------|------|---------|
|
|
154
|
+
| `reference/dashboard-guide.md` | 大屏布局模式、KPI 卡片、动态背景、骨架模板 | Step 0 检测到大屏关键词时加载 |
|
|
155
|
+
| `reference/chart-mapping.md` | 完整图表类型映射表和冲突解决规则 | Step 1 前必须加载 |
|
|
156
|
+
| `reference/data-processing.md` | 数据获取降级链和格式转换规则 | Step 2 前必须加载 |
|
|
157
|
+
| `reference/echarts-templates.md` | ECharts option 模板和通用配置 | Step 5 前必须加载 |
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# 图表类型映射表
|
|
2
|
+
|
|
3
|
+
## 优先级规则
|
|
4
|
+
|
|
5
|
+
1. 从用户输入中提取所有业务关键词
|
|
6
|
+
2. 按下表优先级顺序匹配,取**最高优先级**匹配项
|
|
7
|
+
3. 同一优先级内多个关键词匹配时,选择第一个匹配的类型
|
|
8
|
+
4. 完全无匹配时默认 `bar`
|
|
9
|
+
5. 多关键词跨优先级时,高优先级覆盖低优先级
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 完整映射表
|
|
14
|
+
|
|
15
|
+
### 优先级 1:趋势/时间序列 → `line`
|
|
16
|
+
|
|
17
|
+
**关键词**:趋势、变化、增长率、走势、时间线、历年、历年变化、同比、环比、时间序列、时序、波动
|
|
18
|
+
|
|
19
|
+
**适用条件**:数据含时间维度(年/月/日/季度)且用户关注变化趋势
|
|
20
|
+
|
|
21
|
+
**option 类型**:`series.type = "line"`
|
|
22
|
+
|
|
23
|
+
**降级方案**:数据分类过多(>20 个时间点)且用户关注排名 → 降级为 `bar`
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
### 优先级 2:占比/构成 → `pie`
|
|
28
|
+
|
|
29
|
+
**关键词**:占比、份额、构成、分布、比例、百分比、比重、几成、多少比例
|
|
30
|
+
|
|
31
|
+
**适用条件**:数据各部分之和有意义(构成整体),分类数 2-10 个
|
|
32
|
+
|
|
33
|
+
**option 类型**:`series.type = "pie"`
|
|
34
|
+
|
|
35
|
+
**降级方案**:
|
|
36
|
+
- 分类 > 10 个 → 降级为 `bar`,取 TOP 10 + 「其他」
|
|
37
|
+
- 数据不含可加总的组成部分 → 降级为 `bar`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### 优先级 3:排名/对比 → `bar`
|
|
42
|
+
|
|
43
|
+
**关键词**:排名、对比、比较、TOP、排行、谁最多、谁最少、哪个最高
|
|
44
|
+
|
|
45
|
+
**适用条件**:需要横向对比不同类别数值大小
|
|
46
|
+
|
|
47
|
+
**option 类型**:`series.type = "bar"`,`xAxis.type = "category"`
|
|
48
|
+
|
|
49
|
+
**降级方案**:分类名过长(>8 个中文字符)→ 改用水平柱状图(`yAxis.type = "category"`)
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### 优先级 4:时间+分类组合 → `bar`(stack) / `line`(areaStyle)
|
|
54
|
+
|
|
55
|
+
**关键词**:堆积、堆叠、构成变化、面积、累计、叠加
|
|
56
|
+
|
|
57
|
+
**适用条件**:同时有时间维度和分类维度,需展示各部分随时间变化
|
|
58
|
+
|
|
59
|
+
**option 类型**:
|
|
60
|
+
- 柱状:`series.type = "bar"` + `series.stack = "total"`
|
|
61
|
+
- 折线:`series.type = "line"` + `series.areaStyle = {}`
|
|
62
|
+
|
|
63
|
+
**降级方案**:系列数 > 5 → 去除 areaStyle,改用多折线
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### 优先级 5:关系/相关性 → `scatter`
|
|
68
|
+
|
|
69
|
+
**关键词**:关系、相关性、关联、散点、相关度、二维分布、交叉分析
|
|
70
|
+
|
|
71
|
+
**适用条件**:数据至少包含两个数值列(X 和 Y 轴)
|
|
72
|
+
|
|
73
|
+
**option 类型**:`series.type = "scatter"`
|
|
74
|
+
|
|
75
|
+
**降级方案**:数据只有一个数值列 → 降级为 `bar`,并说明「散点图需要两个数值维度,当前数据仅一个数值列」
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
### 优先级 6:地域 → `map`
|
|
80
|
+
|
|
81
|
+
**关键词**:地域、地区、省份、城市、全国、各省、地图
|
|
82
|
+
|
|
83
|
+
**适用条件**:数据含中国省/市/自治区名称
|
|
84
|
+
|
|
85
|
+
**option 类型**:`series.type = "map"` + `series.map = "china"`
|
|
86
|
+
|
|
87
|
+
**降级方案**:非中国地图数据 → 降级为 `bar`,并说明「首版仅支持中国地图,其他地区请自行注册 GeoJSON」
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
### 优先级 7:流程/转化 → `funnel`
|
|
92
|
+
|
|
93
|
+
**关键词**:流程、转化、漏斗、阶段、转化率、流失、各环节
|
|
94
|
+
|
|
95
|
+
**适用条件**:数据各阶段呈递减趋势,表示从大到小的转化过程
|
|
96
|
+
|
|
97
|
+
**option 类型**:`series.type = "funnel"`
|
|
98
|
+
|
|
99
|
+
**降级方案**:数据无明显递减 → 降级为 `bar`,并说明「漏斗图适合递减转化数据,当前数据不满足递减特征」
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 优先级 8:进度/KPI → `gauge`
|
|
104
|
+
|
|
105
|
+
**关键词**:进度、完成率、KPI、达成、指标、完成度、百分比仪表
|
|
106
|
+
|
|
107
|
+
**适用条件**:单个数值(0-100 或 0-1),表示完成程度或达成率
|
|
108
|
+
|
|
109
|
+
**option 类型**:`series.type = "gauge"`
|
|
110
|
+
|
|
111
|
+
**降级方案**:多个指标 > 1 → 降级为 `bar`(多个仪表盘不直观)
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### 优先级 9:层级/树形 → `sunburst` / `treemap`
|
|
116
|
+
|
|
117
|
+
**关键词**:层级、树形、嵌套、多级、下钻、子类别、层次
|
|
118
|
+
|
|
119
|
+
**适用条件**:数据具有父子层级关系,如 大类→小类→细类
|
|
120
|
+
|
|
121
|
+
**option 类型**:`series.type = "sunburst"` 或 `series.type = "treemap"`
|
|
122
|
+
|
|
123
|
+
**降级方案**:数据扁平无层级 → 降级为 `pie` 或 `bar`
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 优先级 10:多维指标 → `radar`
|
|
128
|
+
|
|
129
|
+
**关键词**:多维、综合评分、多指标、雷达、多维度评估、能力模型
|
|
130
|
+
|
|
131
|
+
**适用条件**:多个指标在同一尺度下比较,指标数 3-10 个
|
|
132
|
+
|
|
133
|
+
**option 类型**:`series.type = "radar"`
|
|
134
|
+
|
|
135
|
+
**降级方案**:指标数 < 3 → 降级为 `bar`
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### 优先级 11:分布/频次 → `bar`(histogram) / `boxplot`
|
|
140
|
+
|
|
141
|
+
**关键词**:分布、频次、密度、直方图、箱线、数据分布
|
|
142
|
+
|
|
143
|
+
**适用条件**:关注数值的分布形态而非具体值
|
|
144
|
+
|
|
145
|
+
**option 类型**:`series.type = "bar"`(直方图用 bar 近似)或 `series.type = "boxplot"`
|
|
146
|
+
|
|
147
|
+
**降级方案**:ECharts boxplot 需要 echarts-stat 扩展 → 数据量不足以分箱时降级为散点图
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 优先级 12:波动/区间 → `candlestick`
|
|
152
|
+
|
|
153
|
+
**关键词**:波动、范围、区间、K线、开盘、最高最低、极值范围
|
|
154
|
+
|
|
155
|
+
**适用条件**:每个数据点有 4 个值(开/高/低/收 或 最小值/Q1/Q3/最大值)
|
|
156
|
+
|
|
157
|
+
**option 类型**:`series.type = "candlestick"`
|
|
158
|
+
|
|
159
|
+
**降级方案**:数据只有 2 个值(最小/最大)→ 降级为带误差线的 `bar`
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 冲突解决决策树
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
用户输入
|
|
167
|
+
│
|
|
168
|
+
├─ 包含"趋势/变化/增长率"等 → line(优先级 1 胜出)
|
|
169
|
+
│ └─ 但同时说"占比分析" → 仍选 line,Step 4 双轴验证会确认
|
|
170
|
+
│
|
|
171
|
+
├─ 包含"占比/份额/百分比" → pie
|
|
172
|
+
│ └─ 但分类 > 10 → bar
|
|
173
|
+
│
|
|
174
|
+
├─ 包含"排名/对比/TOP" → bar
|
|
175
|
+
│
|
|
176
|
+
├─ 包含"各省/地区/地图" → map(仅中国地图)
|
|
177
|
+
│
|
|
178
|
+
├─ 包含"流程/漏斗/转化" → funnel
|
|
179
|
+
│
|
|
180
|
+
└─ 无明确关键词 → bar(默认)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## 选型结果记录格式
|
|
184
|
+
|
|
185
|
+
在最终输出中,必须包含选型说明,格式如下:
|
|
186
|
+
|
|
187
|
+
> **图表选型**:检测到关键词「XXX」(优先级 N),推荐使用 `<chart-type>` 图表。`<补充理由(如降级原因、适用条件匹配等)>`
|