# 新 lead 回应审查：让销售团队在系统里直接看、直接更新

2026-09-26 · Wai Kit

今天要看「8-23 之后进来的新 lead，谁在 WhatsApp / Zoom / AI call 回应了、说了什么」，只能把四张表
（leads、whatsapp_messages、zoom_meetings、ai_voice_calls）拉出来手工整理成 Excel。这份文件说明系统要加什么，
让销售经理在 Leads 页面直接筛出同一份名单，销售员在同一行里更新跟进结果，不再传 Excel。

## 已经有的，不要重做

| 已有 | 在哪里 |
| --- | --- |
| Leads 列表、筛选、导出（`ExportMenu`） | `Manage/Leads/Index.vue`、`LeadQueryRequest`、`LeadsExport` |
| 每个报名的跟进状态 `follow_up_status`（NPU / Called / Attended Zoom / Not keen / Scheduled …） | `lead_funnels`，`LeadFunnel::FOLLOW_UPS` |
| Agent / Fake 人工判定 | `leads.agent_verdict` / `fake_verdict`，`LeadQualityTags.vue` |
| 「欠客户一个 WhatsApp 回复」 | `ReplyOwed`、列表的 `needs_reply` 筛选 |
| Pay Attention 名单（14 个 flag） | `AttentionFlags` |
| AI call 的完整记录，含 AI 分析 JSON | `ai_voice_calls.analysis` → `custom_analysis_data.interest_level / will_attend / wants_followup` |

缺的不是数据，是把这些数据**按人合成一行**，加上**销售员能改的两个字段**。

## 要加的四样东西

### 1. Leads 列表加一个「回应 Response」栏（系统自动算，不用人填）

每个 lead 一行，三个小格。规则就是这次 Excel 用的规则，写死在一个 support class（建议 `Src\Lead\Support\FirstResponse`），
列表栏、筛选和导出都读同一个 class，不要各写一份。

| 小格 | 值 | 怎么算 |
| --- | --- | --- |
| WhatsApp | 无 / 只按按钮 / 有打字 | 该 lead 的 1:1 conversation 里 `direction = in` 的讯息。`type = 9`（按钮快捷回复，"Yes, 我已进群了" / "好的我会出席"）算「只按按钮」；任何其他 type 算「有打字」。hover 显示最后一条打字讯息前 80 字和时间 |
| AI call | 没打 / 没接通 / 接通没说需求 / 接通有兴趣 | 读该 lead 所有 `ai_voice_calls`。**没接通** = 没有一通 `lead_spoke = 1` 且 `duration_seconds > 10`（2–7 秒的 voicemail 也算没接通），再细分原因：无人接听 `dial_no_answer`、拒接 `user_declined`、占线、号码打不出 `telephony_provider_permission_denied`、provider 故障 `telephony_provider_unavailable`、接了立刻挂 `user_hangup`。**接通有兴趣** = `analysis.custom_analysis_data.interest_level` 是 medium / high / hot / warm，或 `will_attend = true`，或 `wants_followup = true`；其余接通的算**接通没说需求** |
| Zoom | 次数 | `zoom_meetings.lead_id` + `zoom_consultations.lead_id` |

筛选：三个小格各一个 multi-select（例：WhatsApp = 有打字；AI call = 接通有兴趣）。
排序：按最后一次回应时间。
导出：`LeadsExport` 加这三栏加「最后打字讯息」。

### 2. 销售员手填的两个字段（新增，放在 `leads` 上）

| 字段 | 类型 | 选项 |
| --- | --- | --- |
| `interest` 兴趣 | 单选 | Event（对 webinar / 训练营）、Product（对 Cochrane 等项目）、Service（贷款评估、卖房等服务）、Not a customer（agent / 公司自动回复）、Unclear（接触了但问不出） |
| `response_note` 他说了什么 | 一行文字 ≤ 200 字 | 例：「要 membership + Cochrane + AI class；AI 打了 3 次没接」 |

