12 KiB
线索实体与字段模型
Type: grilling Status: resolved Blocked by: 04
Question
定义 crm-lead 的线索实体字段全集,作为 crm-lead 的地基。字段来源:新增线索表单 + 四视图列表字段 + 线索详情。
需在本 ticket 定清:
- 基础字段:线索名称、联系电话(含校验:手机/座机)、微信(校验)、电子邮箱(校验)、省份、城市、详细地址、渠道(字典)、品牌(字典)、需求产品(字典)、需求场景(字典)、咨询内容、是否加急。
- 流转/归属字段:线索状态(见 ticket 03)、所属公海池(引用 crm-rule 公海池 id)、领取人(
AuthUser.id)、销售团队/销售部门(冗余还是从领取人推导?)、新增人员、新增时间、超时回收剩余有效期(计算字段还是存储?)。 - 反馈相关字段:反馈情况(有效/无效/未反馈)、反馈内容、最后反馈时间——存最新一条在主表,还是全部在反馈子表由主表冗余最新值?
- 关注:关注是"用户×线索"关联(我的关注列表 + 关注总人数),独立关联表。
- 客户相关文件:线索详情可下载附件——走 crm-file?关联形态。
- 必填/校验/字典绑定:哪些字段绑定哪个字典分组(对齐 crm-dict 的字段-分组绑定约定)。
- 哪些字段冗余:为列表筛选/展示性能,哪些跨模块字段(部门/团队/池名)冗余存储 vs 实时 join。
产出:线索实体字段表(名称/类型/必填/字典绑定/来源/冗余策略),写入 ## Answer;术语进 crm-lead/CONTEXT.md。依赖 03(状态)、04(公海池 id)。
Decisions(grill 定稿)
- [Q1=a] 联系电话单字段
phonevarchar(32),正则同时兼容手机/座机/带区号。 - [Q2=c] 反馈:统一操作日志子表
lead_history+ 主表冗余最新反馈 5 列(feedback_status/content/time/by/product)。写反馈时事务内插子表 + 更新主表最新值。历史记录 Tab 复用同一张lead_history(含领取/释放/反馈/新增/编辑等所有操作类型)。⚠ 见 Amendment 2:拆出lead_feedback独立表(草稿/提交双态)。 - [Q3=a] 团队/部门/领取人名 快照冗余;
dept_id冗余(= 池的 dept_id,因一部门一池永不变);team_dept_id同理。领取/释放时刷新快照。 - [Q4=b]
recycle_deadline/expire_deadline存字段。- 领取时:
recycle_deadline = claim_time + pool.recycle_days - 新增反馈时:重置
recycle_deadline = now + pool.recycle_days(反馈重置回收倒计时) expire_deadline = create_time + pool.expire_days(永不清零;仅激活时按 03 重置)- pool 配置变更时:批量 UPDATE 该池所有已领取/跟进中线索的对应截止时刻;本身不当日回收,等次日定时任务扫。
- 领取时:
- [Q5=a] 附件走 crm-file;关联表
lead_attachment(id, lead_id, file_id)。 - [Q6=a] 关注纯关联表
lead_follow(id, user_id, lead_id, follow_time);关注总人数由COUNT(*)现算,不主表冗余。 - [Q7=ii] 字典字段(channel/brand/product/scene)存 code varchar(64),跨环境稳定;展示时 JOIN crm-dict 取 label。
Answer
一、lead 主表字段全集
| 分组 | 字段 | 类型 | 必填 | 来源/说明 |
|---|---|---|---|---|
| 主键 | id |
bigint | Y | PK |
| 基础 | lead_name |
varchar(200) | N | 线索名称 |
phone |
varchar(32) | N | 单字段兼容手机/座机 | |
wechat |
varchar(64) | N | 微信号(校验) | |
email |
varchar(128) | N | 邮箱(校验) | |
province_region_id |
bigint | Y | sys_region level=1 | |
city_region_id |
bigint | Y | sys_region level=2/3,联动省 | |
address |
varchar(255) | N | 详细地址 | |
| 业务来源 | channel_code |
varchar(64) | Y | 字典 code(渠道分组) |
brand_code |
varchar(64) | Y | 字典 code(品牌分组) | |
product_code |
varchar(64) | Y | 字典 code(需求产品分组) | |
scene_code |
varchar(64) | N | 字典 code(需求场景分组) | |
| 核心 | consult_content |
text | Y | 咨询内容 |
status |
tinyint | Y | 线索状态(见 03,7 态) | |
is_urgent |
tinyint | Y | 是否加急 0/1,默认 0 | |
| 归属 | pool_id |
bigint | Y | 公海池外键(crm-rule) |
pool_name_snapshot |
varchar(100) | Y | 冗余快照,池改名要级联刷 | |
dept_id |
bigint | Y | 冗余 = 池的 dept_id,一部门一池永不变 | |
team_dept_id |
bigint | Y | 冗余 = 池的 team_dept_id | |
owner_user_id |
bigint | N | 领取人;未领取时 NULL | |
owner_name_snapshot |
varchar(64) | N | 领取人姓名冗余 | |
owner_dept_id_snapshot |
bigint | N | 领取时销售所属部门快照(≠ 归属 dept_id,用于审计) | |
create_by / create_time |
Y | BaseEntity, 新增人=销售 | ||
| 时效 | claim_time |
datetime | N | 领取时刻 |
recycle_deadline |
datetime | N | 回收截止时刻(存字段,索引) | |
expire_deadline |
datetime | Y | 失效截止时刻 = create_time + pool.M | |
| 反馈快照 | feedback_status |
tinyint | N | 有效/无效/未反馈 |
feedback_content |
text | N | 最新反馈内容 | |
feedback_time |
datetime | N | 最新反馈时刻 | |
feedback_by_user_id |
bigint | N | 最新反馈人 | |
feedback_product_code |
varchar(64) | N | 最新反馈对应需求产品字典 code | |
| BaseEntity | update_by/update_time/deleted |
逻辑删除;一律不可物理删(见 03) |
必填项 = 城市、渠道、品牌、需求产品、咨询内容 5 项(含省份是必填但由城市联动导出)。原型明标 *。
索引:
idx_pool_status(pool_id, status) — 公海视图筛选idx_owner_status(owner_user_id, status) — 我的线索idx_recycle_deadline(recycle_deadline) — 定时回收 jobidx_expire_deadline(expire_deadline) — 定时失效 jobidx_dept_status(dept_id, status) — 部门负责人/管理员视图筛选
二、关联/子表
lead_history -- 统一操作日志(含反馈)
├─ id, lead_id, op_type, op_time, op_user_id, op_user_dept_name, detail
├─ op_type: CREATE/CLAIM/RELEASE/FEEDBACK/EDIT/ASSIGN/CONVERT/EXPIRE/RECYCLE/ACTIVATE/...
└─ FEEDBACK 类的 detail 含: feedback_status/feedback_content/feedback_product_code
lead_follow(id, user_id, lead_id, follow_time) -- 关注 M:N
UNIQUE(user_id, lead_id)
lead_attachment(id, lead_id, file_id) -- 客户相关文件, file_id 引用 crm-file
关注总人数 用 SELECT COUNT(*) FROM lead_follow WHERE lead_id=? 现算,不入主表冗余。
三、快照刷新时机
| 触发 | 刷新 |
|---|---|
| 领取 | claim_time owner_user_id owner_name_snapshot owner_dept_id_snapshot recycle_deadline |
| 反馈 | feedback_* 5 列 + recycle_deadline = now + pool.N |
| 释放/超时回收 | owner_* 清空、claim_time/recycle_deadline 清空;反馈 5 列不清空(grill #5) |
| 激活(F2) | expire_deadline = now + pool.M + recycle_deadline = now + pool.N(grill #6,N 也重置) |
| 池改名 | 批量刷 pool_name_snapshot |
| 池 recycle_days 变 | 批量刷该池已领取/跟进中的 recycle_deadline = claim_time + new_N |
| 池 expire_days 变 | 批量刷该池全部非终态的 expire_deadline = create_time + new_M |
四、字段-字典绑定(对齐 crm-dict)
| 字段 | 字典分组 code |
|---|---|
channel_code |
lead.channel |
brand_code |
lead.brand |
product_code |
lead.product(反馈中的 feedback_product_code 同 group) |
scene_code |
lead.scene |
存 code,展示 JOIN crm-dict 取 label。
五、依赖声明
- crm-auth:
AuthUser/SysDept(领取人、部门归属、快照)。 - crm-rule:
LeadPool(外键 + 池名快照)。 - crm-dict:4 个字典分组(channel/brand/product/scene)。
- crm-region(ticket 02=1a 新建):
sys_region省市区。 - crm-file:附件文件 id。
六、CONTEXT 登记
crm-lead/CONTEXT.md:线索术语(领取/反馈/释放/关注/加急/回收截止/失效截止)、快照策略、字典绑定、7 状态引用。CONTEXT-MAP.md已有 crm-lead 行,无需新增。
七、下游影响
- 08 转商机 port:转商机时传的字段集从本表选取(Q 待 08 定)。
- 05 权限方向:
dept_id作@DataScope的 dept 列已在 05 定,本表落地。 - 04 池配置变更:pool save service 需触发本表批量刷
recycle_deadline/expire_deadline/pool_name_snapshot。
Status
本 ticket 字段模型已定稿可交付 → resolved。
Amendment(08 追加)—— 省市字段改存 code
原 Answer 中 province_region_id / city_region_id(bigint FK)修正为存国标 code:
| 原字段 | 修正为 | 说明 |
|---|---|---|
province_region_id bigint |
province_code varchar(12) |
国标 GB/T 2260 省代码(6位,如 440000) |
city_region_id bigint |
city_code varchar(12) |
国标 GB/T 2260 市/区代码(如 440100广州市 或 440106天河区) |
理由:
- 存 code 与 crm-dict 存 code 的既有约定一致(Q7=ii)
- 支持前缀 LIKE 祖先查询(
WHERE city_code LIKE '4401%'命中广州市本级 + 所有区),无需 JOIN sys_region - code 是国标稳定标识,跨环境/跨系统对齐
依赖:sys_region 表 code UNIQUE 字段(见 02 Amendment)。
其余 06 定稿不变:字段名、必填标记、其他字段、索引/子表全部保留(相关索引 idx_dept_status 等不涉及省市字段无需改)。
Amendment 2(2026-08-12 grill)—— 拆出 lead_feedback 独立表 + 快照保留 + 激活重置 N
A2.1 [Q2=c] 改写:拆出 lead_feedback 独立表(grill #3)
改前:反馈直接写 lead_history FEEDBACK 记录(detail 含 content),主表冗余最新值。
改后:拆出独立的 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)
- 【保存草稿】:写/更新
lead_feedback行record_status='DRAFT',不校验必填,不改状态机,不写lead_history,不刷主表快照。 - 【保存】(正式提交):
lead_feedback行record_status='SUBMITTED',主表更新 5 列快照,状态迁移(已领取→跟进中),N 重置,写lead_historyFEEDBACK 记录(detail 引用lead_feedback.id,不冗余内容)。
理由:原型有“保存草稿”按钮,spec 未覆盖;拆表后草稿不污染操作日志,历史 Tab 从 lead_history 取,反馈内容从 lead_feedback 取。
⚠(C) 已解决:反馈可上传附件,存 lead_feedback.attachment_ids。
A2.2 快照刷新表修正(grill #5 + #6)
| 触发 | 原规则 | 修正后 |
|---|---|---|
| 释放/超时回收 | owner_* 清空、claim_time/recycle_deadline 清空、反馈 5 列也清空 |
owner_*、claim_time、recycle_deadline 清空;反馈 5 列不清空(保留供下一位参考) |
| 激活 | expire_deadline = now + pool.M |
expire_deadline = now + pool.M + recycle_deadline = now + pool.N(N 也重置) |
A2.3 池 N 改动刷新修正
原快照表“池 recycle_days 变”行写的是 recycle_deadline = claim_time + new_N,对已领取和跟进中未区分。
修正:
- 已领取:
recycle_deadline = claim_time + new_N - 跟进中:
recycle_deadline = last_feedback_time + new_N