在创建急救转运任务时,将用户选择的**转运时间**同时写入主任务表的 planned_start_time 字段(计划开始时间),确保任务调度和时间管理的准确性。
急救转运任务的转运时间具有双重含义:
1. 业务层面:表示预计何时开始转运患者(存储在扩展表的 transfer_time)
2. 系统层面:表示任务计划开始时间(存储在主任务表的 planned_start_time)
这两个时间通常是一致的,因此需要同时写入两个表。
在 buildSubmitData() 方法中添加 plannedStartTime 字段:
const submitData = {
taskType: 'EMERGENCY_TRANSFER',
transferTime: this.taskForm.transferTime, // 转运时间(扩展表字段)
plannedStartTime: this.taskForm.transferTime, // 计划开始时间(主任务表字段)
// ... 其他字段
}
主任务表(sys_task):
-- 计划开始时间
planned_start_time DATETIME
扩展信息表(sys_task_emergency):
-- 转运时间
transfer_time DATETIME
taskForm: {
transferTime: "2025-01-25 14:30:00", // 用户选择的转运时间
// ... 其他字段
}
{
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 |
用户选择的转运时间 |
public class SysTask {
/** 计划开始时间 */
private Date plannedStartTime; // 用户指定的计划开始时间
/** 计划结束时间 */
private Date plannedEndTime; // 预计结束时间(可选)
/** 实际开始时间 */
private Date actualStartTime; // 任务实际开始时记录
/** 实际结束时间 */
private Date actualEndTime; // 任务实际完成时记录
}
根据计划开始时间安排车辆和人员:
-- 查询即将开始的任务(未来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
提前通知执行人员:
// 在计划开始时间前30分钟发送提醒
const reminderTime = new Date(task.plannedStartTime)
reminderTime.setMinutes(reminderTime.getMinutes() - 30)
scheduleNotification({
userId: task.assigneeId,
time: reminderTime,
title: '任务即将开始',
content: `您的转运任务将在30分钟后开始,请做好准备`
})
判断任务是否延迟开始:
// 检查任务是否超时开始
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))
}
按计划开始时间排序显示:
<view class="task-item" v-for="task in sortedTasks" :key="task.taskId">
<text class="task-code">{{ task.taskCode }}</text>
<text class="task-time">计划时间:{{ formatTime(task.plannedStartTime) }}</text>
<text class="task-status" :class="getStatusClass(task)">
{{ getStatusText(task) }}
</text>
</view>
<script>
export default {
computed: {
sortedTasks() {
return this.tasks.sort((a, b) => {
return new Date(a.plannedStartTime) - new Date(b.plannedStartTime)
})
}
},
methods: {
getStatusText(task) {
const now = new Date()
const planned = new Date(task.plannedStartTime)
if (task.taskStatus === 'PENDING') {
if (now > planned) {
return '已超时'
} else if (now > new Date(planned.getTime() - 30 * 60 * 1000)) {
return '即将开始'
}
}
return task.taskStatusText
}
}
}
</script>
转运时间在两个地方存储:
前端代码确保数据一致:
transferTime: this.taskForm.transferTime, // 扩展表
plannedStartTime: this.taskForm.transferTime, // 主任务表
// 两者使用同一个值,确保一致
uni-datetime-picker 组件返回格式:
// 格式:YYYY-MM-DD HH:mm:ss
transferTime: "2025-01-25 14:30:00"
Java Date 类型,JSON序列化格式:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date plannedStartTime;
返回前端示例:json { "plannedStartTime": "2025-01-25 14:30:00" }
MySQL DATETIME 类型:
planned_start_time DATETIME
-- 存储格式:2025-01-25 14:30:00
场景:用户未选择转运时间
处理:javascript transferTime: this.taskForm.transferTime, // 可能为空字符串或null plannedStartTime: this.taskForm.transferTime, // 同样为空
结果:
- planned_start_time = NULL
- 允许后续补充
- 任务可以创建,但可能不会出现在"即将开始"列表中
场景:用户选择的时间已经过去
前端验证(建议添加):
```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
}
```
场景:时间格式不正确
后端验证:java if (task.getPlannedStartTime() == null) { // 允许为空 } else { // 验证时间格式 try { // Spring会自动转换,这里只是示例 Date time = task.getPlannedStartTime(); } catch (Exception e) { throw new ServiceException("转运时间格式错误"); } }
操作:
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
```
操作:
1. 不选择转运时间
2. 保存任务
验证:
- planned_start_time = NULL
- transfer_time = NULL
- 任务创建成功
操作:
1. 创建多个任务,选择不同的转运时间
2. 查看任务列表
验证:
- 任务按计划开始时间正确排序
- 最早的任务显示在前面
操作:
1. 创建任务,转运时间设为当前时间+10分钟
2. 等待10分钟
3. 检查任务状态
验证:
- 任务状态仍为"待处理"
- 但显示"已超时"标记
自动设置为当前时间后1小时:
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)
}
}
提供常用时间快捷按钮:
<view class="quick-time-select">
<button @click="setTransferTime(30)">30分钟后</button>
<button @click="setTransferTime(60)">1小时后</button>
<button @click="setTransferTime(120)">2小时后</button>
<button @click="setTransferTime(180)">3小时后</button>
</view>
<script>
methods: {
setTransferTime(minutes) {
const time = new Date()
time.setMinutes(time.getMinutes() + minutes)
this.taskForm.transferTime = this.formatDateTime(time)
}
}
</script>
检查是否与其他任务时间冲突:
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}个任务,是否继续?`
)
}
}