# 前端埋点审查流程（TypeScript/JavaScript）

## 核心功能

1. **代码分析** - 扫描代码库中的埋点实现
2. **参数验证** - 验证 sub_source、source、event_name 等参数
3. **跨场景验证** - 检查游戏页、结算页、准备页的埋点一致性
4. **报告生成** - 生成详细的审查报告，包含问题和修复方案
5. **验证方法** - 提供代码审查和浏览器控制台测试方法

## 使用流程

### 第零步：理解游戏架构（重要！）

在开始审查前，必须先理解游戏的场景结构：

```bash
# 1. 查找游戏状态定义
Grep pattern: "enum.*GameState|eGameState|GameState.*=|场景"

# 2. 查找场景文件
Glob pattern: "**/*Scene*.ts" or "**/scenes/*.ts"

# 3. 理解状态切换
Grep pattern: "GameState.*Init|GameState.*Prepare|GameState.*Over" with context
```

**关键问题**：
- ❓ 游戏有几个独立场景？（准备页、游戏页、结算页是独立场景还是状态？）
- ❓ 玩家头像在哪些状态下显示？
- ❓ HeadComp等组件在何时初始化？

**常见架构模式**：

1. **多场景模式** - 准备页/游戏页/结算页是独立的Scene
2. **单场景状态机** - 只有一个Game场景，通过状态切换（如Mancala）
3. **弹窗模式** - 结算页是Alert弹窗而非独立场景

⚠️ **不要假设所有游戏都有完整的"准备页-游戏页-结算页"三个场景！**

### 第一步：明确审查范围

询问用户：

1. **审查什么？**
   - 特定事件（AddFriend、SendGift、页面浏览、自定义事件）
   - 特定参数（sub_source、source、event_name 等）
   - 所有埋点实现

2. **审查哪里？**
   - 特定页面/场景（游戏页、结算页、准备页）
   - 特定组件（Player、HeadComp、UI 组件）
   - 整个代码库

3. **输出格式？**
   - 汇总表格
   - 详细报告（含代码片段）
   - 验证方法
   - 修复建议

### 第二步：定位埋点代码

使用系统化的搜索方法：

```typescript
// 使用 Grep 工具的搜索模式：
1. 事件名称: "AddFriend|SendGift|trackScreen|trackEvent"
2. 方法调用: "showUserDialog|clickAddFriend|sendGift|track"
3. 参数: "sub_source|subSource|source"
4. 组件名称: "HeadComp|Player|GameOverAlert|GameLayer"
```

**关键文件检查清单**：
- 平台集成文件（WeplayBase、Platform adapters）
- 处理用户交互的组件文件
- 场景/页面初始化文件
- 工具/辅助文件（TrackUtils 等）

### 第三步：构建埋点调用图

追踪完整的调用链：

```
用户操作
  ↓
UI 组件方法（如 onAvatarClicked）
  ↓
业务逻辑（如 showUserDialog）
  ↓
平台/SDK 方法（如 platform.showUserDialog）
  ↓
原生埋点事件（如 AddFriend 事件）
```

在每一步识别：
- 参数在哪里定义
- 参数如何传递
- 参数是否丢失或被更改

### 第四步：验证参数一致性

为每个场景创建验证表格：

| 场景 | 组件 | 方法 | 参数 | 期望值 | 实际值 | 状态 |
|------|------|------|------|--------|--------|------|

常见问题检查：

1. **硬编码值** - 参数硬编码而非动态传递
2. **缺失参数** - 调用方法时缺少必需参数
3. **作用域错误** - 同一组件在不同场景使用但上下文错误
4. **命名不一致** - 同一概念使用不同名称

### 第五步：生成审查报告

报告结构：

#### 汇总表格
- 发现的埋点总数
- 按严重程度分类的问题（Critical、Warning、Info）
- 按场景/页面的覆盖率

#### 详细发现
每个问题包含：
- **问题 ID** - 唯一标识符
- **严重程度** - Critical / Warning / Info
- **位置** - 文件路径和行号
- **描述** - 问题说明
- **当前代码** - 显示问题的代码片段
- **期望行为** - 应该如何工作
- **修复建议** - 具体的代码修复
- **影响** - 哪些测试用例会失败

