MesProcessParamLimitCheckService.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. package com.jeesite.modules.mes.service;
  2. import java.math.BigDecimal;
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7. import com.alibaba.fastjson.JSONArray;
  8. import com.alibaba.fastjson.JSONObject;
  9. import com.jeesite.common.lang.StringUtils;
  10. import com.jeesite.modules.mes.entity.MesProcessParamLimit;
  11. import com.jeesite.modules.mes.entity.MesProductArcWelding;
  12. import com.jeesite.modules.mes.entity.MesProductCmt;
  13. import com.jeesite.modules.mes.entity.MesProductProd;
  14. import com.jeesite.modules.mes.entity.MesProductQm;
  15. import com.jeesite.modules.mes.entity.MesWelderParamRecord;
  16. import org.springframework.beans.BeanWrapperImpl;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18. import org.springframework.stereotype.Service;
  19. /**
  20. * 工艺参数上下限校验Service
  21. * @author mes
  22. * @version 2026-09-07
  23. */
  24. @Service
  25. public class MesProcessParamLimitCheckService {
  26. private static final Map<String, String[]> ARC_PARAM_ALIASES = new HashMap<>();
  27. static {
  28. ARC_PARAM_ALIASES.put("current", new String[]{"current", "current1", "current2", "robot1Current", "robot2Current", "i1", "i2", "I1", "I2"});
  29. ARC_PARAM_ALIASES.put("current1", new String[]{"current1", "robot1Current", "i1", "I1"});
  30. ARC_PARAM_ALIASES.put("current2", new String[]{"current2", "robot2Current", "i2", "I2"});
  31. ARC_PARAM_ALIASES.put("voltage", new String[]{"voltage", "voltage1", "voltage2", "robot1Voltage", "robot2Voltage", "v1", "v2", "V1", "V2"});
  32. ARC_PARAM_ALIASES.put("voltage1", new String[]{"voltage1", "robot1Voltage", "v1", "V1"});
  33. ARC_PARAM_ALIASES.put("voltage2", new String[]{"voltage2", "robot2Voltage", "v2", "V2"});
  34. ARC_PARAM_ALIASES.put("speed", new String[]{"speed", "speed1", "speed2", "wireSpeed", "wireFeedSpeed", "sendWireSpeed", "robot1Speed", "robot2Speed", "feedSpeed"});
  35. ARC_PARAM_ALIASES.put("speed1", new String[]{"speed1", "robot1Speed", "wireSpeed", "wireFeedSpeed", "sendWireSpeed"});
  36. ARC_PARAM_ALIASES.put("speed2", new String[]{"speed2", "robot2Speed", "wireSpeed", "wireFeedSpeed", "sendWireSpeed"});
  37. }
  38. @Autowired
  39. private MesProcessParamLimitService mesProcessParamLimitService;
  40. public void markQm(List<MesProductQm> list, String qmCategory) {
  41. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  42. if (list == null || list.isEmpty()) {
  43. return;
  44. }
  45. String processKey = normalizeProcessKey(qmCategory);
  46. for (MesProductQm row : list) {
  47. row.setLimitFlag(checkBeanRow(row, limitMap.get(processKey)) ? "1" : "0");
  48. }
  49. }
  50. public void markProd(List<MesProductProd> list) {
  51. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  52. if (list == null || list.isEmpty()) {
  53. return;
  54. }
  55. for (MesProductProd row : list) {
  56. row.setLimitFlag(checkBeanRow(row, limitMap.get("prod")) ? "1" : "0");
  57. }
  58. }
  59. public void markWelder(List<MesWelderParamRecord> list) {
  60. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  61. if (list == null || list.isEmpty()) {
  62. return;
  63. }
  64. for (MesWelderParamRecord row : list) {
  65. row.setLimitFlag(checkBeanRow(row, limitMap.get("welder")) ? "1" : "0");
  66. }
  67. }
  68. public void markArc(List<MesProductArcWelding> list, String weldingCategory) {
  69. markArc(list, weldingCategory, null);
  70. }
  71. public void markArc(List<MesProductArcWelding> list, String weldingCategory, String processName) {
  72. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  73. if (list == null || list.isEmpty()) {
  74. return;
  75. }
  76. for (MesProductArcWelding row : list) {
  77. String processKey = resolveArcProcessKey(row, weldingCategory, processName);
  78. row.setLimitFlag(checkArcRow(row, limitMap.get(processKey)) ? "1" : "0");
  79. }
  80. }
  81. public void markCmt(List<MesProductCmt> list) {
  82. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  83. if (list == null || list.isEmpty()) {
  84. return;
  85. }
  86. List<NormalizedLimit> limits = limitMap.get("arc115");
  87. for (MesProductCmt row : list) {
  88. row.setLimitFlag(checkArcContent(row == null ? null : row.getContent(), limits) ? "1" : "0");
  89. }
  90. }
  91. public List<ArcLimitRule> findArcLimitRules(MesProductArcWelding row, String weldingCategory) {
  92. return findArcLimitRules(row, weldingCategory, null);
  93. }
  94. public List<ArcLimitRule> findArcLimitRules(MesProductArcWelding row, String weldingCategory, String processName) {
  95. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  96. List<NormalizedLimit> limits = limitMap.get(resolveArcProcessKey(row, weldingCategory, processName));
  97. return toArcLimitRules(limits);
  98. }
  99. public List<ArcLimitRule> findCmtLimitRules() {
  100. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  101. return toArcLimitRules(limitMap.get("arc115"));
  102. }
  103. private List<ArcLimitRule> toArcLimitRules(List<NormalizedLimit> limits) {
  104. List<ArcLimitRule> result = new ArrayList<>();
  105. if (limits == null || limits.isEmpty()) {
  106. return result;
  107. }
  108. for (NormalizedLimit limit : limits) {
  109. result.add(new ArcLimitRule(limit.paramCode, limit.lowerLimit, limit.upperLimit));
  110. }
  111. return result;
  112. }
  113. public boolean checkArcRecord(MesProductArcWelding row, String weldingCategory) {
  114. return checkArcRecord(row, weldingCategory, null);
  115. }
  116. public boolean checkArcRecord(MesProductArcWelding row, String weldingCategory, String processName) {
  117. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  118. return checkArcRow(row, limitMap.get(resolveArcProcessKey(row, weldingCategory, processName)));
  119. }
  120. public boolean checkCmtRecord(MesProductCmt row) {
  121. Map<String, List<NormalizedLimit>> limitMap = loadLimitMap();
  122. return checkArcContent(row == null ? null : row.getContent(), limitMap.get("arc115"));
  123. }
  124. private Map<String, List<NormalizedLimit>> loadLimitMap() {
  125. Map<String, List<NormalizedLimit>> map = new HashMap<>();
  126. for (MesProcessParamLimit limit : mesProcessParamLimitService.findEnabledList()) {
  127. String processKey = normalizeProcessKey(StringUtils.defaultString(limit.getProcessKey(), limit.getProcessName()));
  128. String paramCode = normalizeParamCode(StringUtils.defaultString(limit.getParamCode(), limit.getParamName()));
  129. if (StringUtils.isBlank(processKey) || StringUtils.isBlank(paramCode)) {
  130. continue;
  131. }
  132. NormalizedLimit normalized = new NormalizedLimit(processKey, paramCode, limit.getLowerLimit(), limit.getUpperLimit());
  133. map.computeIfAbsent(processKey, k -> new ArrayList<>()).add(normalized);
  134. }
  135. return map;
  136. }
  137. private boolean checkBeanRow(Object row, List<NormalizedLimit> limits) {
  138. if (row == null || limits == null || limits.isEmpty()) {
  139. return false;
  140. }
  141. BeanWrapperImpl wrapper = new BeanWrapperImpl(row);
  142. for (NormalizedLimit limit : limits) {
  143. if (!wrapper.isReadableProperty(limit.paramCode)) {
  144. continue;
  145. }
  146. Object value = wrapper.getPropertyValue(limit.paramCode);
  147. if (isOutOfRange(value, limit)) {
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. private boolean checkArcRow(MesProductArcWelding row, List<NormalizedLimit> limits) {
  154. return checkArcContent(row == null ? null : row.getContent(), limits);
  155. }
  156. private boolean checkArcContent(String content, List<NormalizedLimit> limits) {
  157. if (limits == null || limits.isEmpty() || StringUtils.isBlank(content)) {
  158. return false;
  159. }
  160. for (JSONObject sample : parseArcSamples(content)) {
  161. for (NormalizedLimit limit : limits) {
  162. for (String value : readArcValues(sample, limit.paramCode)) {
  163. if (isOutOfRange(value, limit)) {
  164. return true;
  165. }
  166. }
  167. }
  168. }
  169. return false;
  170. }
  171. private List<JSONObject> parseArcSamples(String content) {
  172. List<JSONObject> result = new ArrayList<>();
  173. try {
  174. String text = StringUtils.trim(content);
  175. if (StringUtils.isBlank(text)) {
  176. return result;
  177. }
  178. if (text.startsWith("{")) {
  179. JSONObject root = JSONObject.parseObject(text);
  180. JSONArray samples = root == null ? null : root.getJSONArray("samples");
  181. if (samples != null) {
  182. for (int i = 0; i < samples.size(); i++) {
  183. JSONObject sample = samples.getJSONObject(i);
  184. if (sample != null) {
  185. result.add(sample);
  186. }
  187. }
  188. }
  189. return result;
  190. }
  191. if (text.startsWith("[")) {
  192. JSONArray arr = JSONArray.parseArray(text);
  193. if (arr != null) {
  194. for (int i = 0; i < arr.size(); i++) {
  195. String record = arr.getString(i);
  196. appendOldArcRecord(record, result);
  197. }
  198. }
  199. return result;
  200. }
  201. appendOldArcRecord(text, result);
  202. return result;
  203. } catch (Exception ex) {
  204. return result;
  205. }
  206. }
  207. private void appendOldArcRecord(String record, List<JSONObject> result) {
  208. if (StringUtils.isBlank(record)) {
  209. return;
  210. }
  211. String valueText = StringUtils.trim(record);
  212. if (valueText.startsWith("\"") && valueText.endsWith("\"") && valueText.length() > 1) {
  213. valueText = StringUtils.trim(valueText.substring(1, valueText.length() - 1));
  214. }
  215. if (StringUtils.isBlank(valueText)) {
  216. return;
  217. }
  218. String[] values = valueText.split("\\|");
  219. if (values.length < 3) {
  220. return;
  221. }
  222. JSONObject sample = new JSONObject();
  223. for (int i = 0; i < values.length; i++) {
  224. sample.put("v" + i, values[i]);
  225. }
  226. if (values.length >= 11) {
  227. sample.put("robot1Voltage", values[0]);
  228. sample.put("robot1Current", values[1]);
  229. sample.put("robot1Speed", values[2]);
  230. sample.put("robot2Voltage", values[5]);
  231. sample.put("robot2Current", values[6]);
  232. sample.put("robot2Speed", values[7]);
  233. sample.put("time", values[values.length - 1]);
  234. }
  235. result.add(sample);
  236. }
  237. private List<String> readArcValues(JSONObject sample, String paramCode) {
  238. List<String> values = new ArrayList<>();
  239. String[] aliases = ARC_PARAM_ALIASES.get(paramCode);
  240. if (aliases == null || aliases.length == 0) {
  241. String value = sample.getString(paramCode);
  242. if (StringUtils.isNotBlank(StringUtils.trim(value))) {
  243. values.add(value.toString());
  244. }
  245. return values;
  246. }
  247. for (String alias : aliases) {
  248. Object value = sample.get(alias);
  249. if (value != null && StringUtils.isNotBlank(StringUtils.trim(value.toString()))) {
  250. String text = value.toString();
  251. if (!values.contains(text)) {
  252. values.add(text);
  253. }
  254. }
  255. }
  256. return values;
  257. }
  258. private boolean isOutOfRange(Object value, NormalizedLimit limit) {
  259. if (value == null || limit == null) {
  260. return false;
  261. }
  262. return isOutOfRange(value.toString(), limit);
  263. }
  264. private boolean isOutOfRange(String value, NormalizedLimit limit) {
  265. if (StringUtils.isBlank(value) || limit == null) {
  266. return false;
  267. }
  268. BigDecimal actual;
  269. try {
  270. actual = new BigDecimal(normalizeNumberText(value));
  271. } catch (Exception ex) {
  272. return false;
  273. }
  274. BigDecimal lower = parseDecimal(limit.lowerLimit);
  275. BigDecimal upper = parseDecimal(limit.upperLimit);
  276. if (lower != null && upper != null && lower.compareTo(upper) > 0) {
  277. BigDecimal tmp = lower;
  278. lower = upper;
  279. upper = tmp;
  280. }
  281. if (lower != null && actual.compareTo(lower) < 0) {
  282. return true;
  283. }
  284. return upper != null && actual.compareTo(upper) > 0;
  285. }
  286. private BigDecimal parseDecimal(String value) {
  287. if (StringUtils.isBlank(value)) {
  288. return null;
  289. }
  290. try {
  291. return new BigDecimal(normalizeNumberText(value));
  292. } catch (Exception ex) {
  293. return null;
  294. }
  295. }
  296. private String normalizeNumberText(String value) {
  297. if (value == null) {
  298. return null;
  299. }
  300. String text = StringUtils.trim(value);
  301. if (StringUtils.isBlank(text)) {
  302. return text;
  303. }
  304. return text.replace('\u2212', '-') // minus sign
  305. .replace('\u2013', '-') // en dash
  306. .replace('\u2014', '-') // em dash
  307. .replace('\uFF0D', '-') // full-width hyphen-minus
  308. .replace('\uFE63', '-') // small hyphen-minus
  309. .replace('\uFF0B', '+') // full-width plus
  310. .replace(" ", "");
  311. }
  312. private String resolveArcProcessKey(MesProductArcWelding row, String weldingCategory) {
  313. return resolveArcProcessKey(row, weldingCategory, null);
  314. }
  315. private String resolveArcProcessKey(MesProductArcWelding row, String weldingCategory, String processName) {
  316. String category = normalizeProcessKey(processName);
  317. if (!isArcProcessKey(category)) {
  318. category = "";
  319. }
  320. if (StringUtils.isBlank(category)) {
  321. category = normalizeProcessKey(weldingCategory);
  322. }
  323. if (StringUtils.isBlank(category) && row != null) {
  324. category = normalizeProcessKey(row.getWeldingCategory());
  325. }
  326. if (StringUtils.isBlank(category)) {
  327. return "arc";
  328. }
  329. if ("arc".equals(category)) {
  330. return "arcHev";
  331. }
  332. if ("spot".equals(category)) {
  333. return "spotHev";
  334. }
  335. return category;
  336. }
  337. private boolean isArcProcessKey(String processKey) {
  338. return "arc115".equals(processKey) || "arcHev".equals(processKey)
  339. || "spot115".equals(processKey) || "spotHev".equals(processKey)
  340. || "arc".equals(processKey) || "spot".equals(processKey);
  341. }
  342. private String normalizeProcessKey(String value) {
  343. if (StringUtils.isBlank(value)) {
  344. return "";
  345. }
  346. String text = StringUtils.trim(value);
  347. if ("whitePart".equalsIgnoreCase(text) || "白件气密".equals(text)) {
  348. return "whitePart";
  349. }
  350. if ("assembly".equalsIgnoreCase(text) || "总成气密".equals(text)) {
  351. return "assembly";
  352. }
  353. if ("prod".equalsIgnoreCase(text) || "拉铆".equals(text)) {
  354. return "prod";
  355. }
  356. if ("welder".equalsIgnoreCase(text) || "凸焊".equals(text)) {
  357. return "welder";
  358. }
  359. if ("arc115".equalsIgnoreCase(text) || "115弧焊".equals(text) || "115弧焊参数".equals(text)) {
  360. return "arc115";
  361. }
  362. if ("arcHev".equalsIgnoreCase(text) || "HEV弧焊".equalsIgnoreCase(text) || "HEV弧焊参数".equals(text)) {
  363. return "arcHev";
  364. }
  365. if ("spot115".equalsIgnoreCase(text) || "115点焊".equals(text) || "115点焊参数".equals(text)) {
  366. return "spot115";
  367. }
  368. if ("spotHev".equalsIgnoreCase(text) || "HEV点焊".equalsIgnoreCase(text) || "HEV点焊参数".equals(text)) {
  369. return "spotHev";
  370. }
  371. if ("spot".equalsIgnoreCase(text)) {
  372. return "spot";
  373. }
  374. if ("arc".equalsIgnoreCase(text)) {
  375. return "arc";
  376. }
  377. return text;
  378. }
  379. private String normalizeParamCode(String value) {
  380. if (StringUtils.isBlank(value)) {
  381. return "";
  382. }
  383. String text = StringUtils.trim(value);
  384. if ("current1".equalsIgnoreCase(text) || "电流1".equals(text)) {
  385. return "current1";
  386. }
  387. if ("current2".equalsIgnoreCase(text) || "电流2".equals(text)) {
  388. return "current2";
  389. }
  390. if ("voltage1".equalsIgnoreCase(text) || "电压1".equals(text)) {
  391. return "voltage1";
  392. }
  393. if ("voltage2".equalsIgnoreCase(text) || "电压2".equals(text)) {
  394. return "voltage2";
  395. }
  396. if ("speed1".equalsIgnoreCase(text) || "送丝速度1".equals(text)) {
  397. return "speed1";
  398. }
  399. if ("speed2".equalsIgnoreCase(text) || "送丝速度2".equals(text)) {
  400. return "speed2";
  401. }
  402. if ("testPressure".equalsIgnoreCase(text) || "测试压".equals(text)) {
  403. return "testPressure";
  404. }
  405. if ("leakVal".equalsIgnoreCase(text) || "泄漏值".equals(text)) {
  406. return "leakVal";
  407. }
  408. if ("fout".equalsIgnoreCase(text) || "拉力".equals(text)) {
  409. return "fout";
  410. }
  411. if ("sout".equalsIgnoreCase(text) || "行程".equals(text)) {
  412. return "sout";
  413. }
  414. if ("current".equalsIgnoreCase(text) || "电流".equals(text)) {
  415. return "current";
  416. }
  417. if ("voltage".equalsIgnoreCase(text) || "电压".equals(text)) {
  418. return "voltage";
  419. }
  420. if ("speed".equalsIgnoreCase(text) || "送丝速度".equals(text)) {
  421. return "speed";
  422. }
  423. if ("capVoltage".equalsIgnoreCase(text) || "电容电压".equals(text)) {
  424. return "capVoltage";
  425. }
  426. if ("weldPeakCurrent".equalsIgnoreCase(text) || "焊接峰值电流".equals(text)) {
  427. return "weldPeakCurrent";
  428. }
  429. return text;
  430. }
  431. private static class NormalizedLimit {
  432. private final String processKey;
  433. private final String paramCode;
  434. private final String lowerLimit;
  435. private final String upperLimit;
  436. private NormalizedLimit(String processKey, String paramCode, String lowerLimit, String upperLimit) {
  437. this.processKey = processKey;
  438. this.paramCode = paramCode;
  439. this.lowerLimit = lowerLimit;
  440. this.upperLimit = upperLimit;
  441. }
  442. }
  443. public static class ArcLimitRule {
  444. private final String paramCode;
  445. private final String lowerLimit;
  446. private final String upperLimit;
  447. public ArcLimitRule(String paramCode, String lowerLimit, String upperLimit) {
  448. this.paramCode = paramCode;
  449. this.lowerLimit = lowerLimit;
  450. this.upperLimit = upperLimit;
  451. }
  452. public String getParamCode() {
  453. return paramCode;
  454. }
  455. public String getLowerLimit() {
  456. return lowerLimit;
  457. }
  458. public String getUpperLimit() {
  459. return upperLimit;
  460. }
  461. }
  462. }