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.

47 lines
5.2 KiB

2 weeks ago
<!-- wayfinder:map -->
# 线索视图统计卡片改版(/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#stats``ILeadService#countStats``LeadViewQueryImpl#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
<!-- 一行一个已关闭 ticket:够判断相关性即可,细节回 ticket 里看 -->
- [作废/过期线索的统计口径能否突破「列表可见范围」](issues/01-作废过期口径vs可见范围.md) — 定了**作废态保留 owner_user_id**(不再清空):名额 hold_limit / 可转商机目录均按 status IN(3,4) 排除作废,不依赖 owner=null,故保留 owner 不影响名额;清 owner 原本唯一副作用就是让作废线索离开「我的线索」,而那正是不想要的。目的地据此扩容(选 i)。
- [作废保留 owner 的状态机小改](issues/04-作废保留owner状态机小改.md) — 字段取舍(owner/name/claim_time 保留、recycle_deadline 清 null);回收/激活/DataScope/边#15 均自洽或选定“顶替”;列出文档待改行号与回归断言。下游 02 预填两格:各视图作废计数=自然过滤+status=7、「我的线索」含 owner=我的作废。
- [四视图口径映射表](issues/02-四视图口径映射表.md) — 定了核心公式:**所有分卡 = `applyViewFilters` + 单 status 条件**,无逐格特判、不叠 owner 断言。开展六项定镀:“线索总量”=视图内 count(*);卡片吃全部 `/page` 动态筛选;“今日”按 JVM 时区 `LocalDate.now()` + `create_time` 范围条件(不看当前 status);销售持有 = `status IN(3,4)` 纯 status;「我的关注」含别人 owner 的作废/过期;MANAGE = 无业务过滤 + `@DataScope`(数字随角色变);需求✗格不追问。
- [DTO 字段形态与前端返回契约](issues/03-DTO字段与返回契约.md) — 定了最终 **10 字段 shape**:`claimed` 收窄为仅 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
<!-- 超出本次目的、已排除的工作 -->