#### 代码示例
包含：
- ✅ 正确的实现（参考示例）
- ❌ 错误的实现（发现的问题）
- 🔧 修复后的代码（推荐的改动）

### 第六步：提供验证方法

提供验证指南：

1. **代码审查清单** - 逐步验证每个调用点
2. **浏览器测试方法** - 在控制台mock埋点方法拦截参数
3. **快速测试指南** - 手动测试步骤和预期结果

## 常见埋点模式

### 模式 1：通过用户弹窗的社交互动

```typescript
// 正确模式
HeadComp.setup(uid, avatar, subSource)  // subSource 由场景决定
  ↓
HeadComp.onAvatarClicked()
  ↓
platform.showUserDialog(uid, this.subSource)  // 传递 subSource
  ↓
用户在弹窗中点击 AddFriend/SendGift
  ↓
原生埋点使用正确的 sub_source
```

### 模式 2：直接操作按钮

```typescript
// ❌ 错误模式 (Mancala结算页的问题)
async onBtnAddClicked() {
    let uid = this.localPlayer.uid;
    const isFriend = await app.platform.clickAddFriend(uid);  // 缺少subSource!
    this.addNode.active = !isFriend;
}

// ✅ 正确模式
async onBtnAddClicked() {
    let uid = this.localPlayer.uid;
    const isFriend = await app.platform.clickAddFriend(uid, "结算页");  // 传递subSource
    this.addNode.active = !isFriend;
}
```

**调用链**：
```
组件初始化时设置 subSource 属性
  ↓
按钮点击处理器
  ↓
platform.clickAddFriend(uid, this.subSource)  // 使用实例的 subSource
  ↓
原生埋点使用正确的 sub_source
```

### 模式 3：组件跨场景复用

```typescript
// 问题：同一组件在多个场景使用
Player.initPlayer(data, "游戏页")     // 游戏场景 - 正确
Player.initPlayer(data, "结算页")     // 结算场景 - 正确
Player.initPlayer(data)               // 缺少 subSource - 错误！

// 解决方案：初始化时始终传递 subSource
```

## Sub_Source 验证规则

### 标准 Sub_Source 值

基于常见游戏结构：

- `"准备页"` - 准备/等待房间场景
- `"游戏页"` - 活跃游戏场景
- `"结算页"` - 游戏结束/结算场景
- `"大厅"` - 大厅/主页场景
- `"房间"` - 房间场景
- `"好友列表"` - 好友列表页面

**不要使用**：
- 实现细节："头像旁快捷加好友"、"弹窗加好友"
- 技术术语："HeadComp"、"Player component"
- 通用术语："按钮"、"点击"

### 验证清单

对于每个埋点调用，验证：

- [ ] Sub_source 值与场景名称匹配
- [ ] Sub_source 在共享组件中不是硬编码
- [ ] Sub_source 在整个调用链中传递
- [ ] Sub_source 格式一致（中文页面名或英文键）
- [ ] Sub_source 在参数转发过程中没有丢失

## 分析技术

### 技术 1：基于 Grep 的搜索

```bash
# 查找所有埋点调用
Grep pattern: "showUserDialog|clickAddFriend|sendGift"

# 查找所有 sub_source 赋值
Grep pattern: "sub_source|subSource" with context lines

# 查找组件初始化
Grep pattern: "setup\\(|initPlayer\\(|init\\(" with context
```

### 技术 2：调用链追踪

对于每个埋点事件：
1. 找到原生/平台方法
2. 搜索所有调用者（向后追溯）
3. 追踪每层的参数流
4. 识别参数的起源

**标准追踪模板**：

```
场景初始化 (Game.ts / GameOverAlert.ts)
  ↓ [确认场景何时创建组件]
组件初始化 (Player.initPlayer / GameOverPlayer.initPlayer)
  ↓ [检查initPlayer调用]
头像初始化 (Player.initHead / GameOverPlayer.initHead)
  ↓ [检查HeadComp.setup调用及subSource值]
HeadComp.setup(uid, avatar, subSource)
  ↓ [确认subSource被存储]
用户点击头像
  ↓
HeadComp.onAvatarClicked()
  ↓ [检查是否使用this.subSource]
app.platform.showUserDialog(uid, this.subSource)
  ↓ [查看WeplayBase接口定义]
原生SDK处理 → AddFriend/SendGift事件
  ↓
埋点上报 (sub_source参数)
```

