You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

49 KiB

商机业务 PRD

版本:V1.0(冻结自 spec effort .scratch/opportunity-module,票 01–14 全部 resolved) 用途:给其他智能体 / 产品 / 开发按原型页逐条核对,每条决策挂原型页码。 原型基准:蓝湖 V1.0-20260815;demo nginx/html/保伦CRM系统demo-重构版-S1_0803.html范围:spec-only,不含实现代码。⚠ = 实现前须产品拍板的待确认项。


§1 领域定义

出处:票 01 domain-vocab-boundary,原型 A3-x-x 总览。

1.1 什么是商机

商机(Opportunity)= 一条正在推进、准备转成项目的销售机会。

两条入口,进系统后完全平权(同样的流程 / 公海 / 视图,不因来路不同而区别对待):

入口 说明 原型页
线索转入 销售在线索里跟进成熟后转成商机 A3-1-1(线索详情转商机入口)
直接新建 销售跳过线索,直接建一条商机 A3-1-1-2-1

直接新建时默认负责人 = 当前操作人(原型 A3-1-1-2-1 明证)。

1.2 两条正交轴

商机同时有两个独立维度,不互相干扰

字段 通俗解释 原型对应
轴 1 归属流转状态 opp_status(tinyint,5 态) 这条商机归谁、现在处于什么归属处境 详情顶部「商机状态:推进中」A3-1-1-1-1
轴 2 业务阶段 current_stage_id(指向节点) 业务打法走到第几步 详情进度条 A3-1-1-1-1;阶段设置 A7-3-2-1

一句话:「状态」管归属,「阶段」管业务打法

1.3 核心角色

角色 定义 字段
负责人(领取人) 当前持有该商机的销售,归属 + 默认可见性双重含义 owner_user_id
团队成员 负责人拉入协作的人员,带项目角色(商机负责人 / 方案工程师 / 招标专员 / 现场工程师等)与权限(读写 / 只读 / 可写跟进 / 可推进节点等);是行级授权白名单,绕开 DataScope 部门天花板——生效边界 = 详情/子表读 + 个人工作区视图;管理/公海工作区严格按 DataScope 不混白名单(grill 补拍 20260821) opportunity_team(关联表)
创建人 全生命周期不变 creator_user_id
  • 抛公海只清空负责人,不动团队成员(产品明确,票 01)。
  • 转商机时自动插一条团队成员:领取人 = 商机负责人(票 02)。
  • 权限模型:按钮可见即可点,权限全由权限点配置决定,与「是否负责人」无关(票 01 产品明确)。

1.4 模块边界

crm-opportunity  →  crm-rule(阶段模板 / 方案卡模板 / 公海规则,零反依赖)
                 →  crm-auth(DataScope / SysUser)
                 →  crm-dict(字典码)
                 →  crm-file(附件上传)
                 →  crm-preference(列偏好 / 自定义视图)

商机规则(阶段模板 / 方案卡模板 / 公海规则 / 字典)住 crm-rule,商机模块只消费。

1.5 权限点需求清单(grill 梳理 20260821,编码实现阶段按平台规范登记)

权限模型(§1.3):按钮可见即可点,权限全由权限点配置决定。以下为需要权限点的动作全集

