|
|
|
@ -40,7 +40,7 @@ |
|
|
|
| 角色 | 定义 | 字段 | |
|
|
|
|---|---|---| |
|
|
|
| **负责人(领取人)** | 当前持有该商机的销售,归属 + 默认可见性双重含义 | `owner_user_id` | |
|
|
|
| **团队成员** | 负责人拉入协作的人员,带项目角色(商机负责人 / 方案工程师 / 招标专员 / 现场工程师等)与权限(读写 / 只读 / 可写跟进 / 可推进节点等);是行级授权白名单,绕开 DataScope 部门天花板——**生效边界 = 详情/子表读 + 个人工作区视图;管理/公海工作区严格按 DataScope 不混白名单**(grill 补拍 20260821) | `opportunity_team`(关联表) | |
|
|
|
| **团队成员** | 负责人拉入协作的人员,带**项目角色(纯回显标签:商机负责人 / 方案工程师 / 招标专员 / 现场工程师等,不带任何读写权限,grill 拍板 20260821)**与权限(读写 / 只读 / 可写跟进 / 可推进节点等,**权限与角色无关、单独配**);是行级授权白名单,绕开 DataScope 部门天花板——**生效边界 = 详情/子表读 + 个人工作区视图;管理/公海工作区严格按 DataScope 不混白名单**(grill 补拍 20260821) | `opportunity_team`(关联表) | |
|
|
|
| **创建人** | 全生命周期不变 | `creator_user_id` | |
|
|
|
|
|
|
|
- 抛公海只清空负责人,**不动团队成员**(产品明确,票 01)。 |
|
|
|
@ -70,8 +70,8 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
| 归属流转 | 领取(公海)/ 分配(管理)/ 抛公海(个人主动)/ 领导释放(管理强制)/ 暂缓 / 取消暂缓 / 移交 | |
|
|
|
| 跟进 | 写跟进 / 删除跟进 | |
|
|
|
| 方案卡 | 新增 / 编辑 / 提交 / 推送 | |
|
|
|
| 团队成员 | 添加 / 调整角色与权限 / 移除(成员行上的读写/只读/可写跟进/可推进节点 = **行级角色配置,不走全局权限点**) | |
|
|
|
| 关联客户 | 新增 / 编辑 / 删除 | |
|
|
|
| 团队成员 | 添加 / 调整角色与权限 / 移除(成员行上的读写/只读/可写跟进/可推进节点 = **行级权限配置,不走全局权限点**;**项目角色纯回显标签、不带权限,与权限列各自独立配置**,grill 拍板 20260821) | |
|
|
|
| 关联客户 | 新增 / 编辑(改客户角色、切主要意向标记)——**无删除动作**(原型/票 13 无删除,grill 纠偏 20260821) | |
|
|
|
| 现场勘察 | 新增 / 编辑 / 删除 | |
|
|
|
| 附件 | 上传 / 删除 | |
|
|
|
| 视图 | 关注 / 取关;自定义视图新增/编辑/删除;批量领取/分配/关注/领导释放(同单条动作权限点,批量不加新点) | |
|
|
|
@ -111,8 +111,9 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|---|---|---| |
|
|
|
| `opp_status` | tinyint | 归属流转状态(轴 1),见 §3 | |
|
|
|
| `owner_user_id` 负责人 | bigint | 抛公海后清空 | |
|
|
|
| `owner_name_snapshot` 负责人姓名快照 | varchar(100) | 调岗不自动更新 | |
|
|
|
| `owner_name_snapshot` 负责人姓名快照 | varchar(64) | 调岗不自动更新(长度对齐票 03 B1「对称 lead」;此处原误记 varchar(100),回填 20260824) | |
|
|
|
| `owner_dept_id` 负责人部门快照 | bigint | 公海可见范围锚点;调岗不变 | |
|
|
|
| `origin_dept_id` 原始血缘部门 | bigint | **创建时写入 = 首个负责人部门,此后永不变**(移交/抛公海/回收/领取/分配均不动;grill 拍板 20260821);仅审计/血缘追溯用(列表可选筛选/oplog 展示),**不参与公海规则匹配、不参与 DataScope 可见性**(匹配/可见性仍锚 `owner_dept_id`) | |
|
|
|
| `creator_user_id` 创建人 | bigint | 全生命周期不变 | |
|
|
|
| `claim_time` 领取时间 | datetime | 领取/分配/两入口创建时=now(「进入名下时间」,P1-6 拍板) | |
|
|
|
| `last_valid_follow_time` 最近有效跟进时间 | datetime | 自动回收计时锚点(票 05);领取/分配**重置**=now;两入口创建以进入名下时间(=创建时刻)为起点;有效跟进时刷新(§5.3 定义,配置化 P1-8) | |
|
|
|
@ -123,6 +124,11 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
| `pool_reason` 进入公海原因 | varchar(32) | 抛公海/回收时写(见 §3.2);公海列表筛选 | |
|
|
|
| `primary_customer_id` 主要意向客户 id | bigint | 冗余快查,= 关联客户表 `is_primary_intended=1` 那条 | |
|
|
|
| `primary_customer_name_snapshot` 主客户名快照 | varchar(200) | 列表/详情顶部免 join | |
|
|
|
| `pause_time` 暂缓开始时刻 | datetime | E4 暂缓写=now,E5 取消暂缓清空;取消暂缓时算 `now−pause_time` 顺推 `last_valid_follow_time`(冲突8) | |
|
|
|
| `pause_reason` 暂缓原因 | varchar(32) | 字典码;E4 写、E5 清空 | |
|
|
|
| `pause_expected_restart_date` 预计重启日期 | date | 必填≥今天;E4 写、E5 清空 | |
|
|
|
| `pause_remark` 暂缓补充说明 | varchar(500) | E4 写、E5 清空 | |
|
|
|
| `version` 乐观锁版本号 | int not null default 0 | 商机级写并发防护:状态迁移 CAS(§3.4,票 04)与切主客户(§7.1,票 13)复用;票 03 落列,生效接线归后续票(回填 20260824,补登 §7.1/§3.4 已引用的列) | |
|
|
|
|
|
|
|
继承 `BaseEntity`(id / create_time / update_time / creator / updater / 逻辑删除)。 |
|
|
|
|
|
|
|
@ -170,12 +176,12 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
| E1 | 领取 | `ClaimCmd` | 1→2 | 设 owner + 部门/姓名快照 + `claim_time`;刷新 `last_valid_follow_time`=now | A3-3-1-1(公海领取) | |
|
|
|
| E2 | 分配 | `AssignToUserCmd` | 1→2 | 设 owner=指派对象 + 快照 + `claim_time`;重置 `last_valid_follow_time`=now(P1-6 拍板) | A3-2-1(管理页分配) | |
|
|
|
| E3 | 抛公海 | `ReleaseToPoolCmd` | 2→1 | 清 `owner_user_id` + `owner_name_snapshot` + `claim_time`;**`owner_dept_id` 保留**(公海可见范围锚点,票 05);记 `pool_reason`(销售主动释放/特殊原因暂停/领导释放);保留 `current_stage_id` 供公海展示;**不动团队成员**;入口受规则 `allow_manual_pool` 开关控制 | A3-1-1-2-7 | |
|
|
|
| E4 | 暂缓 | `PauseCmd` | 2→3 | 保留 owner + 团队;记暂缓原因(字典) + 预计重启日期(必填≥今天) + 补充说明 | A3-1-1-2-6 | |
|
|
|
| E5 | 取消暂缓 | `ResumeCmd` | 3→2 | 保留 owner;回暂缓前阶段(阶段字段未动);清暂缓附加字段 | A3-1-1-2-6(取消按钮) | |
|
|
|
| E4 | 暂缓 | `PauseCmd` | 2→3 | 保留 owner + 团队;写 `pause_time`=now + `pause_reason`(字典) + `pause_expected_restart_date`(必填≥今天) + `pause_remark` | A3-1-1-2-6 | |
|
|
|
| E5 | 取消暂缓 | `ResumeCmd` | 3→2 | 保留 owner;回暂缓前阶段(阶段字段未动);清暂缓附加字段(`pause_time`/`pause_reason`/`pause_expected_restart_date`/`pause_remark`);**回收锚点顺推(grill 拍板 20260821)**:`last_valid_follow_time += now−pause_time`(把暂缓时长从未跟进时长中扣除,等价「暂缓期间冻结回收」);此后回收判定回归无状态实时比较 | A3-1-1-2-6(取消按钮) | |
|
|
|
| E6 | 关闭 | `CloseCmd` | 2,3→4 | 保留 owner(只读锁定);记关闭原因(字典) + 补充说明(选「其他」时必填) + 确认勾选 | A3-1-1-2-9 | |
|
|
|
| E7 | 重启 | `ReopenCmd` | 4→2 | 保留 owner;记重开原因(必填);统一回「推进中」 | A3-1-1(重新开启入口) | |
|
|
|
| E8 | 转项目 | `ConvertToProjectCmd` | 2→5 | **触发源 = ① 标准路径:推送方案卡成功(系统自动创建项目);② 特殊路径:项目侧建项目关联商机后回调**(grill 补拍 20260821),无独立「转项目」动作;保留 owner(锁死);对接 A5 项目模块(本模块只占端口);列表「转项目」按钮 = 推送流程快捷入口 | A3-1-1-2-x(转项目) | |
|
|
|
| E9 | 移交 | `HandoverCmd` | 2,3→自环 | 换 owner = 移交对象 + 姓名/部门快照同步刷新(`owner_dept_id` 换为移交对象部门,公海规则匹配锚点跟人走,grill 补拍 20260821);`claim_time` 不重置;入口在团队成员页 | A3-1-1-1-8(团队成员 Tab) | |
|
|
|
| E8 | 转项目 | `ConvertToProjectCmd` | 2→5 | **本期可达触发源 = 仅特殊路径:项目侧建项目关联商机后回调(A5 调 `OpportunityConvertPort`)**;① 标准路径(推送方案卡→系统建项目)**本期不可达、随推送票 spin-out**(grill 拍板 20260821);无独立「转项目」动作;保留 owner(锁死);列表「转项目」按钮 = 推送流程快捷入口(推送票落地后启用) | A3-1-1-2-x(转项目) | |
|
|
|
| E9 | 移交 | `HandoverCmd` | 2,3→自环 | 换 owner = 移交对象 + 姓名/部门快照同步刷新(`owner_dept_id` 换为移交对象部门,公海规则匹配锚点跟人走,grill 补拍 20260821);`claim_time` 不重置;**同步维护 team 表(grill 拍板 20260821)**:① 新负责人 upsert 一条 team 行、角色标签=「商机负责人」(已是成员则改标签);② 原负责人 team 行角色标签从「商机负责人」改为普通协作(保留其权限列不动——角色不带权限,原负责人是否还能写取决于其 team 行原本权限),**留在团队继续协作、落入「我参与的」**;入口在团队成员页 | A3-1-1-1-8(团队成员 Tab) | |
|
|
|
| E10 | 超时回收 | `executeRecycle` | 2→1(批量) | 清 `owner_user_id` + `owner_name_snapshot` + `claim_time`;`owner_dept_id` 保留定公海可见范围;`pool_reason`=超期回收;保留 `current_stage_id` 快照;暂缓中(3)**不参与回收**;实际执行的规则版本快照写 `opportunity_oplog`(§5.4) | **crm-opportunity 自建 `@Scheduled` 单 Job**(先提醒后回收串行,对齐线索域 ADR-0019 竞态规避;cron 配置占位符默认每日凌晨,grill 补拍 20260821) | |
|
|
|
|
|
|
|
> **「领导释放」**(E3 变体)= 管理侧强制抛公海,操作人 ≠ owner,`pool_reason`=领导释放(原型 A3-2-1 管理页)。 |
|
|
|
@ -245,7 +251,7 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
### 4.4 「已转项目」固定节点 × 轴 1 联动 |
|
|
|
|
|
|
|
- 「已转项目」是每个模板的**固定节点**(`is_fixed=1`,字典值固定 `OPP_STAGE_05`),配模板时自带、**不可删**(原型校验「除固定节点外至少创建一个阶段节点」),且**不可拖到非末位**(语义要求,落地校验)。 |
|
|
|
- **推送方案卡成功(系统自动创建项目)→ 触发轴 1 转项目终态(E8)+ 轴 2 落到固定节点**(标准路径,grill 补拍 20260821);无独立「转项目」动作,列表「转项目」按钮 = 推送流程快捷入口。 |
|
|
|
- **推送方案卡成功(系统自动创建项目)→ 触发轴 1 转项目终态(E8)+ 轴 2 落到固定节点**(标准路径,**本期不可达、随推送票 spin-out**,grill 拍板 20260821);本期 E8 仅由特殊路径(A5 回调)触发。无独立「转项目」动作,列表「转项目」按钮 = 推送流程快捷入口(推送票落地后启用)。 |
|
|
|
|
|
|
|
### 4.5 绑定与不迁移(V-CONFIG 12) |
|
|
|
|
|
|
|
@ -291,8 +297,8 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
| `allow_free_claim=1` | 适用范围内且具备公海权限的销售可自领;领取成功 owner=领取人,记录领取时间/人/规则版本(E1) | |
|
|
|
| `allow_free_claim=0` | 无自领入口,只能管理员分配(E2) | |
|
|
|
| `auto_recycle_enabled=1` | 回收锚点 = `last_valid_follow_time`;连续未有效跟进天数 = now − 锚点,≥ `recycle_days` 触发 E10 自动回收 | |
|
|
|
| 暂缓中(3) | **不参与回收**,回收计时暂停;取消暂缓回推进中后按剩余天数续算 | |
|
|
|
| `recycle_remind_enabled=1` | 提醒时间 = 预计回收时间 − `remind_days`;**由回收 Job 同一 `@Scheduled` 内先扫提醒再扫回收**(提醒先于回收,对齐线索域 ADR-0019;grill 补拍 20260821) | |
|
|
|
| 暂缓中(3) | **不参与回收**(回收 Job 跳过暂缓中);取消暂缓时把 `last_valid_follow_time` 顺推暂缓时长(E5)→ 回收判定为无状态实时比较 `now − last_valid_follow_time ≥ 当前匹配规则.recycle_days`,**不存「剩余天数」伪状态**;移交换部门后续算自然用新部门当前规则(grill 拍板 20260821) | |
|
|
|
| `recycle_remind_enabled=1` | 提醒时间 = 预计回收时间 − `remind_days`;**由回收 Job 同一 `@Scheduled` 内先扫提醒再扫回收**(提醒先于回收,对齐线索域 ADR-0019;grill 补拍 20260821)。**提醒只落待发记录、不直接发送**(grill 拍板 20260821):Job 扫到「预计回收时间 − remind_days ≤ now 且尚无待发记录」的商机 → upsert 一条 `opportunity_pending_notice`(`notice_type=RECYCLE_REMIND`,见 §7.10);实际发送走平台通知能力(spin-out 留白,与暂缓到期提醒/催办统一挂起) | |
|
|
|
|
|
|
|
- **有效跟进**(刷新锚点,P1-8 拍板)= **商机状态为推进中(2) 且动作 = 写跟进**(本期唯一动作;上附件/编辑字段/方案卡/勘察等不计,产品二次修订 20260821)。动作类型集合是**配置项**:落 `crm-rule` 第四族「有效跟进规则」`opportunity_follow_rule`(V-CONFIG 同族,动作类型多选子表,本期默认仅「写跟进」,以后经配置新增),回收 Job 按商机 `owner_dept_id` 实时匹配当前发布中规则拿动作集合(与公海规则同匹配引擎)。领取/分配重置锚点=now;两入口创建锚点=进入名下时间(P1-6)。 |
|
|
|
|
|
|
|
@ -340,7 +346,9 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|
|
|
|
> **公海商机在管理视图的可见性**(grill 补拍 20260821):owner 空但 `owner_dept_id` 保留作 DataScope 部门锚点,按查看者档位自然判定——全部档可见;部门档看 `owner_dept_id` 是否在其可见部门集合;仅本人档永不可见(owner 空 ≠ 本人)。故 E2 分配入口(管理页)对全部/部门档管理员数据可达,无需去公海页。 |
|
|
|
|
|
|
|
> **详情聚合接口可见性**(grill 补拍 20260821)= **DataScope 可见 OR 团队成员白名单命中**——保证「我参与的」视图点进详情链路闭环;写操作再按成员自身权限点校验。 |
|
|
|
> **详情聚合接口可见性**(grill 补拍 20260821)= **DataScope 可见 OR 团队成员白名单命中(仅存活行 `deleted=0`)**——保证「我参与的」视图点进详情链路闭环;写操作再按成员自身权限点校验。 |
|
|
|
|
|
|
|
> **视图非权限旁路(通则,grill 拍板 20260821)**:任何视图(最近访问/我参与的/我关注的/自定义检索)**只决定可见入口,不豁免任何动作校验**。例:被回收的商机仍留在原负责人「最近访问」里(团队白名单命中可进详情),但「领取」按钮仍走 E1 完整校验(`allow_free_claim` + 适用部门 + 权限点 + 状态 CAS),与从公海页领取同一代码路径。 |
|
|
|
|
|
|
|
> 视图不是状态切片:同一商机可同时出现在多视图(如自己负责 + 最近访问过)。 |
|
|
|
|
|
|
|
@ -350,7 +358,7 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|---|---|---| |
|
|
|
| `recent` | 最近访问 | 当前用户打开过详情的商机,访问时间倒序、按商机 id 去重留最新,上限可配置(本期默认 50);「访问」= 调用详情聚合接口,任意皮肤(个人/管理/公海)都算(grill 补拍 20260821);**落库 `opportunity_view_log`**(§7.9,访问即 upsert) | |
|
|
|
| `mine` | 我负责的销售机会 | `owner_user_id = 当前用户`;**不按状态切片**(已关闭/已转项目仍在列——原型样例首行即「已转项目」商机;需只看活跃的用自定义视图按状态过滤,grill 补拍 20260821) | |
|
|
|
| `participated` | 我参与的销售机会 | **团队成员且非负责人**:`EXISTS(opportunity_team WHERE opportunity_id=? AND user_id=当前用户) AND owner_user_id <> 当前用户`;与 `mine` 互斥 | |
|
|
|
| `participated` | 我参与的销售机会 | **团队成员且非负责人**:`EXISTS(opportunity_team WHERE opportunity_id=? AND user_id=当前用户 AND deleted=0) AND owner_user_id <> 当前用户`;与 `mine` 互斥。**成员身份判定一律带存活过滤 `deleted=0`**(grill 拍板 20260821):移除团队成员=软删 team 行(deleted 0→1),被移除后立即从本视图与详情白名单消失,仅 oplog/成员历史留痕;移交降级的旧负责人是存活行(只改角色)仍命中。 | |
|
|
|
| `followed` | 我关注的销售机会 | 当前用户关注表 `opportunity_focus` 命中(§7.8) | |
|
|
|
|
|
|
|
### 6.3 销售机会工作区 — 自定义视图(「自定义检索」Tab) |
|
|
|
@ -437,6 +445,18 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|
|
|
|
## §7 详情子表族 |
|
|
|
|
|
|
|
> **子表删除与唯一索引通用约定(grill 拍板 20260821,对齐 `crm-rule` `LeadPool` 既有实践)**:带业务字段/需审计的子表走**软删除 + 唯一索引复用键 `delete_key`**(存活 `delete_key=0`,逻辑删除时 `delete_key=id`;唯一索引挂 `delete_key` 而非裸列,保证同键可重新添加)。纯行为/收藏表走物理硬删。 |
|
|
|
> |
|
|
|
> | 表 | 删除方式 | 唯一索引 | |
|
|
|
> |---|---|---| |
|
|
|
> | `opportunity_customer` 关联客户 | 无独立删除,仅随商机级联逻辑删 | `UNIQUE(opportunity_id, customer_id)` | |
|
|
|
> | `opportunity_scheme_card` 方案卡 | 软删 + `delete_key` | `UNIQUE(opportunity_id, customer_id, delete_key)` | |
|
|
|
> | `opportunity_team` 团队成员 | 软删 + `delete_key`(移交/移除保留历史) | `UNIQUE(opportunity_id, user_id, delete_key)` | |
|
|
|
> | `opportunity_focus` 关注 | 物理硬删 | `UNIQUE(opportunity_id, user_id)` | |
|
|
|
> | `opportunity_view_log` 最近访问 | 物理硬删/裁剪 | `UNIQUE(user_id, opportunity_id)` | |
|
|
|
> |
|
|
|
> **硬删表的排查日志(grill 拍板 20260821,选项 C)**:`focus`/`view_log` 为纯行为/收藏流水,产品日志页无关注/浏览类目→**不入 oplog、不软删**;关注/取关/访问裁剪动作发生时**往应用日志(logback)打一条 INFO**(谁/何时/哪条商机/什么动作)供线上排查(时序完整、零表膨胀)——排查靠应用日志而非 DB 软删墓碎行。 |
|
|
|
|
|
|
|
### 7.1 关联客户 `opportunity_customer` |
|
|
|
|
|
|
|
**出处**:票 13 `opportunity-customer-relation`,原型 A3-1-1-2-4。 |
|
|
|
@ -449,7 +469,9 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
| `is_primary_intended` | tinyint 0/1 | ✅ | 是否主要意向客户,一商机唯一 =1 | |
|
|
|
|
|
|
|
- 线索转商机填的「意向客户」→ 落 `is_primary_intended=1`;商机侧添加普通关联客户 → `is_primary_intended=0`。 |
|
|
|
- **无删除动作(grill 纠偏 20260821,原型/票 13 均无删除)**:关联客户一律不可单独删(仅随商机级联清理,软删口径随商机)。要更换主要意向客户走「改主要意向客户」切标记(事务内旧主→0、新主→1),不删行。因无单独删 → 不存「删一客户又重加同 customer_id」场景,唯一索引无需 `delete_key`。 |
|
|
|
- 约束:`UNIQUE(opportunity_id, customer_id)`(一客户一商机只关联一次);主要意向客户唯一(应用层事务 + 部分唯一索引)。 |
|
|
|
- **「改主要意向客户」一致性(grill 拍板 20260821)**:一个事务内三步原子完成——① 旧主 `is_primary_intended` 1→0;② 新主 0→1;③ 刷主表冗余 `primary_customer_id`/`primary_customer_name_snapshot`=新主(主表冗余与子表标记永不中间不一致)。**并发防护 = 复用商机主表乐观锁 `version`**(切主客户=商机级写,CAS `WHERE opportunity_id=? AND version=?`,并发切换仅一胜出、其余版本失配重试/报错);子表部分唯一索引 `UNIQUE(opportunity_id) WHERE is_primary_intended=1` 作 DB 最后防线。 |
|
|
|
|
|
|
|
### 7.2 方案卡 `opportunity_scheme_card` |
|
|
|
|
|
|
|
@ -457,9 +479,10 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|
|
|
|
- **一客户一卡**:`UNIQUE(opportunity_id, customer_id)`;每张卡必挂一个当前商机下的关联客户(无孤立卡)。 |
|
|
|
- **状态机**:`草稿1 / 已提交2 / 已推送3`(「未创建」= 0 卡展示态,不入库)。 |
|
|
|
- 保存草稿 → 草稿;确认 → 已提交(核心字段锁);推送 A7-3-2-3 → 已推送(**本期可达**,推送方案补票,grill 补拍 20260821)。 |
|
|
|
- 保存草稿 → 草稿;确认 → 已提交(核心字段锁);推送 A7-3-2-3 → 已推送(**本期不可达**,推送链路随推送票 spin-out;本期卡最高至已提交 2,grill 拍板 20260821)。 |
|
|
|
- **推送成功 → 系统自动创建项目 → 商机转终态 5 + 落「已转项目」固定节点**(E8 触发源,grill 补拍 20260821)。 |
|
|
|
- **可编辑性**:草稿(1)/已提交(2) 均可改全部字段;仅已推送(3) 整卡只读(`card_status < 3` 可编辑),要改新建卡。不做字段级锁。 |
|
|
|
- **终态优先级高于方案卡自身状态机(grill 补拍 20260821)**:**任一方案卡推送成功即触发整商机转项目终态(E8,2→5)**——一商机多客户多卡,只要其中一张推送成功、系统建项目,整商机立刻进 `STATUS_CONVERTED(5)` 锁死。此后**其余草稿/已提交卡一律冻结为只读**(终态压制方案卡自身「草稿/已提交可编辑」口径)。故上一行「`card_status<3` 可编辑」的前提是**商机未处于关闭(4)/终态(5)**;商机一旦关闭或转项目,全部卡只读。 |
|
|
|
|
|
|
|
| 关键字段 | 说明 | |
|
|
|
|---|---| |
|
|
|
@ -476,6 +499,8 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
- 创建方案卡时**手动选模板版本**(不自动匹配,产品明确)。 |
|
|
|
- 候选范围 = 模板适用范围命中**商机 `owner_dept_id`**(所有商机档 + 指定部门命中档)的**「发布中」版本**;草稿/停用版本不可选。 |
|
|
|
- 选定后卡存 `card_template_id`(版本行 id)**锁版本**,模板发新版后在途卡继续用原版(V-CONFIG 7),不自动迁移。 |
|
|
|
- **无发布中模板→ 不能创建方案卡(grill 拍板 20260821)**:创建入口置灰,提示「当前无可用方案卡模板,请联系管理员」。候选匹配 = **专用优先、通用兵底**(命中本部门专用发布中版本 ∪ 所有部门通用发布中版本,与公海规则引擎口径统一),两者皆无才置灰。 |
|
|
|
- **系统初始化种子模板(grill 拍板 20260821,由 `crm-rule` seed 植入)**:初始化时种一条**「全公司通用」发布中方案卡模板作兵底(适用范围=所有部门),保证「无发布中→不能建卡」实践上几不触发。兵底模板可被管理员停用(二次确认警示,不硬锁)。字段集见附录 A。 |
|
|
|
|
|
|
|
### 7.3 现场勘察 `opportunity_site_survey` |
|
|
|
|
|
|
|
@ -520,8 +545,12 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|
|
|
|
**出处**:票 09 P6,原型 A3-1-1-1-9。 |
|
|
|
|
|
|
|
- **字段级变更审计**:实体对象/字段名称/旧值/新值/操作说明/来源(系统自动 vs 人工)/时间/操作人。普通用户只读。 |
|
|
|
- **与线索 `lead_history` 口径不同**:线索是动作枚举+JSON,商机是字段级旧新值审计。 |
|
|
|
- **双维度模型(grill 拍板 20260821)**:一条日志由两个正交枚举描述。 |
|
|
|
- **`op_kind` 记录形态**(怎么存):`FIELD_CHANGE`(有旧值/新值)/ `ROW_ADD`(整行新增,无旧值)/ `ROW_DELETE`(整行删除,无新值,带 `biz_ref` 被删行业务标识 + 快照摘要 JSON)。子表整行增删(关联客户/团队成员/勘察等)走 `ROW_ADD`/`ROW_DELETE`,日志可读为「删除关联客户:上海XX公司」而非 `deleted 0→1` 废记录。 |
|
|
|
- **`log_type` 业务类别**(原型 line 1745,决定前端日志页是否展示):`FIELD_CHANGE` 字段变更 / `STATUS_FLOW` 状态流转 / `STAGE_FLOW` 阶段流转 / `ATTACHMENT` 附件上传 / `SCHEME_PUSH` 方案推送 / `ROW_CHANGE` 子表增删(以上前端日志页可见)/ `SYSTEM_INTERNAL` 系统内部(**记库、前端日志页过滤不显**)。**枚举不含浏览/关注**(冲突6 定为硬删+logback、不入 oplog)。 |
|
|
|
- **记/不记口径(P1-5 + grill 20260821)**:默认全记 + 短黑名单排除(直接不记)。黑名单 = 纯技术字段(`create_time`/`update_time`/乐观锁列)+ 无业务含义的系统自动刷新(`last_valid_follow_time`)→ 连 `SYSTEM_INTERNAL` 都不落;`SYSTEM_INTERNAL` 只给「有排查价值、不给终端用户看」的少数系统动作(如 executeRecycle 系统侧写、推送联动终态),记库而不显(黑名单 ∩ SYSTEM_INTERNAL = ∅)。 |
|
|
|
- **删除留痕**:软删子表的删除动作记一条 `ROW_DELETE` oplog(给人看轨迹)+ 依赖 BaseEntity `updater_id`/`update_time`(给排查看谁在何时删),**不单加 `deleted_by`/`deleted_time`**。 |
|
|
|
- **与线索 `lead_history` 口径不同**:线索是动作枚举+JSON,商机是字段级旧新值审计 + 双维度分类。 |
|
|
|
- 状态/阶段迁移另有专用快照表 `opportunity_status_history` / `opportunity_stage_history`,与本通用审计并存不重。 |
|
|
|
|
|
|
|
### 7.8 关注 `opportunity_focus` |
|
|
|
@ -543,6 +572,26 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
- 裁剪:recent 视图只取上限条数(本期默认 50),表内历史行靠后台 Job 按容量/时间裁剪(超出视图范围的历史无业务用途)。 |
|
|
|
- 「最近访问」视图 = 该表命中当前用户,按 `last_view_time` 倒序取上限。 |
|
|
|
|
|
|
|
### 7.10 待发通知 `opportunity_pending_notice` |
|
|
|
|
|
|
|
**出处**:grill 拍板 20260821(回收提醒需落地、但平台通知能力未建)。 |
|
|
|
|
|
|
|
**通用待发通知表**——承接三处「向负责人发通知」需求(回收前提醒/暂缓到期提醒/催办)。本期只落待发记录,发送等平台通知能力就绪后由另一消费者补发。 |
|
|
|
|
|
|
|
| 字段 | 类型 | 说明 | |
|
|
|
|---|---|---| |
|
|
|
| `opportunity_id` | bigint | 所属商机 | |
|
|
|
| `notice_type` | varchar(32) | `RECYCLE_REMIND` 回收前提醒(本期唯一实际写入);预留 `PAUSE_EXPIRE` 暂缓到期 / `URGE` 催办 | |
|
|
|
| `target_user_id` | bigint | 应通知对象快照 = 当前负责人 | |
|
|
|
| `plan_notify_time` | datetime | 应发提醒时刻 | |
|
|
|
| `payload_json` | text | 提醒上下文(预计回收日/`recycle_days`/已无跟进天数等,**无「剩余天数」伪状态**) | |
|
|
|
| `notice_status` | tinyint | 待发0 / 已发1 / 已失效2 | |
|
|
|
|
|
|
|
- **幂等**:`UNIQUE(opportunity_id, notice_type, 批次键)` 防重复堆积;回收 Job upsert 待发记录。 |
|
|
|
- **补发**:平台通知能力就绪后,另起消费者扫 `notice_status=待发` 发出、置「已发」。 |
|
|
|
- **失效**:提醒发出前商机被回收/领取/暂缓/关闭 → 对应待发记录置「已失效」(不再补发过期提醒)。 |
|
|
|
- 本期只 `RECYCLE_REMIND` 真实写入;`PAUSE_EXPIRE`/`URGE` 随对应 spin-out 功能就绪时接入(不重建表)。 |
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
## §8 上下游集成 |
|
|
|
@ -552,7 +601,8 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
**出处**:票 02 `lead-port-consumer-contract`,原型 A3-1-1(线索转商机)。 |
|
|
|
|
|
|
|
- 线索侧提供 `CreateOpportunityCmd`(out-port),商机模块消费,转商机时自动带 `source_lead_id`。 |
|
|
|
- **契约变更(票 02 拍板,票 11 实现)**:`CreateOpportunityCmd` 新增 `customerId`(Long,**必填**);`intendedCustomer` 保留为客户名快照(走法 B:引用 + 快照并存)。 |
|
|
|
- **契约现状 vs 目标(grill 补拍 20260821,定性)**:本 PRD 描述的是**目标契约**;`crm-lead` 侧代码 `CreateOpportunityCmd` 是**现状**(尚未含 `customerId`,字段命名为 `intendedCustomer`/`regionCode`/`industryCode`);**票 11 = 差量**(把代码改齐目标)。实现方勿把本节读成「代码已如此」。 |
|
|
|
- **契约变更(票 02 拍板,票 11 实现)**:目标 = `CreateOpportunityCmd` 新增 `customerId`(Long,**必填**);`intendedCustomer` 保留为客户名快照(走法 B:引用 + 快照并存)。**字段命名以主表 §2.1 为准**——票 11 落地时做一次字段对齐:`regionCode`→拆 `province_code`/`city_code`;`intendedCustomer`→拆 `customerId`(引用)+ 客户名快照。 |
|
|
|
- 线索转商机弹窗:意向客户改为**下拉选客户**(选中拿到 `customer_id`);线索转商机前置要求「必须有意向客户」。 |
|
|
|
- 转商机时商机侧动作:建主表 + 建团队成员一条(领取人=商机负责人)+ 建关联客户一条(`is_primary_intended=1`,`customer_id`=cmd.customerId)。 |
|
|
|
- **幂等**:`UNIQUE(source_lead_id)` 保证一条线索只能关联一条商机。 |
|
|
|
@ -569,9 +619,10 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
### 8.3 商机 → 项目(转项目端口占位) |
|
|
|
|
|
|
|
- E8 转项目:对接 A5 项目模块(本模块只占端口,转项目后商机锁死终态 5)。 |
|
|
|
- **标准路径(grill 补拍 20260821)**:创建商机 → 填写方案卡 → **推送方案卡 → 系统自动创建项目** → 商机触发轴 1 终态 + 轴 2 固定节点「已转项目」。列表「转项目」按钮 = 推送流程快捷入口。 |
|
|
|
- **标准路径(grill 补拍 20260821;本期 spin-out 不可达)**:创建商机 → 填写方案卡 → **推送方案卡 → 系统自动创建项目** → 商机触发轴 1 终态 + 轴 2 固定节点「已转项目」。列表「转项目」按钮 = 推送流程快捷入口(推送票未拆,本期不可达)。 |
|
|
|
- **特殊路径(grill 补拍 20260821)**:跳过商机录入,项目侧直接创建项目,可关联方案卡(选填)——归 A5 项目模块定义。**关联即联动(grill 补拍 20260821)**:项目创建成功且关联了商机(或商机下的方案卡)时,A5 **回调商机模块触发 E8**(2→5)+ 落「已转项目」固定节点;本模块暴露回调端口(入参 = 商机 id 或方案卡 id),校验关联合法性后执行 E8 侧效(幂等:商机已终态则拒绝/跳过)。 |
|
|
|
- **推送方案本期做(grill 补拍 20260821,票 07 边界修订)**:推送流程页 A3-1-1-2-5 + 方案推送规则 A7-3-2-3 + **项目查重规则 A7-3-2-4 一并纳入**,**补一张推送票**(流程/规则细则待该票定;原型推送链路 = 选卡 → 查重校验 → 创建项目);推送成功 → A5 建项目 → 触发 E8。E8 两个触发源(标准/特殊)本期均真实可达。 |
|
|
|
- **转项目回调端口契约定死(grill 拍板 20260821,对称 lead→opp port)**——本期就出 interface,不留给 A5:① **定义方 = 商机侧 inbound port**(`crm-opportunity/port/inbound`,命名 `OpportunityConvertPort`),A5 调用(与 lead→opp 方向相反、范式一致);② **入参 record `ConvertToProjectCmd(opportunityId, schemeCardId, projectId)`**:`opportunityId`(Long 必填、幂等主键)/ `schemeCardId`(Long 选填、标哪张卡触发、无则 null)/ `projectId`(Long 已建项目 id,写快照/oplog)——“商机 id 或方案卡 id”含糊收敛为:商机 id 必填做幂等键、方案卡 id 选填标来源;③ **幂等命中(已终态 5)= 安静跳过返回**(对齐 lead port 口径,不抛异常),**校验失败(不存在/非可转态)= 抛 `OpportunityConvertException`**(对称 `OpportunityCreationException`);④ 本模块出 interface + record + exception 三件(对称 lead port 三件)。 |
|
|
|
- **推送方案本期 spin-out(grill 拍板 20260821,翻转 20260821 初拍“本期做”)**:推送流程页 A3-1-1-2-5 + 方案推送规则 A7-3-2-3 + 项目查重规则 A7-3-2-4 整体随一张**推送票 spin-out**(尚未拆)。理由:推送链路(选卡→查重→建项目)依赖 A5 项目模块 + 查重规则,与 A5 同为未建下游,硬说“本期可达”是给实现方埋雷。**本期 E8 仅特殊路径(A5 回调 `OpportunityConvertPort`)真实可达**;标准路径推送不可达。 |
|
|
|
|
|
|
|
### 8.4 商机 ↔ 客户(A4 客户模块) |
|
|
|
|
|
|
|
@ -633,6 +684,32 @@ crm-opportunity → crm-rule(阶段模板 / 方案卡模板 / 公海规则 |
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
## 附录 A 方案卡种子模板「全公司通用」字段集(grill 拍板 20260821) |
|
|
|
|
|
|
|
**来源**:原型 A7-3-2-2 预览填写页(OCR 校准 `1787558225260_*.png`)。由 `crm-rule` 初始化 seed 植入一条适用范围=所有部门、状态=发布中的模板,作为建卡兵底(冲突11)。`crm-opportunity` 只消费不负责 seed。 |
|
|
|
|
|
|
|
| 序 | 字段名称 | 字段类型 | 显示 | 必填 | A4 依赖 | 本期 seed | 备注 | |
|
|
|
|---|---|---|---|---|---|---|---| |
|
|
|
| 1 | 客户名称 | 关联对象 | 是 | 是 | ✅依赖 A4 | ⛳暂缓植入 | 从卡所挂关联客户引用带出(非卡冗余存储) | |
|
|
|
| 2 | 客户类型 | 单选下拉 | 是 | 是 | — | ✅植入 | 选项可 `option_source` 引 crm-dict「客户角色/类型」分组 | |
|
|
|
| 3 | 客户联系人 | 关联对象 | 是 | 是 | ✅依赖 A4 | ⛳暂缓植入 | 引用带出(依赖 A4) | |
|
|
|
| 4 | 客户联系电话 | 自动回填 | 是 | 否 | ✅依赖 A4 | ⛳暂缓植入 | `autofill_source`=联系人电话 | |
|
|
|
| 5 | 项目阶段 | 单选下拉 | 是 | 是 | — | ✅植入 | | |
|
|
|
| 6 | 招标形式 | 单选下拉 | 是 | 是 | — | ✅植入 | `option_source` 引字典「招标形式」 | |
|
|
|
| 7 | 是否有看现场 | 是/否 | 是 | 否 | — | ✅植入 | 布尔型 | |
|
|
|
| 8 | 现场勘察资料 | 附件上传 | 是 | 否 | — | ✅植入 | crm-file | |
|
|
|
| 9 | 方案预算金额 | 金额 | 是 | 否 | — | ✅植入 | = `scheme_budget`,列表「方案预算」列取主客户卡此值 | |
|
|
|
| 10 | 设计配置 | 单选下拉 | 是 | 否 | — | ✅植入 | | |
|
|
|
| 11 | 客户需求描述 | 多行文本 | 是 | 是 | — | ✅植入 | | |
|
|
|
|
|
|
|
**A4 缺席期的最小可跑子集(grill 拍板 20260821,选项 A)**:本期 `crm-rule` seed **只植入不依赖 A4 的字段**(序 2/5/6/7/8/9/10/11),保证 A4 缺席时建卡链路真可跑。依赖 A4 的 3 字段(序 1/3/4)**字段定义保留于 `opportunity_scheme_field_def`、但本期不进 seed 模板字段集**(标「A4 上线后启用」);A4 到达后管理员发新版模板把这 3 字段加回即可(V-CONFIG 发新版,无需改表)。 |
|
|
|
|
|
|
|
**字段类型初始枚举(`opportunity_scheme_field_def.field_type`,P0-3 自建字段库)**:关联对象 / 单选下拉 / 自动回填 / 是/否 / 附件上传 / 金额 / 多行文本(取自原型 11 字段,grill 20260821)。 |
|
|
|
|
|
|
|
对齐说明:① 前 4 字段(客户名称/类型/联系人/电话)为关联客户引用带出的展示字段,非卡新存业务数据;② 原型本版未列「预计成交时间」(P0-1 它是方案卡内部字段、可由模板配置,不强塞进种子模板)。 |
|
|
|
|
|
|
|
--- |
|
|
|
|
|
|
|
## §11 待确认清单索引(实现前须产品拍板) |
|
|
|
|
|
|
|
> 完整版见 `.scratch/opportunity-module/产品待确认清单.md`。以下均**不阻塞建模/表结构**(各票已给默认处置)。 |
|
|
|
|