**每一步验证**：
- ✅ 参数是否传递？
- ✅ 参数值是否正确？
- ✅ 参数是否丢失？
- ✅ 是否有硬编码？

### 技术 3：交叉引用验证

构建矩阵：

```
         | 游戏页    | 结算页    | 准备页      |
---------|-----------|-----------|-------------|
HeadComp | ✅ "游戏页" | ❌ "游戏页" | ? 未找到     |
AddBtn   | ❌ "快捷"   | N/A       | N/A         |
```

### 技术 4：组件复用分析

找到在多个场景使用的组件：
1. 识别共享组件（Player、HeadComp 等）
2. 找到所有初始化点
3. 检查是否传递场景上下文
4. 验证上下文是否正确使用

## 报告模板

### 执行摘要模板

```markdown
# 埋点审查报告

**审查日期**: {date}
**项目**: {project_name}
**范围**: {scope_description}

## 摘要

- **埋点总数**: {count}
- **发现问题**: {critical} 个 Critical，{warning} 个 Warning
- **覆盖率**: {scenes_checked}/{total_scenes} 个场景

## 关键发现

1. {最关键的问题}
2. {第二关键的问题}
3. {其他值得注意的问题}

## 建议

{整体修复优先级和方法}
```

### 详细问题模板

```markdown
### 问题 #{id}: {标题}

**严重程度**: {Critical/Warning/Info}
**位置**: [{file}:{line}]({file_link})
**组件**: {component_name}
**场景**: {scene_name}

**问题描述**:
{问题说明}

**当前代码**:
```{language}
{code_snippet}
```

**期望行为**:
{应该如何工作}

**修复建议**:
```{language}
{fixed_code}
```

**影响**:
- 受影响的测试用例: {test_case_ids}
- 埋点准确性: {impact_description}
```

## 沟通指南

### 展示发现时：

1. **从摘要开始** - 详细信息之前先提供高层概览
2. **使用可视化** - 用表格、图表展示复杂关系
3. **提供上下文** - 解释为什么问题重要
4. **具体明确** - 包含文件路径、行号、准确的参数值
5. **提供解决方案** - 不仅指出问题，还要建议修复
6. **优先排序** - 帮助用户首先关注关键问题

### 好的摘要示例：

> "我发现了 3 个 sub_source 参数问题：
> 1. ❌ **Critical**: 结算页使用错误的 sub_source（"游戏页" 应为 "结算页"）
> 2. ❌ **Warning**: 快捷加好友按钮使用实现细节（"头像旁快捷加好友"）
> 3. ⚠️ **Info**: 未找到准备页埋点 - 可能尚未实现
>
> 建议首先修复问题 #1 和 #2，因为它们影响埋点准确性。"

## 输出交付物

审查结束时提供：

1. **主报告**（Markdown）：执行摘要、详细发现、修复建议、验证计划
2. **验证指南**：代码审查清单、浏览器测试方法、手动测试步骤
3. **快速参考**（Markdown）：汇总表格、验证要点、修复优先级
4. **代码修复**（如果需要）：修复后的代码片段、显示更改的 Diff

## Mancala游戏案例

### 关键学习点

- 游戏采用单场景状态机模式，没有独立准备页
- 区分两种埋点模式：通过原生弹窗 vs 直接按钮调用
- 结算页加好友按钮缺少subSource参数

### 测试流程示例

```
1. 理解架构 → 发现GameStateInit/Prepare是状态而非场景
2. 定位组件 → Player.ts和GameOverPlayer.ts
3. 追踪调用链 → HeadComp.setup → showUserDialog
4. 发现问题 → GameOverPlayer加好友按钮缺少subSource
5. 生成报告 → 包含调用链图、代码对比、修复建议
```

### 适用场景

- 测试多场景埋点参数传递
- 验证复用组件的subSource正确性
- 识别直接按钮调用缺少参数的问题