权限点动作
入口 销售机会工作区 / 商机管理工作区 / 商机公海工作区
商机主表 新增商机 / 编辑商机 / 关闭 / 重启
归属流转 领取(公海)/ 分配(管理)/ 抛公海(个人主动)/ 领导释放(管理强制)/ 暂缓 / 取消暂缓 / 移交
跟进 写跟进 / 删除跟进
方案卡 新增 / 编辑 / 提交 / 推送
团队成员 添加 / 调整角色与权限 / 移除(成员行上的读写/只读/可写跟进/可推进节点 = 行级角色配置,不走全局权限点
关联客户 新增 / 编辑 / 删除
现场勘察 新增 / 编辑 / 删除
附件 上传 / 删除
视图 关注 / 取关;自定义视图新增/编辑/删除;批量领取/分配/关注/领导释放(同单条动作权限点,批量不加新点)
审计 操作日志查看
后台(crm-rule 侧) 阶段模板管理 / 方案卡模板管理 / 公海规则管理 / 有效跟进规则管理
  • 颗粒度口径:动作级(一个动作一个点),不按「视图 × 动作」拆——同一动作在个人/管理/公海共用一个权限点,界面差异由视角 + 状态驱动(§6.7)。
  • 催办/督办本期不做(§6.6 spin-out 留白),不登记权限点。

§2 商机主表

出处:票 03 opportunity-main-table,原型 A3-1-1-2-1(新增表单)。

2.1 新增必填字段(原型 A3-1-1-2-1)

字段 类型 必填 说明
opp_name 商机名称 varchar(200)
opp_source 商机来源 varchar(64) 字典码 渠道归因;线索转入时默认置「线索转入」
opp_type 商机类型 varchar(64) 字典码
industry_code 行业 varchar(64) 字典码
bid_form 招标形式 varchar(64) 字典码
locality_type 项目属地 varchar(64) 字典码 本地/异地分类标签,非地理坐标
party_a_clear 甲方是否明确 tinyint 0/1
party_a 甲方名称 varchar(200) 条件必填 party_a_clear=1 时必填
province_code 省份 varchar(12)
city_code 市/区 varchar(12) 既可填市码也可填区/县码,不单建 district_code
remark 备注 text
project_amount 项目金额 decimal(14,2) 项目整体总包金额,选填可后补;默认人民币元,不建币种字段(Amendment 1)
意向客户(主要意向客户) 表单项,落 opportunity_customer 首条(is_primary_intended=1)+ 主表冗余快照;两条入口均必填(grill 补拍 20260821,与票 02 customerId 必填对齐);数据源依赖 A4 ⚠

2.2 系统生成字段

字段 类型 说明
opp_status tinyint 归属流转状态(轴 1),见 §3
owner_user_id 负责人 bigint 抛公海后清空
owner_name_snapshot 负责人姓名快照 varchar(100) 调岗不自动更新
owner_dept_id 负责人部门快照 bigint 公海可见范围锚点;调岗不变
creator_user_id 创建人 bigint 全生命周期不变
claim_time 领取时间 datetime 领取/分配/两入口创建时=now(「进入名下时间」,P1-6 拍板)
last_valid_follow_time 最近有效跟进时间 datetime 自动回收计时锚点(票 05);领取/分配重置=now;两入口创建以进入名下时间(=创建时刻)为起点;有效跟进时刷新(§5.3 定义,配置化 P1-8)
current_stage_id 当前阶段 bigint 指向 opportunity_stage_node.id(版本绑定,票 06)
stage_template_id 阶段模板版本 bigint 存模板版本行 id,锁死,发新版不自动迁移(票 06)
stage_template_version 模板版本号冗余 varchar(20) 展示用,免 join(如 V1.2)
source_lead_id 来源线索 bigint UNIQUE 幂等键;NULL 不参与唯一(直接创建可多条 NULL)
pool_reason 进入公海原因 varchar(32) 抛公海/回收时写(见 §3.2);公海列表筛选
primary_customer_id 主要意向客户 id bigint 冗余快查,= 关联客户表 is_primary_intended=1 那条
primary_customer_name_snapshot 主客户名快照 varchar(200) 列表/详情顶部免 join

继承 BaseEntity(id / create_time / update_time / creator / updater / 逻辑删除)。

2.3 DataScope 注解

@DataScope(module = "opportunity", ownerColumn = "owner_user_id", deptColumn = "owner_dept_id")

2.4 核心索引

索引 用途
UNIQUE idx_source_lead (source_lead_id) 一条线索只能关联一条商机(幂等键)
idx_owner_status (owner_user_id, opp_status) 「我负责的」视图
idx_owner_dept_status (owner_dept_id, opp_status) 公海视图 + 部门天花板

2.5 不建的字段(已明确排除)

  • pool_id:票 05 定稿删——商机域无独立池实体,公海 = 逻辑视图
  • dept_id:只用 owner_dept_id 快照做 DataScope 天花板
  • recycle_deadline:票 05 推翻,改为 last_valid_follow_time 实时算
  • 预计成交时间:产品二次拍板——商机主表不建、商机列表不展示;仅方案卡内部字段(票 07/10)

§3 归属流转状态机(轴 1)

出处:票 04 ownership-state-machine,原型 A3-1-1-1-1 / A3-1-1-2-x。

3.1 状态取值域(opp_status tinyint)

常量 名称 说明 终态
1 STATUS_IN_POOL 待领取(在公海) 无人持有,躺在商机公海
2 STATUS_ADVANCING 推进中 有负责人、正常推进
3 STATUS_PAUSED 暂缓中 短期挂起,保留负责人
4 STATUS_CLOSED 已关闭 只读锁定,可重启 半终态
5 STATUS_CONVERTED 已转项目 锁死,无任何出边 终态

3.2 迁移边全图

# 动作 Cmd 起始态→目标态 侧效摘要 原型页
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_timeowner_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(取消按钮)
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)
E10 超时回收 executeRecycle 2→1(批量) owner_user_id + owner_name_snapshot + claim_timeowner_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 管理页)。

3.3 受限态出边约束

状态 禁止的动作
已关闭(4) 仅允许 E7 重启;暂缓/抛公海/关闭/转项目/写跟进/推进节点 全禁;整商机只读、所有子表写全禁(原型 A3-1-1-2-9:推进类隐藏/置灰/禁止,只读操作保留)
已转项目(5) 无任何出边,全禁
暂缓中(3) 允许 E5/E6/E9;推进节点/转项目 受限(需先取消暂缓);一切编辑操作全禁,必须先取消暂缓回到推进中才能写(写跟进/子表写同禁,P1-7 拍板)

无删除动作(grill 补拍 20260821):商机不提供删除接口,终法只有关闭(→4)/转项目(→5),历史数据(含子表)永不删。

3.4 守卫与 CAS

  • 无「操作人==负责人」guard:商机侧详情页顶部操作区动作可见即可点,权限全由权限点决定(票 01 产品明确)。
  • CAS 乐观锁:每条迁移边在 WHERE id=? AND opp_status IN (合法起始态) 执行;更新 0 行抛 CODE_STATUS_NOT_ALLOWED
  • 移交 E9 CAS:WHERE id=? AND opp_status IN (2,3) AND owner_user_id=?原owner(防并发移交/抛公海竞态)。
  • 操作日志(P6):每条 Cmd 执行后 INSERT 一条 opportunity_oplog,含动作类型/操作人/时间/附加说明。

3.5 pool_reason 枚举(进入公海原因)

触发边 说明
销售主动释放 E3(销售本人操作)
特殊原因暂停 E3(销售本人操作,特殊原因)
领导释放 E3(管理侧操作,操作人≠owner)
超期回收 E10 executeRecycle 自动 Job

