@ -95,7 +95,7 @@
| 10 | 已领取 / 跟进中 | 手动【释放】 | 待领取 | 清领取人;N 停 |
| 10 | 已领取 / 跟进中 | 手动【释放】 | 待领取 | 清领取人;N 停 |
| 11 | 已领取 / 跟进中 | 超时回收(N 到期无跟进) | 待领取 | 清领取人;N 停 |
| 11 | 已领取 / 跟进中 | 超时回收(N 到期无跟进) | 待领取 | 清领取人;N 停 |
| 12 | 未分发 / 待领取 / 已领取 / 跟进中 | 失效计时 M 到期 | 过期失效 | 若被持有则保留领取人;只读 |
| 12 | 未分发 / 待领取 / 已领取 / 跟进中 | 失效计时 M 到期 | 过期失效 | 若被持有则保留领取人;只读 |
| 13 | 过期失效 | 管理员【激活】 | 恢复失效前状态与原领取人 | M 重置(起点=激活时刻) |
| 13 | 过期失效 | 管理员【激活】(单条/批量) | 恢复失效前状态与原领取人 | **N 和 M 均 重置** (起点=激活时刻,`recycle_deadline = now + pool.N`,`expire_deadline = now + pool.M` ) |
| C | ⚠ | ⚠ | 线索作废 | ⚠ 待确认(A) |
| C | ⚠ | ⚠ | 线索作废 | ⚠ 待确认(A) |
### 3.3 状态 × 操作 权威矩阵
### 3.3 状态 × 操作 权威矩阵
@ -110,7 +110,7 @@
| 转商机 | — | — | ✓(持有人) | ✓(持有人) | — | — | — |
| 转商机 | — | — | ✓(持有人) | ✓(持有人) | — | — | — |
| 释放 | — | — | ✓(持有人) | ✓(持有人) | — | — | — |
| 释放 | — | — | ✓(持有人) | ✓(持有人) | — | — | — |
| 关注/取关 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 关注/取关 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| 删除 | ✓(管理) | ✓(管理) | ✓(管理·强确认) | ✓(管理·强确认) | ✓(管理·强确认) | ** ✗ 不可删** | ⚠ |
| 删除 | ✓(管理) | ✓(管理) | ✓(管理·强确认) | ✓(管理·强确认) | ✓(管理·强确认) | ✓(管理/持有人·强确认) | ⚠ |
| 激活 | — | — | — | — | — | ✓(管理) | — |
| 激活 | — | — | — | — | — | ✓(管理) | — |
「管理」= 具有该线索所属数据范围的管理权限;具体谁是"管理"随 §9 权限 PRD 定。
「管理」= 具有该线索所属数据范围的管理权限;具体谁是"管理"随 §9 权限 PRD 定。
@ -144,6 +144,20 @@
**⚠ 待确认(B)**:销售换部门后,`owner_dept_id_snapshot` 是否需要刷新?当前定为**不刷**(快照即历史)。
**⚠ 待确认(B)**:销售换部门后,`owner_dept_id_snapshot` 是否需要刷新?当前定为**不刷**(快照即历史)。
### 4.1.1 公海池换部门时的 dept_id 联动
管理员可修改公海池的归属部门(如从 A 部门改挂到 B 部门)。此时线索 `dept_id` 的联动规则:
| 线索状态 | dept_id 是否跟池走 | 说明 |
|---|:---:|---|
| 未分发 / 待领取 | ✓ 跟池走 | 批量 `UPDATE lead SET dept_id = new_dept_id WHERE pool_id=? AND status IN ('未分发','待领取')` ,新部门成员可查到、可领取 |
| 已领取 / 跟进中 | ✗ 不动 | `dept_id` 保持原值(=旧部门),已归属销售的私海线索不受池换部门影响 |
| 已转商机 / 过期失效 / 线索作废 | ✗ 不动 | 终态/失效线索不参与 |
**前置校验**:目标部门必须当前**无池**(`UNIQUE(dept_id)` 约束);源部门换出后无池不拦截。
**改写 [I]**:`dept_id` 不再是"恒定永不变动",而是"池归属部门变更时,待领取/未分发线索 dept_id 跟池走;已领取/跟进中线索 dept_id 不动"。
### 4.3 公海池(`lead_pool`,crm-rule 定义)
### 4.3 公海池(`lead_pool`,crm-rule 定义)
一个公海池 = 一个**部门**的线索容器 + 一组**规则参数**:
一个公海池 = 一个**部门**的线索容器 + 一组**规则参数**:
@ -157,6 +171,8 @@
**池名**全局 UNIQUE;**删除**软删且必须"池下无非终态线索"。
**池名**全局 UNIQUE;**删除**软删且必须"池下无非终态线索"。
**换部门**:管理员可修改 `dept_id` ,前置校验目标部门当前无池(`UNIQUE(dept_id)`)。换部门后,待领取/未分发线索 `dept_id` 批量跟池走,已领取/跟进中线索 `dept_id` 不动(见 §4.1.1)。
---
---
## 5. 双计时器
## 5. 双计时器
@ -184,7 +200,9 @@
### 5.3 池规则参数变更时的批量刷新
### 5.3 池规则参数变更时的批量刷新
管理员改了池的 N 或 M:
管理员改了池的 N 或 M:
- N 改动 → 批量 `UPDATE lead SET recycle_deadline = claim_time + new_N WHERE pool_id=? AND status IN ('已领取','跟进中')` (对跟进中的按最后反馈时刻算:`last_feedback_time + new_N`)
- N 改动 → 分状态批量刷新:
- 已领取:`UPDATE lead SET recycle_deadline = claim_time + new_N WHERE pool_id=? AND status='已领取'`
- 跟进中:`UPDATE lead SET recycle_deadline = last_feedback_time + new_N WHERE pool_id=? AND status='跟进中'`
- M 改动 → 批量 `UPDATE lead SET expire_deadline = create_time + new_M WHERE pool_id=? AND status != '已转商机'`
- M 改动 → 批量 `UPDATE lead SET expire_deadline = create_time + new_M WHERE pool_id=? AND status != '已转商机'`
**当日不批量清算已超时的**——只改截止时刻,实际状态转移交给次日定时任务自然执行(对齐原型 A7-3-1 口径)。
**当日不批量清算已超时的**——只改截止时刻,实际状态转移交给次日定时任务自然执行(对齐原型 A7-3-1 口径)。
@ -233,8 +251,8 @@
**入口**:【线索公海】列表 → 单条【领取】 / 批量勾选后【批量领取】。
**入口**:【线索公海】列表 → 单条【领取】 / 批量勾选后【批量领取】。
**前置**(应用层校验):
**前置**(应用层校验):
1. 当前用户在池的可领取成员集合内(`claim_rule=1` 时=部门全员;`claim_rule=2` 时**销售不可自领**,按钮隐藏)
1. 当前用户在池的可领取成员集合内(`claim_rule=1` 时=部门全员;`claim_rule=2` 时**销售不可自领**,按钮隐藏)
2. 未超"每日领取上限"`daily_claim_limit`(0=无限)
2. 未超"每日领取上限"`daily_claim_limit`(0=无限);**"每日" = 自然日**(00:00-23:59,`DATE(op_time) = CURRENT_DATE`)
3. 未超"个人持有上限"`hold_limit`
3. 未超"个人持有上限"`hold_limit`;**计数口径 = 仅已领取 + 跟进中**(已转商机、过期失效、线索作废不占名额)
4. 目标线索状态 = 待领取
4. 目标线索状态 = 待领取
**副作用**:设 `owner_user_id` ;快照 owner 姓名/部门;状态转 已领取(边 #6 );启动 N;写 CLAIM 历史。
**副作用**:设 `owner_user_id` ;快照 owner 姓名/部门;状态转 已领取(边 #6 );启动 N;写 CLAIM 历史。
@ -249,12 +267,27 @@
### 6.4 反馈(持有人 · a2-1-2 系列)
### 6.4 反馈(持有人 · a2-1-2 系列)
**入口**:详情页 / 列表操作【反馈】按钮。
**入口**:详情页 / 列表操作【反馈】按钮。
**表单**:反馈情况(有效/无效/未反馈)· 反馈内容 · 需求产品(可切换)· ⚠ 待确认(C):反馈是否可上传附件?
**表单**:反馈情况(有效/无效/未反馈)· 反馈内容 · 需求产品(可切换)· 附件(走 crm-file,存 `lead_feedback.attachment_ids` )。
**副作用**:
- 落 `lead_history` FEEDBACK 记录
**草稿/提交双态**(改写 [Q2=c],拆出独立 `lead_feedback` 表):
- ** 【保存草稿】**:写/更新 `lead_feedback` 行 `record_status='DRAFT'` ,**不校验必填**,不改状态机,不写 `lead_history` ,不刷主表快照。草稿按 `(user_id, lead_id)` 唯一,重复保存为覆盖写。
- ** 【保存】(正式提交)**:`lead_feedback` 行 `record_status='SUBMITTED'` ,同时:
- 主表更新 5 列反馈快照(`feedback_status/content/time/by/product_code`)
- 主表更新 5 列反馈快照(`feedback_status/content/time/by/product_code`)
- 状态:已领取 → 跟进中(边 #7 );跟进中 → 跟进中(边 #8 )
- 状态:已领取 → 跟进中(边 #7 );跟进中 → 跟进中(边 #8 )
- **回收计时 N 重置** (起点=`now`)
- **回收计时 N 重置** (起点=`now`)
- 写 `lead_history` FEEDBACK 记录(detail 引用 `lead_feedback.id` ,不冗余内容)
- 清除同 `(user_id, lead_id)` 的草稿行(转为 SUBMITTED)
**`lead_feedback` 表结构**:
```
lead_feedback
├─ id, lead_id, user_id
├─ feedback_status, content, product_code
├─ attachment_ids json -- crm-file 文件 id 列表
├─ record_status tinyint -- 1=DRAFT, 2=SUBMITTED
├─ created_at, submitted_at
└─ INDEX(lead_id, user_id, record_status)
```
### 6.5 转商机(持有人 · a2-1-2 转商机弹窗)
### 6.5 转商机(持有人 · a2-1-2 转商机弹窗)
@ -272,7 +305,7 @@
### 6.6 释放(持有人 · a2-1-2)
### 6.6 释放(持有人 · a2-1-2)
**前置**:`status IN (已领取, 跟进中)`;当前用户=持有人。
**前置**:`status IN (已领取, 跟进中)`;当前用户=持有人。
**副作用**:清 `owner_user_id` ;状态转"待领取"(边 #10 );N 停;写 RELEASE 历史。线索回到池内待领取,原持有人失去所有非查看权限。
**副作用**:清 `owner_user_id` 、`owner_name_snapshot`、`owner_dept_id_snapshot`、`claim_time`、`recycle_deadline` ;状态转"待领取"(边 #10 );N 停;写 RELEASE 历史。**反馈快照 5 列不清空**(保留上一位持有人的反馈,供下一位领取人参考) 。线索回到池内待领取,原持有人失去所有非查看权限。
### 6.7 定时任务:超时回收 & 失效
### 6.7 定时任务:超时回收 & 失效
@ -292,10 +325,35 @@ WHERE expire_deadline < now() AND status IN ('未分发','待领取','已领取'
**⚠ 待确认(D)**:两个 Job 的执行节奏(每日凌晨?每小时?按公海池独立?)。当前定为**统一每日 02:00 全库扫**。
**⚠ 待确认(D)**:两个 Job 的执行节奏(每日凌晨?每小时?按公海池独立?)。当前定为**统一每日 02:00 全库扫**。
### 6.8 激活失效线索(管理员)
### 6.8 激活失效线索(管理员/持有人)
**入口**:过期失效线索详情 → 【激活】(单条);线索管理列表 → 勾选多条 → 【批量激活】。
**副作用**:状态恢复为失效前状态、owner 保留;`expire_deadline = now + pool.expire_days`(M 重置);**`recycle_deadline = now + pool.recycle_days`(N 同步重置)**;写 ACTIVATE 历史。
**批量激活**:逐条执行单条激活逻辑,**部分成功**——成功 N 条、失败 M 条(已被他人操作),弹结果提示。非原子。
**入口**:过期失效线索详情 → 【激活】。
### 6.9 编辑线索(管理/持有人)
**副作用**:状态恢复为失效前状态、owner 保留;`expire_deadline = now + pool.expire_days`(M 重新计);写 ACTIVATE 历史。
**入口**:列表操作【编辑】按钮,打开线索详情编辑页(含【线索详情】【历史记录】双 Tab)。
**可编辑字段**(= 新增线索表单的业务字段):
| 分组 | 可编辑字段 |
|---|---|
| 基础 | 线索名称、联系电话、微信、电子邮箱、省份、城市、详细地址 |
| 业务来源 | 渠道、品牌、需求产品、需求场景 |
| 核心 | 咨询内容、是否加急 |
**不可编辑字段**:状态、所属公海池、领取人、领取时刻、所有时效字段(`recycle_deadline`/`expire_deadline`)、所有快照字段(`pool_name_snapshot`/`owner_*`/`feedback_*`)——由状态机和业务流程管,不走编辑入口。
**权限**:
- 未分发 / 待领取 → **管理**可编辑
- 已领取 / 跟进中 → **持有人**可编辑
- 已转商机 / 过期失效 → **不可编辑** (终态锁 / 只读)
- 线索作废 → ⚠ 待确认(A)
**副作用**:
- 写 `lead_history` EDIT 记录,detail 含变更字段清单(旧值→新值)
- **不改状态** ,不影响 N/M 计时器
---
---
@ -379,7 +437,7 @@ record ColumnPreference(List<String> visibleKeys, List<String> columnOrder) {}
|---|---|:---:|:---:|
|---|---|:---:|:---:|
| ** ⚠ (A)** | 线索作废:触发方(自动/手动)、入口状态、可逆性、归属处理 | 03 收尾 | P1 |
| ** ⚠ (A)** | 线索作废:触发方(自动/手动)、入口状态、可逆性、归属处理 | 03 收尾 | P1 |
| ** ⚠ (B)** | 销售换部门后 `owner_dept_id_snapshot` 是否刷新?(当前定"不刷") | 04 完善 | P2 |
| ** ⚠ (B)** | 销售换部门后 `owner_dept_id_snapshot` 是否刷新?(当前定"不刷") | 04 完善 | P2 |
| ** ⚠ (C)** | 反馈是否可上传附件? | 06 完善 | P2 |
| ~~⚠ (C)~~ | ~~反馈是否可上传附件?~~ ** ✅ 已解决**:反馈可上传附件,存 `lead_feedback.attachment_ids` (本轮 grill #3 ) | — | — |
| ** ⚠ (D)** | 回收/失效 Job 执行节奏(每日 02:00?每小时?按池独立?) | §6.7 | P2 |
| ** ⚠ (D)** | 回收/失效 Job 执行节奏(每日 02:00?每小时?按池独立?) | §6.7 | P2 |
| ** ⚠ (E)** | 线索公海视图是否显示"已被别人领取"的线索(只读观察态) | §7 | P2 |
| ** ⚠ (E)** | 线索公海视图是否显示"已被别人领取"的线索(只读观察态) | §7 | P2 |
| ** ⚠ PRD-1** | 行级授权**触发动作清单**是否完整 | 05、§9 | **P0** |
| ** ⚠ PRD-1** | 行级授权**触发动作清单**是否完整 | 05、§9 | **P0** |
@ -403,7 +461,25 @@ record ColumnPreference(List<String> visibleKeys, List<String> columnOrder) {}
见各 ticket Answer:
见各 ticket Answer:
- `lead` 主表 → `issues/06-线索实体与字段模型.md`
- `lead` 主表 → `issues/06-线索实体与字段模型.md`
- `lead_feedback` (独立反馈实体,DRAFT/SUBMITTED) → 本 PRD §6.4(本轮 grill #3 改写 [Q2=c])
- `lead_pool` + 3 关联表 → `issues/04-公海池实体与归属建模.md`
- `lead_pool` + 3 关联表 → `issues/04-公海池实体与归属建模.md`
- `sys_region` → `issues/02-行政区划数据源调研.md`
- `sys_region` → `issues/02-行政区划数据源调研.md`
- `user_column_preference` → `issues/07-preference列偏好scope模型与契约.md`
- `user_column_preference` → `issues/07-preference列偏好scope模型与契约.md`
- `OpportunityCreationPort` → `issues/08-转商机outbound-port契约.md`
- `OpportunityCreationPort` → `issues/08-转商机outbound-port契约.md`
### 12.1 本轮 grill 决策清单(2026-08-12)
| # | 决策 | 影响章节 |
|---|---|---|
| 1 | 池换部门允许;待领取/未分发 `dept_id` 跟池走,已领取/跟进中不动;目标部门须无池 | §4.1.1、§4.3,改写 [I] |
| 2 | 线索合并不做,Out of scope | map.md |
| 3 | 拆出 `lead_feedback` 独立表(DRAFT/SUBMITTED),改写 [Q2=c] | §6.4 |
| 4 | 过期失效线索可删(管理/持有人·强确认) | §3.3 矩阵 |
| 5 | 释放/回收时反馈快照不清空 | §6.6 |
| 6 | 激活时 N 和 M 均重置 | §3.2 边 #13 、§6.8 |
| 7 | `hold_limit` 只算已领取 + 跟进中 | §6.2 |
| 8 | 批量激活,部分成功 | §6.8 |
| 9 | `daily_claim_limit` "每日" = 自然日 | §6.2 |
| 10 | 导入线索不做,留 fog | map.md |
| 11 | 销售可删自己过期失效线索(持有人·强确认) | §3.3 矩阵 |
| 12 | 编辑范围 = 业务字段可改,状态/池/归属/时效/快照不可改 | §6.9 |