# 转运时间写入planned_start_time功能说明 ## 功能概述 在创建急救转运任务时,将用户选择的**转运时间**同时写入主任务表的 `planned_start_time` 字段(计划开始时间),确保任务调度和时间管理的准确性。 ## 业务背景 急救转运任务的转运时间具有双重含义: 1. **业务层面**:表示预计何时开始转运患者(存储在扩展表的 transfer_time) 2. **系统层面**:表示任务计划开始时间(存储在主任务表的 planned_start_time) 这两个时间通常是一致的,因此需要同时写入两个表。 ## 技术实现 ### 前端数据提交 在 `buildSubmitData()` 方法中添加 `plannedStartTime` 字段: ```javascript const submitData = { taskType: 'EMERGENCY_TRANSFER', transferTime: this.taskForm.transferTime, // 转运时间(扩展表字段) plannedStartTime: this.taskForm.transferTime, // 计划开始时间(主任务表字段) // ... 其他字段 } ``` ### 数据库字段 **主任务表(sys_task)**: ```sql -- 计划开始时间 planned_start_time DATETIME ``` **扩展信息表(sys_task_emergency)**: ```sql -- 转运时间 transfer_time DATETIME ``` ## 数据结构 ### 前端表单数据 ```javascript taskForm: { transferTime: "2025-01-25 14:30:00", // 用户选择的转运时间 // ... 其他字段 } ``` ### 提交数据 ```javascript { taskType: "EMERGENCY_TRANSFER", transferTime: "2025-01-25 14:30:00", // 扩展表:转运时间 plannedStartTime: "2025-01-25 14:30:00", // 主任务表:计划开始时间 // ... 其他字段 } ``` ### 数据库存储 **主任务表(sys_task)**: | 字段 | 值 | 说明 | |------|-----|------| | task_id | 10001 | 任务ID | | planned_start_time | 2025-01-25 14:30:00 | 计划开始时间 | | actual_start_time | NULL | 实际开始时间(任务开始后填写) | **扩展信息表(sys_task_emergency)**: | 字段 | 值 | 说明 | |------|-----|------| | emergency_id | 20001 | 扩展信息ID | | task_id | 10001 | 关联任务ID | | transfer_time | 2025-01-25 14:30:00 | 转运时间 | ## 数据映射关系 | 前端字段 | 主任务表字段 | 扩展表字段 | 说明 | |---------|------------|----------|------| | `taskForm.transferTime` | `planned_start_time` | `transfer_time` | 用户选择的转运时间 | ## 时间相关字段说明 ### 主任务表时间字段 ```java public class SysTask { /** 计划开始时间 */ private Date plannedStartTime; // 用户指定的计划开始时间 /** 计划结束时间 */ private Date plannedEndTime; // 预计结束时间(可选) /** 实际开始时间 */ private Date actualStartTime; // 任务实际开始时记录 /** 实际结束时间 */ private Date actualEndTime; // 任务实际完成时记录 } ``` ### 时间字段使用场景 1. **planned_start_time**(计划开始时间): - 任务创建时由用户指定 - 用于任务调度和提醒 - 判断任务是否超时(actual_start_time > planned_start_time) 2. **actual_start_time**(实际开始时间): - 司机点击"出发"按钮时自动记录 - 用于统计实际执行情况 - 计算任务延迟时间 3. **actual_end_time**(实际结束时间): - 任务完成时自动记录 - 用于计算任务耗时 - 绩效考核的重要依据 ## 应用场景 ### 1. 任务调度 根据计划开始时间安排车辆和人员: ```sql -- 查询即将开始的任务(未来2小时内) SELECT t.task_id, t.task_code, t.planned_start_time, t.assignee_name, v.vehicle_no FROM sys_task t LEFT JOIN sys_task_vehicle tv ON t.task_id = tv.task_id LEFT JOIN tb_vehicle_info v ON tv.vehicle_id = v.vehicle_id WHERE t.task_status = 'PENDING' AND t.planned_start_time BETWEEN NOW() AND DATE_ADD(NOW(), INTERVAL 2 HOUR) ORDER BY t.planned_start_time ``` ### 2. 任务提醒 提前通知执行人员: ```javascript // 在计划开始时间前30分钟发送提醒 const reminderTime = new Date(task.plannedStartTime) reminderTime.setMinutes(reminderTime.getMinutes() - 30) scheduleNotification({ userId: task.assigneeId, time: reminderTime, title: '任务即将开始', content: `您的转运任务将在30分钟后开始,请做好准备` }) ``` ### 3. 超时检测 判断任务是否延迟开始: ```javascript // 检查任务是否超时开始 function isDelayedStart(task) { if (!task.actualStartTime || !task.plannedStartTime) { return false } return new Date(task.actualStartTime) > new Date(task.plannedStartTime) } // 计算延迟时长(分钟) function getDelayMinutes(task) { if (!isDelayedStart(task)) { return 0 } const planned = new Date(task.plannedStartTime) const actual = new Date(task.actualStartTime) return Math.floor((actual - planned) / (1000 * 60)) } ``` ### 4. 任务列表显示 按计划开始时间排序显示: ```vue {{ task.taskCode }} 计划时间:{{ formatTime(task.plannedStartTime) }} {{ getStatusText(task) }} ``` ## 数据一致性 ### 双重存储说明 转运时间在两个地方存储: 1. **主任务表(sys_task.planned_start_time)** - 用于通用任务调度 - 所有类型任务统一使用 - 便于跨任务类型统计和查询 2. **扩展表(sys_task_emergency.transfer_time)** - 保留急救转运的业务语义 - 便于业务人员理解 - 与旧系统字段对应 ### 数据同步保证 前端代码确保数据一致: ```javascript transferTime: this.taskForm.transferTime, // 扩展表 plannedStartTime: this.taskForm.transferTime, // 主任务表 // 两者使用同一个值,确保一致 ``` ## 时间格式说明 ### 前端时间格式 uni-datetime-picker 组件返回格式: ```javascript // 格式:YYYY-MM-DD HH:mm:ss transferTime: "2025-01-25 14:30:00" ``` ### 后端时间格式 Java Date 类型,JSON序列化格式: ```java @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date plannedStartTime; ``` 返回前端示例: ```json { "plannedStartTime": "2025-01-25 14:30:00" } ``` ### 数据库时间格式 MySQL DATETIME 类型: ```sql planned_start_time DATETIME -- 存储格式:2025-01-25 14:30:00 ``` ## 异常处理 ### 1. 未选择转运时间 **场景**:用户未选择转运时间 **处理**: ```javascript transferTime: this.taskForm.transferTime, // 可能为空字符串或null plannedStartTime: this.taskForm.transferTime, // 同样为空 ``` **结果**: - planned_start_time = NULL - 允许后续补充 - 任务可以创建,但可能不会出现在"即将开始"列表中 ### 2. 时间已过期 **场景**:用户选择的时间已经过去 **前端验证**(建议添加): ```javascript validateForm() { // ... 其他验证 if (this.taskForm.transferTime) { const selectedTime = new Date(this.taskForm.transferTime) const now = new Date() if (selectedTime < now) { this.$modal.confirm('选择的转运时间已过期,是否继续?').then(() => { // 用户确认继续 }).catch(() => { return false }) } } return true } ``` ### 3. 时间格式错误 **场景**:时间格式不正确 **后端验证**: ```java if (task.getPlannedStartTime() == null) { // 允许为空 } else { // 验证时间格式 try { // Spring会自动转换,这里只是示例 Date time = task.getPlannedStartTime(); } catch (Exception e) { throw new ServiceException("转运时间格式错误"); } } ``` ## 测试建议 ### 测试场景1:正常选择时间 **操作**: 1. 选择转运时间:2025-01-25 14:30:00 2. 保存任务 **验证**: ```sql -- 检查主任务表 SELECT planned_start_time FROM sys_task WHERE task_id = ? -- 预期:2025-01-25 14:30:00 -- 检查扩展表 SELECT transfer_time FROM sys_task_emergency WHERE task_id = ? -- 预期:2025-01-25 14:30:00 ``` ### 测试场景2:未选择时间 **操作**: 1. 不选择转运时间 2. 保存任务 **验证**: - planned_start_time = NULL - transfer_time = NULL - 任务创建成功 ### 测试场景3:时间列表排序 **操作**: 1. 创建多个任务,选择不同的转运时间 2. 查看任务列表 **验证**: - 任务按计划开始时间正确排序 - 最早的任务显示在前面 ### 测试场景4:超时提醒 **操作**: 1. 创建任务,转运时间设为当前时间+10分钟 2. 等待10分钟 3. 检查任务状态 **验证**: - 任务状态仍为"待处理" - 但显示"已超时"标记 ## 优化建议 ### 1. 默认时间设置 自动设置为当前时间后1小时: ```javascript data() { return { taskForm: { transferTime: this.getDefaultTransferTime(), // ... } } }, methods: { getDefaultTransferTime() { const now = new Date() now.setHours(now.getHours() + 1) now.setMinutes(0) now.setSeconds(0) // 格式化为 YYYY-MM-DD HH:mm:ss return this.formatDateTime(now) } } ``` ### 2. 快捷选择 提供常用时间快捷按钮: ```vue ``` ### 3. 时间冲突检测 检查是否与其他任务时间冲突: ```javascript async checkTimeConflict() { const params = { vehicleId: this.selectedVehicleId, plannedStartTime: this.taskForm.transferTime } const conflicts = await checkVehicleSchedule(params) if (conflicts.length > 0) { this.$modal.confirm( `所选车辆在该时间段已有${conflicts.length}个任务,是否继续?` ) } } ``` ## 版本历史 - **2025-01-25 v1**: 初始版本 - ✅ 添加 plannedStartTime 字段 - ✅ 与 transferTime 使用相同的值 - ✅ 确保主任务表和扩展表数据一致