- 每个字段带 `_by` / `_at`，谁改的、什么时候，和 `agent_verdict` 一样的做法。
- **AI 可以预填，销售员确认后才算数**（和 2026-09-25 五项标签的决定一致）：`interest` 由 AI call 的 `custom_analysis_data` 预填成建议值，
  显示为灰色「AI 建议」，销售员点一下才变成正式记录；`response_note` 预填 AI call 的 `call_summary` 第一句或最后一条打字讯息。
- **在列表的行里直接改**（和 Status、Verdict 下拉一样），也在 `LeadDetailModal` 里改。不做新页面。
- 这两个字段是**第一次接触**的记录；2026-09-25 提的五项标签是 **Zoom 之后**的深度记录。两套不合并，但同在 lead 上。
- 路由：`POST manage/leads/{id}/first-response`（`FirstResponseRequest`：`interest` nullable in 选项；`response_note` nullable string max 200），
  `LeadRepository::setFirstResponse()`，权限 `MANAGE_LEADS` + `LeadVisibility`。

### 3. 「建立日期」范围筛选

销售经理要问的是「8-23 之后进来的」。Leads 列表如果还没有按 `leads.created_at` 的日期范围筛选，加一个（`useResourceIndex` 的 `dateRange: true`）。
默认不设范围，页面行为不变。

### 4. 三个新的 Pay Attention flag + 一个系统修正

| Flag | 问题 | 规则 |
| --- | --- | --- |
| `unreachable_number` 号码打不出 | AI 每次打都被 provider 拒 | 该 lead 每一通 `ai_voice_calls` 都是 `telephony_provider_permission_denied` 或 `refusal_reason = not_placed`。这次 12 个 +65 号码全部如此 |
| `typed_no_reply` 打字了没人回 | 客户打字进来，系统里没有我们的回复 | WhatsApp = 有打字，且该 conversation 在客户最后一条打字之后没有 `direction = out`。先确认 `needs_reply` 是否已覆盖；这次有 26 人 |
| `duplicate_phone` 重复 lead | 同一个电话两条 lead | `user_profiles.phone` 相同（去掉非数字后比较）。这次 Carmen 是 #15650 和 #16433 |

系统修正：AI caller 对 +65（新加坡）号码每次都失败，是 Twilio 的 geo-permission 没开。要么在 Twilio 开 Singapore，
要么 AI caller 遇到非 +60 号码直接跳过并标 `unreachable_number`，让人用 WhatsApp 跟进，不要一直空打。

## 一个例子

Kelvin Hong，8-23 从「Trust Nurturing」ads 进来。

| 栏 | 系统自动显示 | 销售员填 |
| --- | --- | --- |
| Response · WhatsApp | 有打字 · 8-25「请问还有其他天吗？」 | |
| Response · AI call | 接通有兴趣（130 秒，interest = medium） | |
| Response · Zoom | 0 | |
| Interest | AI 建议：Event | 销售员改成 **Service**（AI call 里他说想卖 1–2 间房） |
| 他说了什么 | | 「明天出席不了，问其他场次；想卖 1–2 间，关心楼市走势」 |
| follow_up_status（已有） | | Called |

销售经理筛「建立日期 8-23 ~ 今天、AI call = 接通有兴趣」就得到这次 Excel 的「AI 有兴趣」表；
筛「WhatsApp = 有打字」得到「WA 打字回复」表；导出就是同一份 Excel。

## 验收

1. 筛 8-23 ~ 9-26，Response 三格的人数和这次的 Excel 一致：WhatsApp 有打字 50、只按按钮 93、AI 接通有兴趣 27、AI 没接通 201。
2. 在列表行里改 Interest，刷新后还在，`interest_by` 是改的人。
3. 导出的 Excel 有新的栏，数字和页面一样。
4. Pay Attention 面板出现三个新 flag，`/manage/leads/pay-attention` 规则书有它们的解释。
5. `php artisan test --filter=Lead` 全绿；每个新规则有一个测试。

## 不要做的

- 不做新页面，不做新的 AI call，不改 `follow_up_status` 的选项。
- 「回应」栏不写进数据库，每次从四张表算（列表已经这样算 `wa_pending_count`）；只有销售员填的两个字段才是新栏位。
- 这份 Excel 里的姓名电话是客户资料，只在团队内传，不要贴进 ticket。
