项目:值班排班管理系统
【摘要】 一、今日工作概述对 scheduling-app 项目进行全量代码审查,完成两项 P0 级修复,通过全部测试后发布至华为云开发者作品展览馆。阶段内容耗时(估)代码审查拉取仓库,逐文件审阅,产出优化建议清单—P0 修复#1 防连续值班 + #4 year 参数校验—测试验证新增 1 个测试用例,9/9 全部通过—作品发布截图 → 封面 → 详情文章 → 发布 → 领积分— 二、代码审查结论对...
一、今日工作概述
对 scheduling-app 项目进行全量代码审查,完成两项 P0 级修复,通过全部测试后发布至华为云开发者作品展览馆。
| 阶段 | 内容 | 耗时(估) |
|---|---|---|
| 代码审查 | 拉取仓库,逐文件审阅,产出优化建议清单 | — |
| P0 修复 | #1 防连续值班 + #4 year 参数校验 | — |
| 测试验证 | 新增 1 个测试用例,9/9 全部通过 | — |
| 作品发布 | 截图 → 封面 → 详情文章 → 发布 → 领积分 | — |
二、代码审查结论
对 app.py、scheduler.py、test_scheduler.py、app.js、index.html、style.css 逐文件审查后,按影响程度分六层提出 19 项优化建议,摘录如下:
按优先级分布
| 级别 | 数量 | 代表项 |
|---|---|---|
| 🔴 P0(必修) | 2 | 防连续值班、year 参数校验 |
| 🟡 P1(应修) | 3 | 多年份测试、导出 CSV、生产部署文档 |
| 🟢 P2(建议) | 14 | 死代码清理、类型注解、日志、CI、Dockerfile 等 |
关键发现
- 算法层:
sparse_score(×10)权重远低于yearly_score(×100),无法有效阻止同一人连续值班;monthly_avg未扣除轮休天数导致月度均衡评分系统性偏移。 - 安全面:
year参数无边界校验,/api/regenerate的data.get('year')不做类型转换,非法输入直接 500。 - 测试层:仅覆盖 2025 年,未验证闰年(2024)等边界条件;无 API 层测试;未测试 seed 可复现性。
三、代码变更明细
3.1 scheduler.py — 防连续值班硬约束
问题:原算法仅靠 sparse_score = days_since_last * 10 作为软偏好,被 yearly_score(×100)轻易压过,同一人可能连续 2-3 天值班。
修复:在 generate_month 的每日循环中,计算完 available(已排除轮休人员)后,加入硬约束排除逻辑:
# 防止同一人连续值班:当可用人员 ≥ 2 时,排除昨天值班的人
if len(available) > 1:
yesterday = date(self.year, month, day) - timedelta(days=1)
just_duty = [p for p in available
if self.last_duty_date[p] == yesterday]
if just_duty and len(available) > len(just_duty):
available = [p for p in available if p not in just_duty]
设计考量:
- 用硬排除而非软扣分——保证无论评分如何,都不会连班。
- 保留 fallback:排除后无人可用时不排除(总不能空班),实际测试中未触发。
- 跨月边界自然生效:
last_duty_date在全年生成时跨月持续维护。 - 新增
from datetime import date, timedelta导入。
3.2 app.py — year 参数校验
问题:year 参数无边界校验,/api/regenerate 的 data.get('year', 2025) 不做类型转换,传入字符串直接透传给 Scheduler,后续 calendar.monthrange 报 500。
修复:新增 _validate_year() 函数,两个接口都接入:
MIN_YEAR = 2000
MAX_YEAR = 2100
def _validate_year(year):
try:
year = int(year)
except (TypeError, ValueError):
return None, 'year 必须是整数'
if year < MIN_YEAR or year > MAX_YEAR:
return None, f'year 必须在 {MIN_YEAR}-{MAX_YEAR} 之间'
return year, None
/api/schedule 和 /api/regenerate 均改为先校验再使用,非法返回 400 + 错误信息。
3.3 test_scheduler.py — 新增防连续值班测试
def test_no_consecutive_duty(self):
"""同一人不应连续两天值班(跨月边界也要检查)"""
prev_person = None
for month_data in self.result['months']:
for day_info in month_data['days']:
duty = day_info['duty_person']
if duty is not None and prev_person is not None:
self.assertNotEqual(duty, prev_person, ...)
prev_person = duty
变更统计
app.py | 26 ++++++++++++++++++++++++--
scheduler.py | 11 ++++++++++-
test_scheduler.py | 14 ++++++++++++++
3 files changed, 48 insertions(+), 3 deletions(-)
四、测试结果
test_balance_gap_within_target ... ok 固定6人全年均衡差距 ≤ 2
test_fixed_people_have_similar_total_duties ... ok
test_every_day_has_duty_person ... ok 每天恰好1人值班
test_no_consecutive_duty ... ok ★ 新增:无连续值班
test_duty_person_is_valid ... ok 值班人在当月人员名单中
test_resting_people_not_on_duty ... ok 轮休人当天不值班
test_extra_people_only_in_sep_to_dec ... ok 额外人员仅9-12月
test_month_days_match_calendar ... ok 月天数与日历一致
test_year_has_12_months ... ok 全年12个月
Ran 9 tests in 0.034s — OK
API 层验证(年份校验)
| 请求 | 状态码 | 说明 |
|---|---|---|
year=2025 |
200 | 正常 |
year=1999 |
400 | 超出下限 |
year=9999 |
400 | 超出上限 |
year=abc |
400 | 非整数 |
POST {"year":"not_a_number"} |
400 | 非整数 |
六、待办事项(P1,计划明日完成)
| 序号 | 项目 | 说明 |
|---|---|---|
| #8 | 多年份测试 | 当前仅测 2025,需覆盖 2024(闰年)、2026、2027 等 |
| #14 | 导出 CSV | 用户最可能立刻需要的功能,加一个"导出本月"按钮 |
其他 P2 项(不急)
- #9 API 层测试(Flask test client)
- #10 seed 可复现性测试
- #11 清理死代码(
FIXED_PEOPLE/EXTRA_PEOPLE/ALL_PEOPLE兼容别名) - #12 添加类型注解
- #13 引入 logging
- #15 标记"今天"行高亮
- #17 CI 配置
- #18 Dockerfile
- #19 健康检查端点
七、反思
做得好的:
- 审查时分层归类、按优先级排序,避免一把抓。
- P0 修复用硬约束而非软评分,从根上解决问题。
- 每步改完立刻跑测试,没有攒一堆再验。
可改进的:
- 审查时花了不少时间读前端 CSS(400 行),其实 CSS 对排班质量无影响,优先级应该更低。
- 发布流程中封面设计尝试了一次就过了,如果字形校验没过会卡比较久——下次可以先把字体门禁跑完再写封面 HTML。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)