公海列表可按 pool_reason 筛选(原型 A3-3-1 筛选项)。


§4 业务阶段轴(轴 2)

出处:票 06 stage-template-versioning,原型 A7-3-2-1(商机阶段设置,列表/详情/新增 3 页)。

4.1 模型分层

  • 模板 + 节点住 crm-rule(版本化配置,遵 V-CONFIG 范式,见 §9)。
  • 运行时位置 + 版本快照住 crm-opportunity(主表 current_stage_id + stage_template_id + stage_template_version)。

4.2 阶段模板头表 opportunity_stage_template(crm-rule)

字段 类型 必填 说明
template_code 模板编码 varchar(64) 系统生成(如 OPP_GUIDE_01),同模板多版本共用,只读
version_no 版本号 varchar(20) 系统生成(V1.0/V1.1…),只读
status 状态 tinyint 1=草稿 / 2=发布中 / 3=已停用
apply_scope 适用范围 tinyint 1=所有商机 / 2=指定部门(两档单选,本期不做「指定业务类型」档)
is_default 是否默认 tinyint 同「适用范围+适用对象」内唯一
template_desc 模板说明 varchar
  • 适用对象子表 opportunity_stage_template_dept(apply_scope=2 时,适用部门多值)。apply_scope=1 → 无适用对象(原型「适用对象展示 --」)。

4.3 阶段节点表 opportunity_stage_node(crm-rule,从属模板版本)

字段 类型 必填 说明
template_id 所属模板版本 bigint opportunity_stage_template.id(版本级,每版本一套节点快照)
seq_no 阶段序号 int 推进顺序(轨道图左→右),增删/拖拽后系统重算
stage_dict_code 阶段字典值 varchar(64) 引用「商机阶段」字典分组项(如 OPP_STAGE_04),引用关系,自定义名不反写字典
custom_node_name 自定义节点名称 varchar(100) 本模板实际展示名,空则带入字典名
is_fixed 固定节点 tinyint 1=固定(「已转项目」)/ 0=普通

4.4 「已转项目」固定节点 × 轴 1 联动

  • 「已转项目」是每个模板的固定节点is_fixed=1,字典值固定 OPP_STAGE_05),配模板时自带、不可删(原型校验「除固定节点外至少创建一个阶段节点」),且不可拖到非末位(语义要求,落地校验)。
  • 推送方案卡成功(系统自动创建项目)→ 触发轴 1 转项目终态(E8)+ 轴 2 落到固定节点(标准路径,grill 补拍 20260821);无独立「转项目」动作,列表「转项目」按钮 = 推送流程快捷入口。

4.5 绑定与不迁移(V-CONFIG 12)

  • 商机绑定模板时记录具体版本stage_template_id = 版本行 id)。
  • 模板发新版后,在途商机继续用原版本,不自动迁移;新建/重新匹配的商机用当时最新发布版本(按适用范围匹配)。
  • 新建默认落首节点(客户圈定)。

⚠ P2-5:默认排序维度待产品定(建议最近跟进时间倒序)。


§5 商机公海规则

出处:票 05 opportunity-pool-rules,原型 A7-3-2-5(3 页一手正文)。

重要:商机公海规则 = 版本化规则配置(遵 V-CONFIG),非线索的 lead_pool 池实体。商机域无独立池实体——「公海」= opp_status=1 且 owner 为空 的逻辑视图,可见范围由 owner_dept_id + 匹配规则适用范围判定。

5.1 规则表 opportunity_pool_rule(crm-rule,版本化)

同一 rule_code 一套规则、多版本,每版本一行。核心配置五项:

字段 类型 必填 说明
rule_code 规则编码 varchar(64) 系统生成(如 POOL_RULE_01),同规则多版本共用
version_no 版本号 varchar(20) 系统生成,只读
apply_scope 适用范围 tinyint 1=所有商机 / 2=指定部门
allow_manual_pool 允许负责人手动转入公海 tinyint 0/1,控制「抛公海」入口是否对负责人开放
auto_recycle_enabled 启用自动回收 tinyint 0/1
  recycle_days 自动回收天数 N int auto_recycle_enabled=1 时必填;>0;连续未有效跟进达 N 天回收
allow_free_claim 允许自由领取 tinyint 0/1,控制适用范围内销售能否自领
recycle_remind_enabled 回收前提醒 tinyint 0/1,仅 auto_recycle_enabled=1 时可开
  remind_days 提前提醒天数 int recycle_remind_enabled=1 时必填;>0 且 < recycle_days(原型硬校验)

5.2 版本约束

  • 同一 rule_code 同时仅一个草稿 + 仅一个发布中
  • 复制 = 生成独立新规则(新 rule_code,非后续版本)。

5.3 领取 / 回收行为

场景 行为
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)
  • 有效跟进(刷新锚点,P1-8 拍板)= 商机状态为推进中(2) 且动作 = 写跟进(本期唯一动作;上附件/编辑字段/方案卡/勘察等不计,产品二次修订 20260821)。动作类型集合是配置项:落 crm-rule 第四族「有效跟进规则」opportunity_follow_rule(V-CONFIG 同族,动作类型多选子表,本期默认仅「写跟进」,以后经配置新增),回收 Job 按商机 owner_dept_id 实时匹配当前发布中规则拿动作集合(与公海规则同匹配引擎)。领取/分配重置锚点=now;两入口创建锚点=进入名下时间(P1-6)。

5.4 规则版本:实时匹配 vs 锅版本(关键区分)

公海规则与阶段模板的版本口径不同,核对时切勿混淆:

