日期: 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 一致)。
#10b981;label-position="top";弹窗无背景模糊。已占/名额);未配置显示未排班。capacity(可只启用部分班次)。source=assign,写入 user_id + person_name;指定人数不得超过该班次剩余名额。{PUBLIC_WEB_ORIGIN}/#/public/duty/{access_token}。link_status;关链后 H5 展示关闭态;日历仍可见数据。capacity 不得小于当前有效报名数。duty_day + slots,生成 access_token;再次保存更新 slots/安排,token 不变(D12)。对齐原型 docs/demos/duty-h5-grab-demo.html;视觉用三墙 Token(#0a9f6d),与管理端色值不混用。
| 状态 | 表现 |
|---|---|
| 可抢 | 班次卡片独立罗列;可填姓名提交;满员卡片禁用 |
| 提交成功 | 展示日期 / 班次 / 姓名摘要 |
| 链接关闭 | 「报名已关闭」 |
| token 无效 | 「链接无效或已失效」 |
| 能力 | 说明 |
|---|---|
| 月历查询 | 按年月返回每日摘要(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(及前端等价排除,若有)。公开响应不返回其他日期或其他租户数据。
| 场景 | 行为 |
|---|---|
| 抢班时刚好满员 | 返回失败,H5 提示名额已满并刷新人数 |
| 关链后提交 | 拒绝,展示关闭态 |
| 管理端缩容过大 | 保存失败,提示先删除多余人员 |
| 删除不存在的 assignment | 幂等或明确 404 |
docs/demos/duty-schedule-v1-demo.htmldocs/demos/duty-h5-grab-demo.html