|
|
@@ -1,12 +1,22 @@
|
|
1
|
1
|
package com.water.dispatch.service;
|
|
|
2
|
+
|
|
2
|
3
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
3
|
4
|
import com.water.dispatch.entity.*;
|
|
4
|
5
|
import com.water.dispatch.mapper.*;
|
|
5
|
6
|
import lombok.RequiredArgsConstructor;
|
|
6
|
7
|
import org.springframework.stereotype.Service;
|
|
7
|
|
-import java.time.*; import java.util.*;
|
|
8
|
|
-@Service @RequiredArgsConstructor
|
|
|
8
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
9
|
+
|
|
|
10
|
+import java.time.*;
|
|
|
11
|
+import java.util.*;
|
|
|
12
|
+
|
|
|
13
|
+/**
|
|
|
14
|
+ * 调度业务核心服务 — 值班管理 + 指令全生命周期 + 工单 + 调度策略 + 应急
|
|
|
15
|
+ */
|
|
|
16
|
+@Service
|
|
|
17
|
+@RequiredArgsConstructor
|
|
9
|
18
|
public class DispatchBizService {
|
|
|
19
|
+
|
|
10
|
20
|
private final DutyScheduleMapper dutyMapper;
|
|
11
|
21
|
private final DispatchCommandMapper cmdMapper;
|
|
12
|
22
|
private final WorkOrderMapper woMapper;
|
|
|
@@ -14,68 +24,221 @@ public class DispatchBizService {
|
|
14
|
24
|
private final DispatchStrategyMapper stratMapper;
|
|
15
|
25
|
private final EmergencyPlanMapper planMapper;
|
|
16
|
26
|
|
|
|
27
|
+ // ── 值班管理 ──────────────────────────────────
|
|
|
28
|
+
|
|
|
29
|
+ /** 获取今日值班列表 */
|
|
17
|
30
|
public List<DutySchedule> getTodayDuty() {
|
|
18
|
31
|
return dutyMapper.selectList(new LambdaQueryWrapper<DutySchedule>()
|
|
19
|
|
- .eq(DutySchedule::getDutyDate, LocalDate.now()));
|
|
20
|
|
- }
|
|
21
|
|
- public Map<String,Object> createCommand(Map<String,Object> req) {
|
|
22
|
|
- DispatchCommand c = new DispatchCommand();
|
|
23
|
|
- c.setCmdNo("CMD-" + System.currentTimeMillis());
|
|
24
|
|
- c.setTitle((String)req.get("title")); c.setContent((String)req.get("content"));
|
|
25
|
|
- c.setType((String)req.getOrDefault("type","常规")); c.setStatus(0);
|
|
26
|
|
- cmdMapper.insert(c);
|
|
27
|
|
- return Map.of("id",c.getId(),"cmdNo",c.getCmdNo());
|
|
28
|
|
- }
|
|
29
|
|
- public Map<String,Object> issueCommand(String cmdNo) {
|
|
30
|
|
- DispatchCommand c = cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
|
31
|
|
- .eq(DispatchCommand::getCmdNo, cmdNo));
|
|
32
|
|
- if(c==null) throw new RuntimeException("指令不存在");
|
|
33
|
|
- c.setStatus(1); c.setIssuedTime(LocalDateTime.now());
|
|
34
|
|
- cmdMapper.updateById(c);
|
|
35
|
|
- return Map.of("cmdNo",cmdNo,"status",1);
|
|
36
|
|
- }
|
|
37
|
|
- public List<DispatchCommand> listCommands(Integer status) {
|
|
|
32
|
+ .eq(DutySchedule::getDutyDate, LocalDate.now())
|
|
|
33
|
+ .orderByAsc(DutySchedule::getStartTime));
|
|
|
34
|
+ }
|
|
|
35
|
+
|
|
|
36
|
+ /** 创建值班安排 */
|
|
|
37
|
+ @Transactional
|
|
|
38
|
+ public DutySchedule createDutySchedule(DutySchedule schedule) {
|
|
|
39
|
+ schedule.setStatus(0);
|
|
|
40
|
+ dutyMapper.insert(schedule);
|
|
|
41
|
+ return schedule;
|
|
|
42
|
+ }
|
|
|
43
|
+
|
|
|
44
|
+ /** 开始值班 */
|
|
|
45
|
+ @Transactional
|
|
|
46
|
+ public DutySchedule startDuty(Long scheduleId) {
|
|
|
47
|
+ DutySchedule ds = dutyMapper.selectById(scheduleId);
|
|
|
48
|
+ if (ds == null) throw new RuntimeException("值班安排不存在");
|
|
|
49
|
+ ds.setStatus(1);
|
|
|
50
|
+ dutyMapper.updateById(ds);
|
|
|
51
|
+ return ds;
|
|
|
52
|
+ }
|
|
|
53
|
+
|
|
|
54
|
+ /** 交接班 */
|
|
|
55
|
+ @Transactional
|
|
|
56
|
+ public DutySchedule handoverDuty(Long fromScheduleId, Long toUserId) {
|
|
|
57
|
+ DutySchedule from = dutyMapper.selectById(fromScheduleId);
|
|
|
58
|
+ if (from == null) throw new RuntimeException("值班安排不存在");
|
|
|
59
|
+
|
|
|
60
|
+ // 完成当前值班
|
|
|
61
|
+ from.setStatus(2);
|
|
|
62
|
+ dutyMapper.updateById(from);
|
|
|
63
|
+
|
|
|
64
|
+ // 记录交接日志
|
|
|
65
|
+ DutyLog handoverLog = new DutyLog();
|
|
|
66
|
+ handoverLog.setScheduleId(fromScheduleId);
|
|
|
67
|
+ handoverLog.setUserId(from.getUserId());
|
|
|
68
|
+ handoverLog.setLogType("HANDOVER");
|
|
|
69
|
+ handoverLog.setContent("交接给用户ID:" + toUserId);
|
|
|
70
|
+ logMapper.insert(handoverLog);
|
|
|
71
|
+
|
|
|
72
|
+ return from;
|
|
|
73
|
+ }
|
|
|
74
|
+
|
|
|
75
|
+ // ── 调度指令全生命周期 ──────────────────────────
|
|
|
76
|
+
|
|
|
77
|
+ /** 创建指令 (ISSUED 状态) */
|
|
|
78
|
+ @Transactional
|
|
|
79
|
+ public DispatchCommand createCommand(DispatchCommand command) {
|
|
|
80
|
+ command.setCommandNo("CMD-" + System.currentTimeMillis());
|
|
|
81
|
+ command.setStatus("ISSUED");
|
|
|
82
|
+ command.setIssuedAt(LocalDateTime.now());
|
|
|
83
|
+ cmdMapper.insert(command);
|
|
|
84
|
+ return command;
|
|
|
85
|
+ }
|
|
|
86
|
+
|
|
|
87
|
+ /** 下发指令 → RECEIVED */
|
|
|
88
|
+ @Transactional
|
|
|
89
|
+ public DispatchCommand issueCommand(String commandNo) {
|
|
|
90
|
+ DispatchCommand cmd = cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
|
|
91
|
+ .eq(DispatchCommand::getCommandNo, commandNo));
|
|
|
92
|
+ if (cmd == null) throw new RuntimeException("指令不存在: " + commandNo);
|
|
|
93
|
+ cmd.setStatus("RECEIVED");
|
|
|
94
|
+ cmd.setReceivedAt(LocalDateTime.now());
|
|
|
95
|
+ cmdMapper.updateById(cmd);
|
|
|
96
|
+ return cmd;
|
|
|
97
|
+ }
|
|
|
98
|
+
|
|
|
99
|
+ /** 开始执行 → EXECUTING */
|
|
|
100
|
+ @Transactional
|
|
|
101
|
+ public DispatchCommand startExecution(String commandNo) {
|
|
|
102
|
+ DispatchCommand cmd = cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
|
|
103
|
+ .eq(DispatchCommand::getCommandNo, commandNo));
|
|
|
104
|
+ if (cmd == null) throw new RuntimeException("指令不存在: " + commandNo);
|
|
|
105
|
+ if (!"RECEIVED".equals(cmd.getStatus())) throw new RuntimeException("指令状态不正确,当前: " + cmd.getStatus());
|
|
|
106
|
+ cmd.setStatus("EXECUTING");
|
|
|
107
|
+ cmd.setExecutedAt(LocalDateTime.now());
|
|
|
108
|
+ cmdMapper.updateById(cmd);
|
|
|
109
|
+ return cmd;
|
|
|
110
|
+ }
|
|
|
111
|
+
|
|
|
112
|
+ /** 完成指令 → COMPLETED */
|
|
|
113
|
+ @Transactional
|
|
|
114
|
+ public DispatchCommand completeCommand(String commandNo, String executeResult) {
|
|
|
115
|
+ DispatchCommand cmd = cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
|
|
116
|
+ .eq(DispatchCommand::getCommandNo, commandNo));
|
|
|
117
|
+ if (cmd == null) throw new RuntimeException("指令不存在: " + commandNo);
|
|
|
118
|
+ cmd.setStatus("COMPLETED");
|
|
|
119
|
+ cmd.setCompletedAt(LocalDateTime.now());
|
|
|
120
|
+ cmd.setExecuteResult(executeResult);
|
|
|
121
|
+ cmdMapper.updateById(cmd);
|
|
|
122
|
+ return cmd;
|
|
|
123
|
+ }
|
|
|
124
|
+
|
|
|
125
|
+ /** 驳回指令 → REJECTED */
|
|
|
126
|
+ @Transactional
|
|
|
127
|
+ public DispatchCommand rejectCommand(String commandNo, String rejectReason) {
|
|
|
128
|
+ DispatchCommand cmd = cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
|
|
129
|
+ .eq(DispatchCommand::getCommandNo, commandNo));
|
|
|
130
|
+ if (cmd == null) throw new RuntimeException("指令不存在: " + commandNo);
|
|
|
131
|
+ cmd.setStatus("REJECTED");
|
|
|
132
|
+ cmd.setRejectReason(rejectReason);
|
|
|
133
|
+ cmdMapper.updateById(cmd);
|
|
|
134
|
+ return cmd;
|
|
|
135
|
+ }
|
|
|
136
|
+
|
|
|
137
|
+ /** 查询指令列表 */
|
|
|
138
|
+ public List<DispatchCommand> listCommands(String status) {
|
|
38
|
139
|
return cmdMapper.selectList(new LambdaQueryWrapper<DispatchCommand>()
|
|
39
|
|
- .eq(status!=null, DispatchCommand::getStatus, status));
|
|
40
|
|
- }
|
|
41
|
|
- public Map<String,Object> createWorkOrder(Map<String,Object> req) {
|
|
42
|
|
- WorkOrder w = new WorkOrder();
|
|
43
|
|
- w.setOrderNo("WO-" + System.currentTimeMillis());
|
|
44
|
|
- w.setTitle((String)req.get("title")); w.setDescription((String)req.get("description"));
|
|
45
|
|
- w.setType((String)req.getOrDefault("type","维修")); w.setStatus(0);
|
|
46
|
|
- w.setPriority((String)req.getOrDefault("priority","中"));
|
|
47
|
|
- woMapper.insert(w);
|
|
48
|
|
- return Map.of("id",w.getId(),"orderNo",w.getOrderNo());
|
|
49
|
|
- }
|
|
50
|
|
- public Map<String,Object> updateWorkOrderStatus(Long id, int status) {
|
|
51
|
|
- WorkOrder w = woMapper.selectById(id);
|
|
52
|
|
- if(w==null) throw new RuntimeException("工单不存在");
|
|
53
|
|
- w.setStatus(status);
|
|
54
|
|
- if(status==2) w.setCompletedAt(LocalDateTime.now());
|
|
55
|
|
- woMapper.updateById(w);
|
|
56
|
|
- return Map.of("id",id,"status",status);
|
|
57
|
|
- }
|
|
58
|
|
- public void addDutyLog(Long scheduleId, Long userId, String type, String content) {
|
|
59
|
|
- DutyLog l = new DutyLog();
|
|
60
|
|
- l.setScheduleId(scheduleId); l.setUserId(userId);
|
|
61
|
|
- l.setLogType(type); l.setContent(content);
|
|
62
|
|
- logMapper.insert(l);
|
|
|
140
|
+ .eq(status != null, DispatchCommand::getStatus, status)
|
|
|
141
|
+ .orderByDesc(DispatchCommand::getIssuedAt));
|
|
|
142
|
+ }
|
|
|
143
|
+
|
|
|
144
|
+ /** 根据指令编号获取指令详情 */
|
|
|
145
|
+ public DispatchCommand getCommandByNo(String commandNo) {
|
|
|
146
|
+ return cmdMapper.selectOne(new LambdaQueryWrapper<DispatchCommand>()
|
|
|
147
|
+ .eq(DispatchCommand::getCommandNo, commandNo));
|
|
|
148
|
+ }
|
|
|
149
|
+
|
|
|
150
|
+ // ── 工单管理 ──────────────────────────────────
|
|
|
151
|
+
|
|
|
152
|
+ /** 创建工单 */
|
|
|
153
|
+ @Transactional
|
|
|
154
|
+ public WorkOrder createWorkOrder(WorkOrder wo) {
|
|
|
155
|
+ wo.setOrderNo("WO-" + System.currentTimeMillis());
|
|
|
156
|
+ wo.setStatus(0);
|
|
|
157
|
+ woMapper.insert(wo);
|
|
|
158
|
+ return wo;
|
|
|
159
|
+ }
|
|
|
160
|
+
|
|
|
161
|
+ /** 更新工单状态 */
|
|
|
162
|
+ @Transactional
|
|
|
163
|
+ public WorkOrder updateWorkOrderStatus(Long id, int status) {
|
|
|
164
|
+ WorkOrder wo = woMapper.selectById(id);
|
|
|
165
|
+ if (wo == null) throw new RuntimeException("工单不存在");
|
|
|
166
|
+ wo.setStatus(status);
|
|
|
167
|
+ if (status == 2) wo.setCompletedAt(LocalDateTime.now());
|
|
|
168
|
+ woMapper.updateById(wo);
|
|
|
169
|
+ return wo;
|
|
|
170
|
+ }
|
|
|
171
|
+
|
|
|
172
|
+ /** 查询工单列表 */
|
|
|
173
|
+ public List<WorkOrder> listWorkOrders(Integer status) {
|
|
|
174
|
+ return woMapper.selectList(new LambdaQueryWrapper<WorkOrder>()
|
|
|
175
|
+ .eq(status != null, WorkOrder::getStatus, status)
|
|
|
176
|
+ .orderByDesc(WorkOrder::getCreatedTime));
|
|
|
177
|
+ }
|
|
|
178
|
+
|
|
|
179
|
+ // ── 值班日志 ──────────────────────────────────
|
|
|
180
|
+
|
|
|
181
|
+ /** 添加值班日志 */
|
|
|
182
|
+ @Transactional
|
|
|
183
|
+ public DutyLog addDutyLog(Long scheduleId, Long userId, String type, String content) {
|
|
|
184
|
+ DutyLog log = new DutyLog();
|
|
|
185
|
+ log.setScheduleId(scheduleId);
|
|
|
186
|
+ log.setUserId(userId);
|
|
|
187
|
+ log.setLogType(type);
|
|
|
188
|
+ log.setContent(content);
|
|
|
189
|
+ logMapper.insert(log);
|
|
|
190
|
+ return log;
|
|
63
|
191
|
}
|
|
|
192
|
+
|
|
|
193
|
+ /** 获取值班日志列表 */
|
|
64
|
194
|
public List<DutyLog> getDutyLogs(Long scheduleId) {
|
|
65
|
195
|
return logMapper.selectList(new LambdaQueryWrapper<DutyLog>()
|
|
66
|
|
- .eq(DutyLog::getScheduleId, scheduleId));
|
|
|
196
|
+ .eq(DutyLog::getScheduleId, scheduleId)
|
|
|
197
|
+ .orderByDesc(DutyLog::getCreatedTime));
|
|
67
|
198
|
}
|
|
|
199
|
+
|
|
|
200
|
+ // ── 调度策略 ──────────────────────────────────
|
|
|
201
|
+
|
|
|
202
|
+ /** 查询调度策略列表 */
|
|
68
|
203
|
public List<DispatchStrategy> listStrategies(String type) {
|
|
69
|
204
|
return stratMapper.selectList(new LambdaQueryWrapper<DispatchStrategy>()
|
|
70
|
|
- .eq(type!=null, DispatchStrategy::getType, type));
|
|
|
205
|
+ .eq(type != null, DispatchStrategy::getType, type)
|
|
|
206
|
+ .orderByAsc(DispatchStrategy::getCreatedTime));
|
|
71
|
207
|
}
|
|
72
|
|
- public List<EmergencyPlan> listPlans(String type) {
|
|
|
208
|
+
|
|
|
209
|
+ // ── 应急管理 ──────────────────────────────────
|
|
|
210
|
+
|
|
|
211
|
+ /** 查询应急预案列表 */
|
|
|
212
|
+ public List<EmergencyPlan> listEmergencyPlans(String type) {
|
|
73
|
213
|
return planMapper.selectList(new LambdaQueryWrapper<EmergencyPlan>()
|
|
74
|
|
- .eq(type!=null, EmergencyPlan::getType, type));
|
|
|
214
|
+ .eq(type != null, EmergencyPlan::getType, type)
|
|
|
215
|
+ .orderByAsc(EmergencyPlan::getCreatedTime));
|
|
75
|
216
|
}
|
|
76
|
|
- public Map<String,Object> simulateEmergency(String type, double lng, double lat) {
|
|
77
|
|
- return Map.of("type",type,"lng",lng,"lat",lat,
|
|
78
|
|
- "affectedArea","半径500米","affectedUsers",120,
|
|
79
|
|
- "estimatedDuration","4小时");
|
|
|
217
|
+
|
|
|
218
|
+ /** 应急模拟推演 — 基于预案计算影响范围 */
|
|
|
219
|
+ public Map<String, Object> simulateEmergency(String type, double lng, double lat) {
|
|
|
220
|
+ // 根据应急类型查匹配预案
|
|
|
221
|
+ List<EmergencyPlan> plans = planMapper.selectList(new LambdaQueryWrapper<EmergencyPlan>()
|
|
|
222
|
+ .eq(EmergencyPlan::getType, type)
|
|
|
223
|
+ .eq(EmergencyPlan::getStatus, 1));
|
|
|
224
|
+
|
|
|
225
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
226
|
+ result.put("type", type);
|
|
|
227
|
+ result.put("lng", lng);
|
|
|
228
|
+ result.put("lat", lat);
|
|
|
229
|
+
|
|
|
230
|
+ if (!plans.isEmpty()) {
|
|
|
231
|
+ EmergencyPlan plan = plans.get(0);
|
|
|
232
|
+ result.put("matchedPlan", plan.getName());
|
|
|
233
|
+ result.put("planNo", plan.getPlanNo());
|
|
|
234
|
+ result.put("resourceConfig", plan.getResourceConfig());
|
|
|
235
|
+ }
|
|
|
236
|
+
|
|
|
237
|
+ // 默认影响范围估算
|
|
|
238
|
+ result.put("affectedArea", "半径500米");
|
|
|
239
|
+ result.put("affectedUsers", 120);
|
|
|
240
|
+ result.put("estimatedDuration", "4小时");
|
|
|
241
|
+
|
|
|
242
|
+ return result;
|
|
80
|
243
|
}
|
|
81
|
244
|
}
|