阶段模板(§4) 公海规则(本节)
绑定方式 主表存 stage_template_id(版本行 id),锁死版本 商机不存规则 id,只存 owner_dept_id
发新版 在途商机继续用原版本,不迁移(V-CONFIG 12) 待处理判断实时按当前发布中的版本
典型场景 商机“走什么打法”,中途换会打乱在途流程→锁版 “谁能碰这个部门公海”的当下策略,改规则就是要立刻生效→实时

口径(产品拍板,原型 A7-3-2-5):

  1. 「谁能领」判断→用当前发布中的版本(可见性归 @DataScope,见下节 grill 补拍口径)。池里商机无需“迁移”:拿 owner_dept_id 实时匹配当前发布中规则。管理员发新版(如关掉自由领取 / 新增部门专属规则圈进该商机)→ 立即对存量公海商机生效
  2. 历史动作不重算(原型明写): 已完成的领取/回收/提醒锁旧版快照,发新版不回溯。例:旧规则下已被领走的商机,不因发新版而撤销。
  3. 版本快照落操作日志(已定): 领取/回收时把实际执行的规则版本写进 opportunity_oplog(票 09),不上主表(一商机多次领/回收,主表存不下历史)。作用:查旧账(说清“当时凭哪版规则领/回收”)+ 落实口径 2 “历史不重算”。

一句记忆:公海规则跟着商机的部门、按当下发布中版本实时算;阶段模板锁版不迁移。

⚠ P2-6:原型 recycle_days/remind_days 样例值(30/7、45/7、20/5)非验收值,由规则配置录入。

5.4 规则匹配与执行语义(票 05「三」补抄,grill 20260821 核对)

  • 匹配锚点 = 商机自身的 owner_dept_id(规则跟着商机走,不跟查看人部门走):按该部门匹配 apply_scope=2 且部门命中 的发布中规则;匹配不到 → 发布中的所有部门通用默认规则兑底;部门专用 > 通用默认,发布约束保证唯一命中。专属规则决定该商机在公海谁能领(适用部门外不可领,grill 补拍 20260821 暂定,待产品终审);可见性归 @DataScope——公海视图查询自动叠加部门过滤(同管理视图口径),「看得到但领不了」场景领取按钮置灰提示。
  • 实时匹配,不锁版本:公海规则不存于商机主表,查看/领取/回收时拿 owner_dept_id 实时匹配当前发布中版本。管理员发新版立即对在池商机生效(如关掉「允许自由领取」→ 立刻不能自领)。⚠ 与阶段模板口径相反(阶段模板主表存 stage_template_id 锁死版本不迁移;公海规则实时匹配)。
  • 已完成的动作不重算,不回溯:旧规则下已领走/已回收的记录继续关联原规则版本(原型 A7-3-2-5 明写)。
  • 落库手段:每笔领取/回收把当时实际执行的规则版本快照写操作日志 opportunity_oplog,不上主表(一条商机会多次领/回收,主表只能存最新一次;存档 research-a7325 line 533/1097/1832)。

§6 视图体系

出处:票 10 four-views-query + 票 14 custom-views-and-builtin-view-family,原型 A3-1-1/A3-2-1/A3-3-1/A3-0-1;demo 0803 oppModule

6.1 三个工作区(workspace)

工作区 数据范围 原型 自定义视图
销售机会(个人) 见 6.2 内置视图 + 自定义视图 A3-1-1 本期开
商机管理 @DataScope 可见范围(复用 crm-auth,不自建数据权限) A3-2-1 本期不开
商机公海 opp_status=1 且 owner 空 逻辑视图;可见性 = @DataScope 自动叠加(按 owner_dept_id 部门锚点,同管理视图口径);公海规则适用范围管领取资格(grill 补拍 20260821,待产品终审) A3-3-1 本期不开

公海商机在管理视图的可见性(grill 补拍 20260821):owner 空但 owner_dept_id 保留作 DataScope 部门锚点,按查看者档位自然判定——全部档可见;部门档看 owner_dept_id 是否在其可见部门集合;仅本人档永不可见(owner 空 ≠ 本人)。故 E2 分配入口(管理页)对全部/部门档管理员数据可达,无需去公海页。

详情聚合接口可见性(grill 补拍 20260821)= DataScope 可见 OR 团队成员白名单命中——保证「我参与的」视图点进详情链路闭环;写操作再按成员自身权限点校验。

视图不是状态切片:同一商机可同时出现在多视图(如自己负责 + 最近访问过)。

6.2 销售机会工作区 — 内置四视图(「常用检索」Tab,固定不可删/改)

code 名称 数据范围
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 互斥
followed 我关注的销售机会 当前用户关注表 opportunity_focus 命中(§7.8)

6.3 销售机会工作区 — 自定义视图(「自定义检索」Tab)

用户保存的检索,加入常用检索列表(排在内置四视图之后)。一个自定义视图 =:

  • 检索名称(同一用户同一 scope 内唯一)
  • 检索条件:条件列表 [{field, operator, value}, …]
    • field列表所有可筛选列(字段池归商机模块定义)
    • operator等于 / 不等于 / 包含 / 不包含 / 为空 / 不为空
    • 本期前端只提交 1 组条件;契约按列表建模,预留多组(AND/OR)/ 高级公式扩展位
  • 排序条件:排序字段(∈字段池)+ 方向(asc/desc)

生命周期动作(用户私有):保存为常用检索 / 另存为新检索 / 编辑保存 / 重命名 / 删除(删当前视图回落 mine)。

