ParkUtils.java 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. package com.ebei.screen.common.util;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DatePattern;
  4. import cn.hutool.core.date.LocalDateTimeUtil;
  5. import cn.hutool.core.map.MapUtil;
  6. import cn.hutool.crypto.SecureUtil;
  7. import cn.hutool.http.HttpRequest;
  8. import cn.hutool.setting.dialect.Props;
  9. import cn.hutool.setting.dialect.PropsUtil;
  10. import com.alibaba.fastjson.JSON;
  11. import com.alibaba.fastjson.JSONArray;
  12. import com.alibaba.fastjson.JSONObject;
  13. import com.ebei.screen.common.constants.CommonConstants;
  14. import com.ebei.screen.common.constants.ParkExceptionType;
  15. import com.ebei.screen.common.constants.ParkType;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.apache.commons.lang3.StringUtils;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.data.mongodb.core.MongoTemplate;
  20. import org.springframework.data.mongodb.core.query.Criteria;
  21. import org.springframework.data.mongodb.core.query.Query;
  22. import org.springframework.data.mongodb.core.query.Update;
  23. import org.springframework.stereotype.Component;
  24. import java.time.Duration;
  25. import java.time.LocalDateTime;
  26. import java.util.*;
  27. import java.util.concurrent.TimeUnit;
  28. import java.util.stream.Collectors;
  29. /**
  30. * 车场大屏工具类
  31. *
  32. * @author Levi.u
  33. * @date 2021/1/13 21:03
  34. */
  35. @Slf4j
  36. @Component
  37. public class ParkUtils {
  38. private static MongoTemplate mongoTemplate;
  39. private static final String pno = "JYTDSY";
  40. private static final String secret = "d52ee6b8a5ed4060a1d1654a3d31e247";
  41. private static final String BASE_URL = "http://jhtdc.jslife.com.cn/api";
  42. private static final String LOGIN_URL = BASE_URL + "/login";
  43. private static final String IMAGE_URL = BASE_URL + "/pic/picSearch";
  44. public static String token;
  45. @Autowired
  46. public void setMongoTemplate(MongoTemplate mongoTemplate) {
  47. ParkUtils.mongoTemplate = mongoTemplate;
  48. }
  49. public static List<Map> getEmptyTemplate() {
  50. List<Map> dayList = new ArrayList<>();
  51. for (int c = 0; c <= 23; c++) {
  52. dayList.add(Levi.by("hour", c).set("data", new ArrayList<>()).set("count", 0));
  53. }
  54. return dayList;
  55. }
  56. public static JSONObject getEmptyHourTemplate() {
  57. List<String> hours = Arrays.asList("1", "3", "6", "9", "12");
  58. JSONObject result = new JSONObject();
  59. hours.forEach(x -> result.put(x, new ArrayList<>()));
  60. return result;
  61. }
  62. /**
  63. * 用于存储数据 精确到天
  64. *
  65. * @param obj 插入的对象
  66. * @param pkId 区分键
  67. * @param collectionName 集合名字
  68. * @param flag true 覆盖原有数据只保留一条最新的 false追加原有数据
  69. * @param orderKey 排序的时间key
  70. * @param other 要插入的其他字段
  71. * @return
  72. */
  73. public static List<Map> setDataField(Object obj, String pkId, String collectionName, boolean flag, String orderKey, Levi<String, String> other) {
  74. LocalDateTime now = LocalDateTime.now();
  75. int hour = now.getHour();
  76. String format = LocalDateTimeUtil.format(now, DatePattern.PURE_DATE_PATTERN);
  77. Map dayMap = mongoTemplate.findById(pkId + "_" + format, Map.class, collectionName);
  78. if (MapUtil.isEmpty(dayMap)) {
  79. dayMap = Levi.by("_id", pkId + "_" + format).set("data", getEmptyTemplate());
  80. }
  81. List<Map> hourList = (List<Map>) dayMap.get("data");
  82. Map hourMap = hourList.get(hour);
  83. List<Map> dataList = (List<Map>) hourMap.get("data");
  84. List<Map> result = LeviUtils.deepCopy((List<Map>) obj);
  85. int size = result.size();
  86. if (CollUtil.isNotEmpty(dataList) && !flag) {
  87. result.addAll(dataList);
  88. }
  89. hourMap.put("count", result.size());
  90. hourMap.put("data", StringUtils.isNotBlank(orderKey) ? sortDateList(result, orderKey, true) : result);
  91. // 按小时存入数据用于统计
  92. Query query = new Query();
  93. query.addCriteria(Criteria.where("_id").is(pkId + "_" + format));
  94. Update update = new Update();
  95. update.set("data", hourList);
  96. // 统计数字
  97. if (dayMap.get("count") != null) {
  98. int count = Integer.parseInt(dayMap.get("count").toString());
  99. update.set("count", count + size);
  100. } else {
  101. update.set("count", size);
  102. }
  103. if (other != null) {
  104. other.keySet().forEach(x -> update.set(x, other.get(x)));
  105. }
  106. mongoTemplate.upsert(query, update, collectionName);
  107. return hourList;
  108. }
  109. /**
  110. * 获取封装后的结果集
  111. *
  112. * @param params
  113. * @param image 如果要查询图片 则传入 空不查
  114. * @return
  115. */
  116. public static Map<String, List<Map>> getInsertMap(Map params, String image) {
  117. List<Map> dataItems = JSON.parseObject((String) params.get("dataItems"), List.class);
  118. if (CollUtil.isEmpty(dataItems)) {
  119. return null;
  120. }
  121. Map<String, List<Map>> result = new HashMap<>(16);
  122. dataItems.forEach(x -> {
  123. String parkCode = x.get("parkCode").toString();
  124. List<Map> maps = new ArrayList<>();
  125. if (result.containsKey(parkCode)) {
  126. maps = result.get(parkCode);
  127. }
  128. maps.add(x);
  129. maps.forEach(y -> {
  130. y.put("sn", params.get("sn").toString());
  131. y.put("homra", LocalDateTimeUtil.format(LocalDateTime.now(), "HH"));
  132. });
  133. result.put(parkCode, maps);
  134. });
  135. return result;
  136. }
  137. public static Map<String, List<Map>> getInsertMap(Map params) {
  138. return getInsertMap(params, null);
  139. }
  140. /**
  141. * 初始化入场或出场数据
  142. *
  143. * @param params 参数
  144. * @param type 类型 入场或出场
  145. */
  146. public static void parkInOrOut(Map params, ParkType type) {
  147. Map<String, List<Map>> insertMap = ParkUtils.getInsertMap(params, type.getImage());
  148. String pno = params.get("pno").toString();
  149. if (MapUtil.isNotEmpty(insertMap)) {
  150. insertMap.keySet().forEach(key -> {
  151. // 按小时存入数据用于统计
  152. ParkUtils.setDataField(insertMap.get(key), key, type.getCode(), false, type.getSort(), Levi.by("pno", pno).set("ts", params.get("ts")));
  153. // 按车场存入数据 实时统计当前车场内所有车辆信息
  154. Query query = new Query();
  155. query.addCriteria(Criteria.where("_id").is(key));
  156. JSONObject obj = mongoTemplate.findById(key, JSONObject.class, "parkCarList");
  157. JSONArray data = obj != null ? obj.getJSONArray("data") : new JSONArray();
  158. List<Map> maps = data.toJavaList(Map.class);
  159. if (type.getNo().equals(1)) {
  160. // 入场
  161. maps.addAll(insertMap.get(key));
  162. } else if (type.getNo().equals(2)) {
  163. // 出场
  164. List<Map> listMaps = insertMap.get(key);
  165. if (CollUtil.isNotEmpty(listMaps)) {
  166. List<String> itemIds = listMaps.stream().map(x -> x.get("itemId").toString()).collect(Collectors.toList());
  167. maps = maps.stream().filter(x -> !itemIds.contains(x.get("itemId").toString())).collect(Collectors.toList());
  168. }
  169. }
  170. Update update = new Update();
  171. update.set("data", sortDateList(maps, "inTime", true));
  172. update.set("pno", pno);
  173. update.set("ts", params.get("ts"));
  174. update.set("count", maps.size());
  175. mongoTemplate.upsert(query, update, "parkCarList");
  176. // 校验是否存在异常数据
  177. insertException(key, insertMap.get(key), type.getNo().toString());
  178. });
  179. }
  180. }
  181. /**
  182. * 获取今日停车时长统计对象
  183. *
  184. * @param subList 分类完成后的集合
  185. * @param obj 当前mongo中查询出的对象
  186. * @return
  187. */
  188. public static JSONObject sortHourList(List<Map> subList, JSONObject obj) {
  189. JSONObject result = new JSONObject();
  190. JSONObject data = obj != null ? obj.getJSONObject("data") : getEmptyHourTemplate();
  191. subList.forEach(x -> {
  192. String key = calcHour(x);
  193. JSONArray array = data.getJSONArray(key);
  194. array.add(x);
  195. data.put(key, array);
  196. });
  197. result.put("data", data);
  198. data.keySet().forEach(x -> result.put("count" + x, data.getJSONArray(x).size()));
  199. return result;
  200. }
  201. /**
  202. * 获取停车时长归属时间段
  203. *
  204. * @param map
  205. * @return
  206. */
  207. public static String calcHour(Map map) {
  208. long second = Long.parseLong(map.get("serviceFeeTime") != null ? map.get("serviceFeeTime").toString() : "0");
  209. Long hour = TimeUnit.SECONDS.toHours(second);
  210. List<String> hours = Arrays.asList("1", "3", "6", "9", "12");
  211. return hours.get((hour.intValue() / 3) > hours.size() ? hours.size() - 1 : (hour.intValue() / 3));
  212. }
  213. /**
  214. * 根据时间对集合进行排序 yyyy-MM-dd HH:mm:ss
  215. *
  216. * @param jsonArray jsonArray集合
  217. * @param sortKey 排序的key
  218. * @param flag true正序 false倒序
  219. * @return
  220. */
  221. public static List<Map> sortDateList(JSONArray jsonArray, String sortKey, boolean flag) {
  222. List<Map> maps = jsonArray.toJavaList(Map.class);
  223. return sortDateList(maps, sortKey, flag);
  224. }
  225. /**
  226. * 根据时间对集合进行排序 yyyy-MM-dd HH:mm:ss
  227. *
  228. * @param maps list集合
  229. * @param sortKey 排序的key
  230. * @param flag true正序 false倒序
  231. * @return
  232. */
  233. public static List<Map> sortDateList(List<Map> maps, String sortKey, boolean flag) {
  234. if (CollUtil.isEmpty(maps)) {
  235. return new ArrayList<>();
  236. }
  237. int i = flag ? 1 : -1;
  238. if (sortKey.equals(ParkType.EXCEPTION.getSort())) {
  239. Collections.sort(maps, (m1, m2) -> ((m1.get(sortKey) == null ? 0 : Integer.parseInt(m1.get(sortKey).toString())) > (m2.get(sortKey) == null ? 0 : Integer.parseInt(m2.get(sortKey).toString()))) ? 1 * i : -1 * i);
  240. return maps;
  241. }
  242. if (StringUtils.isNotBlank(sortKey)) {
  243. Collections.sort(maps, (m1, m2) -> (m1.get(sortKey) == null ? LocalDateTime.now() : LocalDateTimeUtil.parse(m1.get(sortKey).toString(), DatePattern.NORM_DATETIME_PATTERN)).isAfter(m2.get(sortKey) == null ? LocalDateTime.now() : LocalDateTimeUtil.parse(m2.get(sortKey).toString(), DatePattern.NORM_DATETIME_PATTERN)) ? 1 * i : -1 * i);
  244. }
  245. return maps;
  246. }
  247. /**
  248. * 获取当前所有的停车场编号
  249. *
  250. * @return
  251. */
  252. public static List<String> getParkCodeList() {
  253. Levi<String, String> results = initParkCodeList();
  254. return results.keySet().stream().collect(Collectors.toList());
  255. }
  256. /**
  257. * 初始化内置的停车场信息
  258. *
  259. * @return
  260. */
  261. public static Levi<String, String> initParkCodeList() {
  262. Props prop = PropsUtil.get("parkName");
  263. Levi<String, String> result = Levi.create();
  264. prop.keySet().stream().forEach(x -> result.set(x.toString(), prop.get(x).toString()));
  265. JSONObject obj = mongoTemplate.findById("parkInfo", JSONObject.class, "parkInfo");
  266. if (obj != null && obj.getJSONArray("data") != null) {
  267. List<Map> maps = obj.getJSONArray("data").toJavaList(Map.class);
  268. maps.forEach(x -> result.set(x.get("parkCode").toString(), x.get("parkName").toString()));
  269. }
  270. Query query = new Query();
  271. query.addCriteria(Criteria.where("_id").is("parkCodeList"));
  272. Update update = new Update();
  273. update.set("data", result);
  274. mongoTemplate.upsert(query, update, "parkCodeList");
  275. return result;
  276. }
  277. /**
  278. * 给车场项目排序
  279. *
  280. * @param list
  281. * @return
  282. */
  283. public static List<Map> sortList(List<Map> list) {
  284. JSONObject obj = mongoTemplate.findById(CommonConstants.PARK_ORDER, JSONObject.class, CommonConstants.PARK_ORDER);
  285. List<String> crmIds = obj != null ? obj.getJSONArray("data").toJavaList(String.class) : new JSONArray().toJavaList(String.class);
  286. Collections.sort(list, Comparator.comparingInt(o -> crmIds.indexOf(o.get("projectId").toString())));
  287. return list.stream().filter(x -> x.get("projectName") != null).collect(Collectors.toList());
  288. }
  289. /**
  290. * 获取登录token
  291. *
  292. * @return
  293. */
  294. public static String getLoginToken() {
  295. String str = HttpRequest.post(LOGIN_URL)
  296. .header("content-type", "application/json")
  297. .body(JSON.toJSONString(Levi.by("pno", pno).set("secret", secret)))
  298. .execute().body();
  299. String token = JSON.parseObject(str).getString("tn");
  300. if (StringUtils.isNotBlank(token)) {
  301. ParkUtils.token = token;
  302. return token;
  303. }
  304. return null;
  305. }
  306. /**
  307. * 传入业务参数获取封装后的参数
  308. *
  309. * @param param
  310. * @return
  311. */
  312. public static String getCommonParams(Levi param) {
  313. String ts = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_MS_PATTERN);
  314. String dataItems = JSON.toJSONString(Arrays.asList(param));
  315. // sn=md5(secret+ts+dataItems)
  316. String sn = SecureUtil.md5(secret + ts + dataItems).toUpperCase();
  317. return JSON.toJSONString(Levi.by("pno", pno).set("tn", token).set("ts", ts).set("ve", "1.0").set("sn", sn).set("dataItems", dataItems));
  318. }
  319. /**
  320. * 根据图片路径获取图片外链
  321. *
  322. * @param photo
  323. * @return
  324. */
  325. public static String getImgUrlById(String photo) {
  326. String str = HttpRequest.post(IMAGE_URL)
  327. .header("content-type", "application/json")
  328. .body(getCommonParams(Levi.by("filePath", photo)))
  329. .execute().body();
  330. JSONArray dataItems = JSON.parseObject(str).getJSONArray("dataItems");
  331. System.out.println("getImgUrlById:" + dataItems);
  332. if (dataItems != null) {
  333. String image = dataItems.toJavaList(Map.class).get(0).get("image").toString();
  334. return image;
  335. }
  336. return null;
  337. }
  338. /**
  339. * 判断数据是否存在异常 并插入异常信息
  340. *
  341. * @param params
  342. */
  343. public static void insertException(String parkCode, List<Map> params, String type) {
  344. String format = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.PURE_DATE_PATTERN);
  345. Query query = new Query();
  346. query.addCriteria(Criteria.where("_id").is(parkCode + "_" + format));
  347. Update update = new Update();
  348. JSONObject obj = mongoTemplate.findById(parkCode + "_" + format, JSONObject.class, ParkType.EXCEPTION.getCode());
  349. JSONObject data = obj != null ? obj.getJSONObject("data") : new JSONObject();
  350. if (CommonConstants.SERVICE_IN.equals(type)) {
  351. // 车牌无法识别
  352. List<Map> list = params.stream().filter(x -> x.get("carNumber").toString().startsWith("无")).collect(Collectors.toList());
  353. List<Map> maps = data.getJSONArray(ParkExceptionType.A.getCode()) == null ? new ArrayList<>() : data.getJSONArray(ParkExceptionType.A.getCode()).toJavaList(Map.class);
  354. maps.addAll(list);
  355. System.out.println("异常处理之前:" + JSON.toJSONString(maps));
  356. List<Map> feesTime = ParkUtils.sortDateList(maps, ParkType.IN.getSort(), true);
  357. if (CollUtil.isNotEmpty(feesTime)) {
  358. feesTime.forEach(x -> {
  359. x.put("imageUrl", x.get(ParkType.IN.getImage()));
  360. x.put("operator", x.get("inOperator"));
  361. });
  362. }
  363. System.out.println("异常处理之后:" + JSON.toJSONString(feesTime));
  364. data.put(ParkExceptionType.A.getCode(), feesTime);
  365. update.set("data", data);
  366. update.set(ParkExceptionType.A.getCode() + "Count", feesTime.size());
  367. mongoTemplate.upsert(query, update, ParkType.EXCEPTION.getCode());
  368. } else if (CommonConstants.SERVICE_OUT.equals(type)) {
  369. // 车牌无法识别
  370. List<Map> list = params.stream().filter(x -> x.get("carNumber").toString().startsWith("无")).collect(Collectors.toList());
  371. List<Map> maps = data.getJSONArray(ParkExceptionType.A.getCode()) == null ? new ArrayList<>() : data.getJSONArray(ParkExceptionType.A.getCode()).toJavaList(Map.class);
  372. maps.addAll(list);
  373. List<Map> feesTime = ParkUtils.sortDateList(maps, ParkType.OUT.getSort(), true);
  374. if (CollUtil.isNotEmpty(feesTime)) {
  375. feesTime.forEach(x -> {
  376. x.put("imageUrl", x.get(ParkType.OUT.getImage()));
  377. x.put("operator", x.get("outOperator"));
  378. x.put("equipName", x.get("outEquipName"));
  379. });
  380. }
  381. data.put(ParkExceptionType.A.getCode(), feesTime);
  382. // 支付时间过长
  383. String now = LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN);
  384. List<Map> list2 = params.stream().filter(x -> getDimSS(x.get("outTime") == null ? now : x.get("outTime").toString(), x.get("openDoor") == null ? now : x.get("openDoor").toString()) > 60
  385. ).collect(Collectors.toList());
  386. List<Map> maps2 = data.getJSONArray(ParkExceptionType.B.getCode()) == null ? new ArrayList<>() : data.getJSONArray(ParkExceptionType.B.getCode()).toJavaList(Map.class);
  387. maps2.addAll(list2);
  388. List<Map> feesTime2 = ParkUtils.sortDateList(maps2, ParkType.OUT.getSort(), true);
  389. if (CollUtil.isNotEmpty(feesTime2)) {
  390. feesTime2.forEach(x -> {
  391. x.put("imageUrl", x.get(ParkType.OUT.getImage()));
  392. x.put("operator", x.get("outOperator"));
  393. x.put("equipName", x.get("outEquipName"));
  394. });
  395. }
  396. data.put(ParkExceptionType.B.getCode(), feesTime2);
  397. // 判断是否撞杆
  398. List<Map> list3 = params.stream().filter(x -> x.get("remark") != null && x.get("remark").toString().contains("撞杆")).collect(Collectors.toList());
  399. List<Map> maps3 = data.getJSONArray(ParkExceptionType.D.getCode()) == null ? new ArrayList<>() : data.getJSONArray(ParkExceptionType.D.getCode()).toJavaList(Map.class);
  400. maps3.addAll(list3);
  401. List<Map> feesTime3 = ParkUtils.sortDateList(maps3, ParkType.OUT.getSort(), true);
  402. if (CollUtil.isNotEmpty(feesTime3)) {
  403. feesTime3.forEach(x -> {
  404. x.put("imageUrl", x.get(ParkType.OUT.getImage()));
  405. x.put("operator", x.get("outOperator"));
  406. x.put("equipName", x.get("outEquipName"));
  407. });
  408. }
  409. data.put(ParkExceptionType.D.getCode(), feesTime3);
  410. update.set("data", data);
  411. update.set(ParkExceptionType.B.getCode() + "Count", feesTime2.size());
  412. update.set(ParkExceptionType.D.getCode() + "Count", feesTime3.size());
  413. mongoTemplate.upsert(query, update, ParkType.EXCEPTION.getCode());
  414. } else if (CommonConstants.SERVICE_INFO.equals(type)) {
  415. // 月卡过期
  416. List<Map> list = params.stream().filter(x ->
  417. Duration.between(LocalDateTime.now(), x.get("endTime") == null ? LocalDateTime.now() : LocalDateTimeUtil.parse(x.get("endTime").toString(), DatePattern.NORM_DATETIME_PATTERN)).getSeconds() < 0
  418. ).collect(Collectors.toList());
  419. List<Map> maps = data.getJSONArray(ParkExceptionType.C.getCode()) == null ? new ArrayList<>() : data.getJSONArray(ParkExceptionType.C.getCode()).toJavaList(Map.class);
  420. maps.addAll(list);
  421. List<Map> feesTime = ParkUtils.sortDateList(maps, "operateTime", true);
  422. data.put(ParkExceptionType.C.getCode(), feesTime);
  423. if (CollUtil.isNotEmpty(feesTime)) {
  424. feesTime.forEach(x -> {
  425. x.put("operator", x.get("operateName"));
  426. x.put("equipName", x.get("cardTypeName"));
  427. });
  428. }
  429. update.set("data", data);
  430. update.set(ParkExceptionType.C.getCode() + "Count", feesTime.size());
  431. mongoTemplate.upsert(query, update, ParkType.EXCEPTION.getCode());
  432. }
  433. }
  434. /**
  435. * 计算两个时间相差秒数
  436. *
  437. * @param s1 yyyy-MM-dd HH:mm:ss
  438. * @param s2 yyyy-MM-dd HH:mm:ss
  439. * @return
  440. */
  441. public static Integer getDimSS(String s1, String s2) {
  442. LocalDateTime s1Time = LocalDateTimeUtil.parse(s1, DatePattern.NORM_DATETIME_PATTERN);
  443. LocalDateTime s2Time = LocalDateTimeUtil.parse(s2, DatePattern.NORM_DATETIME_PATTERN);
  444. Duration dur = Duration.between(s1Time, s2Time);
  445. Long abs = Math.abs(dur.getSeconds());
  446. return abs.intValue();
  447. }
  448. /**
  449. * 获取某个时间点的异常信息
  450. *
  451. * @param dataList
  452. * @param timeIndex
  453. * @return
  454. */
  455. public static List<Map> getExceptionDataListByHour(List<Map> dataList, Integer timeIndex) {
  456. if (CollUtil.isEmpty(dataList)) {
  457. return new ArrayList<>();
  458. }
  459. String format = String.format("%02d", timeIndex);
  460. return dataList.stream().filter(x -> (x.get("homra") == null ? "" : x.get("homra").toString()).equals(format)).collect(Collectors.toList());
  461. }
  462. }