From 9a9d6a3270eba52397f37d5386a81bf17691a204 Mon Sep 17 00:00:00 2001 From: luoweijian <1329394916@qq.com> Date: Mon, 24 Aug 2026 17:42:03 +0800 Subject: [PATCH] =?UTF-8?q?docs(opportunity):=20=E5=95=86=E6=9C=BA?= =?UTF-8?q?=E5=9F=9F=20spec=20=E5=AE=9A=E7=A8=BF=E6=94=B6=E5=B0=BE?= =?UTF-8?q?=EF=BC=88grill=20=E8=A1=A5=E6=8B=8D=2020260821=20=E5=9B=9E?= =?UTF-8?q?=E5=A1=AB=20PRD/map/=E5=BE=85=E7=A1=AE=E8=AE=A4=E6=B8=85?= =?UTF-8?q?=E5=8D=95=20+=20OCR=20=E5=AD=98=E6=A1=A3=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PRD V1.0 冻结态补拍:origin_dept_id、E8/E9/E10 迁移细化、切主客户一致性、待发通知表、 子表软删复用键 delete_key 约定等 grill 拍板内容 - 实现期回填两处一致性修正(票 03 code-review Spec 轴发现): * §2.2 owner_name_snapshot varchar(100)→varchar(64)(对齐票 03 B1「对称 lead」,lead 即 64) * §2.2 补登 version 乐观锁行(§7.1/§3.4 已引用但字段表漏登) - 方案卡模板 OCR 原始存档(1787558225260_*.png + ocr-scheme-card/doc_0.md) --- ...25260_a92d0f4eea8a41d7a958ff78622c232c.png | Bin 0 -> 48586 bytes .scratch/opportunity-module/map.md | 2 +- .../ocr-scheme-card/doc_0.md | 6 + .../产品待确认清单.md | 1 + .../opportunity-module/商机业务-PRD.md | 115 +++++++++++++++--- 5 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 .scratch/opportunity-module/1787558225260_a92d0f4eea8a41d7a958ff78622c232c.png create mode 100644 .scratch/opportunity-module/ocr-scheme-card/doc_0.md diff --git a/.scratch/opportunity-module/1787558225260_a92d0f4eea8a41d7a958ff78622c232c.png b/.scratch/opportunity-module/1787558225260_a92d0f4eea8a41d7a958ff78622c232c.png new file mode 100644 index 0000000000000000000000000000000000000000..5a235785fb9040956fc432da34c61e88d41c2669 GIT binary patch literal 48586 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

`p_T}3_tmWS=4V}=!JY*taTW$S4*NFh zt~-S--!^a~TF(tO6?!9JsQp|*uYsKd{TJ#e6M;q~Bo8+t`FbS#<1=%^q9Q4-Bhf{> zcT73U>mQ5VaF+{^Zw z_aV|W#KNZzSJJ4`d~=RgEQCZ1lI^+8Ug6UeN}?<{`V6Fs=?%E?6-F+M8@4p4AYow( z=W`3Y*vOJ1N>)|h4HSY(=P|&P@*h_5bncG3ZRv+HlT5= zcA;29t(2`5C?i?vBOX{o{jr)G$w0mEX!@~xgwpJkIF>3?XF|l=qaYtQLVMqD?ku;U zEtA3jmdCFee3nwfj`&Gy#&4}cx4g7PsZc`~u)UuVz|BDS(c1UL1l+(Q#R_o?n{o{x z7%@TEY^cjJ{6%+2npwOjT`9Z5E~alIzRi0kR=%RN7R|aUJB79 zhum@=Lz@${o?yj(z&Ed>$}57;)~)8CO|?fOGw-BWT20~_N%Xxhc?sC_D0yE&c_@@i zTRmd9-rjwZ*??<&>Zz?&QHl@a>S5bgCyjIy9?xU7GijR=lz19!E+ToZ#k$sZnR0#% zM?ks~Hqza|d6|@N?uSQxz1s?<1uXK{17DIdLFU7%`C#-MC8ycr?uM@} zsUsf}r`;AZA&uc@mNl)osDK~Bls-u(-ynkXSkIjC_SrIr?uk9=#_wW+46bIwZ4R-6 zT6cxV98KF`jW0`o9V6Z%RNGc2-DKgLnM=-Ur@t!H7F3^LQyC*eH6awssPFwFa@$&W zvmDNDex3_@cYgQnCaG{Rm2lx_1YZSF;G#fP`4SZgd5fFn)Z#RiRoR9#SKJ7{=!gqJ zCOh=Mm`BOit+f|JgLIY^DfrZ5yhP2G<%OY)4mNsxXm$%U0U^l3RtQkrt#Q9gQcZl9G`*OL8pBexCAcV^>jOv8GD5HGl^4m!JF!Hg~yzkuFvzwZFue=)D&;~ zx;=ct%dpEgS^GJ8eBD+ji=ja9bZTZ

$2}?pgWn2_q^gc82g*O&pc>#Mo(d0~!_B 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 adjaPw^9VTbX#CfnCK*WuXo + + +
序号字段名称字段类型显示必填
1客户名称关联对象
2客户类型单选下拉
3客户联系人关联对象
4客户联系电话自动回填
5项目阶段单选下拉
6招标形式单选下拉
7是否有看现场是/否
8现场勘察资料附件上传
9方案预算金额金额
10设计配置单选下拉
11客户需求描述多行文本
\ No newline at end of file diff --git a/.scratch/opportunity-module/产品待确认清单.md b/.scratch/opportunity-module/产品待确认清单.md index 88ae6a3..dabc392 100644 --- a/.scratch/opportunity-module/产品待确认清单.md +++ b/.scratch/opportunity-module/产品待确认清单.md @@ -154,6 +154,7 @@ ### 票 11 — CreateOpportunityCmd 新增 customerId + 线索侧意向客户下拉 - **性质**:改代码实现票(决策已在票 02 钉死)。 +- **契约现状(grill 补拍 20260821)**:代码中 `CreateOpportunityCmd` **尚未含 `customerId`**,且字段命名(`intendedCustomer`/`regionCode`/`industryCode`)与主表 §2.1 不对齐。PRD 描述目标契约,本票 = 差量:① 新增 `customerId`;② `regionCode`→`province_code`/`city_code`;③ `intendedCustomer`→`customerId`+客户名快照。 - **阻塞**:**依赖 A4 客户模块(未建)**——「下拉选客户」需线索侧能查客户列表,A4 到达前无法完整落地。 ### 票 12 — 商机侧新增入口:关联线索校验 diff --git a/.scratch/opportunity-module/商机业务-PRD.md b/.scratch/opportunity-module/商机业务-PRD.md index d0cacf8..5dfceb2 100644 --- a/.scratch/opportunity-module/商机业务-PRD.md +++ b/.scratch/opportunity-module/商机业务-PRD.md @@ -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`。以下均**不阻塞建模/表结构**(各票已给默认处置)。