默认视图(图钉):每个视图(内置四 + 自定义任一)可图钉设为该用户在此 scope 的默认视图,用户级单值;未设默认 → mine

6.4 落 crm-preference 平台能力

  • 自定义视图 = crm-preference 平台级能力(与「列偏好」并列),按 scope_key 分组、用户私有,对齐 ADR-0024「每菜单独立」。
  • 新实体 user_saved_view(user_id, scope_key, view_id, name, filter_json, sort_field, sort_direction, is_default, seq_no)filter_json 序列化条件列表;crm-preference 不校验字段合法性(字段池归业务方)。
  • 本期 scope = opportunity.sales(单一);后续菜单加 scope 即复用(产品确认「目前只销售机会、但要灵活性」)。
  • 内置视图不入库——口径硬编码在业务方,本表只存用户自建视图。
  • 契约:现有列偏好 get/save 之外,为自定义视图加 list / save / delete / setDefault(方法签名留实现阶段定)。

6.5 列表字段(个人/管理/最近访问共用基础列)

序号 / 选择框 / 商机名称 / 甲方 / 意向客户 / 行业 / 地区 / 预计金额 / 当前工作节点 / 节点停留时间 / 最近跟进 / 下一节点 / 方案卡状态 / 操作。

计算列口径(不冗余存,实时算/join):

口径
当前工作节点 current_stage_id 对应节点名
下一节点 模板中当前节点的下一 seq_no 节点(展示用「建议下一步」)
节点停留时间 今 − 进入当前节点日期(opportunity_stage_history 最新 to_time)
最近跟进 最新 opportunity_follow.create_time;无则 --
方案卡状态 主要意向客户is_primary_intended=1)那张方案卡的 card_status;无 → 「未创建」
方案预算 取主要意向客户那张方案卡的 scheme_budget;无则空
预计金额 主表 project_amount
当前负责人 owner_user_id 反查;个人页默认隐藏,管理/公海显示

6.6 各视图差异

视图 专属列 操作按钮 新增入口
个人 A3-1-1 负责人默认隐藏 详情 / 写跟进 「+新增商机」(默认归当前用户)
管理 A3-2-1 负责人显示 详情 / 分配 / 关闭 + 批量分配/关注/领导释放;催办/批量催办本期不做(spin-out 留白,grill 补拍 20260821)
公海 A3-3-1 入池前工作节点 / 进入公海原因 / 当前负责人 详情 / 关注 / 领取 + 批量领取/关注
最近访问 A3-0-1 按访问时间排序 详情 / 写跟进 / 关注 / 领取(按角色+商机态动态)

批量操作语义(grill 拍板 20260821):批量领取/关注/分配/领导释放 = 逐条处理、部分成功——成功的成功,失败的逐条给出失败原因,前端展示「成功 x 条,失败 y 条 + 失败明细」;无全批回滚、无长事务。

6.7 详情三皮肤

同一详情聚合,按视角展示不同操作区,非三套数据。Tab 结构一致(概览/客户信息/方案卡/现场勘察/相关附件/跟进记录/工作计划/团队成员/操作日志);差异在头部操作按钮 + 进入权限:

  • 个人 A3-1-1-1:写跟进/编辑/暂缓/抛公海/关闭/新增方案卡
  • 管理 A3-2-1-1:+ 分配/关闭;催办/督办本期不做(A3-2-1-1-1 督办功能 spin-out,催办随督办,grill 补拍 20260821)
  • 公海 A3-3-1-1:领取/关注,无跟进/推进入口(未领取不可推进)

⚠ P2-4:管理视角「领导 ▾」层级数据范围与 @DataScope 精确映射待实现阶段定。

spin-out 留白(grill 补拍 20260821)催办/督办 = 管理侧督促功能(A3-2-1-1-1),本期不实现——催办本质是向负责人发通知,而平台通知基础设施未建(暂缓到期提醒的发送渠道同因挂起);留白待平台通知能力就绪后与督办功能一并规划落地,本期管理视图隐藏催办/督办相关按钮。 ⚠ P2-7:自定义视图数量上限 / 多组条件开放时机 / 是否支持共享 待产品定。

6.8 视图形态(正交于视图内容,grill 补拍 20260821)

出处:原型 line 1281「分屏 split / 列表 list / 看板 board——展示模式切换,与『哪个视图/检索』正交」;A3-2-1「标题栏左侧视图切换 [ 列表、分屏、看板 ]」;票 10/14 均未定义此维度。

三种展示形态,与「哪个视图/检索」(6.2/6.3)正交——同一份列表数据三种渲染,后端列表接口不变(同一查询、同一 DataScope、同一分页),形态 = 前端渲染维度:

形态 code 定义 默认
列表视图 list 传统表格(§6.5 基础列 + 列偏好) 默认形态
分屏视图 split 左列表 + 右详情面板;面板复用详情聚合接口,非新数据源
看板视图 board 按「当前工作节点」分列的卡片流(列 = 阶段节点,列头带「共 N 条」计数;卡片 = 商机;底部「已展示 X/共 Y + 加载更多」——按列 or 整体加载的实现粒度留实现阶段定)
  • 适用范围:三个工作区(销售机会/商机管理/商机公海)+ 最近访问入口均支持三形态切换;切换入口 = 标题栏左侧,切换即刷新数据展示,操作按钮随工作区口径(原型 A3-2-1「切换不同入口时,标题栏、列表数据及可操作按钮同步刷新」)。
  • 列配置仅列表视图生效(grill 拍板 20260821):自定义字段配置 / 列偏好只作用于列表视图;看板卡片字段与分屏面板字段为固定口径,不跟列偏好。
  • 形态偏好落 crm-preference(与自定义视图同族,scope=opportunity.sales):用户切换后记住,下次打开该工作区保持上次形态;未设 → list

