- 添加工作时间配置数据库迁移(V12__add_work_hours_config.sql) - 创建WorkHoursCalculator工具类用于工作时间计算 - 添加工作时间配置API接口(SystemConfigController) - 修改后端服务使用动态工作时间(TaskService、TaskItemService、TaskApprovalService、AnalyticsService) - 在Settings.vue中添加工作时间配置UI - 修改前端时效格式化函数使用动态工作时长(TaskHall.vue、CreateTask.vue) - 所有时间计算(截止时间、延误扣分、时效格式化)现在使用配置的工作时间,替换硬编码的8小时
332 lines
11 KiB
Markdown
332 lines
11 KiB
Markdown
# 工作时间系统实施计划
|
||
|
||
## 一、需求概述
|
||
|
||
### 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. **历史数据重算**:提供工具重新计算历史任务的截止时间和延误扣分
|
||
|