docs(openspec): C2 派单工单 change 提案

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-14 21:53:59 +08:00
parent 4fa03ab69d
commit bec32cf223
9 changed files with 236 additions and 0 deletions

View File

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-10-14

View File

@ -0,0 +1,47 @@
## Context
C1 已有 elder(十态状态机)、svc_org(L4 目录)、staff(护理员)。C2 新增派单工单域,纯新增、不侵入脚手架。设计背景见 `docs/superpowers/specs/2026-10-14-服务机构端-C2派单工单-design.md`。
## Goals / Non-Goals
**Goals:** 服务计划(制定/变更/项数校验)、八态工单(派单/调单/冲突/批量推荐)、老人个人项目库、后台排班派单页。
**Non-Goals:** 垫付 is_prepaid 与结转(C3)、护理员 APP、自动派单、跨机构冲突检测。
## Decisions
1. **表命名**:`svc_plan`/`svc_plan_item`/`svc_order`(服务域)、`ltc_elder_svc`(老人域)。
2. **垫付切分**:C2 只做派单例外(waiting_period 允许派单),is_prepaid/结转 C3。
3. **项数校验为配置数据**:昆明规则表内置为常量(care_mode×care_level → 项数/周次/月时长),州市 `loc_config.item_count_rule` 为空则只提示。
4. **时间冲突检测**:同 assignee_id 且 `time_slot_start < 他人 time_slot_end AND 他人 time_slot_start < time_slot_end` 重叠 → 2001。
5. **快照**:plan_item/order.item_list 存 `svc_name_snapshot`/`svc_code_snapshot`。
6. **批量推荐只读**:权重常量可配置,返回推荐列表 + 理由,不自动派。
## 数据模型(DDL 概览)
通用字段 + UUID v7 + tenantCode + 软删。
- **svc_plan**:id、tenant_code、elder_id、plan_period_start/end(@db.Date)、care_level、care_mode、item_count、item_count_rule、extra_item_count、week_freq、month_hours、plan_status、confirm_elder、confirm_guardian、confirm_time、plan_basis(json)、change_from_plan_id、biz_line。索引 (tenant_code, elder_id)。
- **svc_plan_item**:id、plan_id、svc_id、svc_name_snapshot、svc_code_snapshot、freq_type、freq_value、duration_min、photo_tier、caution_note、is_medical、need_cert。索引 (plan_id)。
- **svc_order**:id、tenant_code、elder_id、plan_id、service_date(@db.Date)、time_slot_start/end(datetime)、assignee_id、assign_time、assign_mode、order_status、item_list(json)、need_photo、cancel_reason、reschedule_log(json)、qualification_check、billable、price_snapshot、settle_period、not_met_reason、not_met_at、biz_line。索引 (tenant_code, assignee_id, service_date)、(tenant_code, elder_id)。
- **ltc_elder_svc**:id、tenant_code、elder_id、svc_id、svc_name_snapshot、svc_code_snapshot、care_mode、is_active。索引 (tenant_code, elder_id)。
PrismaService:四表均为租户级(tenantCode 自动注入);svc_plan/svc_plan_item/svc_order/ltc_elder_svc 加入 SOFT_DELETE。
## 接口(`@Controller('plan')` / `@Controller('order')` / `@Controller('elder-svc')`)
plan:POST `/plan`、POST `/plan/change`、GET `/plan/:id`、POST `/plan/:id/confirm`、GET `/plan/by-elder/:elderId`。
order:POST `/order/generate`、POST `/order/assign`、POST `/order/:id/reassign`、GET `/order/batch-recommend`、GET `/order/today`、POST `/order/:id/cancel`、GET `/order/:id`。
elder-svc:GET `/elder-svc/:elderId`、PUT `/elder-svc/:elderId`。
权限码:plan.create/change/detail/confirm、order.generate/assign/reassign/cancel/detail/today、elder.svcSave(复用)。APIS 登记资源。
## Risks / Trade-offs
- [昆明项数规则可能随细则变化] → 规则为常量配置,改常量即可;州市不校验。
- [时间冲突只做单机构内] → 跨机构冲突 C2 不做(PRD 明确)。
- [快照冗余存储] → 必要(目录改名后历史计划/工单仍显示当时项目名)。
## Migration Plan
新增迁移建 4 张表(utf8mb4_general_ci,手改 collation)。回滚=删除迁移。