§7 详情子表族

7.1 关联客户 opportunity_customer

出处:票 13 opportunity-customer-relation,原型 A3-1-1-2-4。

字段 类型 必填 说明
opportunity_id bigint 所属商机
customer_id bigint 引用客户(A4 客户模块,⚠ 未建)
customer_role varchar(32) 客户角色(机电总包/工程商/集成商…)→ crm-dict「客户角色」分组;全部选填(grill 补拍 20260821)
is_primary_intended tinyint 0/1 是否主要意向客户,一商机唯一 =1
  • 线索转商机填的「意向客户」→ 落 is_primary_intended=1;商机侧添加普通关联客户 → is_primary_intended=0
  • 约束:UNIQUE(opportunity_id, customer_id)(一客户一商机只关联一次);主要意向客户唯一(应用层事务 + 部分唯一索引)。

7.2 方案卡 opportunity_scheme_card

出处:票 07 scheme-card,原型 A3-1-1-1-3 / A7-3-2-2/3。

  • 一客户一卡UNIQUE(opportunity_id, customer_id);每张卡必挂一个当前商机下的关联客户(无孤立卡)。
  • 状态机草稿1 / 已提交2 / 已推送3(「未创建」= 0 卡展示态,不入库)。
    • 保存草稿 → 草稿;确认 → 已提交(核心字段锁);推送 A7-3-2-3 → 已推送(本期可达,推送方案补票,grill 补拍 20260821)。
    • 推送成功 → 系统自动创建项目 → 商机转终态 5 + 落「已转项目」固定节点(E8 触发源,grill 补拍 20260821)。
  • 可编辑性:草稿(1)/已提交(2) 均可改全部字段;仅已推送(3) 整卡只读(card_status < 3 可编辑),要改新建卡。不做字段级锁。
关键字段 说明
card_status 草稿1/已提交2/已推送3(tinyint)
scheme_budget 方案预算金额 decimal(14,2);商机列表「方案预算」列取主要意向客户卡的此值

模板驱动动态字段

  • 模板头 opportunity_scheme_card_template(版本行,遵 V-CONFIG)+ 适用对象子表 _template_dept + 字段项 opportunity_scheme_card_field(有序)。
  • 字段定义库 opportunity_scheme_field_def(crm-rule,自建不复用 crm-dict):field_key/field_name/field_type(控件类型)/option_source/ref_target/autofill_source/default_value/is_deletable组合式:单选下拉类字段的选项集可 option_source=dict_group_code 引用 crm-dict 分组。
  • 运行时值 opportunity_scheme_card_value(card_id, field_key, field_value)(随模板字段)。
  • 「预计成交时间」是方案卡内部字段(非商机主表、非列表列,票 10)。

模板选择与锁定(grill 补拍 20260821)

  • 创建方案卡时手动选模板版本(不自动匹配,产品明确)。
  • 候选范围 = 模板适用范围命中商机 owner_dept_id(所有商机档 + 指定部门命中档)的**「发布中」版本**;草稿/停用版本不可选。
  • 选定后卡存 card_template_id(版本行 id)锁版本,模板发新版后在途卡继续用原版(V-CONFIG 7),不自动迁移。

7.3 现场勘察 opportunity_site_survey

出处:票 08 site-survey,原型 A3-1-1-1-4。

字段 必填 说明
survey_date 现场勘察日期
engineer_user_id 主要工程师 引用 crm-auth SysUser;列表展姓名/部门/联系方式(脱敏,反查不冗余存)
apply_way 申请方式 引用字典
survey_seq 勘察次数 引用字典
apply_no 申请单号 人工录入、选填(外部勘察申请流程未对接,单号线下拿到后补录;grill 拍板 20260821)
  • 勘察附件走统一附件表(biz_type=SITE_SURVEY + biz_id)。

7.4 跟进记录 opportunity_follow

出处:票 09 P2,原型 A3-1-1-1-6 / 写跟进 A3-1-1-2-2。

  • 字段 + opp_id + BaseEntity(create_by/create_time = 记录人/时间)。
  • 跟进附件 → 附件子表 biz_type=FOLLOW_UP,最多 10 个。
  • 保存跟进 → 刷新商机「最近跟进」 + last_valid_follow_time(回收锚点刷新点,票 05 联动)。
  • 支持删除,删除不回退回收锚点(grill 拍板 20260821):删除后 last_valid_follow_time 保持不变(不回退重算,防「写了又删」刷锚点);「最近跟进」计算列按删除后最新留存行自然变化;删除动作入 oplog。编辑本期不做(见清单 P2-9,写错以删除+补写方式修正)。

7.5 附件 opportunity_attachment(统一表)

出处:票 09 P4,原型 A3-1-1-1-5,复用 crm-file。

  • 一张附件表 + biz_type + biz_id 定位,不为每个子表各建附件表。
  • biz_type 枚举:OPP(商机通用) / FOLLOW_UP(跟进) / SITE_SURVEY(勘察) / SCHEME_CARD(方案卡) …
  • 数量上限:仅跟进附件限 10 个/条(原型明画);其余 biz_type 不设业务上限,由 crm-file 层统一管控(grill 补拍 20260821)。
  • 附件归属商机(无孤立附件,硬约束);文件本体走 crm-file,本表存资料类型/说明/上传人/时间。

