Files
qiji/docs/superpowers/specs/2026-07-12-work-plan-auto-status-design.md
T
v6ole 6504a393e3 feat: 个人用户聚合视图 — 客户管理双Tab+四模块数据聚合
- customers 表新增 customer_type 列 (unit/individual)
- 客户管理页:单位客户 | 个人用户 Tab 切换
- 个人用户 Tab: 直接内嵌4 Tab 显示所有个人用户的聚合数据
- 个人用户通过业务模块快速新建产生 (customer_type=individual)
- 4个业务API新增 customer_type 筛选参数(JOIN customers)
- 客户列表排序: 个人用户置顶

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-12 22:14:44 +08:00

123 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 工作计划状态自动流转 — 设计文档
> 日期:2026-07-12 | 状态:已确认
## 一、需求概述
工作计划目前有三种状态(计划中/已完成/已取消),完全依赖手动切换。利用已有的拜访记录数据,实现状态的自动流转,减少客户经理手动操作。
## 二、核心决策
| 决策项 | 结论 |
|--------|------|
| 匹配精度 | 仅匹配 `customer_id`(任何人拜访该客户即触发,与现有逻辑一致) |
| 增强范围 | 创建/更新触发完成 + 逾期自动取消 + Excel 导入联动 |
| 删除回退 | 不做(边缘场景少,复杂度高) |
## 三、现状
- `POST /visits/` 已有自动完成逻辑:同一 `customer_id` + `plan_date <= visit_date` → 标记"已完成"
- 该逻辑嵌在 API 层,不可复用
- 更新拜访、Excel 导入均不触发自动完成
- 逾期计划(`plan_date < today`)只发企微提醒,不自动取消
## 四、设计
### 4.1 抽取可复用函数
**文件:** `backend/app/services/visits.py`(如不存在则新建,如已有则追加)
```python
async def auto_complete_work_plans(
db: AsyncSession,
customer_id: UUID,
visit_date: date,
editor_name: str,
reason: str = "拜访自动完成",
) -> int:
"""将匹配的工作计划自动标记为已完成。返回完成数量。"""
from app.models.work_plan import WorkPlan
from app.utils.edit_log import append_entry as append_edit_log
plans_result = await db.execute(
select(WorkPlan).where(
WorkPlan.customer_id == customer_id,
WorkPlan.status == "计划中",
WorkPlan.plan_date <= visit_date,
)
)
count = 0
for plan in plans_result.scalars().all():
plan.status = "已完成"
append_edit_log(plan, editor_name, [{
"field": "status", "from": "计划中", "to": "已完成",
"reason": reason,
}])
count += 1
return count
```
### 4.2 三处调用点
| 调用点 | 文件 | 触发时机 | reason 参数 |
|--------|------|---------|------------|
| POST /visits/ | `api/visits.py` | 创建拜访后 | `"拜访自动完成"` |
| PUT /visits/{id} | `api/visits.py` | 更新拜访后 | `"拜访更新自动完成"` |
| excel_import.py | `services/excel_import.py` | 导入每条拜访后 | `"旧周报导入自动完成"` |
### 4.3 逾期计划自动取消
**文件:** `backend/app/services/scheduler.py``check_overdue_plans` 函数
在现有「发送企微提醒」逻辑后新增:
```python
# 自动取消:逾期且无匹配拜访记录的计划
for plan in overdue:
has_visit = await db.execute(
select(Visit.id).where(
Visit.customer_id == plan.customer_id,
Visit.visit_date >= plan.plan_date,
)
)
if not has_visit.scalar():
plan.status = "已取消"
append_edit_log(plan, "系统", [{
"field": "status", "from": "计划中", "to": "已取消",
"reason": "逾期自动取消",
}])
```
每日 09:00 执行,与现有逾期检查共用一个调度任务。
### 4.4 状态流转总图
```
计划中 ──┬── 拜访创建/更新/导入(customer_id + plan_date <= visit_date)──→ 已完成
└── 每日 09:00 调度(plan_date < today 且无匹配拜访)───────────→ 已取消
```
## 五、文件变更
### 后端新增/修改
| 文件 | 变更 |
|------|------|
| `backend/app/services/visits.py` | 新增 `auto_complete_work_plans()` 函数 |
| `backend/app/api/visits.py` | POST 重构为调用 service 函数;PUT 新增调用 |
| `backend/app/services/excel_import.py` | 导入拜访后调用自动完成 |
| `backend/app/services/scheduler.py` | `check_overdue_plans` 新增自动取消逻辑 |
### 前端
无需改动。
## 六、验证要点
1. 创建拜访 → 匹配的计划自动变为"已完成"edit_log 有记录
2. 更新拜访日期 → 匹配的计划自动完成
3. 导入旧周报 → 导入的拜访触发计划自动完成
4. 逾期且无拜访的计划 → 每日 09:00 自动变为"已取消"
5. 逾期但有拜访的计划 → 保持"计划中"(已有拜访覆盖,不算僵尸)