11 KiB
线索状态机权威定义
Type: grilling Status: resolved Resolved: 2026-08-13
Question
将散落在各原型页面的状态收敛为 crm-lead 的权威状态机,作为全域第一块地基。已定:单字段、7 个状态——待领取 / 已领取 / 未分发 / 过期失效 / 线索作废 / 已转商机 / 跟进中。
需在本 ticket 定清:
- 每个状态的精确定义。
- 合法迁移边:状态转移图。
- 各状态下允许的操作:状态 × 操作权威矩阵。
- 回收对状态的影响。
产出:状态定义表 + 状态转移图 + 状态 × 操作矩阵,写入 ## Answer。
Answer
一、状态定义表(单字段 leadStatus,7 态)
| 状态 | 含义 | 领取人 | 计时器 | 备注 |
|---|---|---|---|---|
| 未分发 | 管理员新建/导入,未归属任何公海池,悬于池外 | 无 | 失效(M)跑 | 仅管理员可分配 |
| 待领取 | 已分配进某公海池,尚无归属销售,池内成员可自领 | 无 | 失效(M)跑 | 领取/分配的来源态 |
| 已领取 | 某销售持有、尚未产生反馈 | 有 | 回收(N)跑 + 失效(M)跑 | 领取后即可转商机 |
| 跟进中 | 持有销售已产生至少一次反馈 | 有 | 回收(N)跑 + 失效(M)跑 | 反馈使 已领取→跟进中 |
| 已转商机 | 已转化为商机,终态 | 保留 | 全部冻结 | 不可释放/回收/失效/反馈 |
| 过期失效 | 失效计时(M)到期;可发生在任何非终态 | 失效时若被持有则保留、否则无 | 冻结(除激活重置) | 只读;可被管理员激活恢复 |
| 线索作废 | 销售提交反馈且反馈情况=无效时自动进入。可恢复 | 进入时清空;分配后重新写入 | 失效(M)继续跑 | 管理员可分配;被分配销售提交反馈=有效时恢复→已领取 |
反馈情况(有效/无效/未反馈)是独立字段,不进状态机。
二、状态转移图
┌─────────────── 管理员分配到池 ───────────────┐
│ ▼
[新建/导入未归池] [待领取] ◀────────────┐
│ │ │ │
▼ │ │ │ 释放 / 超时回收N
┌─[未分发] │ └──领取/分配──┐ (清领取人)
│ │ 分配到池 │ ▼ │
│ └──────────────────────────────────────────▶ │ [已领取]─┘
│ │ 分配并指定销售 │ │
│ └───────────────────────────────────────────────────────────▶ │ 反馈(首次)
│ ▼
│ [跟进中]
│ │
│ 转商机(已领取/跟进中) │
│ ─────────────────────────────────▶ [已转商机](终态)
│
│ 失效计时M到期(从创建时间算,不清零,任何非终态)
└──────────────────────────────────────────────▶ [过期失效]
│ ▲
管理员激活(F2,恢复失效前态+原领取人,重置N和M)
└──┘
已领取/跟进中
→ [提交反馈,反馈情况=无效] → [线索作废] (清空owner_id)
│ ▲
管理员分配给新销售(仍保持作废状态)
新销售提交反馈,反馈情况=有效 → [已领取]
└──┘
三、迁移边清单
| # | from | 触发 | to | 副作用 |
|---|---|---|---|---|
| 1 | (新建·管理员未归池) | 新建/导入 | 未分发 | 启动失效计时M(创建时间) |
| 2 | (新建·已归池/销售新增) | 新建/导入(指定池) | 待领取 | 启动失效计时M |
| 3 | 待领取(销售新增勾"领取") | 新增即领 | 已领取 | 设领取人=本人;启动回收计时N |
| 4 | 未分发 | 管理员分配到池 | 待领取 | 归池 |
| 5 | 未分发/待领取 | 管理员分配并指定销售 | 已领取 | 设领取人=被指派销售;启动回收N |
| 6 | 待领取 | 成员自助领取 | 已领取 | 设领取人=本人;启动回收N |
| 7 | 已领取 | 首次反馈 | 跟进中 | 写反馈记录 |
| 8 | 跟进中 | 再次反馈 | 跟进中(自环) | 写反馈记录;回收N续期 |
| 9 | 已领取/跟进中 | 转商机 | 已转商机(终态) | 调 OpportunityCreationPort;冻结所有计时器 |
| 10 | 已领取/跟进中 | 手动释放 | 待领取 | 清领取人;回收计时N清零 |
| 11 | 已领取/跟进中 | 超时回收(N天无跟进) | 待领取 | 清领取人;回收计时N清零 |
| 12 | 任何非终态 | 失效计时M到期 | 过期失效 | 若被持有则保留领取人;只读 |
| 13 | 过期失效 | 管理员激活(F2) | 恢复失效前状态+原领取人 | 重置N和M(recycle_deadline=now+pool.N,expire_deadline=now+pool.M) |
| 14 | 已领取/跟进中 | 提交反馈且反馈情况=无效 | 线索作废 | 清空owner_id;失效计时M继续跑 |
| 15 | 线索作废 | 管理员分配给销售 | 线索作废(仍作废) | 写入新owner_id;状态不变 |
| 16 | 线索作废 | 被分配销售提交反馈且反馈情况=有效 | 已领取 | owner_id=当前销售;启动回收N |
计时器口径:
- 回收N:仅私海(已领取/跟进中)计时;"无跟进"=N天内无新反馈;有反馈则续期重计N;退回公海则清零。
- 失效M:从创建时间起全程持续跑,线索作废状态下继续跑;仅"已转商机"冻结、"管理员激活"重置。
四、状态 × 操作 权威矩阵
(✓=可操作,✓—=不可见/不可操作;角色权限叠加见 ticket 05)
| 操作 | 未分发 | 待领取 | 已领取 | 跟进中 | 已转商机 | 过期失效 | 线索作废 |
|---|---|---|---|---|---|---|---|
| 详情(查看) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 编辑 | ✓ | ✓ | ✓(持有人) | ✓(持有人) | ✓—(终态锁) | ✓—(只读) | ✓ |
| 领取 | ✓— | ✓(成员) | ✓— | ✓— | ✓— | ✓— | ✓— |
| 分配 | ✓(管理) | ✓(管理) | ✓— | ✓— | ✓— | ✓— | ✓(管理) |
| 反馈 | ✓— | ✓— | ✓(持有人) | ✓(持有人) | ✓—(终态锁) | ✓— | ✓(持有人) |
| 转商机 | ✓— | ✓— | ✓(持有人) | ✓(持有人) | ✓— | ✓— | ✓— |
| 释放 | ✓— | ✓— | ✓(持有人) | ✓(持有人) | ✓— | ✓— | ✓— |
| 关注/取关 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 删除 | ✓(管理/创建人) | ✓(管理/创建人) | ✓(管理/创建人·强确认) | ✓(管理/创建人·强确认) | ✕禁止(终态) | ✓(管理/创建人·强确认) | ✓(管理/创建人·强确认) |
| 激活 | ✓— | ✓— | ✓— | ✓— | ✓— | ✓(管理) | ✓— |
删除权限全局规则(2026-08-13 修正):
删除 = (状态 ≠ 已转商机) AND (管理员 OR 创建人·强确认)。已转商机是唯一删除禁区(终态,下游商机source_lead_id依赖);之前矩阵里"持有人可删过期失效"的规则废止,改为"创建人可删"。线索作废操作说明:
- 编辑:可以编辑(业务字段)。
- 反馈:被分配的持有人可以提交反馈;反馈情况=有效时自动触发边 #16(→已领取);反馈情况=无效时保持作废。
- 分配:管理员可以将作废线索分配给其他销售;分配后仍保持作废状态。
- 删除:管理员或创建人,强确认。
已 grill 定稿的结论(grill 过程增量记录)
- [A] 未分发 vs 待领取:未分发=未归池;待领取=已归池待领。
- [A-初始态]:销售新增→归池→待领取;管理员未指定池→未分发;指定池→待领取。
- [A-分配]:分配可只到池(未分发→待领取)或一步到销售(→已领取)。
- [B] 转商机前置:已领取或跟进中即可转,不强制先反馈。
- [D] 过期失效归属:失效可发生在任何非终态;持有态失效仍挂领取人名下只读。
- [E] 双计时器:回收N从领取起,有反馈续期;失效M从创建时间起,线索作废下继续跑,不清零。
- [F] 激活目标态:F2 恢复原态+原领取人;重置N和M。
- [G] 释放/回收目标态:待领取+清领取人。
- [H] 已转商机终态:终态锁死,编辑/反馈不可操作。
- [C] 线索作废(2026-08-13 产品确认):
- A1:反馈=无效时自动触发,无需手动点按钮。
- A2:入口状态=已领取/跟进中(能提交反馈的状态)。
- A3:可恢复;管理员分配给销售,销售提交反馈=有效,恢复到已领取。
- A4:进入作废时清空owner_id;分配时写入新owner_id。
- 删除权限全局修正(2026-08-13):全状态=管理员 OR 创建人,强确认。
Amendment 1(2026-08-12 grill)
A1.1 边 #13 激活时 N 也重置
激活时 N 和 M 均重置:recycle_deadline = now + pool.recycle_days,expire_deadline = now + pool.expire_days。
A1.2 过期失效线索可删
矩阵"过期失效 × 删除"= ✓(管理/创建人·强确认)(2026-08-13 进一步修正为创建人替换原持有人)。
Amendment 2(2026-08-13 续 grill)
A2.1 定时任务执行顺序:失效先、回收后(grill #4,ADR-0019)
一条「已领取/跟进中」线索的 recycle_deadline 与 expire_deadline 可能同时过期。固定失效 Job 先跑、回收 Job 后跑:失效把状态改为过期失效(保留 owner)后,回收 Job 的 WHERE status IN ('已领取','跟进中') 天然扫不到它,两者不再竞争。同一条两 deadline 同时过期时最终态为“过期失效(保 owner)”,可被激活连 owner 恢复。节奏:每日 02:00 全库扫。
A2.2 状态迁移统一用状态 CAS 乐观锁(grill #8,ADR-0021)
所有状态迁移的 UPDATE lead 一律带 AND status IN (合法起始态) 作 CAS;行数=0 即判定「已被他人操作」失败。适用领取/分配/激活/释放/反馈/转商机全部边,以及定时任务的 WHERE status IN (...)。批量领取/分配/激活均非原子、逐条 CAS,“部分成功”的“失败” = CAS 行数 0。