View File

@ -0,0 +1,32 @@
## Why
C1 已落地老人档案与十态状态机。C2 交付 PRD 第二块「派单工单」:服务计划(制定/变更/属地项数校验)、排班派单(八态工单/调单/时间冲突/批量推荐)、老人个人项目库——为 C3 履约留痕提供「有效工单」这一 L3 硬锁前提。
## What Changes
- 新增 `svc_plan`/`svc_plan_item`/`svc_order`/`ltc_elder_svc` 四张表。
- 服务计划:制定、变更(新建+指向旧)、三方确认、昆明属地项数校验(≥13/15/18 + 附加≤5,州市只提示)。
- 八态工单 + 派单/调单(≤3步)/取消 + 时间冲突硬拦(2001)+ 批量推荐(人工确认)。
- L1 硬锁消费:派单时 `elder.treat_status ∈ {active, waiting_period}`(waiting_period 垫付例外,is_prepaid 留 C3)。
- 老人个人项目库:制定计划时一键带入(可改)。
- 前端「排班派单」页 + 「服务对象」页加个人项目库/制定计划。
## Capabilities
### New Capabilities
- `backend/plan`: 服务计划 + 老人个人项目库——plan/plan_item/elder_svc,属地项数校验、带入、变更留旧版。
- `backend/order`: 工单——order 八态、派单/调单/取消、时间冲突硬拦、批量推荐。
- `frontend/ad/schedule`: 排班派单页 + 服务对象页扩展。
### Modified Capabilities
- `shared/data-model`: 新增 `svc_plan`/`svc_plan_item`/`svc_order`/`ltc_elder_svc` 四实体。
- `shared/api-contract`: 新增 plan/order/elder-svc 接口。
## Impact
- 后端 ec-nest:新增 plan/order 模块(纯新增)。
- 前端 ec-admin:排班派单页 + 服务对象页扩展。
- 数据:新增 4 张表(迁移,utf8mb4_general_ci)。
- 依赖:C1 的 elder 状态机、svc_org 目录、staff(护理员)。

View File

@ -0,0 +1,33 @@
## Purpose
定义服务机构端工单域的后端行为——八态工单、派单/调单/取消、时间冲突硬拦、批量推荐。
## ADDED Requirements
### Requirement: 派单前置校验
`POST /order/assign` MUST 按序校验:工单态 → 老人态(treat_status ∈ {active, waiting_period},否则 1001)→ 有计划(否则 1002)→ 护理员当班 → 时间冲突(2001 硬拦)→ 资质(1006 提示)。
#### Scenario: 无有效待遇不可派单
- **WHEN** 派单时老人 treat_status 非 active/waiting_period
- **THEN** 返回 1001 拒绝
### Requirement: 时间冲突硬拦
同 assignee_id 且 time_slot 重叠 MUST 拒绝(2001)。
#### Scenario: 同时段重叠
- **WHEN** 同一护理员已有 09:00-10:00 工单,再派 09:30-10:30
- **THEN** 返回 2001,拒绝保存
### Requirement: 调单与批量推荐
`POST /order/:id/reassign` MUST 记 reschedule_log(改前改后/时间/操作人);`GET /order/batch-recommend` MUST 只返回推荐(权重:同资质→历史服务过→距离近→负荷低),不自动派单。
#### Scenario: 调单留痕
- **WHEN** 调单改派护理员
- **THEN** 写 reschedule_log 并通知新护理员
### Requirement: 工单八态
order_status MUST 支持 to_assign/assigned/serving/done/abnormal/cancelled/overdue/not_met;取消必填 cancel_reason。
#### Scenario: 取消需原因
- **WHEN** 取消工单缺 cancel_reason
- **THEN** 拒绝

