qiangdanxitong/工作时间系统实施计划.md
Your Name 124e18ab78 feat: 实施工作时间配置系统
- 添加工作时间配置数据库迁移(V12__add_work_hours_config.sql)
- 创建WorkHoursCalculator工具类用于工作时间计算
- 添加工作时间配置API接口(SystemConfigController)
- 修改后端服务使用动态工作时间(TaskService、TaskItemService、TaskApprovalService、AnalyticsService)
- 在Settings.vue中添加工作时间配置UI
- 修改前端时效格式化函数使用动态工作时长(TaskHall.vue、CreateTask.vue)
- 所有时间计算(截止时间、延误扣分、时效格式化)现在使用配置的工作时间,替换硬编码的8小时
2026-01-14 11:40:43 +08:00

11 KiB
Raw Blame History

工作时间系统实施计划

一、需求概述

1.1 核心需求

  1. 工作时间配置:在系统设置中增加上班时间设置(开始时间、结束时间)
  2. 动态计算:一天的工作时间根据设置的上班时间段作为自然日(替换硬编码的8小时)
  3. 截止时间计算:计算截止时间时只计算到上班时间段内
  4. 延误扣分限制:延误扣分时间也需要限制在上班时间段内才扣分,超过上班时间不扣分

1.2 涉及场景

  • 截止时间计算(任务创建、子任务分配时)
  • 延误扣分计算(任务完成时、进行中任务检查时)
  • 时效格式化显示(前端显示、钉钉通知)
  • 子任务截止日期显示(前端任务卡片)

二、数据库设计

2.1 使用系统配置表(sys_config)

方案选择:使用现有的 sys_config 表存储工作时间配置(参考 site_url 配置的实现方式)

配置项设计:

  • config_key: work_hours.start_time(上班开始时间,格式:HH:mm,如 "09:00")
  • config_key: work_hours.end_time(上班结束时间,格式:HH:mm,如 "18:00")
  • config_group: system
  • value_type: string
  • built_in: 1(系统内置,不可删除)

默认值:

  • work_hours.start_time: "09:00"
  • work_hours.end_time: "18:00"
  • 工作时间长度:9小时(9:00-18:00,不含午休)

2.2 数据库迁移文件

创建 V12__add_work_hours_config.sql:

-- 添加上班时间配置
INSERT INTO `sys_config` (`config_key`, `config_value`, `config_group`, `config_name`, `description`, `value_type`, `built_in`, `sort_order`, `create_time`, `update_time`, `deleted`) 
VALUES 
('work_hours.start_time', '09:00', 'system', '上班开始时间', '工作日上班开始时间,格式:HH:mm(24小时制),例如:09:00', 'string', 1, 20, NOW(), NOW(), 0),
('work_hours.end_time', '18:00', 'system', '上班结束时间', '工作日上班结束时间,格式:HH:mm(24小时制),例如:18:00', 'string', 1, 21, NOW(), NOW(), 0)
ON DUPLICATE KEY UPDATE `update_time` = NOW();

三、后端实现

3.1 工作时间计算工具类

文件路径:backend/src/main/java/com/designhub/util/WorkHoursCalculator.java

核心方法:

  1. getWorkHoursConfig():从系统配置获取工作时间(开始时间、结束时间、工作时长)
  2. calculateDeadline(LocalDateTime startTime, BigDecimal workHours):计算截止时间(只计算工作时间段)
  3. calculateDelayHours(LocalDateTime deadline, LocalDateTime actualTime):计算延误时间(只计算工作时间段内的延误)
  4. formatWorkHours(BigDecimal hours):格式化工时显示(X天X小时,基于工作时间段)

计算逻辑:

  • 截止时间计算:

    • 从开始时间(接单时间)开始,累加工时
    • 只在工作时间段内累加(跳过非工作时间)
    • 如果当前时间不在工作时间内,先移动到下一个工作日的开始时间
    • 如果工时跨越多天,跳过周末(可选,根据需求)
  • 延误时间计算:

    • 从截止时间到实际完成时间
    • 只统计工作时间段内的小时数
    • 跳过非工作时间(下班后、周末)

3.2 系统配置 Service 扩展

