Commit 33403032d926b29d88584a222179bb642886f3b9

Authored by 娄高锋
2 parents 2894f364 4db4b302

Merge branch 'pudong' of 192.168.168.201:panzhaov5/bsth_control into pudong

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