View File

@ -0,0 +1,26 @@
## Purpose
定义服务机构端服务计划与老人个人项目库的后端行为——制定/变更计划、属地项数校验、个人项目库带入。
## ADDED Requirements
### Requirement: 制定服务计划
`POST /plan` MUST 校验:老人存在、项目从本机构 L4 选、属地项数(昆明校验/州市提示)、care_mode×care_level 规则。plan_status 置 active。
#### Scenario: 制定计划
- **WHEN** 质控员制定计划并选够项目
- **THEN** 创建 active 计划,item_count 与 item_count_rule 快照记录
### Requirement: 计划变更不原地改
`POST /plan/change` MUST 新建计划 + change_from_plan_id 指向旧计划,旧计划转 changed。
#### Scenario: 变更留旧版
- **WHEN** 变更计划
- **THEN** 旧计划转 changed、新计划 active,历史工单仍指向旧计划
### Requirement: 老人个人项目库
`PUT /elder-svc/:elderId` MUST 整表覆盖(svc_id 必须落在本机构 L4、care_mode 变更=重制、旧库留档);制定计划可一键带入。
#### Scenario: 带入计划
- **WHEN** 制定计划时选择「从个人项目库带入」
- **THEN** 自动生成 plan_item 初稿,可修改

View File

@ -0,0 +1,19 @@
## Purpose
定义服务机构端「排班派单」页面与「服务对象」页扩展的交互。
## ADDED Requirements
### Requirement: 排班派单页
日视图(横轴时间段/纵轴护理员)MUST 显示工单卡片、空缺橙框、冲突红框;调单面板 ≤3 步;批量推荐需人工确认。
#### Scenario: 调单三步
- **WHEN** 点击卡片→选目标护理员→确认
- **THEN** 生效并自动通知
### Requirement: 服务对象页扩展
档案页 MUST 提供「个人项目库」区块(勾选 L4 项目、可空)与「制定计划」入口(一键带入、可改、校验项数)。
#### Scenario: 从个人项目库带入
- **WHEN** 制定计划并点「从个人项目库带入」
- **THEN** 自动生成计划项初稿,可修改

View File

@ -0,0 +1,15 @@
## ADDED Requirements
### Requirement: 计划与工单接口
`POST /plan`、`POST /plan/change`、`GET /plan/:id`、`POST /plan/:id/confirm`、`GET /plan/by-elder/:elderId`、`POST /order/generate`、`POST /order/assign`、`POST /order/:id/reassign`、`GET /order/batch-recommend`、`GET /order/today`、`POST /order/:id/cancel`、`GET /order/:id`、`GET /elder-svc/:elderId`、`PUT /elder-svc/:elderId` MUST 存在,遵循统一响应。
#### Scenario: 时间冲突硬拒
- **WHEN** 派单时同护理员时间重叠
- **THEN** 返回 2001,拒绝保存
### Requirement: 属地项数校验
制定计划时,昆明按 care_mode×care_level 校验项数(一级≥18/二级≥15/三级≥13,附加≤5),不满足返回 2002(提示级);州市只提示不拦。
#### Scenario: 昆明项数不满足
- **WHEN** 昆明一级护理计划项数 < 18
- **THEN** 返回 2002 提示,不硬拦

View File

