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

332 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 工作时间系统实施计划
## 一、需求概述
### 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`:
```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 对象)
**新增内部类**:
```java
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`
**响应**:
```json
{
"code": 200,
"data": {
"startTime": "09:00",
"endTime": "18:00",
"workHoursPerDay": 9
},
"message": "操作成功"
}
```
### 5.2 更新工作时间配置
**接口**:`PUT /api/system-config/work-hours`
**请求体**:
```json
{
"startTime": "09:00",
"endTime": "18:00"
}
```
**响应**:
```json
{
"code": 200,
"data": true,
"message": "操作成功"
}
```
### 5.3 计算截止时间(可选,如果需要前端计算)
**接口**:`POST /api/system-config/calculate-deadline`
**请求体**:
```json
{
"startTime": "2026-01-14T09:00:00",
"workHours": 16
}
```
**响应**:
```json
{
"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)
### 阶段二:后端核心逻辑修改
5. ✅ 修改 `TaskService.formatHours()` 使用动态工作时长
6. ✅ 修改 `TaskItemService.formatEstimatedHours()` 使用动态工作时长
7. ✅ 修改 `TaskApprovalService.formatEstimatedHours()` 使用动态工作时长
8. ✅ 修改任务创建时的截止时间计算逻辑
9. ✅ 修改子任务创建时的截止时间计算逻辑
10. ✅ 修改 `AnalyticsService` 中的延误扣分计算
11. ✅ 修改 `TaskService.completeTask()` 中的延误扣分计算
### 阶段三:前端实现
12. ✅ 在 `Settings.vue` 中添加工作时间配置 UI
13. ✅ 创建前端 API 调用(`api/system.ts`)
14. ✅ 修改 `TaskCard.vue` 中的截止时间计算
15. ✅ 修改 `TaskHall.vue` 中的截止时间计算
16. ✅ 修改 `CreateTask.vue` 中的截止时间计算
17. ✅ 修改前端时效格式化函数
### 阶段四:测试和优化
18. ✅ 测试工作时间配置的保存和读取
19. ✅ 测试截止时间计算(跨天、跨周末等场景)
20. ✅ 测试延误扣分计算(工作时间段内、外)
21. ✅ 测试时效格式化显示
22. ✅ 测试钉钉通知中的时效显示
23. ✅ 修复发现的 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. **历史数据重算**:提供工具重新计算历史任务的截止时间和延误扣分