Employees, Schedules, Time Clock & Payroll | 更新时间: 2026-02-09
employees/page.tsx (员工列表),
employees/[id]/page.tsx (员工详情 — 基本信息/服务能力/特殊权限),
employees/schedules/page.tsx (排班总览 — List/Kanban 双视图),
employees/schedules/[employeeId]/page.tsx (个人排班日历),
employees/time-clock/page.tsx (打卡面板 — PIN/Click),
employees/time-cards/page.tsx (工时卡 — 员工自助/管理员双模式),
employees/tips/page.tsx (小费汇总),
employees/payroll/page.tsx (工资单),
admin/employees/page.tsx,
admin/schedules/page.tsx,
admin/permissions/roles/page.tsx (角色管理),
admin/permissions/job-titles/page.tsx (职位管理)
AddEmployeeModal.tsx,
ScheduleKanbanBoard.tsx,
AutoScheduleModal.tsx,
GenerateScheduleModal.tsx,
WeeklyTemplateModal.tsx,
ScheduleEditor.tsx,
QuickClockPanel.tsx,
PinSetupModal.tsx,
TimeCardTable.tsx,
TimeCardDetailModal.tsx,
MakeupPunchModal.tsx,
PayrollTable.tsx,
PayrollDetailModal.tsx
backend/api/time-clock.js (打卡/PIN/工时卡/补卡审批/设置),
backend/api/payroll.js (工资单),
backend/api/employee_availability.js,
backend/api/daily_availability.js,
backend/services/timeClockService.js,
backend/services/timeCardService.js,
backend/services/payrollService.js
flowchart TB
EMP["employees\n基本信息/角色/门店"] --> SCH["employee_schedules\n每日排班 (date-specific)"]
EMP --> WKS["employee_work_schedules\n周模板 (recurring)"]
EMP --> CAP["employee_service_capabilities\n服务能力"]
EMP --> PIN["employee_pins\nPIN 打卡码"]
EMP --> TC["time_cards\n每日考勤卡"]
TC --> TP["time_punches\n打卡记录"]
EMP --> PR["payroll_reports\n工资单"]
EMP --> APT["appointments\n被分配的预约"]
WKS -->|"AutoSchedule\n模板生成"| SCH
SCH -->|"影响"| AVAIL["可预约时段\nemployee_available_start_times"]
TC -->|"汇总到"| PR
| 层级 | 数据表 | 说明 | 优先级 |
|---|---|---|---|
| 周模板 | employee_work_schedules | 周一到周日的固定模板(0=Sunday, 6=Saturday) | 最低 — 用于自动生成 |
| 每日排班 | employee_schedules | 具体日期的排班(date, start, end, breaks) | 最高 — 实际执行 |
| punch_type | 说明 | 触发条件 |
|---|---|---|
clock_in | 上班打卡 | 当前未打卡 |
clock_out | 下班打卡 | 当前已打卡且非休息中 |
break_start | 开始休息 | 当前已打卡且非休息中 |
break_end | 结束休息 | 当前处于休息中 |
| CUJ | 优先级 | 描述 | 触发点 | 业务价值 | E2E 状态 |
|---|---|---|---|---|---|
| CUJ-D1 | P0 | 员工列表与详情管理 | 管理员进入员工页面 | 人事基础管理 | 已覆盖 |
| CUJ-D2 | P0 | 排班管理 | 管理员创建/编辑排班 | 排班 → 可预约时段 | 已覆盖 |
| CUJ-D3 | P0 | PIN 打卡与考勤 | 员工上下班打卡 | 考勤 → 工资计算 | 已覆盖 |
| CUJ-D4 | P1 | 工时卡与补卡审批 | 管理员审核 / 员工查看 | 考勤异常处理 | 部分覆盖 |
| CUJ-D5 | P1 | 小费管理 | 查看/分配小费 | 技师收入管理 | 部分覆盖 |
| CUJ-D6 | P2 | 工资单 | 生成周期工资报表 | 薪酬管理 | 部分覆盖 |
P0 人事基础 — 员工 CRUD、服务能力、特殊权限、门店调动
flowchart TD
A["侧边栏 → Employees"] --> B["员工列表\n筛选: 门店/职位/状态"]
B --> C{操作?}
C -->|"添加"| D["AddEmployeeModal\n姓名/邮箱/角色/门店"]
D --> E["自动生成 employee ID"]
C -->|"查看详情"| F["/employees/id"]
F --> G["Tab 1: 基本信息\n姓名/邮箱/角色/职位/头像"]
F --> H["Tab 2: 服务能力\n多选 checklist"]
F --> I["Tab 3: 特殊权限\nGRANT/DENY (super_admin only)"]
C -->|"停用"| J["is_active → false\n不再出现在排班/预约"]
style B fill:#2196F3,stroke:#1565C0,color:#fff
style F fill:#4CAF50,stroke:#2E7D32,color:#fff
/employees测试: employees.spec.ts
must_change_password = true
测试: full-flow/02c-employee-crud.spec.ts
reports:viewemployees:deleteP0 运营基础 — 技师排班直接影响 employee_available_start_times,进而影响可预约时段
flowchart TD
A["/employees/schedules\n排班总览"] --> B{视图模式?}
B -->|"List"| C["表格视图\n排班统计/今日状态"]
B -->|"Kanban"| D["ScheduleKanbanBoard\n周视图所有技师"]
D --> E{操作?}
E -->|"手动"| F["点击空白格子\n设置时间段"]
E -->|"模板"| G["WeeklyTemplateModal\n编辑周模板"]
E -->|"自动生成"| H["GenerateScheduleModal\n按模板批量生成N周"]
E -->|"智能排班"| I["AutoScheduleModal\n规则自动生成"]
C --> J["点击员工\n→ /schedules/employeeId"]
J --> K["个人日历视图\n月度排班详情"]
style A fill:#2196F3,stroke:#1565C0,color:#fff
style K fill:#4CAF50,stroke:#2E7D32,color:#fff
employee_schedules 新增记录测试: full-flow/02d-schedule-crud.spec.ts
employee_schedules测试: schedule-templates/schedule-generation.spec.ts
vacation,is_available = false/employees/schedules/[aliceId]P0 考勤管理 — PIN/Click 两种打卡方式,自动计算迟到/早退
flowchart TD
A["/employees/time-clock\nQuickClockPanel"] --> B{打卡方式?}
B -->|"PIN 打卡"| C["输入 4-6 位 PIN"]
B -->|"Click 打卡"| D["选择员工\n点击打卡按钮"]
C --> E{PIN 正确?}
E -->|"否"| F["错误提示\n失败次数+1"]
F --> G{5次失败?}
G -->|"是"| H["PIN 锁定 30 分钟"]
G -->|"否"| C
E -->|"是"| I{当前状态?}
D --> I
I -->|"未打卡"| J["Clock In\n记录上班时间"]
I -->|"已打卡"| K["Clock Out\n记录下班时间"]
I -->|"休息中"| L["Break End\n结束休息"]
J --> M["对比排班计算\n迟到分钟数"]
K --> N["对比排班计算\n早退分钟数"]
style A fill:#2196F3,stroke:#1565C0,color:#fff
style J fill:#4CAF50,stroke:#2E7D32,color:#fff
style K fill:#FF9800,stroke:#E65100,color:#fff
pin测试: time-clock.spec.ts
POST /time-clock/pin/unlock 手动解锁
employee_pins 表测试: time-clock.spec.ts (部分覆盖)
P1 考勤审核 — 双模式查看工时,补卡需管理员审批
flowchart TD
A["/employees/time-cards"] --> B{用户角色?}
B -->|"员工"| C["My Time Cards\n只看自己的记录"]
B -->|"管理员"| D["All Time Cards\n所有员工 + 筛选"]
D --> E["Tab: cards / pending"]
E -->|"cards"| F["工时卡列表\n汇总: 总天数/总工时/迟到数/早退数"]
E -->|"pending"| G["待审批补卡列表"]
G --> H{审批操作}
H -->|"批准"| I["approveMakeupPunch\n补卡写入工时卡"]
H -->|"拒绝"| J["rejectMakeupPunch\n填写拒绝原因"]
C --> K["查看详情\nTimeCardDetailModal"]
F --> K
K --> L["打卡明细\nclock_in/out/break 时间线"]
style A fill:#2196F3,stroke:#1565C0,color:#fff
style I fill:#4CAF50,stroke:#2E7D32,color:#fff
style J fill:#f44336,stroke:#c62828,color:#fff
time_clock:view_own)/employees/time-cardstime_clock:view_all,且具备对应范围(scope)/employees/time-cardspendingapprovedGET /time-clock/time-cards/export 生成 CSVP1 收入管理 — 查看技师小费明细
/employees/tips测试: employees/tips.spec.ts
tips:view level=view)/employees/tipsP2 薪酬管理 — 生成和管理员工工资单
flowchart LR
A["draft\n草稿"] -->|"finalizePayroll()"| B["finalized\n已确认"]
B -->|"markAsPaid()"| C["paid\n已发放"]
/employees/payroll测试: payroll.spec.ts (部分覆盖)
finalizedpaid
| 从 D 模块 | 关联 CUJ | 关系 |
|---|---|---|
| D2 排班 | CUJ-G1 在线预约 | 排班 → employee_available_start_times → 可选时段 |
| D1 服务能力 | CUJ-G1 技师选择 | employee_service_capabilities → 可选技师列表 |
| D3 打卡 | CUJ-C1 Step 1 | 考勤数据用于日结 OrderStatus 验证 |
| D5 小费 | CUJ-C1 Step 2 | 小费在日结 TipsSettlement 中分配 |
| D6 工资 | CUJ-H 报表 | payroll_reports 数据用于员工报表 |
| D1 特殊权限 | CUJ-A5 RBAC | GRANT/DENY 特殊权限覆盖角色默认 |
employee_work_schedules(周模板)→ AutoSchedule 生成 → employee_schedules(每日排班)→ 系统计算 → employee_available_start_times(可预约时段)→ 在线预约 /slots API 返回。排班变更会自动触发可预约时段重算。
/pin/unlock 和 /pin/reset 紧急解锁/重置time_cards 记录。后续所有打卡(clock_out, break_start, break_end)都关联到该 time_card。
employee_schedules 中的排班时间。clock_in > shift_start 则计算迟到分钟;clock_out < shift_end 则计算早退分钟。无排班记录则标记为 isUnscheduled。
time_clock:punch — 打卡操作time_clock:view_own — 查看自己的工时卡time_clock:view_all — 查看所有人的工时卡time_clock:edit — 编辑工时卡、审批补卡time_clock:pin_manage — 管理 PIN(设置/重置/解锁)time_clock:settings — 管理打卡系统设置