graph TD
APT["Appointment (预约已存在)"]
KIOSK["Kiosk Check-in (自助终端签到)"]
FRONT["Front Desk Check-in (前台签到)"]
WALKIN["Walk-in (无预约到店)"]
QUEUE["Queue (等待队列)"]
ASSIGN["Assign Technician (分配技师)"]
INPROG["In-Progress (服务进行中)"]
COMPLETE["Completed (服务完成)"]
PAY_EXIT["Payment (收款出口)"]
RET_EXIT["Retention (留存出口)"]
OPS_EXIT["Operations (运营出口)"]
APT -->|"D1 Kiosk 签到"| KIOSK
APT -->|"D2 前台签到"| FRONT
WALKIN -->|"D3 Walk-in 自动签到"| KIOSK
KIOSK -->|"D4 入队"| QUEUE
FRONT -->|"D5 入队"| QUEUE
QUEUE -->|"D6 分配技师"| ASSIGN
ASSIGN -->|"D7 开始服务"| INPROG
INPROG -->|"D8 完成服务"| COMPLETE
COMPLETE -->|"D9 收款出口"| PAY_EXIT
COMPLETE -->|"D10 留存出口"| RET_EXIT
COMPLETE -->|"D11 运营出口"| OPS_EXIT
style APT fill:#1a2332,stroke:#3b82f6,color:#e0e0e0
style KIOSK fill:#1a2332,stroke:#06b6d4,color:#e0e0e0
style FRONT fill:#1a2332,stroke:#06b6d4,color:#e0e0e0
style WALKIN fill:#1a2332,stroke:#8b5cf6,color:#e0e0e0
style QUEUE fill:#1a2332,stroke:#f59e0b,color:#e0e0e0
style ASSIGN fill:#1a2332,stroke:#f59e0b,color:#e0e0e0
style INPROG fill:#1a2332,stroke:#22c55e,color:#e0e0e0
style COMPLETE fill:#1a2332,stroke:#22c55e,color:#e0e0e0
style PAY_EXIT fill:#0d2818,stroke:#22c55e,color:#22c55e,stroke-dasharray:5
style RET_EXIT fill:#2d1f0d,stroke:#f59e0b,color:#f59e0b,stroke-dasharray:5
style OPS_EXIT fill:#2d0d0d,stroke:#ef4444,color:#ef4444,stroke-dasharray:5
linkStyle 0 stroke:#22c55e,stroke-width:2px
linkStyle 1 stroke:#22c55e,stroke-width:2px
linkStyle 2 stroke:#22c55e,stroke-width:2px
linkStyle 3 stroke:#22c55e,stroke-width:2px
linkStyle 4 stroke:#22c55e,stroke-width:2px
linkStyle 5 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:5
linkStyle 6 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:5
linkStyle 7 stroke:#22c55e,stroke-width:2px
linkStyle 8 stroke:#22c55e,stroke-width:2px
linkStyle 9 stroke:#f59e0b,stroke-width:2px,stroke-dasharray:5
linkStyle 10 stroke:#ef4444,stroke-width:2px,stroke-dasharray:5
| 状态 | 边 | 涉及端口 | 代码路径 | 备注 |
|---|---|---|---|---|
| ✓ | D1 Appointment → Kiosk 签到 | Kiosk, API |
frontend/.../terminal/[store_code]/page.tsxfrontend/.../terminal/[store_code]/confirm/page.tsxapi/checkin.js POST /api/checkinservices/checkinService.js processCheckin()
|
Kiosk 终端主页输入手机号 → 调用 /api/checkin/verify/:phone 查找今日预约 →
confirm 页面调用 POST /api/checkin 执行签到。链路完整:手机号验证 → 预约匹配 → 签到记录创建 → 状态更新为 in_progress。
|
| ✓ | D2 Appointment → 前台签到 | Web Admin, API |
frontend/.../admin/checkin/page.tsxfrontend/.../admin/checkin/queue/page.tsxapi/checkin.js POST /api/checkinservices/checkinService.js quickVerifyAndCheckin()
|
管理后台签到模块包含三个子页面:Queue、Stats、Config。 Quick Check-in 路径: GET /api/checkin/today-appointments 获取今日预约列表 →
POST /api/checkin/quick-verify 通过手机尾号 4 位验证并签到。Quick check-in 将状态设为 checked_in(注意:与 Kiosk 的 in_progress 不同)。
|
| ✓ | D3 Walk-in → 自动签到 | Kiosk, API |
frontend/.../terminal/[store_code]/walkin/page.tsxapi/public/booking.js POST /api/public/booking/confirmservices/checkinService.js processWalkinCheckin()
|
两条 Walk-in 路径均实现: (a) Kiosk Booking 自动签到:walkin 页面通过 POST /api/public/booking/confirm
创建预约(source: 'kiosk'),若日期为今天则自动插入 checkins 记录并将状态设为 checked_in。
前端通过 auto_checked_in 字段判断。(b) Walk-in 签到: processWalkinCheckin() 创建 walk-in 预约(source: 'walkin',
状态直接设为 in_progress)并自动创建 checkin + queue 记录。
|
| ✓ | D4/D5 Check-in → Queue | API (内部) |
services/checkinService.js addToQueue()表: checkin_queue
|
processCheckin() 和 processWalkinCheckin() 均在签到后调用 addToQueue()。队列记录包含 position、status('waiting')、estimated_start_time。 预计等待时间算法简单:(position - 1) x 30min 固定值。 注意:Quick Check-in ( quickVerifyAndCheckin) 路径仅更新 appointment 状态,
未调用 addToQueue(),即快速签到的客人不进入等待队列。
|
| ⚠ | D6 Queue → 分配技师 | Web Admin, API |
services/booking/auto-assign-service.jsapi/public/booking.js (L2895)components/Checkin/Admin/QueueManager.tsx
|
Auto-assign 在预约创建阶段执行(api/public/booking.js 内 assignTechnician()),
而非在队列阶段。策略为 least-busy(当天最空闲)。Queue → 分配技师的链路不存在:Queue 的 start-service 和 call-next
操作在 QueueManager 前端中调用,但 API 端点 /api/queue/:id/start-service 无路由注册
(server.js 中未挂载 queue 路由,仅有测试文件 tests/api/queue.test.js 引用该 API)。结论:技师分配发生在预约阶段,队列阶段的技师(重新)分配链路断裂。 |
| ⚠ | D7 Queue → In-Progress | Web Admin |
components/Checkin/Admin/QueueManager.tsx startService()API: POST /api/queue/:id/start-service
|
QueueManager 前端调用 POST /api/queue/:queueId/start-service 标记开始服务。但该 API 端点未在 server.js 中挂载(同 D6 问题)。 前端代码已就绪(startService、completeService、markNoShow),后端路由缺失。 间接路径可用:管理后台的 Appointment Board 可通过 PUT /api/appointments/:id/status 手动将状态从 checked_in/in_progress
切换,但绕过了队列系统。
|
| ✓ | D8 In-Progress → Completed | Web, Mobile, API |
api/appointments.js PUT /:id/status (L2062-2084)api/mobile/my-services.js PUT /complete/:appointmentServiceId状态流转: in_progress → ['completed', 'cancelled']
|
两条路径完成服务标记: (a) Web 管理后台:通过 Appointment Board 更新状态,有完整的状态流转校验 (STATUS_TRANSITIONS 映射表)。 (b) 员工移动端: PUT /api/mobile/my-services/complete/:id
从 sub_appointments 查找 appointment_id 并更新状态。状态变为 completed 时触发:conversion tracking、guest tagging event、booking metrics。
|
| ✓ | D9 Completed → Payment 出口 | Web, API |
components/Appointment/AppointmentDetailModal.tsx (L606)frontend/.../checkout/[appointmentId]/page.tsxapi/payment/checkout-routes.js POST /api/payment/checkout
|
AppointmentDetailModal 包含"收款"按钮(canTakePayment 条件守卫),
点击后跳转 /checkout/{appointmentId}。Checkout 页面使用 NewCheckoutFlow 组件,支持 Cash + POS Card + Gift Card 支付方式。链路完整:预约详情 → 收款按钮 → Checkout 页面 → Payment API。 |
| ⚠ | D10 Completed → Retention 出口 | API (event) |
services/automation/trigger-engine.js SERVICE_COMPLETEDapi/appointments.js (L2271) _emitGuestTaggingEventservices/tagging/eventListener.js (L32) handleAppointmentCompletedservices/research/conversionService.js APPOINTMENT_COMPLETED
|
服务完成触发多个事件: (a) Guest Tagging 事件 ( appointment_completed) → 活跃度标签自动更新;(b) Conversion tracking → 研究平台归因; (c) Trigger engine 注册 service_completed 事件类型,可配置自动化模板。但:automation trigger engine 中 service_completed 事件类型已注册,
实际触发调用链未直接从 appointment status update 中发出(仅 tagging 和 conversion)。
Review solicitation 仅在 Agent tool 中存在,未作为 automation action 接入。
|
| ✗ | D11 Completed → Operations 出口 | - |
services/timeClockService.js (独立系统)services/timeCardService.js (独立系统)api/appointments.js 状态更新 handler
|
服务完成不直接触发运营数据记录: Time Clock 是独立的员工打卡系统(clock in/out/break),与服务完成事件无关联。 Payroll 报表通过查询 appointments WHERE status = 'completed' 间接聚合数据,
但不是由完成事件触发的实时数据流。缺失:预约完成后应记录员工实际服务时长(actual_duration vs scheduled_duration), 用于准确的工时统计和佣金计算。当前 commission 记录由支付完成触发(Payment 子图), 而非由服务完成触发。 |
QueueManager.tsx 前端组件调用 /api/queue/:id/start-service、
/api/queue/:id/complete、/api/queue/:id/no-show 等端点,
但 server.js 中未注册 queue 路由。测试文件 tests/api/queue.test.js
定义了完整的 API 契约,说明原本计划实现但未完成路由挂载。
影响:队列管理页面(/admin/checkin/queue)的"开始服务"/"完成"/"未到"按钮均无效。
员工只能通过 Appointment Board 手动改状态,绕过队列系统。
quickVerifyAndCheckin() 仅更新 appointment 状态为 checked_in,
未调用 addToQueue()。通过前台 Quick Check-in 签到的客人不出现在等待队列中,
导致队列数据不完整。
三种签到方式产生不同的 appointment 状态:
processCheckin):in_progressquickVerifyAndCheckin):checked_inpublic/booking.js):checked_inprocessWalkinCheckin):in_progress
checked_in 和 in_progress 在状态流转表中是两个独立状态,
但语义上都表示"客人已到店"。这可能导致报表和队列统计口径不一致。
Appointment 状态变为 completed 时,未记录 actual_end_time 或 actual_duration。
Time Clock 系统是独立的员工打卡系统(上下班),不追踪单次服务时长。
Commission 记录由 Payment 子图触发,而非服务完成触发。
影响:无法准确度量"预约时长 vs 实际服务时长"偏差, 影响排班优化和技师效率分析。
addToQueue() 中预计等待时间计算为 (position - 1) x 30min 固定值,
未参考实际预约的 duration_minutes 或当前服务进度。对客人的等待预期管理不准确。
Delivery 子图的入口是已创建的 Appointment 对象。来源包括:
api/public/booking.js) — 在线预约terminal/walkin/page.tsx) — 到店预约api/appointments.js) — 前台代客预约api/mobile/booking.js) — 移动端预约详见 Conversion 子图(待审计)
服务完成后通过 AppointmentDetailModal 的"收款"按钮进入 Checkout 页面
(/checkout/{appointmentId})。Checkout 页面触发支付流程(Cash / POS Card / Gift Card)。
详见 Payment 子图(待审计)
服务完成触发 appointment_completed 事件,被 Guest Tagging 和 Conversion Tracking 消费。
Trigger engine 注册了 service_completed 事件类型用于自动化营销(如满意度调查、复购优惠)。
但 review solicitation 未接入 automation action,仅在 Agent tool 中可用。
详见 Retention 子图(待审计)
服务完成不直接触发运营数据记录。Time Clock 是独立系统。
Payroll 报表通过 SELECT ... FROM appointments WHERE status = 'completed' 间接聚合,
但不是事件驱动的实时数据流。Commission 记录由 Payment 完成触发(经 Payment 子图)。
详见 Operations 子图(待审计)
stateDiagram-v2
[*] --> pending : 预约创建
pending --> confirmed : 确认
confirmed --> checked_in : Quick Check-in / Kiosk Auto
confirmed --> in_progress : Kiosk Check-in / Walk-in
pending --> checked_in : Quick Check-in
checked_in --> in_progress : 开始服务
in_progress --> completed : 完成服务
completed --> pending_payment : 进入收款 (Payment 子图)
pending_payment --> finished : 支付完成
finished --> closed : 关闭
note right of checked_in : Quick Check-in 和 Kiosk Auto\n产生此状态
note right of in_progress : Kiosk 签到和 Walk-in\n直接产生此状态
note right of completed : 触发 tagging + conversion\n+ automation 事件