一个基于 Next.js 的团队排班系统。用来管理每个月的排班、人员和分组,数据以本地 JSON 文件保存,不需要数据库,这个月谁请假?这个月谁外出培训?一目了然。
以 202609shift.json 这份示例数据为例:
Default 标签页(自动包含全部成员):
IT 标签页(手动分组,只显示该组成员):
人员与分组管理页:
npm install # 安装依赖(需先装 Node.js)
npm run dev # 启动开发服务器打开浏览器访问 http://localhost:3000。改代码后页面会自动热更新。
本地测试通过后,可以部署到 Azure App Service。
所有数据都在 data/ 文件夹里,每个月一个文件,命名为 YYYYMMshift.json(例如 202609shift.json)。
另外有一个 shiftmapping.json,保存所有「工作状态」的图例(颜色、含义),全局共用。
整个系统靠 alias(工号/别名)来认人,它是主键,不能重复、不能拼错。
-
people[]是唯一的「人员主表」。 每个人在这里维护:{ "alias": "john", // 唯一 ID(主键) "name": "John", // 显示的名字 "days": [ // 这个月每一天的排班 { "day": 1, "workType": "W" }, { "day": 2, "workType": "AL" } ] }任何要在页面上出现的人,都必须先在
people[]里。 名字和排班都以这里为准。 -
tag_arrangement[]是分组(页面上的标签页)。 每个组只是按alias挑选people[]里的一部分人:{ "full_name": "IT", "member": [ { "alias": "john", "name": "John" }, { "alias": "mary", "name": "Mary" } ] }⚠️ 组里member的name只是备注,页面实际不看它——显示名字时永远回到people[]里用 alias 查。所以真正要保证正确的只有 alias。alias 对不上people[],那个人就渲染不出来。
Default 的组是你打开页面看到的默认组,你不用手动维护它的成员。系统在读取数据时,会自动把 people[] 里的每个人都放进 Default 组。
所以在文件里 Default 组的 member 保持空数组即可:
{ "full_name": "Default", "member": [] }一句话总结分组逻辑:
- 在
people[]里 → 自动出现在 Default 标签页。 - 想让某人额外出现在 IT / Marketing 等专属标签页 → 手动把他的 alias 加进那个组。
days[].workType 的取值来自 shiftmapping.json,含义如下:
| 代码 | 含义 | 是否在岗 |
|---|---|---|
W |
Work(正常工作) | ✅ |
WD |
Weekend(周末) | — |
MS |
OnCall Shift(值班) | ✅ |
PO |
Holiday OnDuty(假日值班) | ✅ |
T |
Training(培训) | — |
AL |
Annual Leave(年假) | — |
SL |
Sick Leave(病假) | — |
HMAL / HAAL |
上午/下午 年假(半天) | 半天 |
HMSL / HASL |
上午/下午 病假(半天) | 半天 |
PH |
Public Holiday(公共假期) | — |
PM |
Paternity & Maternity(产/陪产假) | — |
OL |
Other Leave(其他假) | — |
各月文件构成一条链:新建某个月时,系统会复制上一个月的人员和分组作为起点(见 createShiftData)。新月份里每个人的排班会按工作日 W、周末 WD 自动初始化,lockdate 清空。
- 前提:要新建的月份,它的上一个月文件必须存在,否则会报
Previous month data not found。因此不要删掉链条中间的月份文件。 - 第一个月(种子月)怎么办:链条最早的那个月没有「上一个月」可复制,需要手工编辑一份 JSON 来初始化:填好
year、month、pod、people[](人和排班)、以及需要的分组。Default 组留空即可,会自动填充。
参考模板:
data/202609shift.json就是一份干净的最小示例(5 个人、IT / Marketing 两组、Default 留空)。
- 顶部标签页切换不同分组视图(
Default显示全体)。 - 点击任意单元格弹出编辑框,选择工作状态并保存。
- 灰色背景的是锁定日期(
lockdate),不可编辑。
右上角 "Manage People & Groups" 进入。
- 新增用户:填 Alias(唯一 ID)和 Display Name,点 "Add User"。新用户自动进入 Default 并初始化当月排班。
- 创建新组:输入组名即可。
- 加人到组:选成员 → 选目标组 → "Add to Group"。这是复制操作——加到新组的同时,此人仍保留在 Default 和其他组里,系统会自动防重复。
每个月你真正要维护的是:
people[](谁 + 每天排班)、非 Default 分组的成员 alias 列表、以及lockdate。 Default 组、member里的 name 这些都会被系统自动处理或忽略,不用操心。



{ "lockdate": [5, 6], // 锁定的日期,这些天在页面上灰掉不可编辑,如需编辑,手动点击日期来解锁 "year": 2026, "month": 9, "pod": "A GREAT TEAM", // 团队的名称,会出现在页面的顶端 "people": [ ... ], // 团队里的所有 + 每人这个月的排班情况 "tag_arrangement": [ ... ] // 小分组情况(标签页) }