# 数数看板生成详解

## 二、飞书文档转数数看板

这是一个**自动化看板配置生成工具**，可以从飞书埋点文档自动生成数数平台的看板配置（JSON 格式），支持国内3个项目和国外18个区服，大幅提升看板创建效率。

### 核心价值

- **自动化**：从飞书文档自动提取事件和字段信息
- **多项目**：支持国内项目（会玩、贪吃蛇小游戏、贪吃蛇app）和国外18个区服
- **智能识别**：国内项目自动省略 app_region 字段，国外项目自动添加区服筛选
- **标准化**：符合数数平台的 JSON 格式规范
- **可导入**：生成的配置可直接导入数数平台

### 工作流程

```
飞书文档 → 转换为 Markdown → 解析埋点事件 → 生成 JSON 配置 → 导入数数平台
```

### 使用场景

#### 场景1：新活动埋点看板创建

**输入**：活动埋点飞书文档
**输出**：可导入数数平台的 JSON 配置
**节省时间**：30分钟 → 3分钟（自动化）

#### 场景2：多区服看板批量创建

**输入**：一份埋点文档（国外项目）
**输出**：18个区服的独立看板配置
**节省时间**：5小时 → 10分钟

#### 场景3：看板配置验证

**输入**：生成的 JSON 文件
**输出**：格式校验报告
**避免问题**：导入失败、字段缺失、格式错误

### 功能特点

1. **智能解析**：自动识别事件名称、字段、筛选条件
2. **项目识别**：区分国内项目和国外项目，自动适配配置
3. **国内支持**：支持会玩、贪吃蛇小游戏、贪吃蛇app，无需 app_region
4. **国外支持**：支持18个海外区服，自动配置 app_region 筛选
5. **格式标准**：符合数数平台 JSON 格式要求
6. **批量生成**：一次生成多个区服配置
7. **验证工具**：内置格式校验脚本

### 支持的项目和区服

#### 国内项目（不需要 app_region）

| 项目名称 | 说明 |
|---------|------|
| 会玩 | 主站项目 |
| 贪吃蛇小游戏 | 小游戏项目 |
| 贪吃蛇app | App 项目 |

#### 国外项目（需要 app_region）

| 代码 | 区服名称 | 代码 | 区服名称 |
|------|---------|------|---------|
| "A" | 阿语服 | "O" | JK服 |
| "Q" | 土语服 | "R" | 俄语服 |
| "P" | 菲律宾服 | "B" | 葡语服 |
| "V" | 越南服 | "T" | 泰服 |
| "C" | 华语服 | "M" | 马尼服 |
| "J" | 日服 | "U" | 美服 |
| "K" | 韩服 | "I" | 印度服 |
| "N" | 巴基斯坦服 | "S" | 西语服 |
| "G" | 德语服 | "F" | 法语服 |

## 使用指南

### 标准流程

#### 步骤1：获取飞书文档

用户提供飞书文档链接：
```
https://wepie.feishu.cn/wiki/xxxxx
```

#### 步骤2：确认用户意图

如果用户只提供链接未说明用途，必须询问：
```
你想对这个飞书文档做什么？
1. 生成数数看板配置（JSON）
2. 生成测试用例（Markdown + XMind）
```

#### 步骤3：确认项目类型和区服

**🚨 重要：国内项目和国外项目的处理方式不同**

**步骤3.1：询问项目类型**

```
这个埋点文档是国内项目还是国外项目？
1. 国内项目（会玩、贪吃蛇小游戏、贪吃蛇app）
2. 国外项目（海外区服）
```

**步骤3.2a：如果是国内项目**

询问具体项目：
```
请选择国内项目：
1. 会玩
2. 贪吃蛇小游戏
3. 贪吃蛇app

请输入项目名称或序号：
```

**国内项目特点**：
- ✅ 不需要 `app_region` 字段
- ✅ 配置更简洁
- ✅ 直接按项目名称生成看板

**步骤3.2b：如果是国外项目**

