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.
 
 
 
 
 
 

5.8 KiB

线索视图统计卡片改版(/api/lead/stats)

Destination

一份可交付的 /api/lead/stats 改版 spec:明确改版后四视图各自要展示哪些统计卡片、每张卡片的口径(映射到哪个 status / 派生条件)LeadStatsDTO 的字段形态,以及口径与「列表可见范围」冲突时的取舍规则。产出决策而非代码;spec 交付后再另起 session 实现。

目的地扩容(2026 grill 决策 01 后):新增一项前置领域小改 —— 作废态保留 owner_user_id(不再清空),使销售能在「我的线索」看到自己作废的线索;名额 hold_limit / 可转商机目录不受影响(二者按 status IN (3,4) 排除,本就不看 owner 是否为空)。本图目的地因此从「纯 stats spec」扩为「作废保留 owner 的状态机小改 + stats 改版 spec」;stats 口径是这个语义改动的下游消费者。

新需求(用户给定)——四视图卡片清单:

  • 线索公海:线索总量、待领取、今日新增
  • 我的线索:线索总量、已领取、跟进中、已转商机、线索作废、过期失效
  • 我的关注:线索总量、待领取、已领取、跟进中、已转商机、线索作废、过期失效
  • 线索管理:线索总量、今日新增、未分发、待领取、销售持有、已转商机、过期失效(销售持有 = 已领取 + 跟进中)

Notes

  • crm-lead 线索模块。状态机 7 态(LeadConstants):1未分发 / 2待领取 / 3已领取 / 4跟进中 / 5已转商机(终态) / 6过期失效 / 7线索作废。
  • 现状代码:接口 LeadController#statsILeadService#countStatsLeadViewQueryImpl#countStats;DTO LeadStatsDTO(现有字段 total/waiting/claimed/converted/todayNew/undistributed/feedbackValid/feedbackInvalid/feedbackNone)。统计口径复用 applyViewFilters,即「统计口径 = 列表口径」是当前的硬约束(P1-7)。
  • 关键冲突(本图的核心):现有视图过滤——
    • MY_LEAD = owner_user_id = 当前用户PUBLIC_POOL 仅可见 status ∈ {2,3,4}(PUBLIC_POOL_VISIBLE_STATUSES)。
    • CONTEXT:线索作废(7) 进入时清空 owner_user_id → 按现有 MY_LEAD 口径,作废线索不在我的线索里,但需求要 我的线索 统计「线索作废」。
    • 过期失效(6) 保留领取人 → 在 我的线索 里可见,口径无冲突。
    • 这决定了「统计口径 = 列表口径」这条硬约束是否还成立,是全图的根。
  • 参考crm-lead/CONTEXT.md(状态/归属语义)、.scratch/clue-module/(原历史 map 与 PRD)。
  • 用到的 skill:/grilling/domain-modeling;如需查历史决策用 /research

Decisions so far

  • 作废/过期线索的统计口径能否突破「列表可见范围」 — 定了作废态保留 owner_user_id(不再清空):名额 hold_limit / 可转商机目录均按 status IN(3,4) 排除作废,不依赖 owner=null,故保留 owner 不影响名额;清 owner 原本唯一副作用就是让作废线索离开「我的线索」,而那正是不想要的。目的地据此扩容(选 i)。
  • 作废保留 owner 的状态机小改 — 字段取舍(owner/name/claim_time 保留、recycle_deadline 清 null);回收/激活/DataScope/边#15 均自洽或选定“顶替”;列出文档待改行号与回归断言。下游 02 预填两格:各视图作废计数=自然过滤+status=7、「我的线索」含 owner=我的作废。
  • 四视图口径映射表 — 定了核心公式:所有分卡 = applyViewFilters + 单 status 条件,无逐格特判、不叠 owner 断言。开展六项定镀:“线索总量”=视图内 count(*);卡片吃全部 /page 动态筛选;“今日”按 JVM 时区 LocalDate.now() + create_time 范围条件(不看当前 status);销售持有 = status IN(3,4) 纯 status;「我的关注」含别人 owner 的作废/过期;MANAGE = 无业务过滤 + @DataScope(数字随角色变);需求✗格不追问。
  • 今日新增卡片下钻的列表联动入参 — 缺口:/pageLeadPageParam 无 create_time 入参,「今日新增」(不看 status 的时间窗)无法用 statusIn 下钻。定方案 B:加语义布尔 todayNewOnly,时间窗由后端按 LocalDate.now() 展开并下沉到 applyViewFilters(page/stats 共用同一段,前后端同一个"今天",严守 P1-7);弃通用区间方案 A(YAGNI)。前端点今日新增传 todayNewOnly:true 且不传 statusIn。
  • DTO 字段形态与前端返回契约 — 定了最终 10 字段 shapeclaimed 收窄为仅 status=3(语义改),新增 following(4)/expired(6)/voided(7)/sellerHolding(3+4);删 feedback 三字段及其 GROUP BY SQL(选甲)。全量返回、四视图同 shape、后端不知视图勾选表(选甲)。statusIn 照传照吃、严守 P1-7、卡片归零是前端渲染事(选丁)。钉定 10 个重写的 countStats_* 断言用例(@DataScope 合并 1 个、✗格字段如实计算)。

Not yet specified

  • 作废保留 owner 的残留触点(已 graduate 为 ticket 04,不再是雾):回收 N / 激活 / @DataScope / 边#15 重新分配 / PRD·CONTEXT 文档 —— 见 04。

全部 decision ticket(01/04/02/03)已 resolved。spec 完整,下一步是实现 session(不在本 wayfinder 图内)。

Out of scope