# 门店 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` gap，A 期不做 |
| 无权限 | 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` | 回访日期已到 | FollowUpTask 为 `pending/in_progress` 且 `dueDate≤今天` | 回访任务 `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, entity:follow_up_task, action:admin_list_leads, action:start_follow_up_task, action:reschedule_follow_up_task, action:close_follow_up_task, rule:BR-FU-001, rule:BR-FU-002, rule:BR-ADMIN-001, rule:BR-ADMIN-002]`

### 6.1 筛选

`status`（open / pending / in_progress / completed / canceled / all）、到期（≤今天）、分页

### 6.2 列表列

客户、联系电话、宠物名、服务、计划回访日、状态、领取人、联系次数、最近结果。完整手机号只在本店已认证员工的开放任务中返回，用于实际电话联系；终态任务、工作台与客户时间线均脱敏。

操作：待领取任务可领取；本人处理中任务可登记未接通/稍后联系并改期、以暂无意向/联系方式无效关闭，或进入代客预约并读取真实号源。`rebooked` 不提供手工结果。

### 6.3 不做（A 期）

自由文本跟进备注 CRM、短信群发、改等级、发券、手工标记再次预约

### 6.4 API 复用

- `GET /api/admin/follow-up-tasks`
- `POST /api/admin/follow-up-tasks/{taskId}/start`
- `POST /api/admin/follow-up-tasks/{taskId}/reschedule`
- `POST /api/admin/follow-up-tasks/{taskId}/close`
- `GET /api/appointment/available-slots` + `POST /api/appointment/create`（携带 `followUpTaskId`）

### 6.5 验收

- [ ] 无 openid/unionid/token/备注；事件、审计和时间线无完整手机号
- [ ] 跨店任务按 404；customer 禁止
- [ ] 他人已领取返回冲突；非领取人不能改期/关闭/再次预约
- [ ] 无号源或预约失败时任务不闭环；成功时生成真实 appointment 与 `rebook_created`
- [ ] 工作台「待回访」下钻数字一致  

---

## 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 | staff，storeId=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` + 3 个回访命令 | `follow_up_task` / `report_lead` | `/api/admin/follow-up-tasks/*` + `/api/appointment/*` |
| 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=30min；Q5 推荐 Vue3 admin |
| 2026-07-10 | 编码启动：`admin/` MVP + `GET /api/admin/service-customers` |
