Commit 457057e423a95a9d8f4a607c68ff6f7c16f013f7

Authored by 王通
1 parent 56146d95

1.解决车辆换线后可能存在第一个班次无法正常执行的问题

src/main/java/com/bsth/data/schedule/DayOfSchedule.java
1 -package com.bsth.data.schedule;  
2 -  
3 -import com.alibaba.fastjson.JSON;  
4 -import com.alibaba.fastjson.JSONArray;  
5 -import com.bsth.common.Constants;  
6 -import com.bsth.common.ResponseCode;  
7 -import com.bsth.data.LineConfigData;  
8 -import com.bsth.data.SystemParamCache;  
9 -import com.bsth.data.gpsdata_v2.GpsRealData;  
10 -import com.bsth.data.gpsdata_v2.utils.GpsDataRecovery;  
11 -import com.bsth.data.schedule.f_a_l.FirstAndLastHandler;  
12 -import com.bsth.entity.realcontrol.LineConfig;  
13 -import com.bsth.entity.realcontrol.ScheduleRealInfo;  
14 -import com.bsth.entity.report.RepairReport;  
15 -import com.bsth.entity.schedule.SchedulePlanInfo;  
16 -import com.bsth.repository.realcontrol.ScheduleRealInfoRepository;  
17 -import com.bsth.service.schedule.SchedulePlanInfoService;  
18 -import com.bsth.websocket.handler.SendUtils;  
19 -import com.fasterxml.jackson.core.JsonProcessingException;  
20 -import com.fasterxml.jackson.databind.ObjectMapper;  
21 -import com.google.common.collect.ArrayListMultimap;  
22 -import com.google.common.collect.HashMultimap;  
23 -import com.google.common.collect.ListMultimap;  
24 -import com.google.common.collect.Multimaps;  
25 -import org.apache.commons.lang3.StringUtils;  
26 -import org.joda.time.format.DateTimeFormat;  
27 -import org.joda.time.format.DateTimeFormatter;  
28 -import org.slf4j.Logger;  
29 -import org.slf4j.LoggerFactory;  
30 -import org.springframework.beans.factory.annotation.Autowired;  
31 -import org.springframework.dao.DataIntegrityViolationException;  
32 -import org.springframework.jdbc.core.BatchPreparedStatementSetter;  
33 -import org.springframework.jdbc.core.JdbcTemplate;  
34 -import org.springframework.stereotype.Component;  
35 -import org.springframework.transaction.TransactionStatus;  
36 -import org.springframework.transaction.support.TransactionCallbackWithoutResult;  
37 -import org.springframework.transaction.support.TransactionTemplate;  
38 -  
39 -import java.sql.PreparedStatement;  
40 -import java.sql.SQLException;  
41 -import java.text.ParseException;  
42 -import java.text.SimpleDateFormat;  
43 -import java.util.*;  
44 -import java.util.concurrent.ConcurrentHashMap;  
45 -import java.util.concurrent.ConcurrentLinkedQueue;  
46 -import java.util.concurrent.ConcurrentMap;  
47 -  
48 -/**  
49 - * @author PanZhao  
50 - * @ClassName: DayOfSchedule  
51 - * @Description: TODO(当日实际排班)  
52 - * @date 2016年8月15日 上午10:16:12  
53 - */  
54 -@Component  
55 -public class DayOfSchedule {  
56 -  
57 - Logger logger = LoggerFactory.getLogger(this.getClass());  
58 -  
59 - //按线路分组的 “原始计划” 排班数据  
60 - public static Map<String, List<SchedulePlanInfo>> schedulePlanMap;  
61 -  
62 - // 按车辆索引的班次数据  
63 - private static ListMultimap<String, ScheduleRealInfo> nbbmScheduleMap;  
64 -  
65 - // 按营运公司索引的班次数据  
66 - private static ListMultimap<String, ScheduleRealInfo> gsBmScheduleMap;  
67 -  
68 - //按线路索引计划用车  
69 - private static HashMultimap<String, String> lineNbbmsMap;  
70 -  
71 - //按路牌索引班次数据 线路编码_路牌名称 ——> 班次list  
72 - private static ArrayListMultimap<String, ScheduleRealInfo> lpScheduleMap;  
73 -  
74 - // 班次主键映射  
75 - private static ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMap;  
76 -  
77 - //车辆 ——> 当前执行班次  
78 - private static ConcurrentMap<String, ScheduleRealInfo> carExecutePlanMap;  
79 -  
80 - // 持久化  
81 - public static ConcurrentLinkedQueue<ScheduleRealInfo> pstBuffer;  
82 -  
83 - // 排序器  
84 - private static ScheduleComparator.FCSJ schFCSJComparator;  
85 -  
86 - private static ScheduleComparator.DFSJ schDFSJComparator;  
87 -  
88 - private static Long sch_max_id=-1L;  
89 -  
90 - private Map<String, RepairReport> incode2report = new ConcurrentHashMap<String, RepairReport>();  
91 -  
92 - @Autowired  
93 - LineConfigData lineConfigData;  
94 -  
95 - @Autowired  
96 - ScheduleRealInfoRepository schRepository;  
97 -  
98 - @Autowired  
99 - SchedulePlanInfoService schPlanService;  
100 -  
101 - @Autowired  
102 - SchAttrCalculator schAttrCalculator;  
103 -  
104 - @Autowired  
105 - SendUtils sendUtils;  
106 -  
107 - @Autowired  
108 - GpsRealData gpsRealData;  
109 -  
110 - /**  
111 - * 线路当前使用的排班的日期  
112 - */  
113 - public static Map<String, String> currSchDateMap;  
114 -  
115 - static {  
116 - nbbmScheduleMap = ArrayListMultimap.create();  
117 - nbbmScheduleMap = Multimaps.synchronizedListMultimap(nbbmScheduleMap);  
118 -  
119 - gsBmScheduleMap = ArrayListMultimap.create();  
120 - lpScheduleMap = ArrayListMultimap.create();  
121 - lineNbbmsMap = HashMultimap.create();  
122 -  
123 - id2SchedulMap = new ConcurrentHashMap<>();  
124 - pstBuffer = new ConcurrentLinkedQueue<>();  
125 - schFCSJComparator = new ScheduleComparator.FCSJ();  
126 - schDFSJComparator = new ScheduleComparator.DFSJ();  
127 - currSchDateMap = new HashMap<>();  
128 - carExecutePlanMap = new ConcurrentHashMap<>();  
129 -  
130 - schedulePlanMap = new HashMap<>();  
131 - }  
132 -  
133 - @Autowired  
134 - LineConfigData lineConfigs;  
135 -  
136 - @Autowired  
137 - GpsDataRecovery gpsDataRecovery;  
138 -  
139 - private static DateTimeFormatter fmtyyyyMMdd = DateTimeFormat.forPattern("yyyy-MM-dd"), fmtHHmm = DateTimeFormat.forPattern("HH:mm");  
140 -  
141 - //数据恢复  
142 - public void dataRecovery() {  
143 - Collection<LineConfig> confs = lineConfigs.getAll();  
144 - String lineCode, currSchDate;  
145 - for (LineConfig conf : confs) {  
146 - lineCode = conf.getLine().getLineCode();  
147 - currSchDate = calcSchDate(lineCode);  
148 - //加载班次数据  
149 - reloadSch(lineCode, currSchDate, false);  
150 - }  
151 -  
152 - //恢复gps数据  
153 - gpsDataRecovery.recovery();  
154 - }  
155 -  
156 - public Map<String, String> getCurrSchDate() {  
157 - return currSchDateMap;  
158 - }  
159 -  
160 - /**  
161 - * @Title: calcSchDateB  
162 - * @Description: TODO(计算线路当前应该使用的排班日期)  
163 - */  
164 - public String calcSchDate(String lineCode) {  
165 - Long t = System.currentTimeMillis();  
166 - LineConfig conf = lineConfigData.get(lineCode);  
167 -  
168 - // 小于当天起始运营时间,则取前一天的排班  
169 - String ct = fmtHHmm.print(t);  
170 - if(ct.compareTo(conf.getStartOpt()) < 0)  
171 - t -= 1000 * 60 * 60 * 24;  
172 -  
173 - String schDate = fmtyyyyMMdd.print(t);  
174 - return schDate;  
175 - }  
176 -  
177 - /**  
178 - * @param @param lineCode 线路编码  
179 - * @param @param schDate 班次日期 yyyy-MM-dd  
180 - * @param @param forcePlan 强制从计划调度重新抓取  
181 - * @Title: reloadSch  
182 - * @Title: reloadSch  
183 - * @Description: TODO(重新载入排班)  
184 - */  
185 - public int reloadSch(String lineCode, String schDate, boolean forcePlan) {  
186 - try {  
187 - boolean generate = SystemParamCache.getEnabledFirstLastGeneration();  
188 - List<ScheduleRealInfo> list;  
189 -  
190 - if (forcePlan)  
191 - removeRealSch(lineCode, schDate);  
192 - else  
193 - clearRAMData(lineCode);  
194 -  
195 - if (existRealSch(lineCode, schDate))  
196 - list = loadRealSch(lineCode, schDate);// 从实际排班表加载  
197 - else {  
198 - list = loadPlanSch(lineCode, schDate);// 从计划排班表加载  
199 - // 写入数据库  
200 - batchSave(list);  
201 - }  
202 -  
203 - //更新线路和班次日期对照  
204 - currSchDateMap.put(lineCode, schDate);  
205 - //添加到缓存  
206 - putAll(list);  
207 -  
208 - //标记首末班  
209 - if (generate) {  
210 - FirstAndLastHandler.marks(list);  
211 - }  
212 -  
213 - Set<String> lps = searchAllLP(list);  
214 - for (String lp : lps) {  
215 - //计算“起点站应到”时间  
216 - schAttrCalculator.calcQdzTimePlan(lpScheduleMap.get(lineCode + "_" + lp));  
217 - }  
218 - Set<String> cars = searchAllCars(list);  
219 - for (String nbbm : cars) {  
220 - //车辆 ——> 要执行的班次对照  
221 - reCalcExecPlan(nbbm);  
222 - }  
223 -  
224 - //分组计划用车  
225 - reCalcLineNbbms();  
226 - // 页面 翻班通知  
227 - //sendUtils.shiftSchedule(lineCode);  
228 - } catch (Exception e) {  
229 - logger.error("", e);  
230 - return -1;  
231 - }  
232 -  
233 - return 0;  
234 - }  
235 -  
236 - public int reloadSch(String lineCode) {  
237 - return reloadSch(lineCode, calcSchDate(lineCode), true);  
238 - }  
239 -  
240 - /**  
241 - * @Title: searchAllCars  
242 - * @Description: TODO(搜索班次集合中的车辆)  
243 - */  
244 - private Set<String> searchAllCars(List<ScheduleRealInfo> list) {  
245 - Set<String> cars = new HashSet<>();  
246 - for (ScheduleRealInfo sch : list)  
247 - cars.add(sch.getClZbh());  
248 -  
249 - return cars;  
250 - }  
251 -  
252 - /**  
253 - * @Title: searchAllCars  
254 - * @Description: TODO(搜索班次集合中的路牌)  
255 - */  
256 - private Set<String> searchAllLP(List<ScheduleRealInfo> list) {  
257 - Set<String> lps = new HashSet<>();  
258 - for (ScheduleRealInfo sch : list)  
259 - lps.add(sch.getLpName());  
260 -  
261 - return lps;  
262 - }  
263 -  
264 - private void putAll(List<ScheduleRealInfo> list) {  
265 - for (ScheduleRealInfo sch : list)  
266 - put(sch);  
267 - }  
268 -  
269 - /**  
270 - * @param @param lineCode 线路编码  
271 - * @param @param schDate 班次日期 yyyy-MM-dd  
272 - * @Title: removeRealSch  
273 - * @Description: TODO(清除实际排班,包括数据库和内存数据)  
274 - */  
275 - public void removeRealSch(String lineCode, String schDate) throws Exception {  
276 - try {  
277 - // 清理数据库数据  
278 - schRepository.deleteByLineCodeAndDate(lineCode + "", schDate);  
279 -  
280 - // 清理内存数据  
281 - clearRAMData(lineCode + "");  
282 - } catch (Exception e) {  
283 - logger.error("removeRealSch error, " + lineCode + " -" + schDate, e);  
284 - throw e;  
285 - }  
286 - }  
287 -  
288 - /**  
289 - * @Title: clearRAMData  
290 - * @Description: TODO(清理内存数据)  
291 - */  
292 - public void clearRAMData(String lineCode) {  
293 - int count = 0;  
294 - List<ScheduleRealInfo> remList = new ArrayList<>();  
295 - Collection<ScheduleRealInfo> all = nbbmScheduleMap.values();  
296 - for (ScheduleRealInfo sch : all) {  
297 - if (sch.getXlBm().equals(lineCode))  
298 - remList.add(sch);  
299 - }  
300 -  
301 - for (ScheduleRealInfo sch : remList) {  
302 - if (null != sch) {  
303 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
304 - id2SchedulMap.remove(sch.getId());  
305 - count++;  
306 -  
307 - //清理路牌对照  
308 - lpScheduleMap.removeAll(sch.getXlBm() + "_" + sch.getLpName());  
309 -  
310 - //清除车辆 ——> 执行班次对照  
311 - carExecutePlanMap.remove(sch.getClZbh());  
312 - }  
313 - }  
314 - //清理计划排班  
315 - schedulePlanMap.remove(lineCode);  
316 -  
317 - remList.clear();  
318 - remList = null;  
319 - logger.info(lineCode + "排班清理 " + count);  
320 - }  
321 -  
322 - /**  
323 - * @Title: existRealSch  
324 - * @Description: TODO(实际排班是否已存在)  
325 - */  
326 - public boolean existRealSch(String lineCode, String schDate) {  
327 - int count = schRepository.countByLineCodeAndDate(lineCode, schDate);  
328 - return count > 0;  
329 - }  
330 -  
331 - /**  
332 - * @Title: loadRealSch  
333 - * @Description: TODO(从实际排班表加载数据)  
334 - */  
335 - public List<ScheduleRealInfo> loadRealSch(String lineCode, String schDate) {  
336 - return schRepository.findByLineCodeAndDate(lineCode, schDate);  
337 - }  
338 -  
339 - /**  
340 - * @Title: loadPlanSch  
341 - * @Description: TODO(从计划排班表加载数据)  
342 - */  
343 - public List<ScheduleRealInfo> loadPlanSch(String lineCode, String schDate) {  
344 - //logger.info("从计划排班表恢复排班,lineCode: " + lineCode + ", schDate: " + schDate);  
345 - List<ScheduleRealInfo> realList = new ArrayList<>();  
346 -  
347 - try {  
348 - Map<String, Object> data = new HashMap<>();  
349 -  
350 - data.put("scheduleDate_eq", fmtyyyyMMdd.parseDateTime(schDate).toDate());  
351 - data.put("xlBm_eq", lineCode);  
352 -  
353 - // 查询计划排班  
354 - List<SchedulePlanInfo> planItr = cleanSchPlanItr(schPlanService.list(data).iterator());  
355 - //保存一份原始计划排班数据  
356 - schedulePlanMap.put(lineCode, planItr);  
357 -  
358 - // 转换为实际排班  
359 - realList = JSONArray.parseArray(JSON.toJSONString(planItr), ScheduleRealInfo.class);  
360 - logger.info("从计划排班表恢复排班,lineCode: " + lineCode + ", schDate: " + schDate + ", size:" + realList.size());  
361 -  
362 - Date d = new Date();  
363 - SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");  
364 - String fcsj;  
365 - for (ScheduleRealInfo sch : realList) {  
366 - sch.setScheduleDateStr(fmtyyyyMMdd.print(sch.getScheduleDate().getTime()));  
367 - sch.setRealExecDate(sch.getScheduleDateStr());  
368 - sch.setCreateDate(d);  
369 -  
370 - if (StringUtils.isEmpty(sch.getFcsj()))  
371 - sch.setFcsj("00:00");  
372 -  
373 - if (sch.getFcsj().equals("24:00"))  
374 - sch.setFcsj("23:59");  
375 -  
376 - if (sch.getFcsj().substring(0, 2).equals("24")) {  
377 - sch.setFcsj("00" + sch.getFcsj().substring(2));  
378 - }  
379 -  
380 - fcsj = sch.getFcsj().trim();  
381 - //处理一下发车时间格式没有:号的问题  
382 - if (fcsj.indexOf(":") == -1 && fcsj.length() >= 4) {  
383 - sch.setFcsj(fcsj.substring(0, 2) + ":" + fcsj.substring(2, 4));  
384 - }  
385 -  
386 - try {  
387 - sdf.parse(sch.getFcsj());  
388 - } catch (ParseException e) {  
389 - //发车时间仍然校验不过的,直接写成00:00  
390 - sch.setFcsj("00:00");  
391 - }  
392 - sch.setDfsj(sch.getFcsj());  
393 -  
394 - // 计划终点时间  
395 - if (sch.getBcsj() != null) {  
396 - sch.setZdsj(fmtHHmm.print(fmtHHmm.parseMillis(sch.getFcsj()) + (sch.getBcsj() * 60 * 1000)));  
397 - sch.setLate(false);  
398 - }  
399 -  
400 - //售票员为空设置为""字符串  
401 - if (StringUtils.isEmpty(sch.getsGh())) {  
402 - sch.setsGh("");  
403 - sch.setsName("");  
404 - }  
405 - sch.setJhlcOrig(sch.getJhlc());  
406 - //保留备注  
407 - if (StringUtils.isNotEmpty(sch.getRemark()))  
408 - sch.setRemarks(sch.getRemark());  
409 - }  
410 - } catch (Exception e) {  
411 - logger.error("", e);  
412 - }  
413 -  
414 - return realList;  
415 - }  
416 -  
417 -  
418 - public synchronized long getId(){  
419 - if(sch_max_id==-1){  
420 - sch_max_id = schRepository.getMaxId();  
421 - if(null == sch_max_id)  
422 - sch_max_id = 3000L;//留一点空间补数据用  
423 - sch_max_id += 5;  
424 - }  
425 - else  
426 - sch_max_id ++;  
427 - return sch_max_id;  
428 - }  
429 -  
430 - /**  
431 - * @Title: batchSave  
432 - * @Description: TODO(批量入库)  
433 - */  
434 - private void batchSave(List<ScheduleRealInfo> list) {  
435 - SimpleDateFormat sdfyyyyMMdd = new SimpleDateFormat("yyyy-MM-dd");  
436 - for (ScheduleRealInfo item : list) {  
437 - item.setSpId(item.getId());// 保留原始的计划ID  
438 - item.setId(getId());// 设置ID  
439 - item.setScheduleDateStr(sdfyyyyMMdd.format(item.getScheduleDate()));  
440 - }  
441 -  
442 - transactionTemplate.execute(new TransactionCallbackWithoutResult() {  
443 - @Override  
444 - protected void doInTransactionWithoutResult(TransactionStatus status) {  
445 - try{  
446 - final List<ScheduleRealInfo> pstList = list;  
447 - //写入  
448 - jdbcTemplate.batchUpdate("insert into bsth_c_s_sp_info_real(id,bc_type,bcs,bcsj,cl_zbh,create_date,dfsj,directive_state,fcno,fcsj,fcsj_actual,j_gh,j_name,jhlc,lp_name,qdz_code,qdz_name,real_exec_date,remarks,s_gh,s_name,schedule_date,schedule_date_str,sflj,sp_id,status,update_date,xl_bm,xl_dir,xl_name,zdsj,zdsj_actual,zdz_code,zdz_name,ccno,df_auto,fgs_bm,fgs_name,gs_bm,gs_name,online,adjust_exps,reissue,jhlc_orig,sigin_compate,drift_status,cc_service,major_station_name,rfid_state,first_rfid_state)" +  
449 - " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", new BatchPreparedStatementSetter() {  
450 - @Override  
451 - public void setValues(PreparedStatement ps, int i) throws SQLException {  
452 - ScheduleRealInfo sch = pstList.get(i);  
453 - ps.setLong(1, sch.getId());  
454 - ps.setString(2, sch.getBcType());  
455 - ps.setInt(3, sch.getBcs()==null?0:sch.getBcs());  
456 - ps.setInt(4, sch.getBcsj()==null?0:sch.getBcsj());  
457 - ps.setString(5, sch.getClZbh());  
458 - ps.setTimestamp(6, new java.sql.Timestamp(sch.getCreateDate().getTime()));  
459 - ps.setString(7, sch.getDfsj());  
460 - ps.setInt(8, sch.getDirectiveState());  
461 - ps.setInt(9, sch.getFcno()==null?0:sch.getFcno());  
462 - ps.setString(10, sch.getFcsj());  
463 - ps.setString(11, sch.getFcsjActual());  
464 - ps.setString(12, sch.getjGh());  
465 - ps.setString(13, sch.getjName());  
466 - ps.setDouble(14, sch.getJhlc());  
467 - ps.setString(15, sch.getLpName());  
468 - ps.setString(16, sch.getQdzCode());  
469 - ps.setString(17, sch.getQdzName());  
470 - ps.setString(18, sch.getRealExecDate());  
471 - ps.setString(19, sch.getRemarks());  
472 - ps.setString(20, sch.getsGh());  
473 - ps.setString(21, sch.getsName());  
474 - ps.setTimestamp(22, new java.sql.Timestamp(sch.getScheduleDate().getTime()));  
475 - ps.setString(23, sch.getScheduleDateStr());  
476 - ps.setBoolean(24, sch.isSflj());  
477 - ps.setLong(25, sch.getSpId());  
478 - ps.setInt(26, sch.getStatus());  
479 - ps.setTimestamp(27, new java.sql.Timestamp(sch.getUpdateDate().getTime()));  
480 - ps.setString(28, sch.getXlBm());  
481 - ps.setString(29, sch.getXlDir());  
482 - ps.setString(30, sch.getXlName());  
483 - ps.setString(31, sch.getZdsj());  
484 - ps.setString(32, sch.getZdsjActual());  
485 - ps.setString(33, sch.getZdzCode());  
486 - ps.setString(34, sch.getZdzName());  
487 - ps.setInt(35, sch.getCcno()==null?0:sch.getCcno());  
488 - ps.setBoolean(36, sch.isDfAuto());  
489 - ps.setString(37, sch.getFgsBm());  
490 - ps.setString(38, sch.getFgsName());  
491 - ps.setString(39, sch.getGsBm());  
492 - ps.setString(40, sch.getGsName());  
493 - ps.setBoolean(41, sch.isOnline());  
494 - ps.setString(42, sch.getAdjustExps());  
495 - ps.setBoolean(43, sch.isReissue());  
496 - ps.setDouble(44, sch.getJhlcOrig());  
497 - ps.setInt(45, sch.getSiginCompate());  
498 - ps.setInt(46, sch.getDriftStatus());  
499 - ps.setBoolean(47, sch.isCcService());  
500 - ps.setString(48, sch.getMajorStationName());  
501 - ps.setInt(49, sch.getRfidState());  
502 - ps.setInt(50, sch.getFirstRfidState());  
503 - }  
504 -  
505 - @Override  
506 - public int getBatchSize() {  
507 - return pstList.size();  
508 - }  
509 - });  
510 - }catch (Exception e){  
511 - status.setRollbackOnly();  
512 - try {  
513 - logger.error(String.format("翻班实际排班数据批量保存异常: %s", mapper.writeValueAsString(list)), e);  
514 - } catch (JsonProcessingException jsonProcessingException) {  
515 - jsonProcessingException.printStackTrace();  
516 - }  
517 - }  
518 - }  
519 - });  
520 - }  
521 -  
522 - public List<SchedulePlanInfo> cleanSchPlanItr(Iterator<SchedulePlanInfo> itrab) {  
523 - List<SchedulePlanInfo> list = new ArrayList<>();  
524 -  
525 - SchedulePlanInfo sp;  
526 - while (itrab.hasNext()) {  
527 - sp = itrab.next();  
528 - sp.setSchedulePlan(null);  
529 - sp.setCreateBy(null);  
530 - sp.setUpdateBy(null);  
531 - list.add(sp);  
532 - }  
533 - return list;  
534 - }  
535 -  
536 - /**  
537 - * @Title: findByLineCode  
538 - * @Description: TODO(lineCode 获取班次)  
539 - */  
540 - public List<ScheduleRealInfo> findByLineCode(String lineCode) {  
541 - List<ScheduleRealInfo> rs = new ArrayList<>();  
542 -  
543 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
544 - for (ScheduleRealInfo sch : schs) {  
545 - if (sch.getXlBm().equals(lineCode))  
546 - rs.add(sch);  
547 - }  
548 - return rs;  
549 - }  
550 -  
551 - /**  
552 - * @Title: findByLineCode  
553 - * @Description: TODO(lineList 获取班次)  
554 - */  
555 - public Map<String, Collection<ScheduleRealInfo>> findByLineCodes(List<String> lineList) {  
556 - ArrayListMultimap<String, ScheduleRealInfo> mMap = ArrayListMultimap.create();  
557 -  
558 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
559 - for (ScheduleRealInfo sch : schs) {  
560 - if (lineList.contains(sch.getXlBm())) {  
561 - mMap.put(sch.getXlBm(), sch);  
562 - }  
563 - }  
564 - return mMap.asMap();  
565 - }  
566 -  
567 - /**  
568 - * @Title: findCarByLineCode  
569 - * @Description: TODO(线路下运营的车辆)  
570 - */  
571 - public Set<String> findCarByLineCode(String lineCode) {  
572 - /*Set<String> rs = new HashSet<>();  
573 -  
574 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
575 - for (ScheduleRealInfo sch : schs) {  
576 - if (sch.getXlBm().equals(lineCode))  
577 - rs.add(sch.getClZbh());  
578 - }  
579 -*/  
580 - return lineNbbmsMap.get(lineCode);  
581 - }  
582 -  
583 - public List<ScheduleRealInfo> findByNbbm(String nbbm) {  
584 - return nbbmScheduleMap.get(nbbm);  
585 - }  
586 -  
587 - /**  
588 - * @Title: findByLineAndUpDown  
589 - * @Description: TODO(lineCode 和走向获取班次)  
590 - */  
591 - public List<ScheduleRealInfo> findByLineAndUpDown(String lineCode, Integer upDown) {  
592 - List<ScheduleRealInfo> list = findByLineCode(lineCode), rs = new ArrayList<>();  
593 -  
594 - for (ScheduleRealInfo sch : list) {  
595 - if (sch.getXlDir().equals(upDown + ""))  
596 - rs.add(sch);  
597 - }  
598 - return rs;  
599 - }  
600 -  
601 - public ScheduleRealInfo get(long id) {  
602 - return id2SchedulMap.get(id);  
603 - }  
604 -  
605 -  
606 - /**  
607 - * @Title: next  
608 - * @Description: TODO(下一个班次)  
609 - */  
610 - public ScheduleRealInfo next(ScheduleRealInfo sch) {  
611 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());  
612 - //排序  
613 - Collections.sort(list, schDFSJComparator);  
614 - return next(list, sch);  
615 - }  
616 -  
617 -  
618 - /**  
619 - * 下一个班次  
620 - *  
621 - * @param list 班次集合  
622 - * @param sch 当前班次  
623 - * @return  
624 - */  
625 - private ScheduleRealInfo next(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {  
626 - int outConfig = -1;  
627 - LineConfig config = lineConfigData.get(sch.getXlBm());  
628 - if (config != null)  
629 - outConfig = config.getOutConfig();  
630 -  
631 - //限定出站既出场的停车场  
632 - List<String> parks = config.findTwinsParkList();  
633 - boolean limitPark = null != parks && parks.size() > 0;  
634 - boolean flag = false;  
635 - ScheduleRealInfo next = null;  
636 - for (ScheduleRealInfo temp : list) {  
637 - if (temp.getId() == sch.getId()) {  
638 - flag = true;  
639 - continue;  
640 - }  
641 - //忽略烂班  
642 - if (temp.isDestroy())  
643 - continue;  
644 -  
645 - //出站既出场,忽略出场班次  
646 - if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)  
647 - && (!limitPark || parks.contains(temp.getQdzCode())))  
648 - continue;  
649 -  
650 - if (flag) {  
651 - next = temp;  
652 - break;  
653 - }  
654 - }  
655 - return next;  
656 - }  
657 -  
658 - private boolean isEmptyMileage(ScheduleRealInfo sch) {  
659 - return sch.getBcsj() == 0 || sch.getJhlcOrig().intValue() == 0;  
660 - }  
661 -  
662 - /**  
663 - * 下一个班次  
664 - *  
665 - * @param list 班次集合  
666 - * @param sch 当前班次  
667 - * @return  
668 - */  
669 - private ScheduleRealInfo next2_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {  
670 - int outConfig = -1;  
671 - LineConfig config = lineConfigData.get(sch.getXlBm());  
672 - if (config != null)  
673 - outConfig = config.getOutConfig();  
674 -  
675 - boolean flag = false;  
676 - ScheduleRealInfo next = null;  
677 - for (ScheduleRealInfo temp : list) {  
678 - if (temp.getId() == sch.getId()) {  
679 - flag = true;  
680 - continue;  
681 - }  
682 -  
683 - if (flag) {  
684 - next = temp;  
685 - break;  
686 - }  
687 - }  
688 - return next;  
689 - }  
690 -  
691 - private ScheduleRealInfo next3_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {  
692 - int outConfig = -1;  
693 - LineConfig config = lineConfigData.get(sch.getXlBm());  
694 - if (config != null)  
695 - outConfig = config.getOutConfig();  
696 -  
697 - //限定出站既出场的停车场  
698 - List<String> parks = config.findTwinsParkList();  
699 - boolean limitPark = null != parks && parks.size() > 0;  
700 - boolean flag = false;  
701 - ScheduleRealInfo next = null;  
702 - for (ScheduleRealInfo temp : list) {  
703 - if (temp.getId() == sch.getId()) {  
704 - flag = true;  
705 - continue;  
706 - }  
707 -  
708 - //出站既出场,忽略出场班次  
709 - if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)  
710 - && (!limitPark || parks.contains(temp.getQdzCode())))  
711 - continue;  
712 -  
713 - if (flag) {  
714 - next = temp;  
715 - break;  
716 - }  
717 - }  
718 - return next;  
719 - }  
720 -  
721 - /**  
722 - * 上一个班次  
723 - *  
724 - * @param sch  
725 - * @return  
726 - */  
727 - public ScheduleRealInfo prev(ScheduleRealInfo sch) {  
728 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());  
729 -  
730 - //boolean flag = false;  
731 - ScheduleRealInfo prev = null;  
732 - int size = list.size();  
733 -  
734 - for (int i = 0; i < size; i++) {  
735 - if (list.get(i).isDestroy())  
736 - continue;  
737 -  
738 - if (list.get(i).getId().equals(sch.getId())) {  
739 - return prev;  
740 - }  
741 - prev = list.get(i);  
742 - }  
743 - return prev;  
744 - }  
745 -  
746 - /**  
747 - * 是否是首班出场  
748 - *  
749 - * @param sch  
750 - * @return  
751 - */  
752 - public boolean isFirstOut(ScheduleRealInfo sch) {  
753 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());  
754 - try {  
755 - if (list.get(0) == sch && sch.getBcType().equals("out"))  
756 - return true;  
757 - } catch (IndexOutOfBoundsException e) {  
758 - logger.error("小小的数组越界,无伤大雅!");  
759 - }  
760 - return false;  
761 - }  
762 -  
763 - public void put(ScheduleRealInfo sch) {  
764 - schAttrCalculator  
765 - .calcRealDate(sch)  
766 - .calcAllTimeByFcsj(sch);  
767 -  
768 - nbbmScheduleMap.put(sch.getClZbh(), sch);  
769 -  
770 - //主键索引  
771 - id2SchedulMap.put(sch.getId(), sch);  
772 - //路牌对照表  
773 - addLPMapp(sch);  
774 -  
775 - //跨24点的,再save一次  
776 - if (!sch.getRealExecDate().equals(sch.getScheduleDateStr()))  
777 - save(sch);  
778 - }  
779 -  
780 - public void addLPMapp(ScheduleRealInfo sch) {  
781 - lpScheduleMap.put(sch.getXlBm() + "_" + sch.getLpName(), sch);  
782 - }  
783 -  
784 - public void delete(ScheduleRealInfo sch) {  
785 - if (!sch.isSflj())  
786 - return;  
787 -  
788 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
789 - id2SchedulMap.remove(sch.getId());  
790 - lpScheduleMap.remove(sch.getXlBm() + "_" + sch.getLpName(), sch);  
791 -  
792 - //如果正在执行该班次  
793 - if (carExecutePlanMap.get(sch.getClZbh()) == sch) {  
794 - //重新计算车辆当前执行班次  
795 - reCalcExecPlan(sch.getClZbh());  
796 - }  
797 - }  
798 -  
799 - public List<ScheduleRealInfo> updateQdzTimePlan(String lpName) {  
800 - List<ScheduleRealInfo> list = lpScheduleMap.get(lpName);  
801 - Collections.sort(list, schFCSJComparator);  
802 - return schAttrCalculator.updateQdzTimePlan(list);  
803 - }  
804 -  
805 - public List<ScheduleRealInfo> updateQdzTimePlan(ScheduleRealInfo sch) {  
806 - return updateQdzTimePlan(sch.getXlBm() + "_" + sch.getLpName());  
807 - }  
808 -  
809 - /**  
810 - * @Title: doneSum  
811 - * @Description: TODO(已完成班次总数)  
812 - */  
813 - public int doneSum(String clZbh) {  
814 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(clZbh);  
815 - int rs = 0;  
816 -  
817 - for (ScheduleRealInfo sch : list) {  
818 - if (sch.getStatus() == 2 && !sch.isDestroy())  
819 - rs++;  
820 - }  
821 - return rs;  
822 - }  
823 -  
824 - public void save(ScheduleRealInfo sch) {  
825 - sch.setUpdateDate(new Date());  
826 - pstBuffer.add(sch);  
827 - }  
828 -  
829 -  
830 - /**  
831 - * @Title: nextByBcType  
832 - * @Description: TODO(获取下一个指定班次类型的班次)  
833 - */  
834 - public ScheduleRealInfo nextByBcType(String nbbm, String bcType) {  
835 - List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);  
836 -  
837 - Collections.sort(list, schFCSJComparator);  
838 - ScheduleRealInfo sch = null;  
839 - for (ScheduleRealInfo temp : list) {  
840 - if (temp.getFcsjActual() == null) {  
841 - sch = temp;  
842 - break;  
843 - }  
844 - }  
845 -  
846 - return sch;  
847 - }  
848 -  
849 -  
850 - /**  
851 - * 搜索离当前时间最近的一个指定类型的班次  
852 - *  
853 - * @param nbbm  
854 - * @param bcType  
855 - * @return  
856 - */  
857 - public ScheduleRealInfo searchNearByBcType(String nbbm, String bcType) {  
858 - List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);  
859 - Collections.sort(list, schFCSJComparator);  
860 -  
861 - long t = System.currentTimeMillis();  
862 - int distance = -1, diff;  
863 -  
864 - ScheduleRealInfo sch = null;  
865 - for (ScheduleRealInfo temp : list) {  
866 - diff = (int) Math.abs(temp.getDfsjT() - t);  
867 - if (diff < distance || distance == -1) {  
868 - sch = temp;  
869 - distance = diff;  
870 - }  
871 - }  
872 - return sch;  
873 - }  
874 -  
875 - public List<ScheduleRealInfo> findByBcType(String nbbm, String bcType) {  
876 - List<ScheduleRealInfo> all = nbbmScheduleMap.get(nbbm), outList = new ArrayList<>();  
877 -  
878 - for (ScheduleRealInfo sch : all) {  
879 - if (sch.getBcType().equals(bcType))  
880 - outList.add(sch);  
881 - }  
882 - return outList;  
883 - }  
884 -  
885 - public Collection<ScheduleRealInfo> findAll() {  
886 - return nbbmScheduleMap.values();  
887 - }  
888 -  
889 - public Collection<ScheduleRealInfo> findAllByLpContainer() {  
890 - return lpScheduleMap.values();  
891 - }  
892 -  
893 - public Collection<ScheduleRealInfo> findAllByIdContainer() {  
894 - return id2SchedulMap.values();  
895 - }  
896 -  
897 - public int getPstSize() {  
898 - return pstBuffer.size();  
899 - }  
900 -  
901 - public boolean addExecPlan(ScheduleRealInfo sch) {  
902 - ScheduleRealInfo oldExec = executeCurr(sch.getClZbh());  
903 - if (sch != null){  
904 - if(sch.getStatus()==2)  
905 - reCalcExecPlan(sch.getClZbh());  
906 - else  
907 - carExecutePlanMap.put(sch.getClZbh(), sch);  
908 - }  
909 - else  
910 - carExecutePlanMap.remove(sch.getClZbh());  
911 -  
912 - return executeCurr(sch.getClZbh()) != oldExec;  
913 - }  
914 -  
915 - public void removeExecPlan(String clzbh) {  
916 - carExecutePlanMap.remove(clzbh);  
917 - }  
918 -  
919 - public Map<String, ScheduleRealInfo> execPlanMap() {  
920 - return carExecutePlanMap;  
921 - }  
922 -  
923 - /**  
924 - * 车辆当前执行的班次  
925 - *  
926 - * @param nbbm  
927 - * @return  
928 - */  
929 - public ScheduleRealInfo executeCurr(String nbbm) {  
930 - if(StringUtils.isEmpty(nbbm))  
931 - return null;  
932 - return carExecutePlanMap.get(nbbm);  
933 - }  
934 -  
935 - /**  
936 - * @param @param sch  
937 - * @param @param newClZbh 新的车辆自编号  
938 - * @Title: changeCar  
939 - * @Description: TODO(班次换车) 返回有更新的班次  
940 - */  
941 - public List<ScheduleRealInfo> changeCar(ScheduleRealInfo sch, String newClZbh) {  
942 - List<ScheduleRealInfo> ups = new ArrayList<>();  
943 -  
944 - String oldClZbh = sch.getClZbh();  
945 - //变更相关映射信息  
946 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
947 -  
948 - sch.setClZbh(newClZbh);  
949 - if (!nbbmScheduleMap.containsEntry(newClZbh, sch)) {  
950 - nbbmScheduleMap.put(newClZbh, sch);  
951 - }  
952 -  
953 - //重新计算车辆当前执行班次  
954 - reCalcExecPlan(newClZbh);  
955 - reCalcExecPlan(oldClZbh);  
956 - //重新分组计划用车  
957 - reCalcLineNbbms();  
958 - return ups;  
959 - }  
960 -  
961 - public void removeNbbm2SchMapp(ScheduleRealInfo sch) {  
962 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
963 - }  
964 -  
965 - public void addNbbm2SchMapp(ScheduleRealInfo sch) {  
966 - nbbmScheduleMap.put(sch.getClZbh(), sch);  
967 - }  
968 -  
969 - public void reCalcExecPlan(String nbbm) {  
970 - List<ScheduleRealInfo> list = nbbmScheduleMap.get(nbbm);  
971 - Collections.sort(list, schDFSJComparator);  
972 -  
973 - ScheduleRealInfo sch = schAttrCalculator.calcCurrentExecSch(list);  
974 - if(null != sch)  
975 - carExecutePlanMap.put(nbbm, sch);  
976 - else  
977 - carExecutePlanMap.remove(nbbm);  
978 - }  
979 -  
980 - /**  
981 - * 空驶任务?  
982 - * 出场、进场、直放、两点间空驶  
983 - * @param sch  
984 - * @return  
985 - */  
986 - public static boolean emptyService(ScheduleRealInfo sch){  
987 - String type = sch.getBcType();  
988 - return type.equals("out") || type.equals("in") || type.equals("venting") || type.equals("ldks");  
989 - }  
990 -  
991 - @Autowired  
992 - JdbcTemplate jdbcTemplate;  
993 -  
994 - @Autowired  
995 - private TransactionTemplate transactionTemplate;  
996 -  
997 - @Autowired  
998 - private ObjectMapper mapper;  
999 -  
1000 - /**  
1001 - * 删除实际排班  
1002 - *  
1003 - * @param lineCode  
1004 - * @return  
1005 - */  
1006 - public Map<String, Object> deleteRealSchedule(String lineCode) {  
1007 - Map<String, Object> rs = new HashMap<>();  
1008 -  
1009 - try {  
1010 - String rq = currSchDateMap.get(lineCode);  
1011 - if (StringUtils.isNotEmpty(rq)) {  
1012 - List<ScheduleRealInfo> all = findByLineCode(lineCode);  
1013 -  
1014 - if(null != all && all.size() > 0){  
1015 - //解除gps 和班次之间的关联  
1016 - List<ScheduleRealInfo> unions = calcUnion(all, carExecutePlanMap.values());  
1017 - for (ScheduleRealInfo sch : unions) {  
1018 - removeExecPlan(sch.getClZbh());  
1019 - }  
1020 - //解除调度指令和班次的外键约束  
1021 - StringBuilder inStr = new StringBuilder("(");  
1022 - for (ScheduleRealInfo sch : all) {  
1023 - inStr.append(sch.getId() + ",");  
1024 - }  
1025 - inStr.deleteCharAt(inStr.length() - 1).append(")");  
1026 - jdbcTemplate.update(Constants.MULTI_REMOVE_DIRECTIVE_SCH_FK + " " + inStr.toString());  
1027 - jdbcTemplate.update(Constants.MULTI_REMOVE_CHILDTASK_SCH_FK + " " + inStr.toString());  
1028 - }  
1029 -  
1030 - //删除班次数据  
1031 - removeRealSch(lineCode, rq);  
1032 -  
1033 - }  
1034 - rs.put("status", ResponseCode.SUCCESS);  
1035 - } catch (Exception e) {  
1036 - logger.error("", e);  
1037 - rs.put("status", ResponseCode.ERROR);  
1038 - if (e instanceof DataIntegrityViolationException)  
1039 - rs.put("msg", "失败,违反数据约束!!");  
1040 - else  
1041 - rs.put("msg", e.getMessage());  
1042 - }  
1043 -  
1044 - return rs;  
1045 - }  
1046 -  
1047 - /**  
1048 - * 计算并集  
1049 - *  
1050 - * @param c1  
1051 - * @param c2  
1052 - * @return  
1053 - */  
1054 - public List<ScheduleRealInfo> calcUnion(Collection<ScheduleRealInfo> c1, Collection<ScheduleRealInfo> c2) {  
1055 - List<ScheduleRealInfo> rs = new ArrayList<>();  
1056 -  
1057 - for (ScheduleRealInfo sch : c1) {  
1058 - if (c2.contains(sch)) {  
1059 - rs.add(sch);  
1060 - }  
1061 - }  
1062 - return rs;  
1063 - }  
1064 -  
1065 - /**  
1066 - * 覆盖一辆车的所有班次  
1067 - *  
1068 - * @param nbbm  
1069 - * @param sets  
1070 - */  
1071 - public void replaceByNbbm(String nbbm, Collection<ScheduleRealInfo> sets) {  
1072 - nbbmScheduleMap.removeAll(nbbm);  
1073 - nbbmScheduleMap.putAll(nbbm, sets);  
1074 - }  
1075 -  
1076 - /**  
1077 - * 获取该班次所在路牌的下一个班次  
1078 - *  
1079 - * @param sch  
1080 - * @return  
1081 - */  
1082 - public ScheduleRealInfo nextByLp(ScheduleRealInfo sch) {  
1083 - List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());  
1084 - Collections.sort(list, schFCSJComparator);  
1085 - return next3_lp(list, sch);  
1086 - }  
1087 -  
1088 - /**  
1089 - * 获取该班次所在路牌的下一个班次,不考虑场既是站  
1090 - *  
1091 - * @param sch  
1092 - * @return  
1093 - */  
1094 - public ScheduleRealInfo nextByLp2(ScheduleRealInfo sch) {  
1095 - List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());  
1096 - Collections.sort(list, schFCSJComparator);  
1097 - return next2_lp(list, sch);  
1098 - }  
1099 -  
1100 - public ArrayListMultimap<String, ScheduleRealInfo> getLpScheduleMap() {  
1101 - return lpScheduleMap;  
1102 - }  
1103 -  
1104 - /**  
1105 - * 重新全量计算路牌下的班次关联性  
1106 - * 临时性的函数  
1107 - */  
1108 - public void _test_reCalcLpSch() {  
1109 - Map<String ,Collection<ScheduleRealInfo>> map = lpScheduleMap.asMap();  
1110 - Set<String> ks = map.keySet();  
1111 - for(String k : ks){  
1112 - schAttrCalculator.calcQdzTimePlan(new ArrayList<ScheduleRealInfo>(map.get(k)));  
1113 - }  
1114 - }  
1115 -  
1116 - public int dbCount(String lineCode, String currSchDate) {  
1117 - int count = -1;  
1118 -  
1119 - try{  
1120 - count = jdbcTemplate.queryForObject("select count(*) from bsth_c_s_sp_info_real where schedule_date='"+currSchDate+"' and xl_bm='"+lineCode+"'", java.lang.Integer.class);  
1121 -  
1122 - }catch (Exception e){  
1123 - logger.error("", e);  
1124 - }  
1125 - return count;  
1126 - }  
1127 -  
1128 - /**  
1129 - * 重新计算ID对照map  
1130 - */  
1131 - public int reCalcIdMaps(){  
1132 - Collection<ScheduleRealInfo> all = findAll();  
1133 - ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMapCopy = new ConcurrentHashMap<>();  
1134 -  
1135 - for(ScheduleRealInfo sch : all){  
1136 - id2SchedulMapCopy.put(sch.getId(), sch);  
1137 - }  
1138 -  
1139 - id2SchedulMap = id2SchedulMapCopy;  
1140 -  
1141 - return id2SchedulMap.size();  
1142 - }  
1143 -  
1144 - /**  
1145 - * 重新计算线路计划用车  
1146 - */  
1147 - public void reCalcLineNbbms(){  
1148 - HashMultimap<String, String> multimap = HashMultimap.create();  
1149 -  
1150 - Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();  
1151 - for (ScheduleRealInfo sch : schs) {  
1152 - multimap.put(sch.getXlBm(), sch.getClZbh());  
1153 - }  
1154 -  
1155 - lineNbbmsMap = multimap;  
1156 - }  
1157 -  
1158 - public String sizeString(){  
1159 - return id2SchedulMap.size() + "/" + nbbmScheduleMap.size();  
1160 - }  
1161 -  
1162 -  
1163 - /**  
1164 - * 按公司编码分组数据  
1165 - */  
1166 - public void groupByGsbm(){  
1167 - Collection<ScheduleRealInfo> all = findAll();  
1168 - ListMultimap<String, ScheduleRealInfo> gsBmMaps = ArrayListMultimap.create();  
1169 -  
1170 - for(ScheduleRealInfo sch : all){  
1171 - gsBmMaps.put(sch.getGsBm(), sch);  
1172 - }  
1173 -  
1174 - if(gsBmMaps.size() > 0){  
1175 - gsBmScheduleMap = null;  
1176 - gsBmScheduleMap = gsBmMaps;  
1177 - }  
1178 - }  
1179 -  
1180 - public Collection<ScheduleRealInfo> findByGsbm(String gsbm){  
1181 - return gsBmScheduleMap.get(gsbm);  
1182 - }  
1183 - /**  
1184 - * 删除班次,删除内存中未清理掉的非当天的班次  
1185 - * @createDate 2019.05.13  
1186 - * @author zhangxianzhou  
1187 - * @param sch  
1188 - */  
1189 - public void deleteBC(ScheduleRealInfo sch) {  
1190 - nbbmScheduleMap.remove(sch.getClZbh(), sch);  
1191 - id2SchedulMap.remove(sch.getId());  
1192 - lpScheduleMap.remove(sch.getXlBm() + "_" + sch.getLpName(), sch);  
1193 - //如果正在执行该班次  
1194 - if (carExecutePlanMap.get(sch.getClZbh()) == sch) {  
1195 - //重新计算车辆当前执行班次  
1196 - reCalcExecPlan(sch.getClZbh());  
1197 - }  
1198 - }  
1199 -  
1200 - /**  
1201 - ** 用于重置维修上报计数,一般只应该在翻班的时候调用  
1202 - */  
1203 - public void resetRepairReport(String incode) {  
1204 - incode2report.remove(incode);  
1205 - }  
1206 -  
1207 - public RepairReport getLastestRepairReport(String incode) {  
1208 - return incode2report.get(incode);  
1209 - }  
1210 -  
1211 - public void setLastestRepairReport(RepairReport rr) {  
1212 - incode2report.put(rr.getIncode(), rr);  
1213 - } 1 +package com.bsth.data.schedule;
  2 +
  3 +import com.alibaba.fastjson.JSON;
  4 +import com.alibaba.fastjson.JSONArray;
  5 +import com.bsth.common.Constants;
  6 +import com.bsth.common.ResponseCode;
  7 +import com.bsth.data.LineConfigData;
  8 +import com.bsth.data.SystemParamCache;
  9 +import com.bsth.data.gpsdata_v2.GpsRealData;
  10 +import com.bsth.data.gpsdata_v2.utils.GpsDataRecovery;
  11 +import com.bsth.data.schedule.f_a_l.FirstAndLastHandler;
  12 +import com.bsth.entity.realcontrol.LineConfig;
  13 +import com.bsth.entity.realcontrol.ScheduleRealInfo;
  14 +import com.bsth.entity.report.RepairReport;
  15 +import com.bsth.entity.schedule.SchedulePlanInfo;
  16 +import com.bsth.repository.realcontrol.ScheduleRealInfoRepository;
  17 +import com.bsth.service.schedule.SchedulePlanInfoService;
  18 +import com.bsth.websocket.handler.SendUtils;
  19 +import com.fasterxml.jackson.core.JsonProcessingException;
  20 +import com.fasterxml.jackson.databind.ObjectMapper;
  21 +import com.google.common.collect.ArrayListMultimap;
  22 +import com.google.common.collect.HashMultimap;
  23 +import com.google.common.collect.ListMultimap;
  24 +import com.google.common.collect.Multimaps;
  25 +import org.apache.commons.lang3.StringUtils;
  26 +import org.joda.time.format.DateTimeFormat;
  27 +import org.joda.time.format.DateTimeFormatter;
  28 +import org.slf4j.Logger;
  29 +import org.slf4j.LoggerFactory;
  30 +import org.springframework.beans.factory.annotation.Autowired;
  31 +import org.springframework.dao.DataIntegrityViolationException;
  32 +import org.springframework.jdbc.core.BatchPreparedStatementSetter;
  33 +import org.springframework.jdbc.core.JdbcTemplate;
  34 +import org.springframework.stereotype.Component;
  35 +import org.springframework.transaction.TransactionStatus;
  36 +import org.springframework.transaction.support.TransactionCallbackWithoutResult;
  37 +import org.springframework.transaction.support.TransactionTemplate;
  38 +
  39 +import java.sql.PreparedStatement;
  40 +import java.sql.SQLException;
  41 +import java.text.ParseException;
  42 +import java.text.SimpleDateFormat;
  43 +import java.util.*;
  44 +import java.util.concurrent.ConcurrentHashMap;
  45 +import java.util.concurrent.ConcurrentLinkedQueue;
  46 +import java.util.concurrent.ConcurrentMap;
  47 +
  48 +/**
  49 + * @author PanZhao
  50 + * @ClassName: DayOfSchedule
  51 + * @Description: TODO(当日实际排班)
  52 + * @date 2016年8月15日 上午10:16:12
  53 + */
  54 +@Component
  55 +public class DayOfSchedule {
  56 +
  57 + Logger logger = LoggerFactory.getLogger(this.getClass());
  58 +
  59 + //按线路分组的 “原始计划” 排班数据
  60 + public static Map<String, List<SchedulePlanInfo>> schedulePlanMap;
  61 +
  62 + // 按车辆索引的班次数据
  63 + private static ListMultimap<String, ScheduleRealInfo> nbbmScheduleMap;
  64 +
  65 + // 按营运公司索引的班次数据
  66 + private static ListMultimap<String, ScheduleRealInfo> gsBmScheduleMap;
  67 +
  68 + //按线路索引计划用车
  69 + private static HashMultimap<String, String> lineNbbmsMap;
  70 +
  71 + //按路牌索引班次数据 线路编码_路牌名称 ——> 班次list
  72 + private static ArrayListMultimap<String, ScheduleRealInfo> lpScheduleMap;
  73 +
  74 + // 班次主键映射
  75 + private static ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMap;
  76 +
  77 + //车辆 ——> 当前执行班次
  78 + private static ConcurrentMap<String, ScheduleRealInfo> carExecutePlanMap;
  79 +
  80 + // 持久化
  81 + public static ConcurrentLinkedQueue<ScheduleRealInfo> pstBuffer;
  82 +
  83 + // 排序器
  84 + private static ScheduleComparator.FCSJ schFCSJComparator;
  85 +
  86 + private static ScheduleComparator.DFSJ schDFSJComparator;
  87 +
  88 + private static Long sch_max_id=-1L;
  89 +
  90 + private Map<String, RepairReport> incode2report = new ConcurrentHashMap<String, RepairReport>();
  91 +
  92 + @Autowired
  93 + LineConfigData lineConfigData;
  94 +
  95 + @Autowired
  96 + ScheduleRealInfoRepository schRepository;
  97 +
  98 + @Autowired
  99 + SchedulePlanInfoService schPlanService;
  100 +
  101 + @Autowired
  102 + SchAttrCalculator schAttrCalculator;
  103 +
  104 + @Autowired
  105 + SendUtils sendUtils;
  106 +
  107 + @Autowired
  108 + GpsRealData gpsRealData;
  109 +
  110 + /**
  111 + * 线路当前使用的排班的日期
  112 + */
  113 + public static Map<String, String> currSchDateMap;
  114 +
  115 + static {
  116 + nbbmScheduleMap = ArrayListMultimap.create();
  117 + nbbmScheduleMap = Multimaps.synchronizedListMultimap(nbbmScheduleMap);
  118 +
  119 + gsBmScheduleMap = ArrayListMultimap.create();
  120 + lpScheduleMap = ArrayListMultimap.create();
  121 + lineNbbmsMap = HashMultimap.create();
  122 +
  123 + id2SchedulMap = new ConcurrentHashMap<>();
  124 + pstBuffer = new ConcurrentLinkedQueue<>();
  125 + schFCSJComparator = new ScheduleComparator.FCSJ();
  126 + schDFSJComparator = new ScheduleComparator.DFSJ();
  127 + currSchDateMap = new HashMap<>();
  128 + carExecutePlanMap = new ConcurrentHashMap<>();
  129 +
  130 + schedulePlanMap = new HashMap<>();
  131 + }
  132 +
  133 + @Autowired
  134 + LineConfigData lineConfigs;
  135 +
  136 + @Autowired
  137 + GpsDataRecovery gpsDataRecovery;
  138 +
  139 + private static DateTimeFormatter fmtyyyyMMdd = DateTimeFormat.forPattern("yyyy-MM-dd"), fmtHHmm = DateTimeFormat.forPattern("HH:mm");
  140 +
  141 + //数据恢复
  142 + public void dataRecovery() {
  143 + Collection<LineConfig> confs = lineConfigs.getAll();
  144 + String lineCode, currSchDate;
  145 + for (LineConfig conf : confs) {
  146 + lineCode = conf.getLine().getLineCode();
  147 + currSchDate = calcSchDate(lineCode);
  148 + //加载班次数据
  149 + reloadSch(lineCode, currSchDate, false);
  150 + }
  151 +
  152 + //恢复gps数据
  153 + gpsDataRecovery.recovery();
  154 + }
  155 +
  156 + public Map<String, String> getCurrSchDate() {
  157 + return currSchDateMap;
  158 + }
  159 +
  160 + /**
  161 + * @Title: calcSchDateB
  162 + * @Description: TODO(计算线路当前应该使用的排班日期)
  163 + */
  164 + public String calcSchDate(String lineCode) {
  165 + Long t = System.currentTimeMillis();
  166 + LineConfig conf = lineConfigData.get(lineCode);
  167 +
  168 + // 小于当天起始运营时间,则取前一天的排班
  169 + String ct = fmtHHmm.print(t);
  170 + if(ct.compareTo(conf.getStartOpt()) < 0)
  171 + t -= 1000 * 60 * 60 * 24;
  172 +
  173 + String schDate = fmtyyyyMMdd.print(t);
  174 + return schDate;
  175 + }
  176 +
  177 + /**
  178 + * @param @param lineCode 线路编码
  179 + * @param @param schDate 班次日期 yyyy-MM-dd
  180 + * @param @param forcePlan 强制从计划调度重新抓取
  181 + * @Title: reloadSch
  182 + * @Title: reloadSch
  183 + * @Description: TODO(重新载入排班)
  184 + */
  185 + public int reloadSch(String lineCode, String schDate, boolean forcePlan) {
  186 + try {
  187 + boolean generate = SystemParamCache.getEnabledFirstLastGeneration();
  188 + List<ScheduleRealInfo> list;
  189 +
  190 + if (forcePlan)
  191 + removeRealSch(lineCode, schDate);
  192 + else
  193 + clearRAMData(lineCode);
  194 +
  195 + if (existRealSch(lineCode, schDate))
  196 + list = loadRealSch(lineCode, schDate);// 从实际排班表加载
  197 + else {
  198 + list = loadPlanSch(lineCode, schDate);// 从计划排班表加载
  199 + // 写入数据库
  200 + batchSave(list);
  201 + }
  202 +
  203 + //更新线路和班次日期对照
  204 + currSchDateMap.put(lineCode, schDate);
  205 + //添加到缓存
  206 + putAll(list);
  207 +
  208 + //标记首末班
  209 + if (generate) {
  210 + FirstAndLastHandler.marks(list);
  211 + }
  212 +
  213 + Set<String> lps = searchAllLP(list);
  214 + for (String lp : lps) {
  215 + //计算“起点站应到”时间
  216 + schAttrCalculator.calcQdzTimePlan(lpScheduleMap.get(lineCode + "_" + lp));
  217 + }
  218 + Set<String> cars = searchAllCars(list);
  219 + for (String nbbm : cars) {
  220 + //车辆 ——> 要执行的班次对照
  221 + reCalcExecPlan(nbbm);
  222 + }
  223 +
  224 + //分组计划用车
  225 + reCalcLineNbbms();
  226 + // 页面 翻班通知
  227 + //sendUtils.shiftSchedule(lineCode);
  228 + } catch (Exception e) {
  229 + logger.error("", e);
  230 + return -1;
  231 + }
  232 +
  233 + return 0;
  234 + }
  235 +
  236 + public int reloadSch(String lineCode) {
  237 + return reloadSch(lineCode, calcSchDate(lineCode), true);
  238 + }
  239 +
  240 + /**
  241 + * @Title: searchAllCars
  242 + * @Description: TODO(搜索班次集合中的车辆)
  243 + */
  244 + private Set<String> searchAllCars(List<ScheduleRealInfo> list) {
  245 + Set<String> cars = new HashSet<>();
  246 + for (ScheduleRealInfo sch : list)
  247 + cars.add(sch.getClZbh());
  248 +
  249 + return cars;
  250 + }
  251 +
  252 + /**
  253 + * @Title: searchAllCars
  254 + * @Description: TODO(搜索班次集合中的路牌)
  255 + */
  256 + private Set<String> searchAllLP(List<ScheduleRealInfo> list) {
  257 + Set<String> lps = new HashSet<>();
  258 + for (ScheduleRealInfo sch : list)
  259 + lps.add(sch.getLpName());
  260 +
  261 + return lps;
  262 + }
  263 +
  264 + private void putAll(List<ScheduleRealInfo> list) {
  265 + for (ScheduleRealInfo sch : list)
  266 + put(sch);
  267 + }
  268 +
  269 + /**
  270 + * @param @param lineCode 线路编码
  271 + * @param @param schDate 班次日期 yyyy-MM-dd
  272 + * @Title: removeRealSch
  273 + * @Description: TODO(清除实际排班,包括数据库和内存数据)
  274 + */
  275 + public void removeRealSch(String lineCode, String schDate) throws Exception {
  276 + try {
  277 + // 清理数据库数据
  278 + schRepository.deleteByLineCodeAndDate(lineCode + "", schDate);
  279 +
  280 + // 清理内存数据
  281 + clearRAMData(lineCode + "");
  282 + } catch (Exception e) {
  283 + logger.error("removeRealSch error, " + lineCode + " -" + schDate, e);
  284 + throw e;
  285 + }
  286 + }
  287 +
  288 + /**
  289 + * @Title: clearRAMData
  290 + * @Description: TODO(清理内存数据)
  291 + */
  292 + public void clearRAMData(String lineCode) {
  293 + int count = 0;
  294 + List<ScheduleRealInfo> remList = new ArrayList<>();
  295 + Collection<ScheduleRealInfo> all = nbbmScheduleMap.values();
  296 + for (ScheduleRealInfo sch : all) {
  297 + if (sch.getXlBm().equals(lineCode))
  298 + remList.add(sch);
  299 + }
  300 +
  301 + Set<String> codes = new HashSet<>();
  302 + for (ScheduleRealInfo sch : remList) {
  303 + if (null != sch) {
  304 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  305 + id2SchedulMap.remove(sch.getId());
  306 + count++;
  307 +
  308 + //清理路牌对照
  309 + lpScheduleMap.removeAll(sch.getXlBm() + "_" + sch.getLpName());
  310 +
  311 + //清除车辆 ——> 执行班次对照
  312 + carExecutePlanMap.remove(sch.getClZbh());
  313 + codes.add(sch.getClZbh());
  314 + }
  315 + }
  316 + for (String code : codes) {
  317 + reCalcExecPlan(code);
  318 + }
  319 + //清理计划排班
  320 + schedulePlanMap.remove(lineCode);
  321 +
  322 + remList.clear();
  323 + remList = null;
  324 + logger.info(lineCode + "排班清理 " + count);
  325 + }
  326 +
  327 + /**
  328 + * @Title: existRealSch
  329 + * @Description: TODO(实际排班是否已存在)
  330 + */
  331 + public boolean existRealSch(String lineCode, String schDate) {
  332 + int count = schRepository.countByLineCodeAndDate(lineCode, schDate);
  333 + return count > 0;
  334 + }
  335 +
  336 + /**
  337 + * @Title: loadRealSch
  338 + * @Description: TODO(从实际排班表加载数据)
  339 + */
  340 + public List<ScheduleRealInfo> loadRealSch(String lineCode, String schDate) {
  341 + return schRepository.findByLineCodeAndDate(lineCode, schDate);
  342 + }
  343 +
  344 + /**
  345 + * @Title: loadPlanSch
  346 + * @Description: TODO(从计划排班表加载数据)
  347 + */
  348 + public List<ScheduleRealInfo> loadPlanSch(String lineCode, String schDate) {
  349 + //logger.info("从计划排班表恢复排班,lineCode: " + lineCode + ", schDate: " + schDate);
  350 + List<ScheduleRealInfo> realList = new ArrayList<>();
  351 +
  352 + try {
  353 + Map<String, Object> data = new HashMap<>();
  354 +
  355 + data.put("scheduleDate_eq", fmtyyyyMMdd.parseDateTime(schDate).toDate());
  356 + data.put("xlBm_eq", lineCode);
  357 +
  358 + // 查询计划排班
  359 + List<SchedulePlanInfo> planItr = cleanSchPlanItr(schPlanService.list(data).iterator());
  360 + //保存一份原始计划排班数据
  361 + schedulePlanMap.put(lineCode, planItr);
  362 +
  363 + // 转换为实际排班
  364 + realList = JSONArray.parseArray(JSON.toJSONString(planItr), ScheduleRealInfo.class);
  365 + logger.info("从计划排班表恢复排班,lineCode: " + lineCode + ", schDate: " + schDate + ", size:" + realList.size());
  366 +
  367 + Date d = new Date();
  368 + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
  369 + String fcsj;
  370 + for (ScheduleRealInfo sch : realList) {
  371 + sch.setScheduleDateStr(fmtyyyyMMdd.print(sch.getScheduleDate().getTime()));
  372 + sch.setRealExecDate(sch.getScheduleDateStr());
  373 + sch.setCreateDate(d);
  374 +
  375 + if (StringUtils.isEmpty(sch.getFcsj()))
  376 + sch.setFcsj("00:00");
  377 +
  378 + if (sch.getFcsj().equals("24:00"))
  379 + sch.setFcsj("23:59");
  380 +
  381 + if (sch.getFcsj().substring(0, 2).equals("24")) {
  382 + sch.setFcsj("00" + sch.getFcsj().substring(2));
  383 + }
  384 +
  385 + fcsj = sch.getFcsj().trim();
  386 + //处理一下发车时间格式没有:号的问题
  387 + if (fcsj.indexOf(":") == -1 && fcsj.length() >= 4) {
  388 + sch.setFcsj(fcsj.substring(0, 2) + ":" + fcsj.substring(2, 4));
  389 + }
  390 +
  391 + try {
  392 + sdf.parse(sch.getFcsj());
  393 + } catch (ParseException e) {
  394 + //发车时间仍然校验不过的,直接写成00:00
  395 + sch.setFcsj("00:00");
  396 + }
  397 + sch.setDfsj(sch.getFcsj());
  398 +
  399 + // 计划终点时间
  400 + if (sch.getBcsj() != null) {
  401 + sch.setZdsj(fmtHHmm.print(fmtHHmm.parseMillis(sch.getFcsj()) + (sch.getBcsj() * 60 * 1000)));
  402 + sch.setLate(false);
  403 + }
  404 +
  405 + //售票员为空设置为""字符串
  406 + if (StringUtils.isEmpty(sch.getsGh())) {
  407 + sch.setsGh("");
  408 + sch.setsName("");
  409 + }
  410 + sch.setJhlcOrig(sch.getJhlc());
  411 + //保留备注
  412 + if (StringUtils.isNotEmpty(sch.getRemark()))
  413 + sch.setRemarks(sch.getRemark());
  414 + }
  415 + } catch (Exception e) {
  416 + logger.error("", e);
  417 + }
  418 +
  419 + return realList;
  420 + }
  421 +
  422 +
  423 + public synchronized long getId(){
  424 + if(sch_max_id==-1){
  425 + sch_max_id = schRepository.getMaxId();
  426 + if(null == sch_max_id)
  427 + sch_max_id = 3000L;//留一点空间补数据用
  428 + sch_max_id += 5;
  429 + }
  430 + else
  431 + sch_max_id ++;
  432 + return sch_max_id;
  433 + }
  434 +
  435 + /**
  436 + * @Title: batchSave
  437 + * @Description: TODO(批量入库)
  438 + */
  439 + private void batchSave(List<ScheduleRealInfo> list) {
  440 + SimpleDateFormat sdfyyyyMMdd = new SimpleDateFormat("yyyy-MM-dd");
  441 + for (ScheduleRealInfo item : list) {
  442 + item.setSpId(item.getId());// 保留原始的计划ID
  443 + item.setId(getId());// 设置ID
  444 + item.setScheduleDateStr(sdfyyyyMMdd.format(item.getScheduleDate()));
  445 + }
  446 +
  447 + transactionTemplate.execute(new TransactionCallbackWithoutResult() {
  448 + @Override
  449 + protected void doInTransactionWithoutResult(TransactionStatus status) {
  450 + try{
  451 + final List<ScheduleRealInfo> pstList = list;
  452 + //写入
  453 + jdbcTemplate.batchUpdate("insert into bsth_c_s_sp_info_real(id,bc_type,bcs,bcsj,cl_zbh,create_date,dfsj,directive_state,fcno,fcsj,fcsj_actual,j_gh,j_name,jhlc,lp_name,qdz_code,qdz_name,real_exec_date,remarks,s_gh,s_name,schedule_date,schedule_date_str,sflj,sp_id,status,update_date,xl_bm,xl_dir,xl_name,zdsj,zdsj_actual,zdz_code,zdz_name,ccno,df_auto,fgs_bm,fgs_name,gs_bm,gs_name,online,adjust_exps,reissue,jhlc_orig,sigin_compate,drift_status,cc_service,major_station_name,rfid_state,first_rfid_state)" +
  454 + " VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", new BatchPreparedStatementSetter() {
  455 + @Override
  456 + public void setValues(PreparedStatement ps, int i) throws SQLException {
  457 + ScheduleRealInfo sch = pstList.get(i);
  458 + ps.setLong(1, sch.getId());
  459 + ps.setString(2, sch.getBcType());
  460 + ps.setInt(3, sch.getBcs()==null?0:sch.getBcs());
  461 + ps.setInt(4, sch.getBcsj()==null?0:sch.getBcsj());
  462 + ps.setString(5, sch.getClZbh());
  463 + ps.setTimestamp(6, new java.sql.Timestamp(sch.getCreateDate().getTime()));
  464 + ps.setString(7, sch.getDfsj());
  465 + ps.setInt(8, sch.getDirectiveState());
  466 + ps.setInt(9, sch.getFcno()==null?0:sch.getFcno());
  467 + ps.setString(10, sch.getFcsj());
  468 + ps.setString(11, sch.getFcsjActual());
  469 + ps.setString(12, sch.getjGh());
  470 + ps.setString(13, sch.getjName());
  471 + ps.setDouble(14, sch.getJhlc());
  472 + ps.setString(15, sch.getLpName());
  473 + ps.setString(16, sch.getQdzCode());
  474 + ps.setString(17, sch.getQdzName());
  475 + ps.setString(18, sch.getRealExecDate());
  476 + ps.setString(19, sch.getRemarks());
  477 + ps.setString(20, sch.getsGh());
  478 + ps.setString(21, sch.getsName());
  479 + ps.setTimestamp(22, new java.sql.Timestamp(sch.getScheduleDate().getTime()));
  480 + ps.setString(23, sch.getScheduleDateStr());
  481 + ps.setBoolean(24, sch.isSflj());
  482 + ps.setLong(25, sch.getSpId());
  483 + ps.setInt(26, sch.getStatus());
  484 + ps.setTimestamp(27, new java.sql.Timestamp(sch.getUpdateDate().getTime()));
  485 + ps.setString(28, sch.getXlBm());
  486 + ps.setString(29, sch.getXlDir());
  487 + ps.setString(30, sch.getXlName());
  488 + ps.setString(31, sch.getZdsj());
  489 + ps.setString(32, sch.getZdsjActual());
  490 + ps.setString(33, sch.getZdzCode());
  491 + ps.setString(34, sch.getZdzName());
  492 + ps.setInt(35, sch.getCcno()==null?0:sch.getCcno());
  493 + ps.setBoolean(36, sch.isDfAuto());
  494 + ps.setString(37, sch.getFgsBm());
  495 + ps.setString(38, sch.getFgsName());
  496 + ps.setString(39, sch.getGsBm());
  497 + ps.setString(40, sch.getGsName());
  498 + ps.setBoolean(41, sch.isOnline());
  499 + ps.setString(42, sch.getAdjustExps());
  500 + ps.setBoolean(43, sch.isReissue());
  501 + ps.setDouble(44, sch.getJhlcOrig());
  502 + ps.setInt(45, sch.getSiginCompate());
  503 + ps.setInt(46, sch.getDriftStatus());
  504 + ps.setBoolean(47, sch.isCcService());
  505 + ps.setString(48, sch.getMajorStationName());
  506 + ps.setInt(49, sch.getRfidState());
  507 + ps.setInt(50, sch.getFirstRfidState());
  508 + }
  509 +
  510 + @Override
  511 + public int getBatchSize() {
  512 + return pstList.size();
  513 + }
  514 + });
  515 + }catch (Exception e){
  516 + status.setRollbackOnly();
  517 + try {
  518 + logger.error(String.format("翻班实际排班数据批量保存异常: %s", mapper.writeValueAsString(list)), e);
  519 + } catch (JsonProcessingException jsonProcessingException) {
  520 + jsonProcessingException.printStackTrace();
  521 + }
  522 + }
  523 + }
  524 + });
  525 + }
  526 +
  527 + public List<SchedulePlanInfo> cleanSchPlanItr(Iterator<SchedulePlanInfo> itrab) {
  528 + List<SchedulePlanInfo> list = new ArrayList<>();
  529 +
  530 + SchedulePlanInfo sp;
  531 + while (itrab.hasNext()) {
  532 + sp = itrab.next();
  533 + sp.setSchedulePlan(null);
  534 + sp.setCreateBy(null);
  535 + sp.setUpdateBy(null);
  536 + list.add(sp);
  537 + }
  538 + return list;
  539 + }
  540 +
  541 + /**
  542 + * @Title: findByLineCode
  543 + * @Description: TODO(lineCode 获取班次)
  544 + */
  545 + public List<ScheduleRealInfo> findByLineCode(String lineCode) {
  546 + List<ScheduleRealInfo> rs = new ArrayList<>();
  547 +
  548 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  549 + for (ScheduleRealInfo sch : schs) {
  550 + if (sch.getXlBm().equals(lineCode))
  551 + rs.add(sch);
  552 + }
  553 + return rs;
  554 + }
  555 +
  556 + /**
  557 + * @Title: findByLineCode
  558 + * @Description: TODO(lineList 获取班次)
  559 + */
  560 + public Map<String, Collection<ScheduleRealInfo>> findByLineCodes(List<String> lineList) {
  561 + ArrayListMultimap<String, ScheduleRealInfo> mMap = ArrayListMultimap.create();
  562 +
  563 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  564 + for (ScheduleRealInfo sch : schs) {
  565 + if (lineList.contains(sch.getXlBm())) {
  566 + mMap.put(sch.getXlBm(), sch);
  567 + }
  568 + }
  569 + return mMap.asMap();
  570 + }
  571 +
  572 + /**
  573 + * @Title: findCarByLineCode
  574 + * @Description: TODO(线路下运营的车辆)
  575 + */
  576 + public Set<String> findCarByLineCode(String lineCode) {
  577 + /*Set<String> rs = new HashSet<>();
  578 +
  579 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  580 + for (ScheduleRealInfo sch : schs) {
  581 + if (sch.getXlBm().equals(lineCode))
  582 + rs.add(sch.getClZbh());
  583 + }
  584 +*/
  585 + return lineNbbmsMap.get(lineCode);
  586 + }
  587 +
  588 + public List<ScheduleRealInfo> findByNbbm(String nbbm) {
  589 + return nbbmScheduleMap.get(nbbm);
  590 + }
  591 +
  592 + /**
  593 + * @Title: findByLineAndUpDown
  594 + * @Description: TODO(lineCode 和走向获取班次)
  595 + */
  596 + public List<ScheduleRealInfo> findByLineAndUpDown(String lineCode, Integer upDown) {
  597 + List<ScheduleRealInfo> list = findByLineCode(lineCode), rs = new ArrayList<>();
  598 +
  599 + for (ScheduleRealInfo sch : list) {
  600 + if (sch.getXlDir().equals(upDown + ""))
  601 + rs.add(sch);
  602 + }
  603 + return rs;
  604 + }
  605 +
  606 + public ScheduleRealInfo get(long id) {
  607 + return id2SchedulMap.get(id);
  608 + }
  609 +
  610 +
  611 + /**
  612 + * @Title: next
  613 + * @Description: TODO(下一个班次)
  614 + */
  615 + public ScheduleRealInfo next(ScheduleRealInfo sch) {
  616 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());
  617 + //排序
  618 + Collections.sort(list, schDFSJComparator);
  619 + return next(list, sch);
  620 + }
  621 +
  622 +
  623 + /**
  624 + * 下一个班次
  625 + *
  626 + * @param list 班次集合
  627 + * @param sch 当前班次
  628 + * @return
  629 + */
  630 + private ScheduleRealInfo next(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {
  631 + int outConfig = -1;
  632 + LineConfig config = lineConfigData.get(sch.getXlBm());
  633 + if (config != null)
  634 + outConfig = config.getOutConfig();
  635 +
  636 + //限定出站既出场的停车场
  637 + List<String> parks = config.findTwinsParkList();
  638 + boolean limitPark = null != parks && parks.size() > 0;
  639 + boolean flag = false;
  640 + ScheduleRealInfo next = null;
  641 + for (ScheduleRealInfo temp : list) {
  642 + if (temp.getId() == sch.getId()) {
  643 + flag = true;
  644 + continue;
  645 + }
  646 + //忽略烂班
  647 + if (temp.isDestroy())
  648 + continue;
  649 +
  650 + //出站既出场,忽略出场班次
  651 + if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)
  652 + && (!limitPark || parks.contains(temp.getQdzCode())))
  653 + continue;
  654 +
  655 + if (flag) {
  656 + next = temp;
  657 + break;
  658 + }
  659 + }
  660 + return next;
  661 + }
  662 +
  663 + private boolean isEmptyMileage(ScheduleRealInfo sch) {
  664 + return sch.getBcsj() == 0 || sch.getJhlcOrig().intValue() == 0;
  665 + }
  666 +
  667 + /**
  668 + * 下一个班次
  669 + *
  670 + * @param list 班次集合
  671 + * @param sch 当前班次
  672 + * @return
  673 + */
  674 + private ScheduleRealInfo next2_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {
  675 + int outConfig = -1;
  676 + LineConfig config = lineConfigData.get(sch.getXlBm());
  677 + if (config != null)
  678 + outConfig = config.getOutConfig();
  679 +
  680 + boolean flag = false;
  681 + ScheduleRealInfo next = null;
  682 + for (ScheduleRealInfo temp : list) {
  683 + if (temp.getId() == sch.getId()) {
  684 + flag = true;
  685 + continue;
  686 + }
  687 +
  688 + if (flag) {
  689 + next = temp;
  690 + break;
  691 + }
  692 + }
  693 + return next;
  694 + }
  695 +
  696 + private ScheduleRealInfo next3_lp(Collection<ScheduleRealInfo> list, ScheduleRealInfo sch) {
  697 + int outConfig = -1;
  698 + LineConfig config = lineConfigData.get(sch.getXlBm());
  699 + if (config != null)
  700 + outConfig = config.getOutConfig();
  701 +
  702 + //限定出站既出场的停车场
  703 + List<String> parks = config.findTwinsParkList();
  704 + boolean limitPark = null != parks && parks.size() > 0;
  705 + boolean flag = false;
  706 + ScheduleRealInfo next = null;
  707 + for (ScheduleRealInfo temp : list) {
  708 + if (temp.getId() == sch.getId()) {
  709 + flag = true;
  710 + continue;
  711 + }
  712 +
  713 + //出站既出场,忽略出场班次
  714 + if (outConfig == 2 && temp.getBcType().equals("out") && isEmptyMileage(temp)
  715 + && (!limitPark || parks.contains(temp.getQdzCode())))
  716 + continue;
  717 +
  718 + if (flag) {
  719 + next = temp;
  720 + break;
  721 + }
  722 + }
  723 + return next;
  724 + }
  725 +
  726 + /**
  727 + * 上一个班次
  728 + *
  729 + * @param sch
  730 + * @return
  731 + */
  732 + public ScheduleRealInfo prev(ScheduleRealInfo sch) {
  733 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());
  734 +
  735 + //boolean flag = false;
  736 + ScheduleRealInfo prev = null;
  737 + int size = list.size();
  738 +
  739 + for (int i = 0; i < size; i++) {
  740 + if (list.get(i).isDestroy())
  741 + continue;
  742 +
  743 + if (list.get(i).getId().equals(sch.getId())) {
  744 + return prev;
  745 + }
  746 + prev = list.get(i);
  747 + }
  748 + return prev;
  749 + }
  750 +
  751 + /**
  752 + * 是否是首班出场
  753 + *
  754 + * @param sch
  755 + * @return
  756 + */
  757 + public boolean isFirstOut(ScheduleRealInfo sch) {
  758 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(sch.getClZbh());
  759 + try {
  760 + if (list.get(0) == sch && sch.getBcType().equals("out"))
  761 + return true;
  762 + } catch (IndexOutOfBoundsException e) {
  763 + logger.error("小小的数组越界,无伤大雅!");
  764 + }
  765 + return false;
  766 + }
  767 +
  768 + public void put(ScheduleRealInfo sch) {
  769 + schAttrCalculator
  770 + .calcRealDate(sch)
  771 + .calcAllTimeByFcsj(sch);
  772 +
  773 + nbbmScheduleMap.put(sch.getClZbh(), sch);
  774 +
  775 + //主键索引
  776 + id2SchedulMap.put(sch.getId(), sch);
  777 + //路牌对照表
  778 + addLPMapp(sch);
  779 +
  780 + //跨24点的,再save一次
  781 + if (!sch.getRealExecDate().equals(sch.getScheduleDateStr()))
  782 + save(sch);
  783 + }
  784 +
  785 + public void addLPMapp(ScheduleRealInfo sch) {
  786 + lpScheduleMap.put(sch.getXlBm() + "_" + sch.getLpName(), sch);
  787 + }
  788 +
  789 + public void delete(ScheduleRealInfo sch) {
  790 + if (!sch.isSflj())
  791 + return;
  792 +
  793 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  794 + id2SchedulMap.remove(sch.getId());
  795 + lpScheduleMap.remove(sch.getXlBm() + "_" + sch.getLpName(), sch);
  796 +
  797 + //如果正在执行该班次
  798 + if (carExecutePlanMap.get(sch.getClZbh()) == sch) {
  799 + //重新计算车辆当前执行班次
  800 + reCalcExecPlan(sch.getClZbh());
  801 + }
  802 + }
  803 +
  804 + public List<ScheduleRealInfo> updateQdzTimePlan(String lpName) {
  805 + List<ScheduleRealInfo> list = lpScheduleMap.get(lpName);
  806 + Collections.sort(list, schFCSJComparator);
  807 + return schAttrCalculator.updateQdzTimePlan(list);
  808 + }
  809 +
  810 + public List<ScheduleRealInfo> updateQdzTimePlan(ScheduleRealInfo sch) {
  811 + return updateQdzTimePlan(sch.getXlBm() + "_" + sch.getLpName());
  812 + }
  813 +
  814 + /**
  815 + * @Title: doneSum
  816 + * @Description: TODO(已完成班次总数)
  817 + */
  818 + public int doneSum(String clZbh) {
  819 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(clZbh);
  820 + int rs = 0;
  821 +
  822 + for (ScheduleRealInfo sch : list) {
  823 + if (sch.getStatus() == 2 && !sch.isDestroy())
  824 + rs++;
  825 + }
  826 + return rs;
  827 + }
  828 +
  829 + public void save(ScheduleRealInfo sch) {
  830 + sch.setUpdateDate(new Date());
  831 + pstBuffer.add(sch);
  832 + }
  833 +
  834 +
  835 + /**
  836 + * @Title: nextByBcType
  837 + * @Description: TODO(获取下一个指定班次类型的班次)
  838 + */
  839 + public ScheduleRealInfo nextByBcType(String nbbm, String bcType) {
  840 + List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);
  841 +
  842 + Collections.sort(list, schFCSJComparator);
  843 + ScheduleRealInfo sch = null;
  844 + for (ScheduleRealInfo temp : list) {
  845 + if (temp.getFcsjActual() == null) {
  846 + sch = temp;
  847 + break;
  848 + }
  849 + }
  850 +
  851 + return sch;
  852 + }
  853 +
  854 +
  855 + /**
  856 + * 搜索离当前时间最近的一个指定类型的班次
  857 + *
  858 + * @param nbbm
  859 + * @param bcType
  860 + * @return
  861 + */
  862 + public ScheduleRealInfo searchNearByBcType(String nbbm, String bcType) {
  863 + List<ScheduleRealInfo> list = findByBcType(nbbm, bcType);
  864 + Collections.sort(list, schFCSJComparator);
  865 +
  866 + long t = System.currentTimeMillis();
  867 + int distance = -1, diff;
  868 +
  869 + ScheduleRealInfo sch = null;
  870 + for (ScheduleRealInfo temp : list) {
  871 + diff = (int) Math.abs(temp.getDfsjT() - t);
  872 + if (diff < distance || distance == -1) {
  873 + sch = temp;
  874 + distance = diff;
  875 + }
  876 + }
  877 + return sch;
  878 + }
  879 +
  880 + public List<ScheduleRealInfo> findByBcType(String nbbm, String bcType) {
  881 + List<ScheduleRealInfo> all = nbbmScheduleMap.get(nbbm), outList = new ArrayList<>();
  882 +
  883 + for (ScheduleRealInfo sch : all) {
  884 + if (sch.getBcType().equals(bcType))
  885 + outList.add(sch);
  886 + }
  887 + return outList;
  888 + }
  889 +
  890 + public Collection<ScheduleRealInfo> findAll() {
  891 + return nbbmScheduleMap.values();
  892 + }
  893 +
  894 + public Collection<ScheduleRealInfo> findAllByLpContainer() {
  895 + return lpScheduleMap.values();
  896 + }
  897 +
  898 + public Collection<ScheduleRealInfo> findAllByIdContainer() {
  899 + return id2SchedulMap.values();
  900 + }
  901 +
  902 + public int getPstSize() {
  903 + return pstBuffer.size();
  904 + }
  905 +
  906 + public boolean addExecPlan(ScheduleRealInfo sch) {
  907 + ScheduleRealInfo oldExec = executeCurr(sch.getClZbh());
  908 + if (sch != null){
  909 + if(sch.getStatus()==2)
  910 + reCalcExecPlan(sch.getClZbh());
  911 + else
  912 + carExecutePlanMap.put(sch.getClZbh(), sch);
  913 + }
  914 + else
  915 + carExecutePlanMap.remove(sch.getClZbh());
  916 +
  917 + return executeCurr(sch.getClZbh()) != oldExec;
  918 + }
  919 +
  920 + public void removeExecPlan(String clzbh) {
  921 + carExecutePlanMap.remove(clzbh);
  922 + }
  923 +
  924 + public Map<String, ScheduleRealInfo> execPlanMap() {
  925 + return carExecutePlanMap;
  926 + }
  927 +
  928 + /**
  929 + * 车辆当前执行的班次
  930 + *
  931 + * @param nbbm
  932 + * @return
  933 + */
  934 + public ScheduleRealInfo executeCurr(String nbbm) {
  935 + if(StringUtils.isEmpty(nbbm))
  936 + return null;
  937 + return carExecutePlanMap.get(nbbm);
  938 + }
  939 +
  940 + /**
  941 + * @param @param sch
  942 + * @param @param newClZbh 新的车辆自编号
  943 + * @Title: changeCar
  944 + * @Description: TODO(班次换车) 返回有更新的班次
  945 + */
  946 + public List<ScheduleRealInfo> changeCar(ScheduleRealInfo sch, String newClZbh) {
  947 + List<ScheduleRealInfo> ups = new ArrayList<>();
  948 +
  949 + String oldClZbh = sch.getClZbh();
  950 + //变更相关映射信息
  951 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  952 +
  953 + sch.setClZbh(newClZbh);
  954 + if (!nbbmScheduleMap.containsEntry(newClZbh, sch)) {
  955 + nbbmScheduleMap.put(newClZbh, sch);
  956 + }
  957 +
  958 + //重新计算车辆当前执行班次
  959 + reCalcExecPlan(newClZbh);
  960 + reCalcExecPlan(oldClZbh);
  961 + //重新分组计划用车
  962 + reCalcLineNbbms();
  963 + return ups;
  964 + }
  965 +
  966 + public void removeNbbm2SchMapp(ScheduleRealInfo sch) {
  967 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  968 + }
  969 +
  970 + public void addNbbm2SchMapp(ScheduleRealInfo sch) {
  971 + nbbmScheduleMap.put(sch.getClZbh(), sch);
  972 + }
  973 +
  974 + public void reCalcExecPlan(String nbbm) {
  975 + List<ScheduleRealInfo> list = nbbmScheduleMap.get(nbbm);
  976 + Collections.sort(list, schDFSJComparator);
  977 +
  978 + ScheduleRealInfo sch = schAttrCalculator.calcCurrentExecSch(list);
  979 + if(null != sch)
  980 + carExecutePlanMap.put(nbbm, sch);
  981 + else
  982 + carExecutePlanMap.remove(nbbm);
  983 + }
  984 +
  985 + /**
  986 + * 空驶任务?
  987 + * 出场、进场、直放、两点间空驶
  988 + * @param sch
  989 + * @return
  990 + */
  991 + public static boolean emptyService(ScheduleRealInfo sch){
  992 + String type = sch.getBcType();
  993 + return type.equals("out") || type.equals("in") || type.equals("venting") || type.equals("ldks");
  994 + }
  995 +
  996 + @Autowired
  997 + JdbcTemplate jdbcTemplate;
  998 +
  999 + @Autowired
  1000 + private TransactionTemplate transactionTemplate;
  1001 +
  1002 + @Autowired
  1003 + private ObjectMapper mapper;
  1004 +
  1005 + /**
  1006 + * 删除实际排班
  1007 + *
  1008 + * @param lineCode
  1009 + * @return
  1010 + */
  1011 + public Map<String, Object> deleteRealSchedule(String lineCode) {
  1012 + Map<String, Object> rs = new HashMap<>();
  1013 +
  1014 + try {
  1015 + String rq = currSchDateMap.get(lineCode);
  1016 + if (StringUtils.isNotEmpty(rq)) {
  1017 + List<ScheduleRealInfo> all = findByLineCode(lineCode);
  1018 +
  1019 + if(null != all && all.size() > 0){
  1020 + //解除gps 和班次之间的关联
  1021 + List<ScheduleRealInfo> unions = calcUnion(all, carExecutePlanMap.values());
  1022 + for (ScheduleRealInfo sch : unions) {
  1023 + removeExecPlan(sch.getClZbh());
  1024 + }
  1025 + //解除调度指令和班次的外键约束
  1026 + StringBuilder inStr = new StringBuilder("(");
  1027 + for (ScheduleRealInfo sch : all) {
  1028 + inStr.append(sch.getId() + ",");
  1029 + }
  1030 + inStr.deleteCharAt(inStr.length() - 1).append(")");
  1031 + jdbcTemplate.update(Constants.MULTI_REMOVE_DIRECTIVE_SCH_FK + " " + inStr.toString());
  1032 + jdbcTemplate.update(Constants.MULTI_REMOVE_CHILDTASK_SCH_FK + " " + inStr.toString());
  1033 + }
  1034 +
  1035 + //删除班次数据
  1036 + removeRealSch(lineCode, rq);
  1037 +
  1038 + }
  1039 + rs.put("status", ResponseCode.SUCCESS);
  1040 + } catch (Exception e) {
  1041 + logger.error("", e);
  1042 + rs.put("status", ResponseCode.ERROR);
  1043 + if (e instanceof DataIntegrityViolationException)
  1044 + rs.put("msg", "失败,违反数据约束!!");
  1045 + else
  1046 + rs.put("msg", e.getMessage());
  1047 + }
  1048 +
  1049 + return rs;
  1050 + }
  1051 +
  1052 + /**
  1053 + * 计算并集
  1054 + *
  1055 + * @param c1
  1056 + * @param c2
  1057 + * @return
  1058 + */
  1059 + public List<ScheduleRealInfo> calcUnion(Collection<ScheduleRealInfo> c1, Collection<ScheduleRealInfo> c2) {
  1060 + List<ScheduleRealInfo> rs = new ArrayList<>();
  1061 +
  1062 + for (ScheduleRealInfo sch : c1) {
  1063 + if (c2.contains(sch)) {
  1064 + rs.add(sch);
  1065 + }
  1066 + }
  1067 + return rs;
  1068 + }
  1069 +
  1070 + /**
  1071 + * 覆盖一辆车的所有班次
  1072 + *
  1073 + * @param nbbm
  1074 + * @param sets
  1075 + */
  1076 + public void replaceByNbbm(String nbbm, Collection<ScheduleRealInfo> sets) {
  1077 + nbbmScheduleMap.removeAll(nbbm);
  1078 + nbbmScheduleMap.putAll(nbbm, sets);
  1079 + }
  1080 +
  1081 + /**
  1082 + * 获取该班次所在路牌的下一个班次
  1083 + *
  1084 + * @param sch
  1085 + * @return
  1086 + */
  1087 + public ScheduleRealInfo nextByLp(ScheduleRealInfo sch) {
  1088 + List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());
  1089 + Collections.sort(list, schFCSJComparator);
  1090 + return next3_lp(list, sch);
  1091 + }
  1092 +
  1093 + /**
  1094 + * 获取该班次所在路牌的下一个班次,不考虑场既是站
  1095 + *
  1096 + * @param sch
  1097 + * @return
  1098 + */
  1099 + public ScheduleRealInfo nextByLp2(ScheduleRealInfo sch) {
  1100 + List<ScheduleRealInfo> list = lpScheduleMap.get(sch.getXlBm() + "_" + sch.getLpName());
  1101 + Collections.sort(list, schFCSJComparator);
  1102 + return next2_lp(list, sch);
  1103 + }
  1104 +
  1105 + public ArrayListMultimap<String, ScheduleRealInfo> getLpScheduleMap() {
  1106 + return lpScheduleMap;
  1107 + }
  1108 +
  1109 + /**
  1110 + * 重新全量计算路牌下的班次关联性
  1111 + * 临时性的函数
  1112 + */
  1113 + public void _test_reCalcLpSch() {
  1114 + Map<String ,Collection<ScheduleRealInfo>> map = lpScheduleMap.asMap();
  1115 + Set<String> ks = map.keySet();
  1116 + for(String k : ks){
  1117 + schAttrCalculator.calcQdzTimePlan(new ArrayList<ScheduleRealInfo>(map.get(k)));
  1118 + }
  1119 + }
  1120 +
  1121 + public int dbCount(String lineCode, String currSchDate) {
  1122 + int count = -1;
  1123 +
  1124 + try{
  1125 + count = jdbcTemplate.queryForObject("select count(*) from bsth_c_s_sp_info_real where schedule_date='"+currSchDate+"' and xl_bm='"+lineCode+"'", java.lang.Integer.class);
  1126 +
  1127 + }catch (Exception e){
  1128 + logger.error("", e);
  1129 + }
  1130 + return count;
  1131 + }
  1132 +
  1133 + /**
  1134 + * 重新计算ID对照map
  1135 + */
  1136 + public int reCalcIdMaps(){
  1137 + Collection<ScheduleRealInfo> all = findAll();
  1138 + ConcurrentMap<Long, ScheduleRealInfo> id2SchedulMapCopy = new ConcurrentHashMap<>();
  1139 +
  1140 + for(ScheduleRealInfo sch : all){
  1141 + id2SchedulMapCopy.put(sch.getId(), sch);
  1142 + }
  1143 +
  1144 + id2SchedulMap = id2SchedulMapCopy;
  1145 +
  1146 + return id2SchedulMap.size();
  1147 + }
  1148 +
  1149 + /**
  1150 + * 重新计算线路计划用车
  1151 + */
  1152 + public void reCalcLineNbbms(){
  1153 + HashMultimap<String, String> multimap = HashMultimap.create();
  1154 +
  1155 + Collection<ScheduleRealInfo> schs = nbbmScheduleMap.values();
  1156 + for (ScheduleRealInfo sch : schs) {
  1157 + multimap.put(sch.getXlBm(), sch.getClZbh());
  1158 + }
  1159 +
  1160 + lineNbbmsMap = multimap;
  1161 + }
  1162 +
  1163 + public String sizeString(){
  1164 + return id2SchedulMap.size() + "/" + nbbmScheduleMap.size();
  1165 + }
  1166 +
  1167 +
  1168 + /**
  1169 + * 按公司编码分组数据
  1170 + */
  1171 + public void groupByGsbm(){
  1172 + Collection<ScheduleRealInfo> all = findAll();
  1173 + ListMultimap<String, ScheduleRealInfo> gsBmMaps = ArrayListMultimap.create();
  1174 +
  1175 + for(ScheduleRealInfo sch : all){
  1176 + gsBmMaps.put(sch.getGsBm(), sch);
  1177 + }
  1178 +
  1179 + if(gsBmMaps.size() > 0){
  1180 + gsBmScheduleMap = null;
  1181 + gsBmScheduleMap = gsBmMaps;
  1182 + }
  1183 + }
  1184 +
  1185 + public Collection<ScheduleRealInfo> findByGsbm(String gsbm){
  1186 + return gsBmScheduleMap.get(gsbm);
  1187 + }
  1188 + /**
  1189 + * 删除班次,删除内存中未清理掉的非当天的班次
  1190 + * @createDate 2019.05.13
  1191 + * @author zhangxianzhou
  1192 + * @param sch
  1193 + */
  1194 + public void deleteBC(ScheduleRealInfo sch) {
  1195 + nbbmScheduleMap.remove(sch.getClZbh(), sch);
  1196 + id2SchedulMap.remove(sch.getId());
  1197 + lpScheduleMap.remove(sch.getXlBm() + "_" + sch.getLpName(), sch);
  1198 + //如果正在执行该班次
  1199 + if (carExecutePlanMap.get(sch.getClZbh()) == sch) {
  1200 + //重新计算车辆当前执行班次
  1201 + reCalcExecPlan(sch.getClZbh());
  1202 + }
  1203 + }
  1204 +
  1205 + /**
  1206 + ** 用于重置维修上报计数,一般只应该在翻班的时候调用
  1207 + */
  1208 + public void resetRepairReport(String incode) {
  1209 + incode2report.remove(incode);
  1210 + }
  1211 +
  1212 + public RepairReport getLastestRepairReport(String incode) {
  1213 + return incode2report.get(incode);
  1214 + }
  1215 +
  1216 + public void setLastestRepairReport(RepairReport rr) {
  1217 + incode2report.put(rr.getIncode(), rr);
  1218 + }
1214 } 1219 }
1215 \ No newline at end of file 1220 \ No newline at end of file