文件路径:backend/src/main/java/com/designhub/service/SystemConfigService.java

新增方法:

  • getWorkHoursConfig():获取工作时间配置(返回 WorkHoursConfig 对象)

新增内部类:

public static class WorkHoursConfig {
    private LocalTime startTime;  // 上班开始时间
    private LocalTime endTime;    // 上班结束时间
    private int workHoursPerDay;  // 每天工作小时数
}

3.3 需要修改的后端文件清单

3.3.1 时效格式化(替换硬编码的8小时)

  • TaskService.java:formatHours() 方法
  • TaskItemService.java:formatEstimatedHours() 方法
  • TaskApprovalService.java:formatEstimatedHours() 方法

修改方式:

  • 从 WorkHoursCalculator.formatWorkHours() 获取格式化结果
  • 使用动态的工作时长(从配置读取)替换硬编码的8小时

3.3.2 截止时间计算

  • TaskService.java:任务创建时的截止时间计算
  • TaskItemService.java:子任务创建时的截止时间计算
  • TaskApprovalService.java:任务审批通过后的截止时间计算

修改方式:

  • 使用 WorkHoursCalculator.calculateDeadline() 计算截止时间

3.3.3 延误扣分计算

  • AnalyticsService.java:
    • getDesignerPerformance():设计师绩效统计中的延误扣分
    • getDesignerDeductionDetails():设计师扣分明细中的延误扣分
  • DelayPenaltyService.java:calculateDelayPenalty() 方法(如果有使用)
  • TaskService.java:任务完成时的延误扣分计算(completeTask() 方法)

修改方式:

  • 使用 WorkHoursCalculator.calculateDelayHours() 计算延误时间
  • 只计算工作时间段内的延误

四、前端实现

4.1 工作时间配置 UI

文件路径:frontend/src/views/Settings.vue

新增标签页:在"网站设置"标签页中添加"工作时间设置"区域

UI 组件:

  • 开始时间选择器(TimePicker,格式:HH:mm)
  • 结束时间选择器(TimePicker,格式:HH:mm)
  • 工作时间长度显示(自动计算,只读)
  • 保存按钮

配置项:

  • work_hours.start_time:上班开始时间
  • work_hours.end_time:上班结束时间

4.2 需要修改的前端文件清单

4.2.1 截止时间计算

  • frontend/src/components/TaskCard.vue:getSubTaskDeadline() 方法
  • frontend/src/views/TaskHall.vue:getSubTaskDeadline() 方法
  • frontend/src/views/CreateTask.vue:estimatedDeadline 计算属性

修改方式:

  • 从系统配置获取工作时间
  • 使用工作时间计算截止时间(调用后端API或前端计算)

4.2.2 时效格式化显示

  • frontend/src/views/TaskHall.vue:formatEstimatedTime() 函数
  • frontend/src/views/CreateTask.vue:formatWorkHours() 函数

修改方式:

  • 从系统配置获取工作时长
  • 使用动态工作时长替换硬编码的8小时

五、API 设计

5.1 获取工作时间配置

接口:GET /api/system-config/work-hours

响应:

{
  "code": 200,
  "data": {
    "startTime": "09:00",
    "endTime": "18:00",
    "workHoursPerDay": 9
  },
  "message": "操作成功"
}

5.2 更新工作时间配置

接口:PUT /api/system-config/work-hours

请求体:

{
  "startTime": "09:00",
  "endTime": "18:00"
}

响应:

{
  "code": 200,
  "data": true,
  "message": "操作成功"
}

5.3 计算截止时间(可选,如果需要前端计算)

接口:POST /api/system-config/calculate-deadline

请求体:

{
  "startTime": "2026-01-14T09:00:00",
  "workHours": 16
}

响应:

{
  "code": 200,
  "data": "2026-01-16T10:00:00",
  "message": "操作成功"
}

六、实施步骤

阶段一:数据库和基础工具类

  1. ✅ 创建数据库迁移文件 V12__add_work_hours_config.sql
  2. ✅ 创建 WorkHoursCalculator 工具类
  3. ✅ 在 SystemConfigService 中添加 getWorkHoursConfig() 方法
  4. ✅ 创建工作时间配置 API(SystemConfigController 或新 Controller)

