petstore-docs/门店管理后台-PhaseA-页面清单PRD.md

468 lines
19 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.

# 门店 Web 后台 · Phase A 页面清单 PRD
> 状态:产品草案(仅文档,未编码)
> 日期2026-07-10
> 上游:`docs/门店管理后台升级方案-对标宠老板.md`
> 本体闸门:`rule:BR-ADMIN-004`(禁止会员卡/储值/收银/库存/寄养/押金/点餐偷渡)
> 证据:本 PRD 描述的页面均为 `documented`;实现后升 `anchored`
---
## 0. 文档约定
### 0.1 目标与非目标
| 目标 | 非目标Phase A |
|------|-------------------|
| 老板用 PC 完成:看今日待办 → 管预约 → 管报告/成片链接 → 处理留资 → 改门店设置 | 收银、库存、寄养、会员升降级、次卡储值、押金、点餐、支付宝渠道、连锁同步 |
| 与小程序共用同一套业务规则与 `/api/**` | 另造第二套状态机 |
| 每页可追溯 `ontologyRefs` | 经营大盘 sparkline / 埋点统计闭环(属 Phase B |
### 0.2 角色与范围
| 规则 | 本体 |
|------|------|
| 仅门店角色进入后台;**boss 与 staff 均可读写**customer 禁止) | `rule:BR-ADMIN-001` |
| 全部数据强制 `current.storeId` | `rule:BR-ADMIN-002` |
| 后台可看公开 API 裁剪掉的内部字段;手机号默认脱敏 | `rule:BR-ADMIN-003` |
| 范围闸门 | `rule:BR-ADMIN-004` |
`staff``boss` 在 Phase A **同等可编辑**本店数据;差异仅保留现网已有规则(例:删店、部分设置仅 boss——见设置页与 `rule:BR-STORE-001` / `rule:BR-USER-001`)。
### 0.3 端分工
| 场景 | 载体 |
|------|------|
| 拍照、填报告、现场履约 | **小程序**(既有) |
| 开始服务 | **小程序与 Web 均可**(同 `POST /api/appointment/start` |
| 检索、复制链接、回访、改设置、看今日全局 | **Web 后台**(本 PRD |
### 0.4 信息架构(锁定)
```text
entity:admin_console
├── /workbench 今日工作台(登录落点)
├── /appointments 预约中心
├── /schedule 排班占用
├── /reports 服务报告
├── /leads 回访线索
├── /customers 服务客户
└── /settings 门店设置(资料 / 服务类型 / 员工)
```
侧栏不出现:收银台、库存、寄养、会员卡、次卡、积分、营销中心、微信商城。
### 0.5 全局交互范式(从对标截图借鉴)
1. 列表页:筛选区 + 查询/重置 +(可选)汇总条 + 表格
2. 搜索合一:姓名 / 手机 / 宠物名(客户页)
3. 手机号列表默认脱敏
4. 敏感操作弹窗带规则提示(若有)
5. 工作台待办可下钻并带筛选
---
## 1. 登录与壳层
**页面 ID**`A0-shell`
**路由**`/*`(布局)
**ontologyRefs**`[entity:admin_console, entity:current_user, entity:session_token, rule:BR-ADMIN-001, rule:BR-ADMIN-002, rule:BR-AUTH-001]`
| 项 | 说明 |
|----|------|
| 登录 | 复用现有 `sessionToken`(老板微信登录 / 现网登录策略);无 token → 登录页 |
| 壳层 | 左导航 + 顶栏(店名、角色、退出)+ 内容区 |
| 退出 | 清本地 token服务端吊销为 `action:logout` gapA 期不做 |
| 无权限 | customer token 访问 → 403 文案「请使用老板账号登录」 |
**API 复用**`GET /api/user/info``action:get_user_info`
---
## 2. 今日工作台
**页面 ID**`A1-workbench`
**路由**`/workbench`(默认首页)
**ontologyRefs**`[entity:workbench, entity:workbench_todo_item, action:view_workbench, action:drilldown_workbench_todo, event:workbench_viewed, rule:BR-ADMIN-001, rule:BR-ADMIN-002, rule:BR-ADMIN-004]`
### 2.1 布局
```text
顶栏 4 指标卡
常驻行动队列(不再每日强弹)
报告漏斗四格(提交/打开/留资已由 BusinessEvent 汇总;转预约仍为「—」)
每组最多 3 条低敏预览 + 准确总数 + 列表下钻
报告漏斗(提交 / 显式确认发送 / 打开 / 留资 / 再预约未知)
```
### 2.2 顶栏指标卡
| 卡 | 口径 | 点击下钻 |
|----|------|----------|
| 今日预约 | 今日 `appointmentTime` 落在当天的预约数(含各状态) | `/appointments?date=today` |
| 逾期未开始 | 所有 `status=new``appointmentTime<now` | `/appointments?status=new&overdue=1` |
| 服务中 | 所有 `status=doing` | `/appointments?status=doing&missingReport=1` |
| 今日完成 | 今日 `updateTime` 变为 `done` 的预约数 | `/appointments?status=done&completedToday=1` |
### 2.3 行动队列(常驻)
| kind | 文案 | count 口径 | 下钻 |
|------|------|------------|------|
| `overdue_appointment` | 预约已过时间 | 所有 `new` 且预约时间早于当前时刻 | 预约列表 `status=new&overdue=1` |
| `in_service` | 服务中,等待收尾 | 所有 `doing`;提交报告后自动退出 | 预约列表 `status=doing&missingReport=1` |
| `upcoming_today` | 今天接下来要到店 | 今日尚未到时刻的 `new` | 预约列表 `status=new&date=today` |
| `highlight_anomaly` | 成片异常 | `failed` + `processing` 超过 30 分钟 | 报告列表 `highlightStatus=anomaly` |
| `unsent_report` | 报告尚未发送 | 仅 `sendStatus=unsent`;历史 `unknown` 不进入待办 | 报告列表 `sendStatus=unsent` |
| `follow_up_due` | 回访日期已到 | `pending``remindDate≤今天` 或日期缺失 | 线索列表 `due=today` |
优先级固定为:逾期预约 → 服务中 → 今日待开始 → 成片异常 → 报告待发送 → 到期回访。每组只返回最多 3 条预览,预览不含手机号、报告 token、媒体 URL 或微信标识;准确总数由服务端按完整数据计算。工作台不再每日强弹,避免值班人员为了关弹窗而忽略真正行动。
**不对标宠老板**:寄养、临期商品、库存、待发货、售后。
### 2.4 报告漏斗四格(差异化)
| 格 | 口径 | 当前实现 |
|----|------|----------|
| 今日已提交报告 | `report_submitted` 按 report 去重 | BusinessEvent 汇总 |
| 已确认发送 | `report_sent` 按 report 去重 | 仅员工显式确认事实;复制/二维码/预览不计入 |
| 已打开 | `report_opened/reopened` 按 report 去重 | BusinessEvent 汇总 |
| 已留资 | `lead_submitted` 按 lead 去重 | BusinessEvent 汇总 |
| 报告转预约 | `rebook_created` | 尚无可靠归因,显示「—」 |
### 2.5 API / 聚合
行动队列使用 `GET /api/admin/workbench/actions`,一次返回 `metrics + actions + reportFunnel``storeId` 只从会话派生,不接受 query storeId。报告漏斗原接口 `GET /api/admin/workbench/report-funnel?date=yyyy-MM-dd` 保留兼容。
`actions[].items` 只包含 resourceType/resourceId、宠物名、服务类型、计划时间、状态和是否逾期详细联系信息必须进入对应受保护列表后按权限读取。
### 2.6 验收
- [ ] 老板登录后默认进入工作台
- [ ] 四指标与行动队列数字来自完整本店数据,不受列表前 200 条截断
- [ ] 今日完成按状态更新时间下钻,逾期预约按当前时刻下钻
- [ ] 行动预览不含手机号、report token、媒体 URL 或微信标识
- [ ] 待办不含库存/寄养类卡片
- [ ] customer 无法打开
- [ ] **staff 与 boss 均可进入并操作本店工作台**
---
## 3. 预约中心
**页面 ID**`A2-appointments`
**路由**`/appointments`
**ontologyRefs**`[entity:appointment, action:admin_list_appointments, action:start_service, action:transition_appointment_status, action:get_appointment_detail, rule:BR-APPT-001, rule:BR-APPT-002, rule:BR-APPT-003, rule:BR-ADMIN-001, rule:BR-ADMIN-002]`
### 3.1 筛选
| 筛选项 | 说明 |
|--------|------|
| 日期 | 单日 / 区间;支持 `today` |
| 状态 | `new` / `doing` / `done` / `cancel` / 全部 |
| 技师 | 本店 staff/boss 列表(可空=全部) |
| 关键词 | 宠主名 / 手机 / 宠物名(若现网 list 不支持A 期可先前端滤或补 query |
| 待出报告 | `doing` 且无报告(工作台下钻) |
### 3.2 列表列
| 列 | 说明 |
|----|------|
| 预约时间 | |
| 状态 | 文案:待开始 / 服务中 / 已完成 / 已取消 |
| 宠主 | 名 + 脱敏手机 |
| 宠物 | 名 / 类型 |
| 服务类型 | |
| 技师 | `assignedUser` 显示名 |
| 报告 | 无 / 有(链到报告详情或报告中心) |
| 操作 | 详情;**开始服务**`new`→调 `POST /api/appointment/start`Web 可点);`new`/`doing`→取消(规则同现网) |
> **产品决策2026-07-10**Web 上允许「开始服务」。拍照/填报告仍引导回小程序;开始服务本身不强制跳转。
### 3.3 详情抽屉/页
只读为主:预约字段、状态流转记录(若无则只显示当前状态)、关联报告入口。
**不在 Web 做拍照填报告**(回小程序)。
### 3.4 状态机(禁止另造)
仅允许:`new→doing`、`new→cancel`、`doing→done`(由提交报告触发)、`doing→cancel`(若产品允许)。
非法迁移返回现网业务码。本体:`rule:BR-APPT-001`。
### 3.5 API 复用
- `GET /api/appointment/list`
- `GET /api/appointment/detail`
- `POST /api/appointment/start`**Web 可调用**
- `PUT /api/appointment/status`
### 3.6 验收
- [ ] 筛选 + 下钻参数生效
- [ ] 跨店数据不可见
- [ ] 非法状态迁移被拒
- [ ] **staff / boss 均可在 Web 点击「开始服务」并成功 `new→doing`**
- [ ] 无「待门店确认接单」状态(与宠老板差异,保持宠小它口径)
---
## 4. 排班占用
**页面 ID**`A6-schedule`
**路由**`/schedule`
**ontologyRefs**`[entity:schedule_block, entity:appointment, action:admin_manage_schedule, action:day_agenda, action:create_schedule_block, action:delete_schedule_block, rule:BR-SCH-001, rule:BR-ADMIN-001, rule:BR-ADMIN-002]`
### 4.1 视图
- 日视图时间轴(半小时容量桶),展示已用/总计/剩余容量
- 叠加:按服务时长跨桶的线上预约 + 可配置时长的 `walk_in` / `blocked` 手动占用
- `walk_in` 消耗一个并发名额;`blocked` 关闭覆盖范围内全部名额
- 操作:新增占用、删除本店占用;不可改他店
### 4.2 API 复用
- `GET /api/schedule/day`
- `POST /api/schedule/block`
- `DELETE` 对应删除接口
### 4.3 验收
- [ ] 与小程序号源占用一致
- [ ] 并发请求不突破门店配置容量;长服务覆盖的后续时段不可超卖
- [ ] staff/boss 同店可操作;跨店 403
---
## 5. 服务报告
**页面 ID**`A3-reports`
**路由**`/reports`
**ontologyRefs**`[entity:report, entity:highlight_video, entity:highlight_fail_reason, action:admin_list_reports, action:generate_highlight, action:get_report_by_token, rule:BR-RPT-002, rule:BR-RPT-005, rule:BR-RPT-006, rule:BR-HL-001, rule:BR-HL-002, rule:BR-ADMIN-001, rule:BR-ADMIN-002, rule:BR-ADMIN-003]`
### 5.1 筛选
日期、成片状态(`processing` / `done` / `failed` / 全部)、关键词(宠物名/宠主)
### 5.2 列表列
| 列 | 说明 |
|----|------|
| 提交时间 | |
| 预约时间 / 宠物 / 服务 | |
| 成片状态 | 三态 + 失败原因短标签(`HighlightFailReason` |
| 操作 | 详情;复制公开链接;失败/可重试时「重新生成」 |
### 5.3 详情
- 报告公开页预览入口(新开 H5
- 前后/过程媒体缩略图(只读)
- 成片播放(若 `done`
- 复制 `report_token` 链接(完整 token 仅后台展示,日志仍 hash`BR-RPT-007`
- **不在此页改报告正文**(报告提交后锁死,`BR-RPT-*`
### 5.4 API 复用
- `GET /api/report/list`
- `GET /api/report/get`(后台带鉴权,可内部字段)
- `POST /api/report/highlight/start`
### 5.5 验收
- [ ] 成片三态与失败文案无技术词
- [ ] 复制链接可用;公开页仍受 `BR-RPT-006` 裁剪
- [ ] 仅 boss/staff 可触发成片(`BR-HL-001`
---
## 6. 回访线索
**页面 ID**`A4-leads`
**路由**`/leads`
**ontologyRefs**`[entity:report_lead, action:admin_list_leads, rule:BR-LEAD-001, rule:BR-LEAD-002, rule:BR-LEAD-003, rule:BR-ADMIN-001, rule:BR-ADMIN-002]`
### 6.1 筛选
`remindStatus`pending / 全部)、到期(≤今天)、日期区间
### 6.2 列表列
宠物名、服务、脱敏手机、建议日期、状态、微信绑定(是/否 + 脱敏 openid 若有)、操作:查看关联报告公开页
### 6.3 不做A 期)
跟进备注 CRM、短信群发、改等级、发券
### 6.4 API 复用
- `GET /api/report/leads`
### 6.5 验收
- [ ] 无完整 openid/unionid
- [ ] 跨店 403
- [ ] 工作台「待回访」下钻数字一致
---
## 7. 服务客户
**页面 ID**`A5-customers`
**路由**`/customers`
**ontologyRefs**`[entity:store_customer, entity:pet, entity:user, action:admin_list_service_customers, rule:BR-SC-001, rule:BR-ADMIN-001, rule:BR-ADMIN-002, rule:BR-ADMIN-003, rule:BR-ADMIN-004]`
### 7.1 定位
服务经营客户投影,**不是**会员资产台账。
### 7.2 筛选与搜索
| 项 | 说明 |
|----|------|
| 来源 | 全部 / 预约 / 报告留资 |
| 有待回访 | 开关 |
| 最近到店 | 日期区间 |
| 搜索 | 姓名 / 手机 / 宠物名 |
### 7.3 汇总条
`客户数` · `待回访数` · `本月到店数`
**禁止**:总余额、押金、积分
### 7.4 列表列
客户(头像/名/脱敏手机)| 宠物(标签,多宠)| 最近到店 | 最近报告 | 留资状态 | 来源 | 操作(详情 / 报告 / 回访)
### 7.5 详情
基础信息、宠物列表、最近预约、最近报告、相关线索。
**不做**:充值、改会员等级、导入持卡会员、次卡。
### 7.6 API产品决策新 API
**新建**聚合接口(实现时同步本体 `anchored`
```text
GET /api/admin/service-customers
Query: source, hasPendingLead, lastVisitFrom, lastVisitTo, q, page, pageSize
Auth: boss | staffstoreId=current.storeId
Response: { total, summary: { customerCount, pendingLeadCount, monthVisitCount }, list: StoreCustomerView[] }
```
`StoreCustomerView` 必含稳定 `storeCustomerId`,并包含 `userId?`、`displayName`、`phoneMasked`、`originSource`、`firstContactAt`、`lastContactAt`、`pets`、`lastVisitAt`、`lastReportId`、`leadStatus`、`source`。明文手机号不得返回。
- 对应动作:`action:admin_list_service_customers`
- 对应实体:`entity:store_customer`
- **不做**前端拼装多接口作为正式方案(可临时 mock上线以新 API 为准)
可选后续:`GET /api/admin/service-customers/{storeCustomerId}` 详情。
### 7.7 验收
- [ ] 无余额/次卡/积分列与汇总
- [ ] 搜索含宠物名
- [ ] 侧栏无「会员卡/次卡」入口
---
## 8. 门店设置
**页面 ID**`A7-settings`
**路由**`/settings`Tab资料 | 服务类型 | 员工)
**ontologyRefs**`[entity:store, entity:service_type, entity:user, action:admin_update_settings, rule:BR-STORE-001, rule:BR-STORE-003, rule:BR-ST-001, rule:BR-USER-001, rule:BR-ADMIN-001, rule:BR-ADMIN-002, rule:BR-ADMIN-003]`
### 8.1 资料 Tab
字段名称、电话、地址、坐标、简介、logo、`bookingDayStart` / `bookingLastSlotStart`
后台可显示 `inviteCode``BR-ADMIN-003`);公开 `GET /api/store/get` 仍裁剪(`BR-STORE-003`
API`GET/PUT` 现有 store 接口
### 8.2 服务类型 Tab瘦身表单
| 字段 | 必填 |
|------|------|
| 名称 | ✓ |
| 适用宠物:不限/猫/犬 | 若字段未上线A 期可先只做名称+排序+启用 |
| 排序 | |
| 预约可选(启用) | |
| 备注 | |
**不做**:多规格、价格、条码、押金、商城上架、富文本(见对标 §11.8
系统默认类型不可改删(`BR-ST-001`
API现有 `service-type/*`
### 8.3 员工 Tab
列表、创建员工、删除(仅 boss同店
展示邀请码(来自门店)供复制
API`user/staff-list`、`create-staff`、删除接口
### 8.4 验收
- [ ] 改营业时段后号源边界变化(与小程序一致)
- [ ] 公开门店接口仍无 inviteCode
- [ ] 服务类型表单无价格字段
---
## 9. 页面—本体—API 总表
| 页面 | 主 Action | 主 Entity | 主要复用 API |
|------|-----------|-----------|--------------|
| A0 壳层 | `get_user_info` | `admin_console` | `/api/user/info` |
| A1 工作台 | `view_workbench` | `workbench` | list 聚合 |
| A2 预约 | `admin_list_appointments` | `appointment` | `/api/appointment/*` |
| A6 排班 | `admin_manage_schedule` | `schedule_block` | `/api/schedule/*` |
| A3 报告 | `admin_list_reports` | `report` / `highlight_video` | `/api/report/*` |
| A4 线索 | `admin_list_leads` | `report_lead` | `/api/report/leads` |
| A5 客户 | `admin_list_service_customers` | `store_customer` | **已实现** `GET /api/admin/service-customers` |
| A7 设置 | `admin_update_settings` | `store` / `service_type` / `user` | store/service-type/user |
---
## 10. 实现分期建议(仍属 Phase A 内)
| 迭代 | 交付 | 说明 |
|------|------|------|
| A.1 | 壳层 + 工作台 + 预约列表/详情 | 登录落点可用 |
| A.2 | 报告中心 + 线索 | 差异化闭环 |
| A.3 | 客户瘦身列表 + 排班 + 设置 | MVP 验收全集 |
编码前须:声明 Owner`Store Admin FE` + `Backend Core`、Service Lock、Paired QA、写入 `.agents` 角色锁。
---
## 11. 验收剧本(端到端)
1. 老板登录 → 默认工作台,见按履约优先级排序的行动队列
2. 点「待出报告」→ 预约列表仅 doing 且无报告
3. 打开某已完成单的报告 → 复制公开链接 → 无痕浏览器打开,字段符合公开裁剪
4. 线索页处理一条待回访(至少能打开关联报告)
5. 设置里改营业结束时间并保存 → 小程序号源反映变化
6. 全程无会员余额/收银/库存入口
---
## 12. 开放问题(已决策)
| # | 问题 | 决策2026-07-10 |
|---|------|-------------------|
| Q1 | staff 是否可登录后台? | **可进且可编辑**(与 boss 同店读写;删店等仍仅 boss |
| Q2 | Web 上是否允许「开始服务」? | **允许**;拍照/填报告仍回小程序 |
| Q3 | 客户列表前端聚合还是新 API | **新 API**`GET /api/admin/service-customers` |
| Q4 | `processing` 超时多久算异常? | **30 分钟**(已锁定) |
| Q5 | 技术选型Vue/React admin | **推荐** Vue3+Vite+Element Plus + `admin/`,见 `docs/门店管理后台-技术选型草案.md`(编码前口头确认) |
---
## 13. 修订记录
| 日期 | 说明 |
|------|------|
| 2026-07-10 | 首版:基于本体 admin 预录入 + 宠老板对标结论 |
| 2026-07-10 | 决策落地staff 可编辑Web 可开始服务;客户列表新 API |
| 2026-07-10 | 线框/选型/编码 brief 已出Q4=30minQ5 推荐 Vue3 admin |
| 2026-07-10 | 编码启动:`admin/` MVP + `GET /api/admin/service-customers` |