MesClient.java 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. package com.mes.ui;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.mes.component.MesRadio;
  4. import com.mes.component.MesWebView;
  5. import com.mes.component.StationPanel;
  6. import com.mes.plc.HeliumFlow;
  7. import com.mes.plc.McPlcClient;
  8. import com.mes.util.DateLocalUtils;
  9. import com.mes.util.HttpUtils;
  10. import com.mes.util.JdbcUtils;
  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.*;
  19. import java.io.*;
  20. import java.sql.ResultSet;
  21. import java.sql.Statement;
  22. import java.time.LocalDateTime;
  23. import java.time.LocalTime;
  24. import java.time.format.DateTimeFormatter;
  25. import java.util.List;
  26. import java.util.Properties;
  27. import java.util.Timer;
  28. import java.util.TimerTask;
  29. import java.util.concurrent.ExecutorService;
  30. import java.util.concurrent.Executors;
  31. public class MesClient extends JFrame {
  32. public static final Logger log = LoggerFactory.getLogger(MesClient.class);
  33. public static int mes_auth = 0; // 权限级别 0=无权限 1=操作工人 2=管理员
  34. public static String mes_gw = ""; // 工位号
  35. public static String mes_gw_des = ""; // 工位名称
  36. public static String mes_server_ip = ""; // 服务器IP地址
  37. public static int mes_heart_icon_cycle = 1;
  38. public static String mes_line_sn = ""; // 产线编号
  39. // PLC(三菱 MC 3E)
  40. public static String plc_ip = "";
  41. public static int plc_port = 2500;
  42. public static String plc_a_code_addr = "D5000";
  43. public static String plc_b_code_addr = "D6000";
  44. public static int plc_code_len = 24;
  45. //session
  46. public static String sessionid = "";
  47. public static JPanel contentPane;
  48. public static MesClient mesClientFrame;
  49. public static JTabbedPane tabbedPane;
  50. // public static JScrollPane searchScrollPane; // 已弃用,改为使用 WorkRecordPanel
  51. public static JScrollPane searchScrollPaneDj;
  52. public static Boolean check_quality_result = false;
  53. public static Integer work_status = 0;
  54. public static JButton heart_beat_menu;
  55. public static JButton status_menu;
  56. public static JButton user_menu;
  57. public static JButton plc_menu;
  58. // 氦检 A/B 双工位
  59. public static StationPanel stationA;
  60. public static StationPanel stationB;
  61. public static JTextArea logArea;
  62. public static String user20 = "";
  63. public static JFrame welcomeWin;
  64. // public static JPanel indexPanelB; // 已弃用,改为使用 WorkRecordPanel
  65. public static MesWebView jfxPanel = null;
  66. public static JPanel indexPanelC;
  67. public static MesWebView jfxPanel2 = null;
  68. public static MesRadio mesRadioHj;
  69. public static JTable table;
  70. public static Object[] columnNames = { "物料名称", "绑定批次", "剩余次数", "操作" };
  71. public static Object[][] rowData = null;
  72. public static void main(String[] args) {
  73. if (LockUtil.getInstance().isAppActive() == true){
  74. // JOptionPane.showMessageDialog(null, "已有一个程序在运行,程序退出");
  75. return;
  76. }else{
  77. EventQueue.invokeLater(new Runnable() {
  78. @Override
  79. public void run() {
  80. try{
  81. //读文件配置
  82. readProperty();
  83. // 显示界面
  84. mesClientFrame = new MesClient();
  85. mesClientFrame.setVisible(false);
  86. JdbcUtils.getConn();
  87. welcomeWin = new LoginFarme();
  88. welcomeWin.setVisible(true);
  89. getMaterailData();
  90. }catch (Exception e){
  91. e.printStackTrace();
  92. }
  93. }
  94. });
  95. }
  96. }
  97. //读配置文件
  98. private static void readProperty() throws IOException{
  99. String enconding = "UTF-8";
  100. InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
  101. Properties pro = new Properties();
  102. BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
  103. pro.load(br);
  104. mes_gw = pro.getProperty("mes.gw");
  105. mes_server_ip = pro.getProperty("mes.server_ip");
  106. mes_line_sn = pro.getProperty("mes.line_sn");
  107. mes_gw_des = OprnoUtil.getGwDes(mes_line_sn,mes_gw);
  108. plc_ip = pro.getProperty("plc.ip", "").trim();
  109. plc_port = Integer.parseInt(pro.getProperty("plc.port", "2500").trim());
  110. plc_a_code_addr = pro.getProperty("plc.a.code_addr", "D5000").trim();
  111. plc_b_code_addr = pro.getProperty("plc.b.code_addr", "D6000").trim();
  112. plc_code_len = Integer.parseInt(pro.getProperty("plc.code_len", "24").trim());
  113. log.info(mes_gw + ";" + mes_gw_des + ";" + mes_server_ip + ";" + plc_ip + ":" + plc_port);
  114. }
  115. //启动心跳包程序
  116. public static java.util.Timer heartBeatTimer;
  117. public static java.util.Timer heartBeatIconTimer;
  118. public static boolean iconREDFlag = true;
  119. public static void startHeartBeatTimer() {
  120. if(heartBeatTimer!=null) {
  121. heartBeatTimer.cancel();
  122. }
  123. //心跳显示图标
  124. if(heartBeatIconTimer!=null) {
  125. heartBeatIconTimer.cancel();
  126. }
  127. heartBeatIconTimer = new Timer();
  128. heartBeatIconTimer.schedule(new TimerTask() {
  129. public void run() {
  130. // if(iconREDFlag) {
  131. // heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  132. // iconREDFlag = false;
  133. // }else {
  134. // heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  135. // iconREDFlag = true;
  136. // }
  137. heart_beat_menu.setText(DateLocalUtils.getCurrentTime());
  138. heart_beat_menu.repaint();
  139. }
  140. }, 100,mes_heart_icon_cycle*1000);
  141. }
  142. public static java.util.Timer onlineTimer;
  143. public static void checkOnline() {
  144. if(onlineTimer!=null) {
  145. onlineTimer.cancel();
  146. }
  147. onlineTimer = new Timer();
  148. onlineTimer.schedule(new TimerTask() {
  149. public void run() {
  150. Boolean retObj = DataUtil.isServerOnlineBySocket();
  151. if(retObj) {
  152. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  153. }else{
  154. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  155. }
  156. heart_beat_menu.repaint();
  157. }
  158. }, 100,5000);
  159. }
  160. //设置tcp连接状态显示
  161. public static void setTcpStatus() {
  162. status_menu.setText("已连接MES服务器");
  163. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  164. heart_beat_menu.repaint();
  165. }
  166. public static void initWarehouseData(){
  167. resetScanA();
  168. }
  169. public static void resetScanA() {
  170. work_status = 0;
  171. check_quality_result = false;
  172. if (stationA != null) {
  173. stationA.reset();
  174. }
  175. if (stationB != null) {
  176. stationB.reset();
  177. }
  178. MesClient.setMenuStatus("等待 PLC 扫码信号",0);
  179. updateMaterailData();
  180. // shiftUserCheck();
  181. }
  182. public static int userLoginHours;//用户登录所处小时
  183. //换班用户信息检查
  184. private static void shiftUserCheck() {
  185. LocalDateTime now = LocalDateTime.now();
  186. // 判断时间范围
  187. if (userLoginHours >= 8 && userLoginHours < 20) {
  188. int hour = now.getHour();
  189. if (hour >= 20 || hour < 8) {
  190. logoff();
  191. }
  192. } else {
  193. int hour = now.getHour();
  194. if (hour >= 8 && hour < 20) {
  195. logoff();
  196. }
  197. }
  198. }
  199. public static void resetScanB() {
  200. }
  201. //获取用户20位
  202. public static void getUser() {
  203. user20 = user_menu.getText().toString();
  204. // String space_tmp1 = "";
  205. // if(user20.length()<20) {
  206. // for(int i=0;i<20-user20.length();i++) {
  207. // space_tmp1 = space_tmp1 + " ";
  208. // }
  209. // }
  210. // user20 = user20 + space_tmp1;
  211. }
  212. //获取barcode内容36位
  213. public static String getBarcode(String barcodeTmp) {
  214. String barcodeRet = barcodeTmp;
  215. if(barcodeTmp.equalsIgnoreCase("")) {
  216. return "";
  217. }else {
  218. if(barcodeTmp.length()<36) {
  219. String space = "";
  220. for(int i=0;i<36-barcodeTmp.length();i++) {
  221. space = space + " ";
  222. }
  223. barcodeRet = barcodeTmp + space;
  224. }
  225. }
  226. return barcodeRet;
  227. }
  228. public static void logoff() {
  229. welcomeWin.setVisible(true);
  230. mesClientFrame.setVisible(false);
  231. }
  232. public MesClient() {
  233. setIconImage(Toolkit.getDefaultToolkit().getImage(MesClient.class.getResource("/bg/logo.png")));
  234. setTitle("MES系统客户端:"+mes_gw + "- " + mes_gw_des);
  235. // setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  236. setBounds(0, 0, 1024, 768);
  237. setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
  238. // 添加窗口监听器
  239. addWindowListener(new WindowAdapter() {
  240. @Override
  241. public void windowClosing(WindowEvent e) {
  242. int choice = JOptionPane.showConfirmDialog(null, "确定要关闭窗口吗?", "关闭确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
  243. if (choice == JOptionPane.YES_OPTION) {
  244. // 如果用户点击“是”,则关闭窗口
  245. dispose(); // 释放窗口资源并关闭窗口
  246. System.exit(0);
  247. }
  248. }
  249. });
  250. JMenuBar menuBar = new JMenuBar();
  251. menuBar.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 26));
  252. setJMenuBar(menuBar);
  253. JMenu fileMenu = new JMenu("用户");
  254. fileMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/user.png")));
  255. fileMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  256. menuBar.add(fileMenu);
  257. JMenuItem exitMenuItem = new JMenuItem("退出");
  258. exitMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/logoff.png")));
  259. exitMenuItem.setFont(new Font("微软雅黑", Font.PLAIN, 22));
  260. fileMenu.add(exitMenuItem);
  261. exitMenuItem.addMouseListener(new MouseAdapter() {
  262. @Override
  263. public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件
  264. super.mouseClicked(e);
  265. //dispose();
  266. logoff();
  267. }
  268. });
  269. JMenu settingMenu = new JMenu("设置");
  270. //settingMenu.setVisible(false);
  271. settingMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/menu_setting.png")));
  272. settingMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  273. menuBar.add(settingMenu);
  274. JMenuItem resetTcpMenu = new JMenuItem("\u91CD\u8FDEMES");
  275. resetTcpMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  276. resetTcpMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  277. resetTcpMenu.addMouseListener(new MouseAdapter() {
  278. @Override
  279. public void mousePressed(MouseEvent e) {
  280. super.mouseClicked(e);
  281. }
  282. });
  283. // settingMenu.add(resetTcpMenu);
  284. JMenuItem resetTcpMenu_1 = new JMenuItem("刷新工件");
  285. resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  286. resetTcpMenu_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  287. resetTcpMenu_1.addMouseListener(new MouseAdapter() {
  288. @Override
  289. public void mousePressed(MouseEvent e) {
  290. super.mouseClicked(e);
  291. resetScanA();
  292. }
  293. });
  294. settingMenu.add(resetTcpMenu_1);
  295. contentPane = new JPanel();
  296. contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
  297. setContentPane(contentPane);
  298. contentPane.setLayout(new BorderLayout(0, 0));
  299. JToolBar toolBar = new JToolBar();
  300. contentPane.add(toolBar, BorderLayout.NORTH);
  301. JLabel equipment_statu_label = new JLabel("状态:");
  302. equipment_statu_label.setHorizontalAlignment(SwingConstants.CENTER);
  303. equipment_statu_label.setForeground(Color.BLACK);
  304. equipment_statu_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  305. equipment_statu_label.setBackground(Color.LIGHT_GRAY);
  306. toolBar.add(equipment_statu_label);
  307. status_menu = new JButton("设备未连接MES服务器");
  308. status_menu.setText("已连接MES服务器");
  309. status_menu.setForeground(Color.GREEN);
  310. status_menu.addActionListener(new ActionListener() {
  311. public void actionPerformed(ActionEvent e) {
  312. }
  313. });
  314. status_menu.setForeground(Color.GREEN);
  315. status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  316. status_menu.setBackground(Color.BLACK);
  317. toolBar.add(status_menu);
  318. JLabel space_1 = new JLabel(" ");
  319. toolBar.add(space_1);
  320. JLabel heart_beat_status_label = new JLabel("心跳:");
  321. heart_beat_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  322. heart_beat_status_label.setForeground(Color.BLACK);
  323. heart_beat_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  324. heart_beat_status_label.setBackground(Color.LIGHT_GRAY);
  325. toolBar.add(heart_beat_status_label);
  326. heart_beat_menu = new JButton("2024-02-20 23:20:10");
  327. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  328. heart_beat_menu.setForeground(Color.GREEN);
  329. heart_beat_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  330. heart_beat_menu.setBackground(Color.BLACK);
  331. toolBar.add(heart_beat_menu);
  332. JLabel space_2 = new JLabel(" ");
  333. toolBar.add(space_2);
  334. JLabel user_status_label = new JLabel("登录用户:");
  335. user_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  336. user_status_label.setForeground(Color.BLACK);
  337. user_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  338. user_status_label.setBackground(Color.LIGHT_GRAY);
  339. toolBar.add(user_status_label);
  340. user_menu = new JButton("JinJuShi");
  341. user_menu.setForeground(Color.GREEN);
  342. user_menu.setFont(new Font("微软雅黑", Font.PLAIN, 22));
  343. user_menu.setBackground(Color.BLACK);
  344. toolBar.add(user_menu);
  345. JLabel space_3 = new JLabel(" ");
  346. toolBar.add(space_3);
  347. JLabel plc_status_label = new JLabel("PLC:");
  348. plc_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  349. plc_status_label.setForeground(Color.BLACK);
  350. plc_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  351. toolBar.add(plc_status_label);
  352. plc_menu = new JButton("未连接");
  353. plc_menu.setForeground(Color.RED);
  354. plc_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  355. plc_menu.setBackground(Color.BLACK);
  356. plc_menu.addActionListener(new ActionListener() {
  357. public void actionPerformed(ActionEvent e) {
  358. showPlcSignals();
  359. }
  360. });
  361. toolBar.add(plc_menu);
  362. tabbedPane = new JTabbedPane(JTabbedPane.TOP);
  363. tabbedPane.setMinimumSize(new Dimension(400, 50));
  364. tabbedPane.setFont(new Font("宋体", Font.BOLD, 22));
  365. contentPane.add(tabbedPane);
  366. //首页
  367. JPanel indexPanelA = new JPanel();
  368. indexPanelA.setLayout(null);
  369. indexPanelA.setBackground(Color.WHITE);
  370. // 氦检双工位面板:A/B 并排卡片 + 底部日志
  371. // 点位顺序:扫码成功、MES允许、检测开始、检测结束、泄露、本底、二维码
  372. // 本底、二维码点位待 PLC 确认,先留空
  373. stationA = new StationPanel("A 工位",
  374. new String[]{"M205", "M206", "M207", "M208", "D200", "--", "D5000"});
  375. stationA.setBounds(10, 10, 460, 375);
  376. indexPanelA.add(stationA);
  377. stationB = new StationPanel("B 工位",
  378. new String[]{"M215", "M216", "M217", "M218", "D210", "--", "D6000"});
  379. stationB.setBounds(485, 10, 460, 375);
  380. indexPanelA.add(stationB);
  381. // A/B 工位之间的分隔竖线
  382. final JPanel divider = new JPanel();
  383. divider.setBackground(new Color(0xBD, 0xBD, 0xBD));
  384. divider.setBounds(472, 10, 2, 375);
  385. indexPanelA.add(divider);
  386. logArea = new JTextArea();
  387. logArea.setEditable(false);
  388. logArea.setFont(new Font("微软雅黑", Font.PLAIN, 16));
  389. logArea.setBackground(Color.WHITE);
  390. logArea.setForeground(Color.BLACK);
  391. logArea.setMargin(new Insets(6, 8, 6, 8));
  392. final JScrollPane logScrollPane = new JScrollPane(logArea);
  393. logScrollPane.setBounds(10, 390, 935, 150);
  394. indexPanelA.add(logScrollPane);
  395. // 面板宽度变化时整体居中,日志高度跟随窗口
  396. indexPanelA.addComponentListener(new ComponentAdapter() {
  397. @Override
  398. public void componentResized(ComponentEvent e) {
  399. int w = indexPanelA.getWidth();
  400. int h = indexPanelA.getHeight();
  401. int offset = Math.max(10, (w - 935) / 2);
  402. stationA.setBounds(offset, 10, 460, 375);
  403. stationB.setBounds(offset + 475, 10, 460, 375);
  404. divider.setBounds(offset + 472, 10, 2, 375);
  405. logScrollPane.setBounds(offset, 390, 935, Math.max(60, h - 400));
  406. }
  407. });
  408. tabbedPane.addTab("检测面板", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexPanelA, null);
  409. tabbedPane.setEnabledAt(0, true);
  410. // searchScrollPane = new JScrollPane((Component) null);
  411. indexPanelC = new JPanel();
  412. searchScrollPaneDj = new JScrollPane(indexPanelC);
  413. indexPanelC.setLayout(null);
  414. tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
  415. // ========== 工作记录 Tab(改造:当前工位Tab + 所有工位Tab) ==========
  416. // 旧代码已注释:
  417. // indexPanelB = new JPanel();
  418. // searchScrollPane = new JScrollPane(indexPanelB);
  419. // indexPanelB.setLayout(null);
  420. // tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
  421. // 创建工作记录的子 TabbedPane
  422. JTabbedPane workRecordTabbedPane = new JTabbedPane(JTabbedPane.TOP);
  423. workRecordTabbedPane.setFont(new Font("微软雅黑", Font.PLAIN, 14));
  424. // OKNG 工位:当前工位 + 所有工位
  425. WorkRecordPanel[] workRecordPanels = new WorkRecordPanel[2];
  426. // 当前工位Tab(使用配置文件中的 mes.gw)
  427. workRecordPanels[0] = new WorkRecordPanel(mes_gw, mes_line_sn);
  428. workRecordTabbedPane.addTab(mes_gw, null, workRecordPanels[0], "查询" + mes_gw + "的工作记录");
  429. // 所有工位Tab(查询整条产线所有工位)
  430. workRecordPanels[1] = new WorkRecordPanel(null, mes_line_sn);
  431. workRecordTabbedPane.addTab("所有工位", null, workRecordPanels[1], "查询整条产线所有工位的工作记录");
  432. // 切换子Tab时自动刷新数据
  433. workRecordTabbedPane.addChangeListener(e -> {
  434. int selectedIndex = workRecordTabbedPane.getSelectedIndex();
  435. if (selectedIndex >= 0 && selectedIndex < workRecordPanels.length) {
  436. workRecordPanels[selectedIndex].refreshData();
  437. }
  438. });
  439. // 将子 TabbedPane 添加到主 TabbedPane
  440. tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), workRecordTabbedPane, null);
  441. tabbedPane.addChangeListener(new ChangeListener() {
  442. @Override
  443. public void stateChanged(ChangeEvent e) {
  444. JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
  445. int selectedIndex = tabbedPane.getSelectedIndex();
  446. System.out.println("selectedIndex:"+selectedIndex);
  447. if(selectedIndex == 1){
  448. }
  449. }
  450. });
  451. }
  452. public static void setMenuStatus(String msg,int error){
  453. if(error == 0){
  454. MesClient.status_menu.setForeground(Color.GREEN);
  455. }else{
  456. MesClient.status_menu.setForeground(Color.RED);
  457. }
  458. MesClient.status_menu.setText(msg);
  459. }
  460. // ===== 氦检工位 UI 更新(PLC 线程可直接调用,内部已切到 EDT) =====
  461. /** 追加一条运行日志,自动滚到底 */
  462. public static void addLog(String msg) {
  463. if (logArea == null) {
  464. return;
  465. }
  466. SwingUtilities.invokeLater(() -> {
  467. logArea.append(LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")) + " " + msg + "\n");
  468. logArea.setCaretPosition(logArea.getDocument().getLength());
  469. });
  470. }
  471. /** PLC 连接状态 */
  472. public static void setPlcStatus(boolean connected) {
  473. if (plc_menu == null) {
  474. return;
  475. }
  476. SwingUtilities.invokeLater(() -> {
  477. plc_menu.setText(connected ? "已连接" : "未连接");
  478. plc_menu.setForeground(connected ? Color.GREEN : Color.RED);
  479. });
  480. }
  481. /** 取工位卡片:1=A,2=B */
  482. public static StationPanel getStation(int station) {
  483. return station == 2 ? stationB : stationA;
  484. }
  485. // ===== PLC 连接 =====
  486. public static McPlcClient plcClient;
  487. public static java.util.Timer plcTimer;
  488. /** 点顶栏 PLC 状态,读取并显示所有点位当前值 */
  489. public static void showPlcSignals() {
  490. if (plcClient == null) {
  491. plcClient = new McPlcClient(plc_ip, plc_port);
  492. }
  493. new Thread(() -> {
  494. if (!plcClient.isConnected()) {
  495. plcClient.connect();
  496. }
  497. if (!plcClient.isConnected()) {
  498. SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(mesClientFrame,
  499. "PLC 未连接 " + plc_ip + ":" + plc_port, "PLC 信号", JOptionPane.WARNING_MESSAGE));
  500. return;
  501. }
  502. StringBuilder sb = new StringBuilder();
  503. appendSignals(sb, "A", "M205", "M206", "M207", "M208", "D200", plc_a_code_addr);
  504. sb.append("\n");
  505. appendSignals(sb, "B", "M215", "M216", "M217", "M218", "D210", plc_b_code_addr);
  506. log.info("PLC 信号:\n" + sb);
  507. JTextArea area = new JTextArea(sb.toString());
  508. area.setEditable(false);
  509. area.setFont(new Font("微软雅黑", Font.PLAIN, 18));
  510. area.setMargin(new Insets(8, 10, 8, 10));
  511. SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(mesClientFrame,
  512. new JScrollPane(area), "PLC 信号 " + plc_ip + ":" + plc_port, JOptionPane.INFORMATION_MESSAGE));
  513. }).start();
  514. }
  515. private static void appendSignals(StringBuilder sb, String name,
  516. String scan, String allow, String start, String end,
  517. String leak, String code) {
  518. sb.append(name).append(" 扫码成功(").append(scan).append(") = ").append(plcClient.readBit(scan)).append("\n");
  519. sb.append(name).append(" MES允许(").append(allow).append(") = ").append(plcClient.readBit(allow)).append("\n");
  520. sb.append(name).append(" 检测开始(").append(start).append(") = ").append(plcClient.readBit(start)).append("\n");
  521. sb.append(name).append(" 检测结束(").append(end).append(") = ").append(plcClient.readBit(end)).append("\n");
  522. sb.append(name).append(" 泄露(").append(leak).append(") = ").append(plcClient.readString(leak, 8)).append("\n");
  523. sb.append(name).append(" 条码(").append(code).append(") = ").append(plcClient.readString(code, plc_code_len)).append("\n");
  524. }
  525. /** 启动 PLC 连接/重连,登录成功后调用 */
  526. public static void startPlcTimer() {
  527. if (plcTimer != null) {
  528. plcTimer.cancel();
  529. }
  530. plcClient = new McPlcClient(plc_ip, plc_port);
  531. plcTimer = new java.util.Timer(true);
  532. plcTimer.schedule(new TimerTask() {
  533. @Override
  534. public void run() {
  535. if (!plcClient.isConnected()) {
  536. plcClient.connect();
  537. if (plcClient.isConnected()) {
  538. setPlcStatus(true);
  539. addLog("PLC 已连接 " + plc_ip + ":" + plc_port);
  540. String sig = "M205=" + plcClient.readBit("M205") + " M215=" + plcClient.readBit("M215");
  541. addLog(sig);
  542. log.info("PLC 点位: " + sig);
  543. startFlows();
  544. } else {
  545. setPlcStatus(false);
  546. }
  547. } else {
  548. // 心跳检测:主动读一次,断线时读失败会自动标记断开,下一轮重连
  549. plcClient.readBit("M205");
  550. if (!plcClient.isConnected()) {
  551. setPlcStatus(false);
  552. addLog("PLC 连接断开,等待重连");
  553. }
  554. }
  555. }
  556. }, 0, 3000);
  557. }
  558. public static HeliumFlow flowA;
  559. public static HeliumFlow flowB;
  560. public static java.util.Timer flowTimer;
  561. /** PLC 连接成功后启动 A/B 工位流程轮询 */
  562. private static void startFlows() {
  563. if (flowTimer != null) {
  564. return;
  565. }
  566. flowA = new HeliumFlow(1, plcClient, stationA,
  567. "M205", "M206", "M207", "M208", "D200", plc_a_code_addr);
  568. flowB = new HeliumFlow(2, plcClient, stationB,
  569. "M215", "M216", "M217", "M218", "D210", plc_b_code_addr);
  570. flowTimer = new java.util.Timer(true);
  571. flowTimer.schedule(new TimerTask() {
  572. @Override
  573. public void run() {
  574. try {
  575. flowA.poll();
  576. flowB.poll();
  577. } catch (Exception e) {
  578. log.info("氦检流程异常: " + e.getMessage());
  579. }
  580. }
  581. }, 500, 500);
  582. addLog("氦检流程已启动");
  583. }
  584. public static void getMaterailData(){
  585. try{
  586. JSONObject retObj = DataUtil.getBindMaterail();
  587. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  588. java.util.List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  589. int i = 0;
  590. rowData = new Object[arrs.size()][7];
  591. for (BindMaterialResp bindMaterialResp:arrs){
  592. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  593. rowData[i][1] = bindMaterialResp.getBatchSn();
  594. rowData[i][2] = bindMaterialResp.getLastTimes();
  595. rowData[i][3] = "";
  596. rowData[i][4] = bindMaterialResp.getCraft();
  597. rowData[i][5] = bindMaterialResp.getMaterialId();
  598. rowData[i][6] = bindMaterialResp.getType();
  599. i++;
  600. }
  601. bindBatchPanel();
  602. }
  603. }catch (Exception e){
  604. log.info(e.getMessage());
  605. }
  606. }
  607. public static void updateMaterailData(){
  608. try{
  609. JSONObject retObj = DataUtil.getBindMaterail();
  610. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  611. List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  612. int i = 0;
  613. for (BindMaterialResp bindMaterialResp:arrs){
  614. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  615. rowData[i][1] = bindMaterialResp.getBatchSn();
  616. rowData[i][2] = bindMaterialResp.getLastTimes();
  617. rowData[i][3] = "";
  618. rowData[i][4] = bindMaterialResp.getCraft();
  619. rowData[i][5] = bindMaterialResp.getMaterialId();
  620. rowData[i][6] = bindMaterialResp.getType();
  621. i++;
  622. }
  623. MesClient.table.repaint();
  624. }
  625. }catch (Exception e){
  626. log.info(e.getMessage());
  627. }
  628. }
  629. // 绑定物料批次码
  630. public static void scanBatchSn(BindMaterialResp bindMaterialResp) {
  631. //弹窗扫工件码
  632. String scanBarcodeTitle = "请扫物料:"+bindMaterialResp.getMaterialTitle();
  633. String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
  634. if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
  635. JSONObject retObj = DataUtil.saveBindMaterail(scanBarcode,bindMaterialResp.getCraft(),bindMaterialResp.getMaterialId(),bindMaterialResp.getType());
  636. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  637. MesClient.setMenuStatus("扫物料:"+bindMaterialResp.getMaterialTitle()+"成功",0);
  638. updateMaterailData();
  639. }else{
  640. if(retObj.get("result")==null){
  641. MesClient.setMenuStatus("请求失败,请重试",-1);
  642. }else{
  643. if(retObj.get("result").toString().equalsIgnoreCase("false")){
  644. MesClient.setMenuStatus(retObj.getString("message"),-1);
  645. }
  646. }
  647. }
  648. }
  649. }
  650. public static void bindBatchPanel(){
  651. JPanel indexPanelBB = new JPanel();
  652. JPanel panel = new JPanel();
  653. panel.setBounds(0, 0, 990, 550);
  654. // panel.setBounds(81, 50, 810, 479);
  655. indexPanelBB.add(panel);
  656. panel.setLayout(new GridLayout(0, 1, 0, 0));
  657. table = new JTable(rowData, columnNames){
  658. public boolean isCellEditable(int row, int column) {
  659. if(column == 3){
  660. return true;
  661. }
  662. return false;
  663. }
  664. };
  665. table.setRowHeight(40);
  666. table.setEnabled(true);
  667. table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
  668. table.getColumnModel().getColumn(3).setCellRenderer(new TableCellRendererButton());
  669. table.getColumnModel().getColumn(3).setCellEditor(new TableCellEditorButton());
  670. JScrollPane scrollPane = new JScrollPane(table);
  671. panel.add(scrollPane);
  672. JScrollPane indexScrollPaneB = new JScrollPane(indexPanelBB);
  673. indexPanelBB.setLayout(null);
  674. tabbedPane.addTab("绑定物料", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), indexScrollPaneB, null);
  675. }
  676. // 开启发送结果定时任务
  677. public static void startUpdateQualityTimer(){
  678. // 创建异步线程池
  679. ExecutorService executorService = Executors.newSingleThreadExecutor();
  680. // 提交任务
  681. executorService.submit(() -> {
  682. log.info("异步任务执行中...");
  683. // 模拟耗时操作
  684. try {
  685. while (true){
  686. try {
  687. // 确保连接已经打开
  688. if (JdbcUtils.conn == null || JdbcUtils.conn.isClosed()) {
  689. JdbcUtils.openConnection();
  690. }
  691. Statement statement = JdbcUtils.conn.createStatement();
  692. String selectSql = "SELECT id, bw FROM submit_record\n" +
  693. "WHERE state = 0 ORDER BY id DESC LIMIT 10";
  694. String updateSql = "UPDATE submit_record \n" +
  695. "SET state = '1'\n" +
  696. "WHERE id = ";
  697. ResultSet rs = statement.executeQuery(selectSql);
  698. while(rs.next()){
  699. int id = rs.getInt("id");
  700. String bw = rs.getString("bw");
  701. // 发送请求
  702. String url = "http://"+MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/updateQualityByTiming";
  703. log.info("质量:"+bw);
  704. String s = HttpUtils.sendPostRequestJson(url, bw );
  705. log.info("结果:"+s);
  706. Boolean result = JSONObject.parseObject(s).getBoolean("result");
  707. if(result) {
  708. // 更改状态为 1
  709. statement.executeUpdate(updateSql + id);
  710. }
  711. }
  712. rs.close();
  713. statement.close();
  714. } catch (Exception e) {
  715. log.info(e.getMessage());
  716. }
  717. try {
  718. Thread.sleep(2000);
  719. }catch (Exception e){
  720. log.info(e.getMessage());
  721. }
  722. }
  723. } catch (Exception e) {
  724. log.info(e.getMessage());
  725. }
  726. log.info("异步任务执行完毕");
  727. });
  728. }
  729. }