询问用户需要哪个区服的看板：
```
请选择区服（app_region）：
1. 阿语服 ("A")
2. 土语服 ("Q")
3. 菲律宾服 ("P")
4. 越南服 ("V")
5. 华语服 ("C")
6. 日服 ("J")
7. 韩服 ("K")
8. 巴基斯坦服 ("N")
9. JK服 ("O")
10. 俄语服 ("R")
11. 葡语服 ("B")
12. 泰服 ("T")
13. 马尼服 ("M")
14. 美服 ("U")
15. 印度服 ("I")
16. 西语服 ("S")
17. 法语服 ("F")
18. 德语服 ("G")

请输入区服代码（如 C、J、K）或序号：
```

**用户可以输入**：
- 区服代码：`C`、`J`、`K`
- 区服名称：`华语服`、`日服`、`韩服`
- 序号：`5`、`6`、`7`

**国外项目特点**：
- ✅ 需要 `app_region` 字段筛选
- ✅ 支持18个海外区服
- ✅ 自动添加区服筛选条件

#### 步骤4：转换飞书文档

自动调用 feishu2md 转换：

```python
# 调用 feishu2md skill
# 输入：飞书文档 URL
# 输出：docs/feishu_doc.md
```

转换后文档保存在：
```
testcase_generation/docs/feishu_doc.md
```

### 解决方案：手动配置事件列表

如果解析结果不完整（如文档有19个事件但只解析到6个），创建 `docs/events_manual.json`：

```json
[
  {
    "title": "1.1 每个阶段获得/消耗不同等級弹珠用户数",
    "event_name": "ActivityTotal",
    "event_filters": [],
    "group_by": ["activity_type", "action", "act_id", "activity", "activity_name"]
  },
  {
    "title": "1.2.1 获得额外充值优惠",
    "event_name": "ActivityTotal",
    "event_filters": [
      {"columnName": "activity_type", "ftv": ["charge_coupon"]},
      {"columnName": "action", "ftv": ["incr_random_coupon"]}
    ],
    "group_by": ["act_id", "activity", "activity_name", "incr_times"]
  },
  {
    "title": "2.1 活动页面曝光",
    "event_name": "ta_pageview",
    "event_filters": [],
    "group_by": ["url", "url_path"]
  }
]
```

**字段说明**：
- `title`：报表名称（在数数平台显示）
- `event_name`：事件名称（如 ActivityTotal、SendReward）
- `event_filters`：固定值筛选条件（用于区分同一事件的不同报表）
  - `columnName`：字段名
  - `ftv`：筛选值列表（Filter Value）
- `group_by`：分组字段列表（用于数据统计的维度）

**完整配置示例**：

参考真实案例：`examples/events_config_example.json`
- ✅ 包含 19 个事件的完整配置
- ✅ 涵盖各种事件类型（ActivityTotal、SendReward、CoinChange、ta_pageview 等）
- ✅ 包含多种筛选条件模式（无筛选、单筛选、多筛选）
- ✅ 分组字段从 2 个到 17 个不等，覆盖简单到复杂的场景
- ✅ 可直接作为复杂文档的配置模板

该示例来自实际活动埋点文档，经过验证可成功生成完整看板。

**步骤3：使用手动配置生成看板**