7.6 工作计划 opportunity_work_plan(结构 only)

出处:票 09 P5,原型 A3-1-1-1-7。

  • 🅿️ 工作计划 = 独立业务模块 A1X,本期挂起(产品拍板 P1-4)。本商机模块只保留子表结构与归属契约(多条/归属商机/内容/deadline/plan_status/finish_time)。
  • plan_status:未完成0/已完成1(逾期=未完成且 now>deadline,实时算)。精确态枚举、状态机、与跟进联动、Tab 读中央模块 全归 A1X 模块定。

7.7 操作日志 opportunity_oplog

出处:票 09 P6,原型 A3-1-1-1-9。

  • 字段级变更审计:实体对象/字段名称/旧值/新值/操作说明/来源(系统自动 vs 人工)/时间/操作人。普通用户只读。
  • 与线索 lead_history 口径不同:线索是动作枚举+JSON,商机是字段级旧新值审计。
  • 状态/阶段迁移另有专用快照表 opportunity_status_history / opportunity_stage_history,与本通用审计并存不重。

7.8 关注 opportunity_focus

出处:票 14 视图引用,grill 补拍 20260821(新建,PRD 此前引用未定义的表)。

  • 纯收藏夹语义,不带通知(通知属平台通知基础设施,未建;后续要通知再加字段,grill 补拍 20260821)。
  • 字段:opportunity_id + user_id + BaseEntity;约束 UNIQUE(opportunity_id, user_id)
  • 关注/取关无需原因、物理删行即可(关注不是审计对象,不入 oplog)。
  • 「我关注的」视图 = 该表命中当前用户;管理/公海/最近访问视图的「关注」按钮读写此表。

7.9 最近访问 opportunity_view_log

出处:grill 补拍 20260821(票 10 recent 视图落库方式未定,拍板新建)。

  • 字段:user_id + opportunity_id + last_view_time + BaseEntity;约束 UNIQUE(user_id, opportunity_id)
  • 写入时机 = 调用详情聚合接口即 upsert(刷新 last_view_time);个人/管理/公海任意皮肤都算(§6.2)。
  • 不写 opportunity_oplog:访问是高频行为数据,oplog 是审计轨迹(行为类别不含浏览,票 09),两者分离。
  • 裁剪:recent 视图只取上限条数(本期默认 50),表内历史行靠后台 Job 按容量/时间裁剪(超出视图范围的历史无业务用途)。
  • 「最近访问」视图 = 该表命中当前用户,按 last_view_time 倒序取上限。

§8 上下游集成

8.1 线索 → 商机(消费线索侧 port)

出处:票 02 lead-port-consumer-contract,原型 A3-1-1(线索转商机)。

  • 线索侧提供 CreateOpportunityCmd(out-port),商机模块消费,转商机时自动带 source_lead_id
  • 契约变更(票 02 拍板,票 11 实现)CreateOpportunityCmd 新增 customerId(Long,必填);intendedCustomer 保留为客户名快照(走法 B:引用 + 快照并存)。
  • 线索转商机弹窗:意向客户改为下拉选客户(选中拿到 customer_id);线索转商机前置要求「必须有意向客户」。
  • 转商机时商机侧动作:建主表 + 建团队成员一条(领取人=商机负责人)+ 建关联客户一条(is_primary_intended=1customer_id=cmd.customerId)。
  • 幂等UNIQUE(source_lead_id) 保证一条线索只能关联一条商机。

8.2 商机侧新增入口 → 关联线索校验

出处:票 12 related-lead-validation,原型 A3-1-1-2-1。

  • 商机侧新增入口当用户选「商机来源 = 线索转入」时,手选一条【关联线索】写 source_lead_id(复用票 02 字段,不新建 related_lead_id)。
  • 候选线索范围 = 线索 status IN (已领取, 跟进中)source_lead_id 未被占用(与线索侧转商机准入对称)。
  • 命中已占用 → 返回错误码 opp.related_lead.taken;靠 UNIQUE(source_lead_id) 保唯一。
  • 直接创建且来源非「线索转入」→ source_lead_id NULL(可多条 NULL)。

8.3 商机 → 项目(转项目端口占位)

  • E8 转项目:对接 A5 项目模块(本模块只占端口,转项目后商机锁死终态 5)。
  • 标准路径(grill 补拍 20260821):创建商机 → 填写方案卡 → 推送方案卡 → 系统自动创建项目 → 商机触发轴 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 两个触发源(标准/特殊)本期均真实可达。

8.4 商机 ↔ 客户(A4 客户模块)

  • A4 客户模块未建。关联客户 customer_idprimary_customer_id、线索转商机「下拉选客户」均引用 A4。
  • 票 11(customerId 契约字段)、票 13(关联客户表)已定契约;「下拉选客户」UI 数据源待 A4 到达。

§9 商机规则三族 · 版本化配置范式(V-CONFIG)

出处:票 06 抽出,票 05/07 复用。

crm-rule 三族配置共享同一版本化范式:

编码前缀样例
阶段模板 opportunity_stage_template OPP_GUIDE_*
公海规则 opportunity_pool_rule POOL_RULE_*
方案卡模板 opportunity_scheme_card_template
有效跟进规则 opportunity_follow_rule FOLLOW_RULE_*

