MesClient.java 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256
  1. package com.mes.ui;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
  4. import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
  5. import com.mes.component.MesRadio;
  6. import com.mes.component.MesWebView;
  7. import com.mes.netty.NettyClient;
  8. import com.mes.netty.ProtocolParam;
  9. import com.mes.util.*;
  10. import javafx.embed.swing.JFXPanel;
  11. import org.slf4j.Logger;
  12. import org.slf4j.LoggerFactory;
  13. import javax.swing.*;
  14. import javax.swing.border.EmptyBorder;
  15. import javax.swing.event.ChangeEvent;
  16. import javax.swing.event.ChangeListener;
  17. import java.awt.*;
  18. import java.awt.event.ActionEvent;
  19. import java.awt.event.ActionListener;
  20. import java.awt.event.MouseAdapter;
  21. import java.awt.event.MouseEvent;
  22. import java.io.*;
  23. import java.lang.reflect.Field;
  24. import java.nio.channels.FileChannel;
  25. import java.nio.channels.FileLock;
  26. import java.nio.channels.OverlappingFileLockException;
  27. import java.sql.ResultSet;
  28. import java.sql.SQLException;
  29. import java.sql.Statement;
  30. import java.time.LocalDateTime;
  31. import java.util.*;
  32. import java.util.List;
  33. import java.util.Timer;
  34. import java.util.concurrent.ExecutorService;
  35. import java.util.concurrent.Executors;
  36. import java.util.concurrent.ScheduledExecutorService;
  37. import java.util.concurrent.ScheduledFuture;
  38. import java.util.concurrent.TimeUnit;
  39. import java.util.regex.Matcher;
  40. import java.util.regex.Pattern;
  41. public class MesClient extends JFrame {
  42. public static final Logger log = LoggerFactory.getLogger(MesClient.class);
  43. public static int mes_auth = 0; // 权限级别 0=无权限 1=操作工人 2=管理员
  44. public static String mes_gw = ""; // 工位号
  45. public static String mes_gw_des = ""; // 工位名称
  46. public static String mes_server_ip = ""; // 服务器IP地址
  47. public static int mes_tcp_port = 3000; // TCP服务端口
  48. public static int mes_heart_beat_cycle = 10; // 心跳周期
  49. public static int mes_heart_icon_cycle = 1;
  50. public static String mes_line_sn = ""; // 产线编号
  51. //TCP连接
  52. public static NettyClient nettyClient;
  53. //TCP连接状态
  54. public static boolean tcp_connect_flag = false;
  55. //TCP连接请求
  56. public static boolean connect_request_flag = false;
  57. //session
  58. public static String sessionid = "";
  59. public static JPanel contentPane;
  60. public static MesClient mesClientFrame;
  61. public static JTabbedPane tabbedPane;
  62. public static JScrollPane indexScrollPaneA;
  63. public static JScrollPane searchScrollPane;
  64. public static JScrollPane searchScrollPaneDj;
  65. public static Boolean check_quality_result = false;
  66. public static Integer work_status = 0;
  67. public static JButton heart_beat_menu;
  68. public static JButton status_menu;
  69. public static JButton user_menu;
  70. public static int scan_type = 0;
  71. public static JButton finish_ok_bt;
  72. public static JButton finish_ng_bt;
  73. public static JTextField product_sn;
  74. public static JButton f_scan_data_bt_1;
  75. public static String user20 = "";
  76. public static JFrame welcomeWin;
  77. public static JPanel indexPanelB;
  78. public static MesWebView jfxPanel = null;
  79. public static JPanel indexPanelC;
  80. public static MesWebView jfxPanel2 = null;
  81. public static MesRadio mesRadioHj;
  82. public static JTable table;
  83. public static Object[] columnNames = { "物料名称", "绑定批次", "剩余次数", "操作" };
  84. public static Object[][] rowData = null;
  85. public static JLabel fxlabel;
  86. /**
  87. * 业务字段
  88. *
  89. */
  90. // 存储工位信息的 Map:key=工位号,value=Oprno 对象
  91. public static Map<String, Oprno> oprnoMap = new HashMap<>();
  92. // 正则表达式:匹配 mes.oprno.${工位号}.${属性名}
  93. private static final Pattern OPRNO_PATTERN = Pattern.compile("mes\\.oprno\\.(\\w+)\\.(\\w+)");
  94. // 需要跳过的属性名(不读入 Map)
  95. private static final String[] SKIP_PROPERTIES = {"hgA_qr_code", "hgB_qr_code"};
  96. // 新增:存储动态生成的工位输入框(key=工位号,value=输入框)
  97. private static Map<String, JTextField> oprnoTextFieldMap = new HashMap<>();
  98. // 输入框相关配置(可调整)
  99. private static final int TEXT_FIELD_WIDTH = 602; // 输入框宽度
  100. private static final int TEXT_FIELD_HEIGHT = 50; // 输入框高度
  101. private static final int TEXT_FIELD_X = 81; // 输入框X坐标(与原有工件码输入框对齐)
  102. private static final int TEXT_FIELD_MARGIN = 20; // 输入框之间的间距
  103. private static final Font TEXT_FIELD_FONT = new Font("微软雅黑", Font.PLAIN, 22); // 输入框字体
  104. // 定时任务池
  105. private static ScheduledExecutorService schedulerPool;
  106. // 存储每个工位的定时任务,用于后续管理和取消
  107. private static Map<String, ScheduledFuture<?>> taskMap = new HashMap<>();
  108. // 定时任务执行间隔(毫秒)
  109. // 定时任务开关状态
  110. public static boolean scheduledTasksEnabled = false;
  111. private static final long TASK_INTERVAL = 1000;
  112. // 时间打印任务间隔(毫秒)
  113. private static final long TIME_PRINT_INTERVAL = 500; // 0.5秒
  114. // 时间打印任务的引用
  115. private static ScheduledFuture<?> timePrintTask = null;
  116. //点检字段
  117. public static Boolean check_info = false;
  118. public static S7PLC s7PLC = new S7PLC(EPlcType.S1200,"10.88.10.80");
  119. public static void main(String[] args) {
  120. if (LockUtil.getInstance().isAppActive() == true){
  121. // JOptionPane.showMessageDialog(null, "已有一个程序在运行,程序退出");
  122. return;
  123. }else{
  124. EventQueue.invokeLater(new Runnable() {
  125. @Override
  126. public void run() {
  127. try{
  128. //读文件配置
  129. readProperty();
  130. // 显示界面
  131. mesClientFrame = new MesClient();
  132. mesClientFrame.setVisible(false);
  133. JdbcUtils.getConn();
  134. welcomeWin = new LoginFarme();
  135. welcomeWin.setVisible(true);
  136. getMaterailData();
  137. }catch (Exception e){
  138. e.printStackTrace();
  139. }
  140. }
  141. });
  142. }
  143. }
  144. //读配置文件
  145. private static void readProperty() throws IOException{
  146. String enconding = "UTF-8";
  147. InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
  148. Properties pro = new Properties();
  149. BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
  150. pro.load(br);
  151. mes_gw = pro.getProperty("mes.gw");
  152. mes_server_ip = pro.getProperty("mes.server_ip");
  153. mes_tcp_port = Integer.parseInt(pro.getProperty("mes.tcp_port"));
  154. mes_heart_beat_cycle = Integer.parseInt(pro.getProperty("mes.heart_beat_cycle"));
  155. mes_line_sn = pro.getProperty("mes.line_sn");
  156. mes_gw_des = OprnoUtil.getGwDes(mes_line_sn,mes_gw);
  157. log.info(mes_gw + ";" + mes_gw_des + ";" + mes_server_ip + ";" + mes_tcp_port + ";" + mes_heart_beat_cycle);
  158. // 2. 读取工位信息并填充到 oprnoMap(自动跳过二维码字段)
  159. loadOprnoMap(pro);
  160. // 循环打印工位信息
  161. for (Map.Entry<String, Oprno> entry : oprnoMap.entrySet()) {
  162. Oprno oprno = entry.getValue();
  163. log.info("工位信息" + oprno.toString());
  164. }
  165. DataUtil.getCheckInfo();
  166. }
  167. // 初始化TCP
  168. public static void initTcpConnection() {
  169. try {
  170. if(nettyClient==null) {
  171. //初始化TCP连接
  172. nettyClient = new NettyClient();
  173. //TCP连接状态
  174. tcp_connect_flag = false;
  175. //设置TCP请求状态
  176. connect_request_flag = true;
  177. DataUtil.synrTcp(nettyClient,mes_gw);
  178. }
  179. } catch (Exception e) {
  180. // TODO Auto-generated catch block
  181. e.printStackTrace();
  182. }
  183. }
  184. /**
  185. * 为指定工位创建定时任务
  186. * @param oprnoCode 工位号
  187. * @param textField 对应的输入框
  188. */
  189. private void createScheduledTask(final String oprnoCode, final JTextField textField) {
  190. // 先取消可能存在的旧任务
  191. if (taskMap.containsKey(oprnoCode)) {
  192. ScheduledFuture<?> oldTask = taskMap.get(oprnoCode);
  193. if (!oldTask.isCancelled()) {
  194. oldTask.cancel(false);
  195. }
  196. }
  197. // 只有当定时任务开关开启时才创建任务
  198. if (scheduledTasksEnabled) {
  199. // 创建新的定时任务
  200. ScheduledFuture<?> task = schedulerPool.scheduleAtFixedRate(() -> {
  201. // 在每次执行前检查开关状态
  202. if (scheduledTasksEnabled) {
  203. try {
  204. // 从PLC读取数据(这里是示例,实际使用时需要根据工位号确定对应的PLC地址)
  205. String sn = S7PLCUtils.getSnInOprno(oprnoMap.get(oprnoCode), s7PLC).trim();
  206. // 使用SwingUtilities确保在事件调度线程中更新UI
  207. SwingUtilities.invokeLater(() -> {
  208. // 更新输入框内容
  209. // System.out.println(sn + "加工完成情况" + s7PLC.readBoolean(oprnoMap.get(oprnoCode).process_ok));
  210. textField.setText(sn);
  211. });
  212. // 当从对应plc中取到加工完成时执行
  213. if (s7PLC.readBoolean(oprnoMap.get(oprnoCode).process_ok)){
  214. textField.setText(oprnoCode+"加工完成");
  215. System.out.println("工位号:"+oprnoCode);
  216. System.out.println("工位dizhi:"+oprnoMap.get(oprnoCode).process_ok);
  217. System.out.println("sn:"+sn);
  218. System.out.println("加工完成:---------------"+sn);
  219. String qret = "OK";
  220. if (!S7PLCUtils.getResultInOprno(oprnoMap.get(oprnoCode),s7PLC)){
  221. qret = "NG";
  222. }
  223. System.out.println("加工结果:---------------"+qret);
  224. Boolean sendret = DataUtil.sendQualityByGW(nettyClient,sn,qret,user20,oprnoCode);
  225. if (!sendret){
  226. log.error("发送数据失败");
  227. }
  228. }
  229. } catch (Exception e) {
  230. log.error("定时任务执行异常,工位号: " + oprnoCode, e);
  231. // 在异常情况下,也在事件调度线程中更新UI显示错误信息
  232. SwingUtilities.invokeLater(() -> {
  233. textField.setText("读取错误");
  234. });
  235. }
  236. }
  237. }, 0, TASK_INTERVAL, TimeUnit.MILLISECONDS);
  238. // 保存任务引用以便后续管理
  239. taskMap.put(oprnoCode, task);
  240. } else {
  241. log.info("定时任务已关闭,未为工位 " + oprnoCode + " 创建定时任务");
  242. }
  243. }
  244. /**
  245. * 新增:动态生成工位输入框(根据 oprnoMap 的 key 数量)
  246. * @param parentPanel 父面板(indexPanelA)
  247. */
  248. private void generateOprnoTextFields(JPanel parentPanel) {
  249. // 输入框起始Y坐标(在返修件提示标签下方,避免与OK/NG按钮重叠)
  250. int startY = 80; // 整体上移,减少顶部空白空间
  251. // 标签宽度设置
  252. int labelWidth = 120;
  253. // 按钮宽度
  254. int buttonWidth = 100;
  255. // 输入框和按钮之间的间距
  256. int gapBetweenFieldAndButton = 5;
  257. // 调整后的输入框宽度(为按钮腾出空间)
  258. int adjustedTextFieldWidth = TEXT_FIELD_WIDTH - labelWidth - buttonWidth - gapBetweenFieldAndButton;
  259. // 初始化定时任务池(如果尚未初始化)
  260. if (schedulerPool == null || schedulerPool.isShutdown()) {
  261. schedulerPool = Executors.newScheduledThreadPool(oprnoMap.size());
  262. }
  263. // 创建一个子面板来容纳所有输入框和标签,便于管理和滚动
  264. JPanel textFieldsPanel = new JPanel();
  265. textFieldsPanel.setLayout(null);
  266. textFieldsPanel.setBounds(TEXT_FIELD_X, startY, TEXT_FIELD_WIDTH, 100 + oprnoMap.size() * (TEXT_FIELD_HEIGHT + TEXT_FIELD_MARGIN));
  267. textFieldsPanel.setVisible(true); // 确保工位输入框和标签面板可见
  268. // 遍历 oprnoMap,生成输入框和标签(按工位号排序)
  269. List<String> oprnoCodes = new ArrayList<>(oprnoMap.keySet());
  270. Collections.sort(oprnoCodes); // 排序,确保输入框顺序固定
  271. int fieldY = 0;
  272. for (String oprnoCode : oprnoCodes) {
  273. // 1. 创建工位号标签
  274. JLabel label = new JLabel(oprnoCode + ":");
  275. label.setFont(TEXT_FIELD_FONT); // 使用与输入框相同的字体,保持一致性
  276. label.setHorizontalAlignment(SwingConstants.RIGHT); // 右对齐,便于与输入框对齐
  277. label.setVerticalAlignment(SwingConstants.CENTER);
  278. label.setBounds(0, fieldY, labelWidth, TEXT_FIELD_HEIGHT);
  279. label.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); // 右侧添加一些边距
  280. textFieldsPanel.add(label);
  281. // 2. 创建输入框
  282. JTextField textField = new JTextField();
  283. textField.setHorizontalAlignment(SwingConstants.CENTER);
  284. textField.setEditable(false); // 设为不可编辑(与工件码输入框一致)
  285. textField.setFont(TEXT_FIELD_FONT);
  286. textField.setToolTipText("工位:" + oprnoCode); // 鼠标悬浮提示工位号
  287. // 设置输入框位置和大小(调整宽度和X坐标,为按钮腾出空间)
  288. textField.setBounds(labelWidth, fieldY, adjustedTextFieldWidth, TEXT_FIELD_HEIGHT);
  289. // 设置输入框默认文本(只显示状态信息,不包含工位号)
  290. textField.setText("");
  291. // 3. 存储输入框到Map(后续可通过工位号获取/修改输入框内容)
  292. oprnoTextFieldMap.put(oprnoCode, textField);
  293. // 4. 创建刷新按钮
  294. JButton refreshButton = new JButton("手动上料");
  295. refreshButton.setFont(new Font("SimHei", Font.PLAIN, 12));
  296. refreshButton.setBounds(labelWidth + adjustedTextFieldWidth + gapBetweenFieldAndButton, fieldY, buttonWidth, TEXT_FIELD_HEIGHT);
  297. refreshButton.setToolTipText("刷新工位:" + oprnoCode);
  298. // 5. 为按钮添加点击事件监听器
  299. final String currentOprnoCode = oprnoCode; // 必须使用final变量在匿名内部类中访问
  300. refreshButton.addActionListener(new ActionListener() {
  301. @Override
  302. public void actionPerformed(ActionEvent e) {
  303. // 获取输入框内容
  304. String inputValue = textField.getText();
  305. // 打印工位号和输入框内容
  306. System.out.println("工位号:" + currentOprnoCode + ", 输入内容:" + inputValue);
  307. s7PLC.writeBoolean(oprnoMap.get(currentOprnoCode).getMes_in(),true);
  308. }
  309. });
  310. // 6. 添加到子面板
  311. textFieldsPanel.add(textField);
  312. textFieldsPanel.add(refreshButton);
  313. // 7. 为当前工位创建定时任务
  314. createScheduledTask(oprnoCode, textField);
  315. // 8. 计算下一个输入框的Y坐标
  316. fieldY += TEXT_FIELD_HEIGHT + TEXT_FIELD_MARGIN;
  317. }
  318. // 添加子面板到父面板
  319. parentPanel.add(textFieldsPanel);
  320. // 调整父面板的首选大小,确保滚动条正常工作
  321. parentPanel.setPreferredSize(new Dimension(parentPanel.getWidth(), Math.max(700, startY + textFieldsPanel.getHeight() + 100)));
  322. log.info("动态生成 {} 个工位输入框和标签", oprnoTextFieldMap.size());
  323. }
  324. //启动心跳包程序
  325. public static java.util.Timer heartBeatTimer;
  326. public static java.util.Timer heartBeatIconTimer;
  327. public static boolean iconREDFlag = true;
  328. // 心跳程序包
  329. public static void startHeartBeatTimer() {
  330. if(heartBeatTimer!=null) {
  331. heartBeatTimer.cancel();
  332. }
  333. heartBeatTimer = new java.util.Timer();
  334. heartBeatTimer.schedule(new TimerTask() {
  335. public void run() {
  336. if(nettyClient!=null&&tcp_connect_flag) {
  337. //System.out.println("发送心跳报文");
  338. DataUtil.heartBeat(nettyClient,mes_gw);
  339. heart_beat_menu.setText(DateLocalUtils.getCurrentTime());
  340. }
  341. }
  342. }, 100,mes_heart_beat_cycle*1000);
  343. //心跳显示图标
  344. if(heartBeatIconTimer!=null) {
  345. heartBeatIconTimer.cancel();
  346. }
  347. heartBeatIconTimer = new Timer();
  348. heartBeatIconTimer.schedule(new TimerTask() {
  349. public void run() {
  350. if(tcp_connect_flag) {
  351. if(iconREDFlag) {
  352. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  353. iconREDFlag = false;
  354. }else {
  355. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  356. iconREDFlag = true;
  357. }
  358. heart_beat_menu.setText(DateLocalUtils.getCurrentTime());
  359. heart_beat_menu.repaint();
  360. }else {
  361. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  362. heart_beat_menu.setText(DateLocalUtils.getCurrentTime());
  363. heart_beat_menu.repaint();
  364. //若未连接则尝试连接
  365. if(nettyClient!=null&&!tcp_connect_flag){
  366. System.out.println("TCP已断开");
  367. //TCP重新同步连接
  368. if(!connect_request_flag) {
  369. //System.out.println("TCP重新同步连接");
  370. //设置TCP请求状态,只重新同步连接一次
  371. connect_request_flag = true;
  372. DataUtil.synrTcp(nettyClient,mes_gw);
  373. }
  374. }
  375. }
  376. }
  377. }, 100,mes_heart_icon_cycle*1000);
  378. }
  379. //设置tcp连接状态显示
  380. public static void setTcpStatus() {
  381. if(tcp_connect_flag) {
  382. status_menu.setText("已连接MES服务器");
  383. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  384. heart_beat_menu.repaint();
  385. }else {
  386. status_menu.setText("未连接MES服务器");
  387. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  388. heart_beat_menu.repaint();
  389. }
  390. }
  391. public static void initWarehouseData(){
  392. resetScanA();
  393. }
  394. public static void resetScanA() {
  395. work_status = 0;
  396. check_quality_result = false;
  397. MesClient.finish_ok_bt.setEnabled(false);
  398. MesClient.finish_ng_bt.setEnabled(false);
  399. product_sn.setText("");
  400. MesClient.fxlabel.setVisible(false);
  401. MesClient.f_scan_data_bt_1.setEnabled(true);
  402. MesClient.status_menu.setText("请扫工件码");
  403. updateMaterailData();
  404. shiftUserCheck();
  405. }
  406. public static int userLoginHours;//用户登录所处小时
  407. //换班用户信息检查
  408. private static void shiftUserCheck() {
  409. LocalDateTime now = LocalDateTime.now();
  410. // 判断时间范围
  411. if (userLoginHours >= 8 && userLoginHours < 20) {
  412. int hour = now.getHour();
  413. if (hour >= 20 || hour < 8) {
  414. logoff();
  415. }
  416. } else {
  417. int hour = now.getHour();
  418. if (hour >= 8 && hour < 20) {
  419. logoff();
  420. }
  421. }
  422. }
  423. //获取用户20位
  424. public static void getUser() {
  425. user20 = user_menu.getText().toString();
  426. String space_tmp1 = "";
  427. if(user20.length()<20) {
  428. for(int i=0;i<20-user20.length();i++) {
  429. space_tmp1 = space_tmp1 + " ";
  430. }
  431. }
  432. user20 = user20 + space_tmp1;
  433. }
  434. //获取barcode内容36位
  435. public static String getBarcode(String barcodeTmp) {
  436. String barcodeRet = barcodeTmp;
  437. if(barcodeTmp.equalsIgnoreCase("")) {
  438. return "";
  439. }else {
  440. if(barcodeTmp.length()<36) {
  441. String space = "";
  442. for(int i=0;i<36-barcodeTmp.length();i++) {
  443. space = space + " ";
  444. }
  445. barcodeRet = barcodeTmp + space;
  446. }
  447. }
  448. return barcodeRet;
  449. }
  450. public static void scanBarcode() {
  451. if(work_status == 1){
  452. JOptionPane.showMessageDialog(mesClientFrame,"工作中,勿扫码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
  453. return;
  454. }
  455. String scanBarcodeTitle = "";
  456. switch(scan_type) {
  457. case 1:
  458. product_sn.setText("");
  459. scanBarcodeTitle = "请扫工件码";
  460. break;
  461. }
  462. //弹窗扫工件码
  463. String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
  464. if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
  465. //获取用户
  466. getUser();
  467. //获取扫码内容36位
  468. String barcode36 = getBarcode(scanBarcode);//处理36为码
  469. //工位号
  470. String gw = "";
  471. switch(scan_type) {
  472. case 1:
  473. product_sn.setText(scanBarcode);
  474. break;
  475. }
  476. //刷新界面
  477. mesClientFrame.repaint();
  478. if(!tcp_connect_flag) {
  479. MesClient.setMenuStatus("设备未连接Mes服务器",-1);
  480. // JOptionPane.showMessageDialog(mesClientFrame,"设备未连接Mes服务器","提示窗口", JOptionPane.INFORMATION_MESSAGE);
  481. return;
  482. }
  483. // 查询工件质量
  484. Boolean sendret = DataUtil.checkQuality(nettyClient,barcode36,user20);
  485. if(!sendret){
  486. MesClient.setMenuStatus("消息发送失败,请重试",-1);
  487. return;
  488. }
  489. }else {
  490. MesClient.setMenuStatus("请扫工件码,请重试",-1);
  491. return;
  492. }
  493. }
  494. public static void logoff() {
  495. welcomeWin.setVisible(true);
  496. mesClientFrame.setVisible(false);
  497. // 关闭定时任务池
  498. shutdownSchedulerPool();
  499. nettyClient = null;
  500. // if(heartBeatTimer!=null) {
  501. // heartBeatTimer.cancel();
  502. // }
  503. // if(heartBeatIconTimer!=null) {
  504. // heartBeatIconTimer.cancel();
  505. // }
  506. tcp_connect_flag = false;
  507. connect_request_flag = false;
  508. }
  509. /**
  510. * 创建时间打印定时任务
  511. */
  512. private void createTimePrintTask() {
  513. // 先取消可能存在的旧任务
  514. if (timePrintTask != null && !timePrintTask.isCancelled()) {
  515. timePrintTask.cancel(false);
  516. }
  517. // 初始化定时任务池(如果尚未初始化)
  518. if (schedulerPool == null || schedulerPool.isShutdown()) {
  519. schedulerPool = Executors.newScheduledThreadPool(oprnoMap.size() + 1); // +1 为时间打印任务
  520. }
  521. // 创建时间打印定时任务
  522. timePrintTask = schedulerPool.scheduleAtFixedRate(() -> {
  523. // 在每次执行前检查开关状态
  524. if (scheduledTasksEnabled) {
  525. try {
  526. // 获取所有工位对象并转换为数组
  527. Oprno[] oprnos = oprnoMap.values().toArray(new Oprno[0]);
  528. // 调用S7PLCUtils.isStart方法检查工位上料状态
  529. Oprno startOprno = S7PLCUtils.isStart(s7PLC, oprnos);
  530. // 处理返回结果
  531. if (startOprno != null) {
  532. // 判断这个工件码的位置是A面还是B面
  533. System.out.println("上料的工位号码:"+ startOprno.getOprno());
  534. String sn = S7PLCUtils.getSnInJXB(startOprno, s7PLC);
  535. if (sn != null && !sn.isEmpty()) {
  536. // 检查质量
  537. Boolean checkQualityResult = DataUtil.checkQualityByGw(nettyClient, sn, user20,startOprno.getOprno());
  538. if (!checkQualityResult) {
  539. MesClient.setMenuStatus("消息发送失败,请重试",-1);
  540. }
  541. }else {
  542. MesClient.setMenuStatus(startOprno.getOprno()+"获取工件码为空",-1);
  543. }
  544. }
  545. } catch (Exception e) {
  546. log.error("时间打印任务执行异常", e);
  547. }
  548. }
  549. }, 0, TIME_PRINT_INTERVAL, TimeUnit.MILLISECONDS);
  550. }
  551. /**
  552. * 关闭定时任务池的方法
  553. */
  554. private static void shutdownSchedulerPool() {
  555. try {
  556. if (schedulerPool != null && !schedulerPool.isShutdown()) {
  557. // 取消时间打印任务
  558. if (timePrintTask != null && !timePrintTask.isCancelled()) {
  559. timePrintTask.cancel(false);
  560. timePrintTask = null;
  561. }
  562. // 取消所有工位定时任务
  563. for (ScheduledFuture<?> future : taskMap.values()) {
  564. if (future != null && !future.isCancelled()) {
  565. future.cancel(false);
  566. }
  567. }
  568. // 清空任务映射
  569. taskMap.clear();
  570. // 关闭调度器池
  571. schedulerPool.shutdown();
  572. // 等待任务池关闭,最多等待3秒
  573. if (!schedulerPool.awaitTermination(3, TimeUnit.SECONDS)) {
  574. // 如果超时,强制关闭
  575. schedulerPool.shutdownNow();
  576. }
  577. log.info("定时任务池已成功关闭");
  578. }
  579. } catch (Exception e) {
  580. log.error("关闭定时任务池时发生异常", e);
  581. // 发生异常时强制关闭
  582. if (schedulerPool != null && !schedulerPool.isTerminated()) {
  583. schedulerPool.shutdownNow();
  584. }
  585. }
  586. }
  587. public MesClient() {
  588. setIconImage(Toolkit.getDefaultToolkit().getImage(MesClient.class.getResource("/bg/logo.png")));
  589. setTitle("MES系统客户端:"+mes_gw + "- " + mes_gw_des);
  590. setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  591. // 添加窗口关闭监听器,确保定时任务池正确关闭
  592. addWindowListener(new java.awt.event.WindowAdapter() {
  593. @Override
  594. public void windowClosing(java.awt.event.WindowEvent windowEvent) {
  595. // 关闭定时任务池
  596. shutdownSchedulerPool();
  597. // 退出程序
  598. System.exit(0);
  599. }
  600. });
  601. setBounds(0, 0, 1024, 768);
  602. JMenuBar menuBar = new JMenuBar();
  603. menuBar.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 26));
  604. setJMenuBar(menuBar);
  605. JMenu fileMenu = new JMenu("用户");
  606. fileMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/user.png")));
  607. fileMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  608. menuBar.add(fileMenu);
  609. JMenuItem exitMenuItem = new JMenuItem("退出");
  610. exitMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/logoff.png")));
  611. exitMenuItem.setFont(new Font("微软雅黑", Font.PLAIN, 22));
  612. fileMenu.add(exitMenuItem);
  613. exitMenuItem.addMouseListener(new MouseAdapter() {
  614. @Override
  615. public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件
  616. super.mouseClicked(e);
  617. //dispose();
  618. logoff();
  619. }
  620. });
  621. JMenu settingMenu = new JMenu("设置");
  622. //settingMenu.setVisible(false);
  623. settingMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/menu_setting.png")));
  624. settingMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  625. menuBar.add(settingMenu);
  626. JMenu mesMenu = new JMenu("MES");
  627. mesMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/menu_data_analysis.png")));
  628. mesMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  629. menuBar.add(mesMenu);
  630. JMenuItem taskToggleMenuItem = new JMenuItem("启动 (关闭)");
  631. taskToggleMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  632. taskToggleMenuItem.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  633. taskToggleMenuItem.addMouseListener(new MouseAdapter() {
  634. @Override
  635. public void mousePressed(MouseEvent e) {
  636. // 如果当前是关闭状态,用户点击想要开启
  637. if (!scheduledTasksEnabled) {
  638. DataUtil.getCheckInfo();
  639. // 先检查开班点检是否完成
  640. if (!check_info) {
  641. // 未完成点检,显示提示并阻止操作
  642. MesClient.setMenuStatus("请先完成开班点检", -1);
  643. return;
  644. }
  645. }
  646. // 切换定时任务状态
  647. scheduledTasksEnabled = !scheduledTasksEnabled;
  648. // 更新菜单项文本和图标
  649. if (scheduledTasksEnabled) {
  650. taskToggleMenuItem.setText("启动 (开启)");
  651. taskToggleMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  652. // 启动定时任务逻辑将在定时任务执行时检查状态
  653. MesClient.setMenuStatus("定时任务已开启", 1);
  654. } else {
  655. taskToggleMenuItem.setText("启动 (关闭)");
  656. taskToggleMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  657. MesClient.setMenuStatus("定时任务已关闭", -1);
  658. }
  659. // 重新创建时间打印任务,确保其与定时任务开关状态同步
  660. createTimePrintTask();
  661. // 当定时任务开启时,为所有工位重新创建读码定时任务
  662. if (scheduledTasksEnabled) {
  663. for (Map.Entry<String, JTextField> entry : oprnoTextFieldMap.entrySet()) {
  664. String oprnoCode = entry.getKey();
  665. JTextField textField = entry.getValue();
  666. createScheduledTask(oprnoCode, textField);
  667. }
  668. }
  669. }
  670. });
  671. mesMenu.add(taskToggleMenuItem);
  672. JMenuItem resetTcpMenu = new JMenuItem("\u91CD\u8FDEMES");
  673. resetTcpMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  674. resetTcpMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  675. resetTcpMenu.addMouseListener(new MouseAdapter() {
  676. @Override
  677. public void mousePressed(MouseEvent e) {
  678. super.mouseClicked(e);
  679. //重连mes
  680. nettyClient.future.channel().close();
  681. }
  682. });
  683. settingMenu.add(resetTcpMenu);
  684. JMenuItem resetTcpMenu_1 = new JMenuItem("刷新工件");
  685. resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  686. resetTcpMenu_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  687. resetTcpMenu_1.addMouseListener(new MouseAdapter() {
  688. @Override
  689. public void mousePressed(MouseEvent e) {
  690. super.mouseClicked(e);
  691. resetScanA();
  692. }
  693. });
  694. settingMenu.add(resetTcpMenu_1);
  695. contentPane = new JPanel();
  696. contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
  697. setContentPane(contentPane);
  698. contentPane.setLayout(new BorderLayout(0, 0));
  699. JToolBar toolBar = new JToolBar();
  700. contentPane.add(toolBar, BorderLayout.NORTH);
  701. JLabel equipment_statu_label = new JLabel("状态:");
  702. equipment_statu_label.setHorizontalAlignment(SwingConstants.CENTER);
  703. equipment_statu_label.setForeground(Color.BLACK);
  704. equipment_statu_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  705. equipment_statu_label.setBackground(Color.LIGHT_GRAY);
  706. toolBar.add(equipment_statu_label);
  707. status_menu = new JButton("设备未连接MES服务器");
  708. if(tcp_connect_flag) {
  709. status_menu.setText("已连接MES服务器");
  710. status_menu.setForeground(Color.GREEN);
  711. }else {
  712. status_menu.setText("未连接MES服务器");
  713. status_menu.setForeground(Color.DARK_GRAY);
  714. }
  715. status_menu.addActionListener(new ActionListener() {
  716. public void actionPerformed(ActionEvent e) {
  717. }
  718. });
  719. status_menu.setForeground(Color.GREEN);
  720. status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  721. status_menu.setBackground(Color.BLACK);
  722. toolBar.add(status_menu);
  723. JLabel space_1 = new JLabel(" ");
  724. toolBar.add(space_1);
  725. JLabel heart_beat_status_label = new JLabel("心跳:");
  726. heart_beat_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  727. heart_beat_status_label.setForeground(Color.BLACK);
  728. heart_beat_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  729. heart_beat_status_label.setBackground(Color.LIGHT_GRAY);
  730. toolBar.add(heart_beat_status_label);
  731. heart_beat_menu = new JButton("2024-02-20 23:20:10");
  732. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  733. heart_beat_menu.setForeground(Color.GREEN);
  734. heart_beat_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  735. heart_beat_menu.setBackground(Color.BLACK);
  736. toolBar.add(heart_beat_menu);
  737. JLabel space_2 = new JLabel(" ");
  738. toolBar.add(space_2);
  739. JLabel user_status_label = new JLabel("登录用户:");
  740. user_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  741. user_status_label.setForeground(Color.BLACK);
  742. user_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  743. user_status_label.setBackground(Color.LIGHT_GRAY);
  744. toolBar.add(user_status_label);
  745. user_menu = new JButton("JinJuShi");
  746. user_menu.setForeground(Color.GREEN);
  747. user_menu.setFont(new Font("微软雅黑", Font.PLAIN, 22));
  748. user_menu.setBackground(Color.BLACK);
  749. toolBar.add(user_menu);
  750. JLabel space_3 = new JLabel(" ");
  751. toolBar.add(space_3);
  752. JLabel space_4 = new JLabel(" ");
  753. toolBar.add(space_4);
  754. tabbedPane = new JTabbedPane(JTabbedPane.TOP);
  755. tabbedPane.setMinimumSize(new Dimension(400, 50));
  756. tabbedPane.setFont(new Font("宋体", Font.BOLD, 22));
  757. contentPane.add(tabbedPane);
  758. //首页
  759. JPanel indexPanelA = new JPanel();
  760. indexScrollPaneA = new JScrollPane(indexPanelA);
  761. indexPanelA.setLayout(null);
  762. product_sn = new JTextField();
  763. product_sn.setHorizontalAlignment(SwingConstants.CENTER);
  764. product_sn.setEditable(false);
  765. product_sn.setFont(new Font("微软雅黑", Font.PLAIN, 28));
  766. product_sn.setBounds(81, 70, 602, 70);
  767. product_sn.setVisible(false); // 隐藏工件码输入框
  768. indexPanelA.add(product_sn);
  769. product_sn.setColumns(10);
  770. f_scan_data_bt_1 = new JButton("扫码");
  771. f_scan_data_bt_1.addActionListener(new ActionListener() {
  772. public void actionPerformed(ActionEvent e) {
  773. scan_type = 1;
  774. scanBarcode();
  775. }
  776. });
  777. f_scan_data_bt_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
  778. f_scan_data_bt_1.setFont(new Font("微软雅黑", Font.PLAIN, 32));
  779. f_scan_data_bt_1.setBounds(693, 70, 198, 70);
  780. f_scan_data_bt_1.setVisible(false); // 隐藏扫码按钮
  781. indexPanelA.add(f_scan_data_bt_1);
  782. // String[] hjtitles = new String[]{"焊机1","焊机2","焊机3"};
  783. // String[] hjvals = new String[]{"HJ001","HJ002","HJ003"};
  784. // mesRadioHj = new MesRadio(hjtitles,hjvals);
  785. // mesRadioHj.setSize(500,50);
  786. // mesRadioHj.setBounds(190,170,500,50);
  787. // indexPanelA.add(mesRadioHj);
  788. fxlabel = new JLabel("该工件为返修件,请仔细检查");
  789. fxlabel.setFont(new Font("微软雅黑", Font.PLAIN, 38));
  790. fxlabel.setBounds(81, 170, 810, 70);
  791. fxlabel.setForeground(Color.RED);
  792. fxlabel.setHorizontalAlignment(SwingConstants.CENTER);
  793. fxlabel.setVisible(false);
  794. indexPanelA.add(fxlabel);
  795. generateOprnoTextFields(indexPanelA);
  796. // 创建时间打印定时任务
  797. createTimePrintTask();
  798. finish_ok_bt = new JButton("OK");
  799. finish_ok_bt.setEnabled(false);
  800. finish_ok_bt.addActionListener(new ActionListener() {
  801. public void actionPerformed(ActionEvent e) {
  802. if(work_status == 1 && check_quality_result){
  803. String sn = getBarcode(product_sn.getText());
  804. if(sn.isEmpty()){
  805. MesClient.setMenuStatus("工件码为空,请重试",-1);
  806. return;
  807. }
  808. getUser();
  809. String qret = "OK";
  810. Boolean sendret = DataUtil.sendQuality(nettyClient,sn,qret,user20);
  811. if(!sendret){
  812. MesClient.setMenuStatus("消息发送失败,请重试",-1);
  813. return;
  814. }else{
  815. // MesClient.resetScanA();
  816. // MesClient.scan_type = 1;
  817. // MesClient.scanBarcode();
  818. // MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
  819. }
  820. }
  821. }
  822. });
  823. finish_ok_bt.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ok_bg.png")));
  824. finish_ok_bt.setFont(new Font("微软雅黑", Font.PLAIN, 32));
  825. finish_ok_bt.setBounds(185, 291, 240, 80);
  826. finish_ok_bt.setEnabled(false);
  827. finish_ok_bt.setVisible(false); // 隐藏OK按钮
  828. indexPanelA.add(finish_ok_bt);
  829. finish_ng_bt = new JButton("NG");
  830. finish_ng_bt.setEnabled(false);
  831. finish_ng_bt.addActionListener(new ActionListener() {
  832. public void actionPerformed(ActionEvent e) {
  833. if(work_status == 1 && check_quality_result){
  834. String sn = getBarcode(product_sn.getText());
  835. if(sn.isEmpty()){
  836. MesClient.setMenuStatus("工件码为空,请重试",-1);
  837. return;
  838. }
  839. getUser();
  840. String qret = "NG";
  841. Boolean sendret = DataUtil.sendQuality(nettyClient,sn,qret,user20);
  842. if(!sendret){
  843. MesClient.setMenuStatus("消息发送失败,请重试",-1);
  844. return;
  845. }else{
  846. // MesClient.resetScanA();
  847. // MesClient.scan_type = 1;
  848. // MesClient.scanBarcode();
  849. // MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
  850. }
  851. }
  852. }
  853. });
  854. finish_ng_bt.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ng_bg.png")));
  855. finish_ng_bt.setFont(new Font("微软雅黑", Font.PLAIN, 32));
  856. finish_ng_bt.setBounds(508, 291, 240, 80);
  857. finish_ng_bt.setEnabled(false);
  858. finish_ng_bt.setVisible(false); // 隐藏NG按钮
  859. indexPanelA.add(finish_ng_bt);
  860. tabbedPane.addTab("工作面板", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA, null);
  861. tabbedPane.setEnabledAt(0, true);
  862. // searchScrollPane = new JScrollPane((Component) null);
  863. indexPanelC = new JPanel();
  864. searchScrollPaneDj = new JScrollPane(indexPanelC);
  865. indexPanelC.setLayout(null);
  866. tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
  867. indexPanelB = new JPanel();
  868. searchScrollPane = new JScrollPane(indexPanelB);
  869. indexPanelB.setLayout(null);
  870. tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
  871. tabbedPane.addChangeListener(new ChangeListener() {
  872. @Override
  873. public void stateChanged(ChangeEvent e) {
  874. JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
  875. int selectedIndex = tabbedPane.getSelectedIndex();
  876. System.out.println("selectedIndex:"+selectedIndex);
  877. if(selectedIndex == 1){
  878. }
  879. }
  880. });
  881. }
  882. //页面菜单状态
  883. public static void setMenuStatus(String msg,int error){
  884. if(error == 0){
  885. MesClient.status_menu.setForeground(Color.GREEN);
  886. }else{
  887. MesClient.status_menu.setForeground(Color.RED);
  888. }
  889. MesClient.status_menu.setText(msg);
  890. }
  891. public static void getMaterailData(){
  892. try{
  893. JSONObject retObj = DataUtil.getBindMaterail();
  894. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  895. java.util.List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  896. int i = 0;
  897. rowData = new Object[arrs.size()][7];
  898. for (BindMaterialResp bindMaterialResp:arrs){
  899. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  900. rowData[i][1] = bindMaterialResp.getBatchSn();
  901. rowData[i][2] = bindMaterialResp.getLastTimes();
  902. rowData[i][3] = "";
  903. rowData[i][4] = bindMaterialResp.getCraft();
  904. rowData[i][5] = bindMaterialResp.getMaterialId();
  905. rowData[i][6] = bindMaterialResp.getType();
  906. i++;
  907. }
  908. bindBatchPanel();
  909. }
  910. }catch (Exception e){
  911. log.info(e.getMessage());
  912. }
  913. }
  914. public static void updateMaterailData(){
  915. try{
  916. JSONObject retObj = DataUtil.getBindMaterail();
  917. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  918. List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  919. int i = 0;
  920. for (BindMaterialResp bindMaterialResp:arrs){
  921. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  922. rowData[i][1] = bindMaterialResp.getBatchSn();
  923. rowData[i][2] = bindMaterialResp.getLastTimes();
  924. rowData[i][3] = "";
  925. rowData[i][4] = bindMaterialResp.getCraft();
  926. rowData[i][5] = bindMaterialResp.getMaterialId();
  927. rowData[i][6] = bindMaterialResp.getType();
  928. i++;
  929. }
  930. MesClient.table.repaint();
  931. }
  932. }catch (Exception e){
  933. log.info(e.getMessage());
  934. }
  935. }
  936. // 绑定物料批次码
  937. public static void scanBatchSn(BindMaterialResp bindMaterialResp) {
  938. //弹窗扫工件码
  939. String scanBarcodeTitle = "请扫物料:"+bindMaterialResp.getMaterialTitle();
  940. String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
  941. if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
  942. JSONObject retObj = DataUtil.saveBindMaterail(scanBarcode,bindMaterialResp.getCraft(),bindMaterialResp.getMaterialId(),bindMaterialResp.getType());
  943. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  944. MesClient.setMenuStatus("扫物料:"+bindMaterialResp.getMaterialTitle()+"成功",0);
  945. updateMaterailData();
  946. }else{
  947. if(retObj.get("result")==null){
  948. MesClient.setMenuStatus("请求失败,请重试",-1);
  949. }else{
  950. if(retObj.get("result").toString().equalsIgnoreCase("false")){
  951. MesClient.setMenuStatus(retObj.getString("message"),-1);
  952. }
  953. }
  954. }
  955. }
  956. }
  957. public static void bindBatchPanel(){
  958. JPanel indexPanelBB = new JPanel();
  959. JPanel panel = new JPanel();
  960. panel.setBounds(0, 0, 990, 550);
  961. // panel.setBounds(81, 50, 810, 479);
  962. indexPanelBB.add(panel);
  963. panel.setLayout(new GridLayout(0, 1, 0, 0));
  964. table = new JTable(rowData, columnNames){
  965. public boolean isCellEditable(int row, int column) {
  966. if(column == 3){
  967. return true;
  968. }
  969. return false;
  970. }
  971. };
  972. table.setRowHeight(40);
  973. table.setEnabled(true);
  974. table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
  975. table.getColumnModel().getColumn(3).setCellRenderer(new TableCellRendererButton());
  976. table.getColumnModel().getColumn(3).setCellEditor(new TableCellEditorButton());
  977. JScrollPane scrollPane = new JScrollPane(table);
  978. panel.add(scrollPane);
  979. JScrollPane indexScrollPaneB = new JScrollPane(indexPanelBB);
  980. indexPanelBB.setLayout(null);
  981. tabbedPane.addTab("绑定物料", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), indexScrollPaneB, null);
  982. }
  983. // 开启发送结果定时任务
  984. public static void startUpdateQualityTimer(){
  985. // 创建异步线程池
  986. ExecutorService executorService = Executors.newSingleThreadExecutor();
  987. // 提交任务
  988. executorService.submit(() -> {
  989. log.info("异步任务执行中...");
  990. // 模拟耗时操作
  991. try {
  992. while (true){
  993. try {
  994. // 确保连接已经打开
  995. if (JdbcUtils.conn == null || JdbcUtils.conn.isClosed()) {
  996. JdbcUtils.openConnection();
  997. }
  998. Statement statement = JdbcUtils.conn.createStatement();
  999. String selectSql = "SELECT id, bw FROM submit_record\n" +
  1000. "WHERE state = 0 ORDER BY id DESC LIMIT 10";
  1001. String updateSql = "UPDATE submit_record \n" +
  1002. "SET state = '1'\n" +
  1003. "WHERE id = ";
  1004. ResultSet rs = statement.executeQuery(selectSql);
  1005. while(rs.next()){
  1006. int id = rs.getInt("id");
  1007. String bw = rs.getString("bw");
  1008. // 发送请求
  1009. String url = "http://"+MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/updateQualityByTiming";
  1010. log.info("质量:"+bw);
  1011. String s = HttpUtils.sendPostRequestJson(url, bw );
  1012. log.info("结果:"+s);
  1013. Boolean result = JSONObject.parseObject(s).getBoolean("result");
  1014. if(result) {
  1015. // 更改状态为 1
  1016. statement.executeUpdate(updateSql + id);
  1017. }
  1018. }
  1019. rs.close();
  1020. statement.close();
  1021. } catch (Exception e) {
  1022. log.info(e.getMessage());
  1023. }
  1024. try {
  1025. Thread.sleep(2000);
  1026. }catch (Exception e){
  1027. log.info(e.getMessage());
  1028. }
  1029. }
  1030. } catch (Exception e) {
  1031. log.info(e.getMessage());
  1032. }
  1033. log.info("异步任务执行完毕");
  1034. });
  1035. }
  1036. /**
  1037. * 从 Properties 中提取所有工位信息,填充到 oprnoMap(跳过指定属性)
  1038. */
  1039. private static void loadOprnoMap(Properties pro) {
  1040. Enumeration<?> keys = pro.propertyNames();
  1041. while (keys.hasMoreElements()) {
  1042. String key = (String) keys.nextElement();
  1043. Matcher matcher = OPRNO_PATTERN.matcher(key);
  1044. if (matcher.find()) {
  1045. String oprnoCode = matcher.group(1); // 工位号(如 OP090A、HSB)
  1046. String propertyName = matcher.group(2); // 属性名(如 hgA_out、hgA_qr_code)
  1047. // 跳过需要忽略的属性(hgA_qr_code、hgB_qr_code)
  1048. if (isSkipProperty(propertyName)) {
  1049. log.debug("跳过忽略的属性:{}(工位:{})", propertyName, oprnoCode);
  1050. continue;
  1051. }
  1052. String propertyValue = pro.getProperty(key); // 属性值
  1053. // 从 Map 中获取或创建 Oprno 对象
  1054. Oprno oprno = oprnoMap.get(oprnoCode);
  1055. if (oprno == null) {
  1056. oprno = new Oprno();
  1057. oprno.setOprno(oprnoCode);
  1058. oprnoMap.put(oprnoCode, oprno);
  1059. }
  1060. // 反射注入属性值
  1061. setOprnoProperty(oprno, propertyName, propertyValue);
  1062. }
  1063. }
  1064. // log.info("成功加载 {} 个工位配置:{}", oprnoMap.size(), oprnoMap.keySet());
  1065. }
  1066. /**
  1067. * 判断属性是否需要跳过
  1068. */
  1069. private static boolean isSkipProperty(String propertyName) {
  1070. for (String skipProp : SKIP_PROPERTIES) {
  1071. if (skipProp.equals(propertyName)) {
  1072. return true;
  1073. }
  1074. }
  1075. return false;
  1076. }
  1077. /**
  1078. * 反射给 Oprno 对象设置属性值
  1079. */
  1080. private static void setOprnoProperty(Oprno oprno, String propertyName, String propertyValue) {
  1081. try {
  1082. Field field = Oprno.class.getDeclaredField(propertyName);
  1083. field.setAccessible(true);
  1084. field.set(oprno, propertyValue);
  1085. } catch (NoSuchFieldException e) {
  1086. // log.warn("Oprno 类不存在字段:{},该属性值未注入", propertyName);
  1087. } catch (IllegalAccessException e) {
  1088. // log.error("设置 Oprno 属性失败:{}", propertyName, e);
  1089. }
  1090. }
  1091. }