@ -0,0 +1,22 @@
## ADDED Requirements
### Requirement: 服务计划实体 svc_plan / svc_plan_item
`svc_plan` 表 MUST 存在(plan_period_start/end、care_level、care_mode、item_count、item_count_rule、plan_status、change_from_plan_id 等);`svc_plan_item` MUST 存在(svc_id 引 L4、svc_name_snapshot、freq_type/value、duration_min、photo_tier、caution_note 等)。计划变更 MUST 新建 + change_from_plan_id 指向旧计划,不原地改。
#### Scenario: 计划变更留旧版
- **WHEN** 变更某老人的服务计划
- **THEN** 生成新计划并指向旧计划,旧计划保留
### Requirement: 工单实体 svc_order
`svc_order` 表 MUST 存在(plan_id、service_date、time_slot_start/end、assignee_id、order_status、item_list(json)、reschedule_log(json)、not_met_reason/at 等)。
#### Scenario: 工单关联计划
- **WHEN** 生成一张工单
- **THEN** 工单带 plan_id,item_list 为计划项目快照
### Requirement: 老人个人项目库实体 ltc_elder_svc
`ltc_elder_svc` 表 MUST 存在(elder_id、svc_id 引 L4、svc_name_snapshot、care_mode、is_active),一人一份;svc_id 必须落在本机构 L4。
#### Scenario: 项目只能从 L4 选
- **WHEN** 保存个人项目库
- **THEN** svc_id 必须在本机构 svc_org 内,否则拒绝

View File

@ -0,0 +1,40 @@
# Tasks — svc-org-c2-plan-order
## 1. 数据层
- [ ] 1.1 `schema.prisma` 新增 `Plan`/`PlanItem`/`Order`/`ElderSvc` 模型(表名 svc_plan/svc_plan_item/svc_order/ltc_elder_svc)。
- [ ] 1.2 `prisma.service.ts`:四模型加入 SOFT_DELETE。
- [ ] 1.3 迁移 `c2_plan_order`(utf8mb4_general_ci)+ `prisma generate`。
## 2. 权限码 + 错误码 + APIS
- [ ] 2.1 确认 `permissions.ts` 已有 plan.*/order.*(C0 预留);缺则补。
- [ ] 2.2 `error-codes.ts` 补域 44:PLAN_NOT_FOUND、PLAN_ITEM_RULE、ORDER_NOT_FOUND、ORDER_CONFLICT(2001 映射)、ORDER_STATUS_INVALID。
- [ ] 2.3 `tenant-template.ts` APIS 登记 plan/order/elder-svc 接口资源。
## 3. plan 模块(计划 + 个人项目库)
- [ ] 3.1 `src/plan/` 模块:制定计划(L4 校验 + 项数校验 + item_count 快照)、变更(新建+指向旧)、确认、按老人查计划。
- [ ] 3.2 项数校验:昆明常量规则表(care_mode×care_level),州市 loc_config 无规则则提示。
- [ ] 3.3 `src/elder-svc/`(或并入 plan):个人项目库 PUT 整表覆盖(svc_id 落 L4、care_mode 变更重制)+ 带入。
- [ ] 3.4 TDD:制定计划、项数校验、变更留旧版、个人项目库带入;`pnpm test` + `tsc --noEmit`。
## 4. order 模块(工单)
- [ ] 4.1 `src/order/` 模块:generate(L2)、assign(L1 + 冲突 2001 + 资质 1006)、reassign(reschedule_log)、cancel(原因必填)、detail、today、batch-recommend(只推荐)。
- [ ] 4.2 时间冲突检测:同 assignee 且 time_slot 重叠 → 2001。
- [ ] 4.3 TDD:派单 L1 例外(waiting_period 允许)、冲突硬拦、调单留痕、取消需原因;`pnpm test` + `tsc --noEmit`。
## 5. 前端
- [ ] 5.1 `src/api/plan.ts`、`src/api/order.ts`、`src/api/elder-svc.ts`。
- [ ] 5.2 排班派单页(`ltc/schedule`):日视图(时间段×护理员)、调单面板、冲突/空缺提示、批量推荐列表。
- [ ] 5.3 服务对象页:个人项目库区块 + 制定计划入口(带入 + 项数校验提示)。
- [ ] 5.4 `pnpm type-check` 通过。
## 6. 验证
- [ ] 6.1 冒烟:制定计划(项数校验)→ 生成工单 → 派单 → 调单 → 取消 → 冲突硬拦。
- [ ] 6.2 L1 例外:waiting_period 老人可派单、benefit_expired 不可派单。
- [ ] 6.3 个人项目库带入计划。
- [ ] 6.4 审计落库(派单/调单/取消/计划变更)。