阶段二:后端核心逻辑修改

  1. ✅ 修改 TaskService.formatHours() 使用动态工作时长
  2. ✅ 修改 TaskItemService.formatEstimatedHours() 使用动态工作时长
  3. ✅ 修改 TaskApprovalService.formatEstimatedHours() 使用动态工作时长
  4. ✅ 修改任务创建时的截止时间计算逻辑
  5. ✅ 修改子任务创建时的截止时间计算逻辑
  6. ✅ 修改 AnalyticsService 中的延误扣分计算
  7. ✅ 修改 TaskService.completeTask() 中的延误扣分计算

阶段三:前端实现

  1. ✅ 在 Settings.vue 中添加工作时间配置 UI
  2. ✅ 创建前端 API 调用(api/system.ts)
  3. ✅ 修改 TaskCard.vue 中的截止时间计算
  4. ✅ 修改 TaskHall.vue 中的截止时间计算
  5. ✅ 修改 CreateTask.vue 中的截止时间计算
  6. ✅ 修改前端时效格式化函数

阶段四:测试和优化

  1. ✅ 测试工作时间配置的保存和读取
  2. ✅ 测试截止时间计算(跨天、跨周末等场景)
  3. ✅ 测试延误扣分计算(工作时间段内、外)
  4. ✅ 测试时效格式化显示
  5. ✅ 测试钉钉通知中的时效显示
  6. ✅ 修复发现的 bug

七、技术难点和注意事项

7.1 工作时间计算复杂性

  • 跨天计算:工时可能跨越多天,需要跳过非工作时间
  • 跨周末:是否需要跳过周末?建议第一版先不考虑,只处理工作日的工作时间段
  • 时区问题:确保使用系统时区

7.2 性能考虑

  • 工作时间配置需要频繁读取,建议缓存(可以使用 Spring Cache)
  • 截止时间计算可能涉及循环,需要优化算法

7.3 向后兼容

  • 如果配置不存在,使用默认值(9:00-18:00,9小时)
  • 确保旧数据不会因为配置缺失而出错

7.4 数据迁移

  • 现有任务的截止时间是否需要重新计算?
    • 建议:不重新计算,只影响新创建的任务和新的延误扣分
  • 现有延误扣分记录是否需要重新计算?
    • 建议:不重新计算,只影响新产生的延误扣分

八、测试用例

8.1 工作时间配置

  • 测试保存和读取工作时间配置
  • 测试配置格式验证(HH:mm 格式)
  • 测试开始时间不能晚于结束时间
  • 测试配置不存在时使用默认值

8.2 截止时间计算

  • 测试同一工作日内完成的任务
  • 测试跨天的任务(例如:16小时工时,从上午开始)
  • 测试从非工作时间开始的任务(例如:晚上接单,从第二天早上开始计算)
  • 测试跨周末的任务(如果实现)

8.3 延误扣分计算

  • 测试在工作时间内延误的扣分
  • 测试跨越下班时间的延误(只计算工作时间内的延误)
  • 测试跨越周末的延误(只计算工作日的延误)
  • 测试提前完成的任务(不扣分)

8.4 时效格式化

  • 测试小时数少于1天的情况
  • 测试小时数等于1天的情况
  • 测试小时数超过1天的情况
  • 测试小数点小时数(如 1.5 小时)

九、预计工作量

  • 数据库设计:0.5 天
  • 后端工具类开发:2 天
  • 后端逻辑修改:3 天
  • 前端 UI 开发:1 天
  • 前端逻辑修改:1.5 天
  • 测试和修复:2 天

总计:约 10 个工作日


十、风险点

  1. 计算逻辑复杂性:工作时间计算涉及复杂的日期时间处理,容易出现边界情况
  2. 性能问题:如果计算逻辑复杂,可能影响性能
  3. 向后兼容性:确保现有功能不受影响
  4. 数据一致性:确保前后端计算逻辑一致

十一、后续优化建议

  1. 支持多时间段:支持上午、下午两个时间段(考虑午休)
  2. 支持周末配置:允许配置周末是否工作
  3. 支持节假日配置:支持配置节假日,跳过计算
  4. 历史数据重算:提供工具重新计算历史任务的截止时间和延误扣分