V-CONFIG 公共约定:

  1. 同一 code 多版本,每版本一行。
  2. version_no 系统生成(V1.0/V1.1/V2.0…),只读。
  3. status:1=草稿 / 2=发布中 / 3=已停用。
  4. 同一 code 同时仅一个草稿 + 仅一个发布中
  5. apply_scope:1=所有商机 / 2=指定部门(两档单选,本期不做「指定业务类型」);apply_scope=2 配适用对象子表(部门多值)。
  6. is_default:同「适用范围+适用对象」内唯一;发布新默认 → 原默认自动取消。
  7. 绑定快照:业务实体绑定配置时记录具体版本;新版本发布后原绑定实体继续用原版本不自动迁移;新建/重新匹配用最新发布版本。
  8. 复制 = 生成独立新规则(新 code,非后续版本)。
  9. 列表按版本维度展示:同 code 的草稿/发布中/停用各占一行,不合并。

crm-rule 对上层零反依赖:规则表不知道 opportunity 实体,靠 apply_scope/部门 + code 弱关联。


§10 字典清单(走 crm-dict,选项值由产品录入)

⚠ P2-1:本模块只定「要做字典」,具体选项值由产品提供。

字典分组 用途 出处
商机来源 opp_source 渠道归因(含「线索转入」) 票 03
商机类型 opp_type 票 03
行业 industry_code 票 03
招标形式 bid_form 票 03
项目属地 locality_type 本地/异地分类 票 03
商机阶段 OPP_STAGE_* 客户圈定/关系摸排/资料采集/方案卡/已转项目… 票 06
进入公海原因 pool_reason 销售主动释放/特殊原因暂停/领导释放/超期回收 票 04/10
暂缓原因 票 04
关闭原因 票 04
客户角色 机电总包/工程商/集成商… 票 13
跟进方式 电话/上门/微信/线上会议/展会… 票 09
跟进结果标签 暂无进展/需求确认/方案推进… 票 09
商机资料类型 现场资料/设计清单·图纸/客户需求资料/招投标相关资料/其它 票 09
申请方式(勘察) 工单申请/线下申请… 票 08
勘察次数 票 08

§11 待确认清单索引(实现前须产品拍板)

完整版见 .scratch/opportunity-module/产品待确认清单.md。以下均不阻塞建模/表结构(各票已给默认处置)。

编号 待确认项 现状
P2-1 各字典具体选项集 P2 走 crm-dict,产品录入
P2-4 管理视角「领导 ▾」层级数据范围 vs @DataScope 精确映射 P2 复用 crm-auth,映射待实现阶段定
P2-5 内置视图默认排序维度 P2 建议最近跟进倒序,待定
P2-6 公海规则数值样例 P2 样例非验收值,规则配置录入
P2-7 自定义视图:数量上限 / 多组条件(AND/OR)+高级公式开放时机 / 是否支持共享 / 管理·公海是否开 P2 本期私有、1 组条件、只销售机会开
P1-4 工作计划精确状态枚举 🅿️ 归 A1X 独立模块,本期挂起
P1-6 归属起点计时初始化(领取/分配重置、两入口创建=进入名下时间) P1 已拍板(产品回复 20260821)
P1-7 暂缓期间子表可写范围 P1 已拍板(暂缓/关闭先解除状态才能编辑)
P1-8 有效跟进定义修订+配置化 P1 已拍板(本期仅写跟进;配置化保留可新增)

已拍板存档(备查): 预计成交时间归属(P0-1,方案卡内部/不上主表/列表删除)、阶段模板适用范围两档(P0-2)、字段定义库自建不复用 crm-dict(P0-3)、方案卡状态枚举+多卡取值锚点(P0-4)、方案卡可编辑性(P1-1,card_status<3)、勘察次数生成(P1-2)、勘察补充说明必填(P1-3)、操作日志关键字段(P1-5)、最近访问去重+上限(P2-2)、方案卡状态列多卡口径(P2-3)。


附:原型事实出处索引

原型页 内容
A3-1-1 商机个人视图列表 / 线索转商机入口
A3-1-1-1-1 商机详情概览(状态条 + 进度条)
A3-1-1-1-3~9 详情 Tab:方案卡/勘察/附件/跟进/工作计划/团队成员/操作日志
A3-1-1-2-1 新增商机表单
A3-1-1-2-2 写跟进
A3-1-1-2-4 添加关联客户
A3-1-1-2-6/7/9 暂缓 / 抛公海 / 关闭
A3-2-1 商机管理视图
A3-3-1 商机公海视图
A3-0-1 最近访问视图
A7-3-2-1 商机阶段设置(阶段模板)
A7-3-2-2/3 方案卡模板 / 方案推送
A7-3-2-5 商机公海与提醒规则
demo 0803 oppModule 视图体系(内置四视图 + 自定义视图交互)

票映射总表:

主题 PRD 章节
01 领域词汇与边界 §1
02 线索侧 port 消费契约 §8.1
03 商机主表 §2
04 归属流转状态机 §3
05 商机公海规则 §5
06 阶段模板版本化 §4 §9
07 方案卡 §7.2
08 现场勘察 §7.3
09 子表族(跟进/附件/工作计划/日志) §7.4–7.7
10 四视图与列表/详情查询 §6
11 CreateOpportunityCmd + customerId §8.1(实现票)
12 商机侧关联线索校验 §8.2(实现票)
13 商机-关联客户 §7.1
14 自定义视图 + 内置视图族 §6.2–6.4

(本 PRD 冻结自 spec,如与原型有出入,以原型 + 票正文为准并回填对应票。)