Files
shanxia2.0/docs/superpowers/specs/2026-08-14-duty-schedule-design.md
T

8.9 KiB
Raw Blame History

值班排班(日历 + 公开链接抢班)— 设计文档

日期: 2026-08-14
状态: 待实现
仓库: shanxia2.0(backend/ + web-admin/)
方案: 方案 1 —「日排班 + 班次名额 + 公开 Token 链接」
UI 原型: docs/demos/duty-schedule-v1-demo.html(管理端)、docs/demos/duty-h5-grab-demo.html(公开 H5)
权威对照: Fresh Mint(docs/web-admin-ui-spec-fresh-mint.md)、公开页可参考运输计划司机免登录(/#/public/pl/transport/{token})

背景

总经理需要按日历安排值班(早班 / 晚班 / 值班等),可设定各班次人数,并可直接指定系统用户;同时生成按日的公开链接,员工免登录填写姓名抢班,满员不可再抢。总经理在日历中可查看历史排班。

参考截图(仅视觉参考):值班系统截图/。第一版不做统计页。

已确认决策

# 决策
D1 管理端在 web-admin 排班;员工通过 公开 H5 链接抢班
D2 一天一个链接(如「8 月 20 日值班」),每次配置某日即对应一条 token 链接
D3 H5 上将当日多个班次独立罗列,不做筛选,方便直接抢
D4 抢班只填姓名;同名不拦截,靠总经理事后核对
D5 总经理「直接安排」从系统用户选择
D6 员工不能自己取消;总经理可删人、改名额/班次、关链接
D7 有人报名后总经理仍可改(不整日锁定)
D8 V1 只要日历 + 历史排班;统计页以后再说
D9 班次类型系统预置(早班 / 晚班 / 值班),暂不可自定义
D10 只能按天建:点日历某日 → 配置 → 生成该日链接(不做批量日期范围)
D11 同一天同一人可以占多个班次(早班 + 晚班互不影响)
D12 关链后重开仍用原 token(V1 不做「重置链接」)
D13 将 capacity 调到小于当前报名人数时禁止保存,须先删人
D14 过往日期仍允许总经理修改(不做历史冻结)
D15 权限按菜单权限控制,不单独硬编码「总经理」角色名

方案选择

采用方案 1(已确认):duty_day + duty_slot + duty_assignment,公开 token 对齐现有免登录链接模式。

未采用:扁平日历事件(名额与关链难控);纯列表无月历(不符合「按日历排班/看历史」)。

架构与边界

端 职责
web-admin 月历、按日配置、指定用户、复制/关闭链接、删人改班、历史翻月
公开页(web-admin #/public/...) token 打开当日抢班页;免登录;只填姓名提交
backend 租户隔离管理 API + 公开抢班 API;名额并发控制;路径加入加密排除列表

公开页落地建议:与司机免登录一致,挂在 web-admin hash 路由,例如 /#/public/duty/{token};链接 Origin 使用现有 PUBLIC_WEB_ORIGIN(或等价配置)拼接。

duty_day (一天 = 一个 access_token)
  └── duty_slot × N(morning / evening / duty,各有 capacity)
        └── duty_assignment × M(source = assign | grab)

数据模型

表名前缀建议 duty_;均含门户公共字段(id, tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag)。字段顺序:id → 业务字段 → 公共字段。软删。

duty_day(值班日)

字段 说明
duty_date 值班日期;同一 tenant_no 下唯一(未删除)
access_token 公开访问令牌;足够长、不可猜;租户内唯一
link_status open / closed

duty_slot(班次名额)

字段 说明
duty_day_id 所属值班日
shift_type 预置:morning(早班)/ evening(晚班)/ duty(值班)
capacity 名额,≥ 1

约束:同一 duty_day_id + shift_type 唯一(未删除)。

duty_assignment(占位)

字段 说明
duty_slot_id 所属班次
source assign(管理端指定)/ grab(H5 抢班)
user_id 指定时必填;抢班为空
person_name 展示名(用户姓名或手填姓名)

满员规则:该 slot 下未删除 assignment 数 < capacity 才可新增。

SQL 变更须同步维护 docs/sql/(与 database-conventions 一致)。

Web 管理端

入口与权限

  • 新菜单「值班排班」(具体挂载位置实现时定),按钮级权限可拆:查看 / 编辑 / 关链(最小也可合并为菜单权限,能进即可改)。
  • UI:Fresh Mint;主色 #10b981;label-position="top";弹窗无背景模糊。
  • 模式:月历主视图;不做统计页(D8)。

月历

  • 月切换 +「今天」。
  • 日格摘要:班次 chip(类型 + 人名或 已占/名额);未配置显示未排班。
  • 点击日期 → 配置弹窗(与 Demo 一致)。

配置某日

  • 配置预置班次及 capacity(可只启用部分班次)。
  • 从系统用户选择直接安排 → source=assign,写入 user_id + person_name;指定人数不得超过该班次剩余名额。
  • 列表展示已报名,区分指定 / 抢班;支持删除 assignment。
  • 复制链接:{PUBLIC_WEB_ORIGIN}/#/public/duty/{access_token}。
  • 关闭 / 打开链接:改 link_status;关链后 H5 展示关闭态;日历仍可见数据。
  • 缩容校验(D13):capacity 不得小于当前有效报名数。
  • 去掉某班次(不再启用):若该 slot 仍有有效报名,禁止删除/停用,须先清空报名。
  • 首次保存某日:创建 duty_day + slots,生成 access_token;再次保存更新 slots/安排,token 不变(D12)。

历史

  • 翻月查看过往排班;过往日仍可编辑(D14)。

公开 H5

对齐原型 docs/demos/duty-h5-grab-demo.html;视觉用三墙 Token(#0a9f6d),与管理端色值不混用。

状态

状态 表现
可抢 班次卡片独立罗列;可填姓名提交;满员卡片禁用
提交成功 展示日期 / 班次 / 姓名摘要
链接关闭 「报名已关闭」
token 无效 「链接无效或已失效」

规则

  • 免登录;只填姓名(D4)。
  • 不可自助取消(D6)。
  • 同天可抢多个班次(D11)。
  • 展示已报名姓名列表(便于员工感知剩余名额;同名风险已知晓)。

API

管理端(登录 + 租户 + 数据权限按现有约定)

能力 说明
月历查询 按年月返回每日摘要(slots + assignments 精简)
日详情 含链接状态、token/完整 URL、slots、assignments
保存日配置 创建或更新 day/slots;校验缩容;可选写入 assign
删除 assignment 释放名额
开关链接 open / closed

用户选择器复用现有系统用户列表接口。

公开(免登录)

接口 说明
GET /api/public/duty/{token} 当日只读:日期、状态、各 slot 与已报名姓名
POST /api/public/duty/{token}/grab body: { shiftType, personName };personName 去首尾空格后非空且长度受限(建议 ≤20);校验开链与名额

须:

  • 注册路由于 app/api/__init__.py 与 app/main.py。
  • 公开路径加入 API_ENCRYPT_EXCLUDE_PATHS(及前端等价排除,若有)。
  • 抢班在事务内检查人数后再插入,防止超卖。
  • 错误:满员 / 已关闭 / token 无效 — 明确文案。
  • V1:按 IP 或 token 做基础限流(实现时可用现有中间件或轻量计数)。

公开响应不返回其他日期或其他租户数据。

错误处理

场景 行为
抢班时刚好满员 返回失败,H5 提示名额已满并刷新人数
关链后提交 拒绝,展示关闭态
管理端缩容过大 保存失败,提示先删除多余人员
删除不存在的 assignment 幂等或明确 404

测试要点(验收)

  1. 按日配置早/晚/值班名额并复制链接,H5 可打开且班次独立展示。
  2. 指定系统用户占名额;H5 抢班占名额;满员后不可再抢。
  3. 关链后 H5 不可抢;打开后可继续抢(同 token)。
  4. 管理端删人后名额释放;缩容小于当前人数被拒。
  5. 同姓名可重复报名;同人同日可抢多个班次。
  6. 翻月可看历史排班。
  7. 租户隔离:A 租户链接不可看到 B 租户数据。

明确不做(V1)

  • 统计页 / 按人汇总卡片
  • 批量按日期范围建排班
  • 自定义班次类型
  • H5 登录、手机号、验证码
  • 员工自助取消
  • 重置 token
  • 历史日期自动冻结

原型索引

  • 管理端月历 + 配置:docs/demos/duty-schedule-v1-demo.html
  • 公开 H5 多状态:docs/demos/duty-h5-grab-demo.html