You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
14 KiB

2 months ago
​
​
​
​
​
​
1 month ago
​
​
2 months ago
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
2 months ago
​
​
​
1 month ago
2 months ago
​
​
​
1 month ago
2 months ago
2 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
2 months ago
2 months ago
2 months ago
​
​
​
​
​
​
1 month ago
2 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
2 months ago
​
1 month ago
2 months ago
​
1 month ago
​
​
​
​
​
​
2 months ago
2 months ago
2 months ago
2 months ago
1 month ago
2 months ago
​
2 months ago
​
​
​
1 month ago
2 months ago
​
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
1 month ago
1 month ago
1 month ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
2 months ago
​
​
​
​
​
​
​
2 months ago
​
2 months ago
2 months ago
​
​
​
​
2 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
2 months ago
​
2 months ago
2 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
1 month ago
​
​
​
​
​
​
​
2 months ago
​
​
​
​
​
​
​
​
2 months ago
2 months ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. package com.gaotao.modules.autoWareHourceHaian.staticData;
  2. import org.springframework.util.StringUtils;
  3. import java.util.Arrays;
  4. import java.util.Collections;
  5. import java.util.List;
  6. import java.util.LinkedHashMap;
  7. import java.util.Locale;
  8. import java.util.Map;
  9. /**
  10. * @author rqrq
  11. * @Description 海安物理站点/点位写死值:入库口、整托出库口、缓冲线、分拣位、异常位。PDA/回调认点位一律走本类,禁止业务侧再写站点字面量;WCS 回调 toBarcode 与业务站点同名,禁止数字码转 D1/D2。已确认入库口、整托出库口;其余立库站点实际编码待确认。 - rqrq
  12. */
  13. public final class HaiAnStationStaticData {
  14. private HaiAnStationStaticData() {
  15. }
  16. /**
  17. * 海安唯一入库口。空托盘通知入库、直接组盘下发 WCS assemblyPosition 固定用此值,禁止再拆入库口1/2。 - rqrq
  18. */
  19. public static final String INBOUND_PORT = "ST-INO1";
  20. /**
  21. * 主动叫料固定站点:Call料、合托、盘点拉板下发 WCS targetPosition。已确认为整托出库口,与普通出库口不是同一点。 - rqrq
  22. */
  23. public static final String DIRECT_OUTBOUND_PORT = "ST-FO-01";
  24. /**
  25. * 普通出库口站点名。主动叫料本阶段不用;WCS「到达出库口」回传点位可能是此值,按回传原样落托盘。待确认站点实际编码。 - rqrq
  26. */
  27. public static final String NORMAL_OUTBOUND_PORT = "ST-OUTO1";
  28. /**
  29. * 立库内允许人工移出/作为地面运输端点的三个口;区域均为A01,不包含货架、输送线、异常位或分拣位。 - rqrq
  30. */
  31. public static final List<String> WAREHOUSE_PORT_STATIONS = Collections.unmodifiableList(
  32. Arrays.asList(INBOUND_PORT, NORMAL_OUTBOUND_PORT, DIRECT_OUTBOUND_PORT)
  33. );
  34. /**
  35. * 判断站点是否为入库口,去首尾空格后比较;空值返回否,不使用区域编码替代站点身份。 - rqrq
  36. */
  37. public static boolean isInboundPort(String stationCode) {
  38. return stationCode != null && INBOUND_PORT.equalsIgnoreCase(stationCode.trim());
  39. }
  40. /**
  41. * 判断站点是否为普通出库口,空值返回否;与整托出库口分别识别以保留原出口分工。 - rqrq
  42. */
  43. public static boolean isNormalOutboundPort(String stationCode) {
  44. return stationCode != null && NORMAL_OUTBOUND_PORT.equalsIgnoreCase(stationCode.trim());
  45. }
  46. /**
  47. * 判断站点是否为整托出库口,空值返回否;Call料、合托、盘点仍以此站点作为固定出口。 - rqrq
  48. */
  49. public static boolean isDirectOutboundPort(String stationCode) {
  50. return stationCode != null && DIRECT_OUTBOUND_PORT.equalsIgnoreCase(stationCode.trim());
  51. }
  52. /**
  53. * 判断三个立库端口的站点集合;用于区域归一、地面权限及目标过滤,未知或空站点一律不放行。 - rqrq
  54. */
  55. public static boolean isWarehousePortStation(String stationCode) {
  56. // 调用同一站点白名单匹配,避免扫描、下发和回调各自维护不同的端口规则 - rqrq
  57. return containsIgnoreCase(WAREHOUSE_PORT_STATIONS, stationCode);
  58. }
  59. /**
  60. * 立库缓冲输送线站点。离开入库口、出货架都把 location_code 写成此值;禁止取消组盘/一键移出的判定之一。老模块写入 Virtual_AS,海安写入本常量,识别时两者都算输送线。待确认站点实际编码。 - rqrq
  61. */
  62. public static final String BUFFER_CONVEYOR = "立库输送线";
  63. /**
  64. * 异常位白名单。到达异常位必须命中本数组才落托盘位置,禁止写死单一编码;1101 仅兼容历史托盘。待确认站点实际编码。 - rqrq
  65. */
  66. public static final List<String> ERROR_STATIONS = Collections.unmodifiableList(
  67. Arrays.asList("EXCP-01", "EXCP-02", "EXCP-03", "EXCP-04")
  68. );
  69. /**
  70. * 地面点位清单只拉空闲点时传给立库的 status。组盘/换站选点必须用此值,避免拉到占用点。 - rqrq
  71. */
  72. public static final String GROUND_LOCATION_IDLE = "IDLE";
  73. /**
  74. * 地面点占用状态同步:移入站点 type=1。人工绑站成功后必须调 update-ground-location-status。 - rqrq
  75. */
  76. public static final Integer GROUND_LOCATION_BIND = 1;
  77. /**
  78. * 地面点占用状态同步:移出站点 type=2。人工解绑成功后必须调 update-ground-location-status。 - rqrq
  79. */
  80. public static final Integer GROUND_LOCATION_REMOVE = 2;
  81. /**
  82. * 自动分拣组盘位白名单,仅 ST-RP-03/ST-RP-04 两个位置;pickingFeedback 命中记“自动分拣”,不包含自动被分拣源盘位和人工分拣位。 - rqrq
  83. */
  84. public static final List<String> AUTO_SORT_STATIONS = Collections.unmodifiableList(
  85. Arrays.asList("ST-RP-03", "ST-RP-04")
  86. );
  87. /**
  88. * 自动被分拣源盘位白名单,仅 ST-RP-01/ST-RP-02 两个位置;用于识别自动分拣来源托盘,不并入人工被分拣白名单,避免放行 PDA 人工放回及回库操作。 - rqrq
  89. */
  90. public static final List<String> AUTO_SORTED_SOURCE_STATIONS = Collections.unmodifiableList(
  91. Arrays.asList("ST-RP-01", "ST-RP-02")
  92. );
  93. /**
  94. * 手工分拣区站点白名单。原有人工分拣组盘工作盘点位,R1 属于本组,不是被分拣位。分拣页按工作盘逻辑:卡清单、扫回还原原托盘、无增量跳过、endFlag=N。 - rqrq
  95. */
  96. public static final List<String> MANUAL_SORT_STATIONS = Collections.unmodifiableList(
  97. Arrays.asList("ST-MP-05", "ST-MP-06", "ST-MP-07", "ST-MP-08")
  98. );
  99. /**
  100. * 海安新增被分拣源盘站点白名单。老模块没有这个站点概念,禁止复用手工分拣 R1–R4。分拣页命中后按放回标签/通知回库处理。站点实际编码待现场确认后只改本数组。 - rqrq
  101. */
  102. public static final List<String> SORTED_SOURCE_STATIONS = Collections.unmodifiableList(
  103. Arrays.asList("ST-MP-01", "ST-MP-02", "ST-MP-03", "ST-MP-04")
  104. );
  105. /** 工作位到被分拣源盘位的一对一映射,仅用于清单查询和看板归属,不修改托盘位置或作业权限。 - rqrq */
  106. private static final Map<String, String> SORTING_SOURCE_BY_WORK;
  107. /** 历史看板编号到实际工作位映射,仅供看板入口与旧订阅兼容,不作为PDA站点白名单。 - rqrq */
  108. private static final Map<String, String> BOARD_WORK_BY_ALIAS;
  109. static {
  110. // 显式登记六组现场配对,禁止依赖数组顺序或数字偏移生成业务关系 - rqrq
  111. Map<String, String> sources = new LinkedHashMap<>();
  112. sources.put("ST-MP-05", "ST-MP-01");
  113. sources.put("ST-MP-06", "ST-MP-02");
  114. sources.put("ST-MP-07", "ST-MP-03");
  115. sources.put("ST-MP-08", "ST-MP-04");
  116. sources.put("ST-RP-03", "ST-RP-01");
  117. sources.put("ST-RP-04", "ST-RP-02");
  118. SORTING_SOURCE_BY_WORK = Collections.unmodifiableMap(sources);
  119. Map<String, String> aliases = new LinkedHashMap<>();
  120. aliases.put("R1H", "ST-MP-05");
  121. aliases.put("R2H", "ST-MP-06");
  122. aliases.put("R3H", "ST-MP-07");
  123. aliases.put("R4H", "ST-MP-08");
  124. aliases.put("J1H", "ST-RP-03");
  125. aliases.put("J2H", "ST-RP-04");
  126. BOARD_WORK_BY_ALIAS = Collections.unmodifiableMap(aliases);
  127. }
  128. /** 按实际托盘站点取得WCS查询源盘位;已是源盘位则原样返回,空值/未知站点抛错阻止错误外呼。 - rqrq */
  129. public static String requireSortingSourceStation(String stationCode) {
  130. String station = stationCode == null ? "" : stationCode.trim().toUpperCase(Locale.ROOT);
  131. String source = SORTING_SOURCE_BY_WORK.get(station);
  132. if (source != null) {
  133. return source;
  134. }
  135. if (SORTING_SOURCE_BY_WORK.containsValue(station)) {
  136. return station;
  137. }
  138. throw new IllegalArgumentException("站点未配置分拣源盘对应关系:" + station);
  139. }
  140. /** WCS返回工作位归属看板;兼容源盘位回传并反查工作位,未知站点返回空串,由看板跳过非本组六屏数据。 - rqrq */
  141. public static String resolveSortingWorkStation(String stationCode) {
  142. String station = stationCode == null ? "" : stationCode.trim().toUpperCase(Locale.ROOT);
  143. // 当前WCS返回分拣工作位,工作位本身就是看板身份;保留源盘位反查兼容旧报文 - rqrq
  144. if (SORTING_SOURCE_BY_WORK.containsKey(station)) {
  145. return station;
  146. }
  147. for (Map.Entry<String, String> entry : SORTING_SOURCE_BY_WORK.entrySet()) {
  148. if (entry.getValue().equals(station)) {
  149. return entry.getKey();
  150. }
  151. }
  152. return "";
  153. }
  154. /** 看板请求工作位归一,兼容R1H–R4H/J1H/J2H;被分拣位、空值和未知编码拒绝,避免串屏。 - rqrq */
  155. public static String requireSortingBoardWorkStation(String stationCode) {
  156. String station = stationCode == null ? "" : stationCode.trim().toUpperCase(Locale.ROOT);
  157. String work = BOARD_WORK_BY_ALIAS.get(station);
  158. if (work != null) {
  159. return work;
  160. }
  161. if (SORTING_SOURCE_BY_WORK.containsKey(station)) {
  162. return station;
  163. }
  164. throw new IllegalArgumentException("不支持的海安看板分拣位:" + station);
  165. }
  166. /** 按工作位取得历史看板别名供兼容主题推送,未知编码返回空串表示无需额外推送。 - rqrq */
  167. public static String resolveSortingBoardAlias(String workStation) {
  168. for (Map.Entry<String, String> entry : BOARD_WORK_BY_ALIAS.entrySet()) {
  169. if (entry.getValue().equalsIgnoreCase(workStation)) {
  170. return entry.getKey();
  171. }
  172. }
  173. return "";
  174. }
  175. /**
  176. * @author rqrq
  177. * @Description 判断当前站点是否为手工分拣区:命中 R1–R4 才算,空值否。用于和被分拣位区分,禁止把手工分拣站当成被分拣源盘。 - rqrq
  178. */
  179. public static boolean isManualSortStation(String locationCode) {
  180. return containsIgnoreCase(MANUAL_SORT_STATIONS, locationCode);
  181. }
  182. /**
  183. * @author rqrq
  184. * @Description 判断当前站点是否为海安被分拣源盘点:只对照 SORTED_SOURCE_STATIONS,空值否;忽略大小写。未配置站点时一律否,避免把 R1 手工分拣区误判成被分拣。 - rqrq
  185. */
  186. public static boolean isSortedSourceStation(String locationCode) {
  187. return containsIgnoreCase(SORTED_SOURCE_STATIONS, locationCode);
  188. }
  189. /**
  190. * @author rqrq
  191. * @Description 判断当前点位是否属于分拣作业站:手工分拣区或海安被分拣站都算。组盘入库/手工组盘必须拦截这类栈板,禁止和分拣页共用放行逻辑。 - rqrq
  192. */
  193. public static boolean isSortingOperateStation(String locationCode) {
  194. return isManualSortStation(locationCode) || isSortedSourceStation(locationCode);
  195. }
  196. /**
  197. * @author rqrq
  198. * @Description 返回分拣作业站中文角色,供组盘页拦截提示区分手工分拣区与被分拣站;未命中返回空串。 - rqrq
  199. */
  200. public static String describeSortingOperateStation(String locationCode) {
  201. if (isManualSortStation(locationCode)) {
  202. return "手工分拣区";
  203. }
  204. if (isSortedSourceStation(locationCode)) {
  205. return "被分拣站";
  206. }
  207. return "";
  208. }
  209. /**
  210. * @author rqrq
  211. * @Description 判断当前站点是否为异常位:命中 ERROR_STATIONS 才算,空值否。用于取消预定拦截与到达异常位校验。 - rqrq
  212. */
  213. public static boolean isErrorStation(String locationCode) {
  214. return containsIgnoreCase(ERROR_STATIONS, locationCode);
  215. }
  216. /**
  217. * @author rqrq
  218. * @Description 校验到达异常位回传点位必须落在异常位数组内,非法则抛错避免把非异常口写成异常落位。 - rqrq
  219. */
  220. public static String requireErrorStation(String stationCode) {
  221. if (!isErrorStation(stationCode)) {
  222. throw new RuntimeException("到达异常位点位非法,不在异常位清单内:" + (stationCode == null ? "" : stationCode.trim()));
  223. }
  224. return stationCode.trim();
  225. }
  226. /**
  227. * @author rqrq
  228. * @Description 判断当前点位是否为自动分拣组盘位,供 pickingFeedback 动作类型分流。 - rqrq
  229. */
  230. public static boolean isAutoSortStation(String assemblyPosition) {
  231. return containsIgnoreCase(AUTO_SORT_STATIONS, assemblyPosition);
  232. }
  233. /**
  234. * 判断业务站点是否为自动被分拣源盘位;输入站点编码去首尾空格并忽略大小写,空值或未知站点返回否,不授予 PDA 人工分拣权限。 - rqrq
  235. */
  236. public static boolean isAutoSortedSourceStation(String locationCode) {
  237. // 调用自动被分拣专用白名单匹配,未命中返回否,避免与自动组盘位或人工被分拣位混淆 - rqrq
  238. return containsIgnoreCase(AUTO_SORTED_SOURCE_STATIONS, locationCode);
  239. }
  240. /**
  241. * @author rqrq
  242. * @Description 判断托盘是否位于输送线:Virtual_AS 或立库输送线都视为输送线态。 - rqrq
  243. */
  244. public static boolean isConveyorStation(String locationCode) {
  245. if (!StringUtils.hasText(locationCode)) {
  246. return false;
  247. }
  248. String normalized = locationCode.trim();
  249. return BUFFER_CONVEYOR.equals(normalized);
  250. }
  251. /**
  252. * @author rqrq
  253. * @Description 白名单忽略大小写匹配,空值直接否。 - rqrq
  254. */
  255. private static boolean containsIgnoreCase(List<String> stations, String value) {
  256. if (!StringUtils.hasText(value) || stations == null) {
  257. return false;
  258. }
  259. String normalized = value.trim();
  260. for (String station : stations) {
  261. if (station.equalsIgnoreCase(normalized)) {
  262. return true;
  263. }
  264. }
  265. return false;
  266. }
  267. }