详见 [常见问题](03-troubleshooting.md#q1解析到的事件数量太少怎么办) 和 [examples/README.md](examples/README.md)

**快速使用**：参考 `examples/events_config_example.json` 创建配置，然后调用生成函数。

#### 飞书文档撰写最佳实践

**推荐格式**（解析器友好）：

```markdown
### 3.1 核心养宠物玩法

**事件名称：**ActivityTotal
**埋点场景：**抽奖时上报
**事件属性：**
activity_type = "lottery"
action = "do_wheel_lottery"
act_id = 158
activity = "爱乐之城·遇见幸运"
box_type = 1
lottery_num = 1
```

**格式要点**：
- ✅ 使用"**事件名称：**"明确标记
- ✅ 每个独立事件单独写一个小节（###）
- ✅ 固定值字段使用 `= "value"` 格式（带引号）
- ✅ 动态字段直接列出字段名
- ❌ 避免同一小节包含多个事件
- ❌ 避免使用【临时事件】、【组件事件】等特殊标记

### 步骤5：确认活动ID（act_id）

**重要**：在生成看板配置前，必须确认活动ID（act_id）是否正确。

#### 确认流程

1. **自动提取 act_id**
   - 系统从飞书文档中自动提取活动ID
   - 通常从文档标题、表格或事件属性中识别

2. **向用户展示并确认**

   ```text
   🔍 检测到活动ID: 6474

   请确认此活动ID是否正确：
   1. 正确 - 继续生成配置
   2. 不正确 - 手动输入正确的 act_id

   请选择（1 或 2）：
   ```

3. **处理用户响应**
   - **用户选择"1"（正确）**：直接使用检测到的 act_id
   - **用户选择"2"（不正确）**：提示用户输入正确的 act_id

     ```text
     请输入正确的活动ID（act_id）：
     ```

4. **使用确认的 act_id**
   - 将确认的 act_id 应用到所有 ActivityTotal 事件的筛选条件中
   - 确保看板配置中所有相关报表都使用正确的活动ID

#### 为什么需要确认

- ✅ **防止解析错误**：自动解析可能识别到错误的ID（如文档中的示例ID）
- ✅ **确保数据准确**：错误的 act_id 会导致看板显示错误活动的数据
- ✅ **避免返工**：提前确认可避免生成后才发现ID错误需要重新生成

#### 注意事项

- 如果文档中未找到 act_id，系统会提示用户手动输入
- 确认的 act_id 会自动添加到所有 ActivityTotal 事件的筛选条件中
- 这是数数看板配置生成的必需步骤，确保所有 ActivityTotal 事件都有正确的活动ID筛选

### 步骤6：生成数数看板配置

根据数数平台的 JSON 格式规范，自动生成看板配置：

#### 配置结构

```json
{
  "dashboardFolders": [...],  // 看板文件夹
  "notes": [],                // 备注
  "reports": [...],           // 报表列表
  "sharedSpaces": []          // 共享空间
}
```

#### 每个报表包含

- **frontConfig**：前端配置
  - displayQuotas：展示指标（事件名称、分析类型）
  - displayGroups：分组展示配置
  - visualInfo：可视化配置

- **openQuery**：查询配置
  - events：事件筛选条件
  - eventView：查询视图配置
    - **filts**：全局筛选条件
      - **国外项目**：包含 app_region 筛选（如 app_region = "C"）
      - **国内项目**：不包含 app_region 筛选
    - **groupBy**：分组字段列表
    - timeParticleSize：时间粒度
    - recentDay：时间范围

### 步骤7：配置全局筛选和分组

#### 全局筛选条件

**🚨 重要：国内项目和国外项目的筛选条件不同**

**国内项目（会玩、贪吃蛇小游戏、贪吃蛇app）**：

```json
"filts": [
  // 仅包含业务相关筛选，如 act_id
  // 不包含 app_region 筛选
]
```

**示例：国内项目（会玩）**
```json
"filts": [
  {
    "ftv": ["1001"],
    "comparator": "equal",
    "columnName": "act_id",
    "filterType": "SIMPLE"
  }
]
```
- ❌ 无 app_region 字段
- ✅ 仅包含业务筛选条件

**国外项目（海外区服）**：

根据用户选择的区服，为所有报表自动添加 app_region 全局筛选：

**示例：用户选择"华语服 (C)"**

```json
"filts": [
  {
    "ftv": ["C"],
    "comparator": "equal",
    "columnName": "app_region",
    "filterType": "SIMPLE"
  },
  {
    "ftv": ["1001"],
    "comparator": "equal",
    "columnName": "act_id",
    "filterType": "SIMPLE"
  }
]
```

**示例：用户选择"日服 (J)"**

```json
"filts": [
  {
    "ftv": ["J"],
    "comparator": "equal",
    "columnName": "app_region",
    "filterType": "SIMPLE"
  },
  {
    "ftv": ["1001"],
    "comparator": "equal",
    "columnName": "act_id",
    "filterType": "SIMPLE"
  }
]
```
- ✅ 包含 app_region 筛选
- ✅ 区分不同区服的数据

#### 智能分组字段

根据埋点事件的属性，自动添加分组字段：

**示例1：RoomWidget 事件（抽奖控件使用）**

```json
"groupBy": [
  {"columnName": "rid"},           // 房间ID
  {"columnName": "owner"},         // 房主uid
  {"columnName": "game_type"},     // 游戏类型
  {"columnName": "event_duration"}, // 控件使用时长
  {"columnName": "gamer_num"}      // 抽奖人数
]
```

**示例2：LotteryDraw 事件（抽奖）**

```json
"groupBy": [
  {"columnName": "game_type"},   // 游戏类型
  {"columnName": "rid"},         // 房间ID
  {"columnName": "user_num"},    // 抽奖时房间内人数
  {"columnName": "scope"},       // 范围（麦上/全员）
  {"columnName": "gamer_num"},   // 抽奖人数
  {"columnName": "join_way"},    // 参与方式
  {"columnName": "time_start"},  // 倒计时
  {"columnName": "lottery_id"}   // 抽奖特定ID
]
```

**示例3：AppClick 事件（按钮点击）**

```json
"groupBy": [
  {"columnName": "btn_name"},    // 按钮名称
  {"columnName": "screen_name"}, // 页面名称
  {"columnName": "game_type"},   // 游戏类型
  {"columnName": "rid"},         // 房间ID
  {"columnName": "label_type"},  // 标签类型
  {"columnName": "room_type"}    // 房间类型
]
```

### 步骤8：生成并保存JSON文件

#### 文件命名规则

**国内项目**：
```text
docs/<文档名称>_数数看板_<项目名>.json
```

文件命名示例：
- 会玩：`亚太6.3.0埋点_数数看板_会玩.json`
- 贪吃蛇小游戏：`亚太6.3.0埋点_数数看板_贪吃蛇小游戏.json`
- 贪吃蛇app：`亚太6.3.0埋点_数数看板_贪吃蛇app.json`

**国外项目**：
```text
docs/<文档名称>_数数看板_<区服名>.json
```

文件命名示例：
- 华语服：`亚太6.3.0埋点_数数看板_华语服.json`
- 日服：`亚太6.3.0埋点_数数看板_日服.json`
- 韩服：`亚太6.3.0埋点_数数看板_韩服.json`

#### 文件特点

- ✅ 格式化输出，易于阅读
- ✅ 包含完整的报表配置
- ✅ 自动配置筛选条件（国外项目包含 app_region，国内项目不包含）
- ✅ 可直接导入数数平台
- ✅ 支持自定义时间范围

### 步骤9：格式校验（必须执行）

**重要：生成JSON文件后，必须校验格式是否符合数数平台标准**

#### 快速校验

```bash
python3 scripts/validate_shushu_json.py docs/生成的文件.json
```

#### 校验时机

- ✅ 生成JSON文件后立即校验
- ✅ 导入数数平台前最后确认
- ✅ 导入失败后排查问题

#### 关键校验项

| 检查项 | 说明 |
|--------|------|
| **reportMappings** | 必须包含7个必需字段（详见[成功导入的关键要素](04-config-reference.md#成功导入的关键要素)） |
| **ui_config** | 必须存在且为字符串格式的JSON |
| **app_region** | 国外项目：全局筛选必须包含正确的区服代码；国内项目：不包含此字段 |
| **act_id** | 所有 ActivityTotal 事件必须包含 act_id 筛选条件 |
| **报表数量** | 每个看板最多30个报表（超过需拆分） |

#### 详细校验方法

- **格式校验**：`python3 scripts/validate_shushu_json.py docs/xxx.json`
- **模板对比**：`python3 scripts/compare_with_template.py docs/xxx.json`

#### 常见格式问题

| 问题 | 原因 | 解决方法 |
|------|------|---------|
| 未成功添加报表 | 缺少 reportMappings 字段 | 参考验证模板补充必需字段 |
| 导入后无数据 | app_region 值错误 | 检查区服代码是否正确 |
| ActivityTotal 数据不准确 | 缺少 act_id 筛选 | 使用步骤5确认的 act_id 重新生成 |
| 报表数量超限 | 超过30个报表 | 运行 `split_dashboard.py` 拆分 |

## 导入数数平台

### 导入步骤

1. 登录数数平台
2. 进入"看板管理"
3. 点击"导入看板"
4. 选择生成的 JSON 文件（位于 `docs/` 目录下）
5. 确认导入
6. 查看生成的看板和报表

### 导入后效果

- ✅ 自动创建看板文件夹
- ✅ 生成所有报表
- ✅ 配置好筛选条件
- ✅ 设置好分组维度
- ✅ 可直接查看数据

## 使用示例

### 示例1：国内项目（会玩）

**用户输入**：
```
帮我把这个 https://wepie.feishu.cn/wiki/EvOcwrbIfiXOW8kp9M4cYfCqn9e
生成 JSON 文件，我要导入到数数平台上面生成看板
```

**系统询问（步骤1）**：
```
这个埋点文档是国内项目还是国外项目？
1. 国内项目（会玩、贪吃蛇小游戏、贪吃蛇app）
2. 国外项目（海外区服）
```

**用户回答**：
```
1  （选择国内项目）
```

**系统询问（步骤2）**：
```
请选择国内项目：
1. 会玩
2. 贪吃蛇小游戏
3. 贪吃蛇app

请输入项目名称或序号：
```

**用户回答**：
```
1  （选择会玩）
```

**系统处理**：
- 转换飞书文档为 Markdown
- 解析埋点事件
- 生成看板配置（不包含 app_region 筛选）
- 保存为：`xxx_数数看板_会玩.json`

### 示例2：国外项目（华语服）

**用户输入**：
```
生成华语服的数数看板配置
https://wepie.feishu.cn/wiki/EvOcwrbIfiXOW8kp9M4cYfCqn9e
```

**系统询问（步骤1）**：
```
这个埋点文档是国内项目还是国外项目？
1. 国内项目（会玩、贪吃蛇小游戏、贪吃蛇app）
2. 国外项目（海外区服）
```

**用户回答**：
```
2  （选择国外项目）
```

**系统询问（步骤2）**：
```
请选择区服（app_region）：
1. 阿语服 ("A")
2. 土语服 ("Q")
3. 菲律宾服 ("P")
4. 越南服 ("V")
5. 华语服 ("C")
6. JK服 ("O")
7. 俄语服 ("R")
8. 葡语服 ("B")
9. 泰服 ("T")
10. 马尼服 ("M")
11. 美服 ("U")
12. 日服 ("J")
13. 韩服 ("K")
14. 印度服 ("I")
15. 西语服 ("S")
16. 巴基斯坦服 ("N")
17. 法语服 ("F")
18. 德语服 ("G")

请输入区服代码（如 C、J、K）或序号：
```

**用户回答**：
```
C  （选择华语服）
```

**系统处理**：
1. 清空临时文件
2. 使用 feishu2md 获取文档内容
3. 解析埋点事件（10个事件）
4. 生成数数看板配置
5. 添加全局筛选（app_region = "C"）
6. 为每个事件配置分组字段
7. 保存 JSON 文件

**输出文件**：
```
docs/亚太6.3.0埋点_数数看板_华语服.json (69K)
```

**包含报表**：
1. 抽奖控件使用（5个分组字段）
2. 抽奖（8个分组字段）
3. 抽奖弹窗曝光（4个分组字段）
4. 抽奖弹窗点击（5个分组字段）
5. 开奖弹窗曝光（4个分组字段）
6. 开奖弹窗点击（4个分组字段）
7. 开启耳返（6个分组字段）
8. 切换原声（6个分组字段）
9. 长按消息检举（3个分组字段）
10. 宠物游乐园入口点击（1个分组字段）

### 示例3：为不同区服生成看板（国外项目）

**场景1：日服看板**

**用户输入**：
```
生成日服的数数看板
```

**系统询问并处理**：
- 确认为国外项目
- 选择 J-日服
- 自动设置 app_region = "J"
- 文件命名：`亚太6.3.0埋点_数数看板_日服.json`

**场景2：韩服看板**

**用户输入**：
```
生成韩服的数数看板
```

**系统询问并处理**：
- 确认为国外项目
- 选择 K-韩服
- 自动设置 app_region = "K"
- 文件命名：`亚太6.3.0埋点_数数看板_韩服.json`

### 示例4：国内项目多项目对比

**场景1：会玩项目**
- 选择国内项目 → 会玩
- 文件命名：`xxx_数数看板_会玩.json`
- 配置特点：无 app_region 筛选

**场景2：贪吃蛇小游戏**
- 选择国内项目 → 贪吃蛇小游戏
- 文件命名：`xxx_数数看板_贪吃蛇小游戏.json`
- 配置特点：无 app_region 筛选

**场景3：贪吃蛇app**
- 选择国内项目 → 贪吃蛇app
- 文件命名：`xxx_数数看板_贪吃蛇app.json`
- 配置特点：无 app_region 筛选

## 注意事项

1. **项目类型和区服选择**：
   - **必须**：生成看板前必须先确认项目类型（国内/国外）
   - **国内项目**：
     - 支持3个项目：会玩、贪吃蛇小游戏、贪吃蛇app
     - **不包含** app_region 筛选条件
     - 文件名格式：`活动名_数数看板_项目名.json`
   - **国外项目**：
     - 支持18个海外区服
     - **包含** app_region 筛选条件
     - 文件名格式：`活动名_数数看板_区服名.json`
   - 系统会自动询问项目类型和具体选择

2. **飞书配置要求**：
   - 需要配置 FEISHU_APP_ID 和 FEISHU_APP_SECRET
   - 配置文件位置：`.env` 或环境变量
   - 确保有飞书文档的访问权限

3. **文档格式要求**：
   - 文档中需要包含明确的埋点事件信息
   - 包含事件名称、属性、场景等关键信息
   - 支持表格、列表等多种格式

4. **分组字段选择**：
   - 所有不确定值的字段都应该加入分组
   - 避免遗漏重要的分析维度
   - 根据实际业务需求调整分组

5. **时间范围配置**：
   - 默认时间范围：最近7天
   - 可在生成后手动调整
   - 支持自定义时间粒度（天/小时/分钟）

6. **报表ID分配**：
   - 自动从 70001 开始递增
   - 避免与现有报表ID冲突
   - 可在导入前手动修改

7. **多区服支持**：
   - 同一份埋点文档可以为不同区服生成独立的看板
   - 每个区服的看板配置相同，仅 app_region 筛选值不同
   - 建议为每个需要的区服都生成一份看板配置

---

## 配置示例对比

### 国内项目 vs 国外项目

#### 国内项目配置示例（会玩）

```json
{
  "reports": [
    {
      "name": "活动总计",
      "openQuery": {
        "eventView": {
          "filts": [
            {
              "columnName": "act_id",
              "comparator": "=",
              "ftv": ["1001"]
            }
          ],
          "groupBy": ["activity_type", "action", "activity_name"]
        }
      }
    }
  ]
}
```

**特点**：
- ✅ 无 app_region 筛选
- ✅ 仅包含业务相关的筛选条件（如 act_id）
- ✅ 适用于国内单一项目

#### 国外项目配置示例（华语服）

```json
{
  "reports": [
    {
      "name": "活动总计",
      "openQuery": {
        "eventView": {
          "filts": [
            {
              "columnName": "app_region",
              "comparator": "=",
              "ftv": ["C"]
            },
            {
              "columnName": "act_id",
              "comparator": "=",
              "ftv": ["1001"]
            }
          ],
          "groupBy": ["activity_type", "action", "activity_name"]
        }
      }
    }
  ]
}
```

**特点**：
- ✅ 包含 app_region = "C" 筛选
- ✅ 过滤出华语服的数据
- ✅ 适用于多区服部署的国外项目

### 关键差异总结

| 项目 | app_region 筛选 | 文件命名 | 适用场景 |
|------|----------------|----------|---------|
| **国内项目** | ❌ 无 | `活动_数数看板_会玩.json` | 会玩、贪吃蛇小游戏、贪吃蛇app |
| **国外项目** | ✅ 有 | `活动_数数看板_华语服.json` | 海外18个区服 |

### 生成流程差异

**国内项目**：
```
1. 询问项目类型 → 国内
2. 选择项目（会玩/贪吃蛇小游戏/贪吃蛇app）
3. 生成配置（无 app_region）
```

**国外项目**：
```
1. 询问项目类型 → 国外
2. 选择区服（C/J/K等）
3. 生成配置（含 app_region 筛选）
```
