MesClient.java 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  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.netty.NettyClient;
  6. import com.mes.netty.ProtocolParam;
  7. import com.mes.util.DateLocalUtils;
  8. import com.mes.util.ErrorMsg;
  9. import com.mes.util.HttpUtils;
  10. import com.mes.util.JdbcUtils;
  11. import javafx.embed.swing.JFXPanel;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import javax.swing.*;
  15. import javax.swing.border.EmptyBorder;
  16. import javax.swing.event.ChangeEvent;
  17. import javax.swing.event.ChangeListener;
  18. import java.awt.*;
  19. import java.awt.event.*;
  20. import java.io.*;
  21. import java.nio.channels.FileChannel;
  22. import java.nio.channels.FileLock;
  23. import java.nio.channels.OverlappingFileLockException;
  24. import java.sql.ResultSet;
  25. import java.sql.SQLException;
  26. import java.sql.Statement;
  27. import java.time.LocalDateTime;
  28. import java.util.List;
  29. import java.util.Properties;
  30. import java.util.Timer;
  31. import java.util.TimerTask;
  32. import java.util.concurrent.ExecutorService;
  33. import java.util.concurrent.Executors;
  34. public class MesClient extends JFrame {
  35. public static final Logger log = LoggerFactory.getLogger(MesClient.class);
  36. public static int mes_auth = 0; // 权限级别 0=无权限 1=操作工人 2=管理员
  37. public static String mes_gw = ""; // 工位号
  38. public static String mes_gw_des = ""; // 工位名称
  39. public static String mes_server_ip = ""; // 服务器IP地址
  40. public static int mes_tcp_port = 3000; // TCP服务端口
  41. public static int mes_heart_beat_cycle = 10; // 心跳周期
  42. public static int mes_heart_icon_cycle = 1;
  43. public static String mes_line_sn = ""; // 产线编号
  44. //TCP连接
  45. public static NettyClient nettyClient;
  46. //TCP连接状态
  47. public static boolean tcp_connect_flag = false;
  48. //TCP连接请求
  49. public static boolean connect_request_flag = false;
  50. //session
  51. public static String sessionid = "";
  52. public static JPanel contentPane;
  53. public static MesClient mesClientFrame;
  54. public static JTabbedPane tabbedPane;
  55. public static JScrollPane indexScrollPaneA;
  56. // public static JScrollPane searchScrollPane;
  57. public static JScrollPane searchScrollPaneDj;
  58. public static Boolean check_quality_result = false;
  59. public static Integer work_status = 0;
  60. public static JButton heart_beat_menu;
  61. public static JButton status_menu;
  62. public static JButton user_menu;
  63. public static int scan_type = 0;
  64. public static JButton finish_ok_bt;
  65. public static JButton finish_ng_bt;
  66. public static JTextField product_sn;
  67. public static JButton f_scan_data_bt_1;
  68. public static JButton nextBtn1; // 面板1的下一步
  69. public static JButton prevBtn2; // 面板2的上一步
  70. public static String user20 = "";
  71. public static JFrame welcomeWin;
  72. // public static JPanel indexPanelB;
  73. public static MesWebView jfxPanel = null;
  74. public static JPanel indexPanelC;
  75. public static MesWebView jfxPanel2 = null;
  76. public static MesRadio mesRadioHj;
  77. public static JTable table;
  78. public static Object[] columnNames = { "物料名称", "绑定批次", "剩余次数", "操作" };
  79. public static Object[][] rowData = null;
  80. public static JLabel fxlabel;
  81. public static JLabel timer_label; // 倒计时显示
  82. public static boolean timer_flag = false; // 开始计时标志 false=非工作开始计时 true=工件开始计时
  83. public static long timer_nums = 0; // 秒数
  84. public static JButton[] weldButtons = new JButton[116]; // 存储按钮对象
  85. public static boolean[] weldClickStates = new boolean[116]; // 存储点击状态
  86. public static JButton btnNormal;
  87. public static JButton btnRepair;
  88. public static int isRepair = 0; // 默认 0:正常, 1:返修
  89. public static void main(String[] args) {
  90. if (LockUtil.getInstance().isAppActive() == true){
  91. // JOptionPane.showMessageDialog(null, "已有一个程序在运行,程序退出");
  92. return;
  93. }else{
  94. EventQueue.invokeLater(new Runnable() {
  95. @Override
  96. public void run() {
  97. try{
  98. //读文件配置
  99. readProperty();
  100. // 显示界面
  101. mesClientFrame = new MesClient();
  102. mesClientFrame.setVisible(false);
  103. JdbcUtils.getConn();
  104. welcomeWin = new LoginFarme();
  105. welcomeWin.setVisible(true);
  106. getMaterailData();
  107. }catch (Exception e){
  108. e.printStackTrace();
  109. }
  110. }
  111. });
  112. }
  113. }
  114. //读配置文件
  115. private static void readProperty() throws IOException{
  116. String enconding = "UTF-8";
  117. InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
  118. Properties pro = new Properties();
  119. BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
  120. pro.load(br);
  121. mes_gw = pro.getProperty("mes.gw");
  122. mes_server_ip = pro.getProperty("mes.server_ip");
  123. mes_tcp_port = Integer.parseInt(pro.getProperty("mes.tcp_port"));
  124. mes_heart_beat_cycle = Integer.parseInt(pro.getProperty("mes.heart_beat_cycle"));
  125. mes_line_sn = pro.getProperty("mes.line_sn");
  126. mes_gw_des = OprnoUtil.getGwDes(mes_line_sn,mes_gw);
  127. log.info(mes_gw + ";" + mes_gw_des + ";" + mes_server_ip + ";" + mes_tcp_port + ";" + mes_heart_beat_cycle);
  128. }
  129. // // 初始化TCP
  130. // public static void initTcpConnection() {
  131. // try {
  132. // if(nettyClient==null) {
  133. // //初始化TCP连接
  134. // nettyClient = new NettyClient();
  135. // //TCP连接状态
  136. // tcp_connect_flag = false;
  137. // //设置TCP请求状态
  138. // connect_request_flag = true;
  139. //
  140. // DataUtil.synrTcp(nettyClient,mes_gw);
  141. // }
  142. // } catch (Exception e) {
  143. // // TODO Auto-generated catch block
  144. // e.printStackTrace();
  145. // }
  146. // }
  147. //启动心跳包程序
  148. public static java.util.Timer heartBeatTimer;
  149. public static java.util.Timer heartBeatIconTimer;
  150. public static boolean iconREDFlag = true;
  151. public static void startHeartBeatTimer() {
  152. if(heartBeatTimer!=null) {
  153. heartBeatTimer.cancel();
  154. }
  155. //心跳显示图标
  156. if(heartBeatIconTimer!=null) {
  157. heartBeatIconTimer.cancel();
  158. }
  159. heartBeatIconTimer = new Timer();
  160. heartBeatIconTimer.schedule(new TimerTask() {
  161. public void run() {
  162. if(iconREDFlag) {
  163. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  164. iconREDFlag = false;
  165. }else {
  166. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  167. iconREDFlag = true;
  168. }
  169. heart_beat_menu.setText(DateLocalUtils.getCurrentTime());
  170. heart_beat_menu.repaint();
  171. }
  172. }, 100,mes_heart_icon_cycle*1000);
  173. }
  174. //设置tcp连接状态显示
  175. public static void setTcpStatus() {
  176. status_menu.setText("已连接MES服务器");
  177. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
  178. heart_beat_menu.repaint();
  179. }
  180. public static void initWarehouseData(){
  181. resetScanA();
  182. }
  183. public static void resetScanA() {
  184. work_status = 0;
  185. check_quality_result = false;
  186. MesClient.finish_ok_bt.setEnabled(false);
  187. MesClient.finish_ng_bt.setEnabled(false);
  188. // product_sn.setText("000020015308-0100101425022500085");
  189. product_sn.setText("");
  190. MesClient.fxlabel.setVisible(false);
  191. MesClient.f_scan_data_bt_1.setEnabled(true);
  192. MesClient.status_menu.setText("请扫工件码");
  193. updateMaterailData();
  194. shiftUserCheck();
  195. // 重置漏点按钮状态
  196. closeWeldButton();
  197. closeRepairButton();
  198. btnNormal.setBackground(null);
  199. btnRepair.setBackground(null);
  200. isRepair = 0;
  201. // 重置时自动跳转回第一个标签页 (索引0)
  202. if (tabbedPane != null) {
  203. tabbedPane.setSelectedIndex(0);
  204. }
  205. }
  206. public static int userLoginHours;//用户登录所处小时
  207. //换班用户信息检查
  208. private static void shiftUserCheck() {
  209. LocalDateTime now = LocalDateTime.now();
  210. // 判断时间范围
  211. if (userLoginHours >= 8 && userLoginHours < 20) {
  212. int hour = now.getHour();
  213. if (hour >= 20 || hour < 8) {
  214. logoff();
  215. }
  216. } else {
  217. int hour = now.getHour();
  218. if (hour >= 8 && hour < 20) {
  219. logoff();
  220. }
  221. }
  222. }
  223. public static void resetScanB() {
  224. }
  225. //获取用户20位
  226. public static void getUser() {
  227. user20 = user_menu.getText().toString();
  228. String space_tmp1 = "";
  229. if(user20.length()<20) {
  230. for(int i=0;i<20-user20.length();i++) {
  231. space_tmp1 = space_tmp1 + " ";
  232. }
  233. }
  234. user20 = user20 + space_tmp1;
  235. }
  236. //获取barcode内容36位
  237. public static String getBarcode(String barcodeTmp) {
  238. String barcodeRet = barcodeTmp;
  239. if(barcodeTmp.equalsIgnoreCase("")) {
  240. return "";
  241. }else {
  242. if(barcodeTmp.length()<36) {
  243. String space = "";
  244. for(int i=0;i<36-barcodeTmp.length();i++) {
  245. space = space + " ";
  246. }
  247. barcodeRet = barcodeTmp + space;
  248. }
  249. }
  250. return barcodeRet;
  251. }
  252. public static void scanBarcode() {
  253. if(work_status == 1){
  254. JOptionPane.showMessageDialog(mesClientFrame,"工作中,勿扫码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
  255. return;
  256. }
  257. String scanBarcodeTitle = "";
  258. switch(scan_type) {
  259. case 1:
  260. product_sn.setText("");
  261. scanBarcodeTitle = "请扫工件码";
  262. break;
  263. }
  264. //弹窗扫工件码
  265. String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
  266. if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
  267. //工位号
  268. String gw = "";
  269. switch(scan_type) {
  270. case 1:
  271. product_sn.setText(scanBarcode);
  272. break;
  273. }
  274. //刷新界面
  275. mesClientFrame.repaint();
  276. // if(!tcp_connect_flag) {
  277. // MesClient.setMenuStatus("设备未连接Mes服务器",-1);
  278. //// JOptionPane.showMessageDialog(mesClientFrame,"设备未连接Mes服务器","提示窗口", JOptionPane.INFORMATION_MESSAGE);
  279. // return;
  280. // }
  281. MesClient.f_scan_data_bt_1.setEnabled(false);
  282. MesClient.startRepairButton();
  283. MesClient.setMenuStatus("请选择正常检查或返修检查", 0);
  284. }else {
  285. MesClient.setMenuStatus("请扫工件码,请重试",-1);
  286. // JOptionPane.showMessageDialog(mesClientFrame,"请扫工件码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
  287. return;
  288. }
  289. }
  290. private static void startInspection(int repairMode) {
  291. String barcode = product_sn.getText();
  292. if (barcode == null || barcode.trim().isEmpty()) {
  293. setMenuStatus("请先扫工件码", -1);
  294. return;
  295. }
  296. getUser();
  297. JSONObject retObj = DataUtil.pcCheck(barcode, user20, repairMode);
  298. if (retObj == null || retObj.get("result") == null) {
  299. setMenuStatus("请求失败,请重试", -1);
  300. return;
  301. }
  302. if (!retObj.get("result").toString().equalsIgnoreCase("true")) {
  303. setMenuStatus(retObj.getString("message"), -1);
  304. return;
  305. }
  306. isRepair = repairMode;
  307. btnNormal.setBackground(repairMode == 0 ? Color.GREEN : null);
  308. btnRepair.setBackground(repairMode == 1 ? Color.GREEN : null);
  309. fxlabel.setVisible(repairMode == 1);
  310. check_quality_result = true;
  311. work_status = 1;
  312. finish_ok_bt.setEnabled(true);
  313. finish_ng_bt.setEnabled(true);
  314. startWeldButton();
  315. closeRepairButton();
  316. setMenuStatus("该工件可以加工", 0);
  317. }
  318. public static void logoff() {
  319. welcomeWin.setVisible(true);
  320. mesClientFrame.setVisible(false);
  321. // nettyClient = null;
  322. // if(heartBeatTimer!=null) {
  323. // heartBeatTimer.cancel();
  324. // }
  325. // if(heartBeatIconTimer!=null) {
  326. // heartBeatIconTimer.cancel();
  327. // }
  328. // tcp_connect_flag = false;
  329. // connect_request_flag = false;
  330. }
  331. public MesClient() {
  332. setIconImage(Toolkit.getDefaultToolkit().getImage(MesClient.class.getResource("/bg/logo.png")));
  333. setTitle("MES系统客户端:"+mes_gw + "- " + mes_gw_des);
  334. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  335. setBounds(0, 0, 1024, 768);
  336. JMenuBar menuBar = new JMenuBar();
  337. menuBar.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 26));
  338. setJMenuBar(menuBar);
  339. // 左侧:工位号和名称
  340. JLabel gwLabel = new JLabel("工位:" + mes_gw + " - " + mes_gw_des);
  341. gwLabel.setFont(new Font("微软雅黑", Font.BOLD, 22));
  342. gwLabel.setForeground(new Color(0, 102, 204));
  343. gwLabel.setBorder(new EmptyBorder(0, 10, 0, 20));
  344. menuBar.add(gwLabel);
  345. // 添加弹簧组件,将后续组件推到右侧
  346. menuBar.add(Box.createHorizontalGlue());
  347. // 右侧:设置菜单
  348. JMenu settingMenu = new JMenu("设置");
  349. //settingMenu.setVisible(false);
  350. settingMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/menu_setting.png")));
  351. settingMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  352. menuBar.add(settingMenu);
  353. JMenuItem resetTcpMenu = new JMenuItem("\u91CD\u8FDEMES");
  354. resetTcpMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  355. resetTcpMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  356. resetTcpMenu.addMouseListener(new MouseAdapter() {
  357. @Override
  358. public void mousePressed(MouseEvent e) {
  359. super.mouseClicked(e);
  360. //重连mes
  361. // nettyClient.future.channel().close();
  362. }
  363. });
  364. settingMenu.add(resetTcpMenu);
  365. JMenuItem resetTcpMenu_1 = new JMenuItem("刷新工件");
  366. resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  367. resetTcpMenu_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  368. resetTcpMenu_1.addMouseListener(new MouseAdapter() {
  369. @Override
  370. public void mousePressed(MouseEvent e) {
  371. super.mouseClicked(e);
  372. resetScanA();
  373. }
  374. });
  375. settingMenu.add(resetTcpMenu_1);
  376. // 右侧:用户菜单
  377. JMenu fileMenu = new JMenu("用户");
  378. fileMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/user.png")));
  379. fileMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  380. menuBar.add(fileMenu);
  381. JMenuItem exitMenuItem = new JMenuItem("退出");
  382. exitMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/logoff.png")));
  383. exitMenuItem.setFont(new Font("微软雅黑", Font.PLAIN, 22));
  384. fileMenu.add(exitMenuItem);
  385. exitMenuItem.addMouseListener(new MouseAdapter() {
  386. @Override
  387. public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件
  388. super.mouseClicked(e);
  389. //dispose();
  390. // logoff();
  391. // 调用带密码验证的退出功能
  392. confirmLogout();
  393. }
  394. });
  395. resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  396. resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
  397. resetTcpMenu_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  398. resetTcpMenu_1.addMouseListener(new MouseAdapter() {
  399. @Override
  400. public void mousePressed(MouseEvent e) {
  401. super.mouseClicked(e);
  402. resetScanA();
  403. }
  404. });
  405. settingMenu.add(resetTcpMenu_1);
  406. contentPane = new JPanel();
  407. contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
  408. setContentPane(contentPane);
  409. contentPane.setLayout(new BorderLayout(0, 0));
  410. JToolBar toolBar = new JToolBar();
  411. contentPane.add(toolBar, BorderLayout.NORTH);
  412. JLabel equipment_statu_label = new JLabel("状态:");
  413. equipment_statu_label.setHorizontalAlignment(SwingConstants.CENTER);
  414. equipment_statu_label.setForeground(Color.BLACK);
  415. equipment_statu_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  416. equipment_statu_label.setBackground(Color.LIGHT_GRAY);
  417. toolBar.add(equipment_statu_label);
  418. status_menu = new JButton("设备未连接MES服务器");
  419. status_menu.setText("已连接MES服务器");
  420. status_menu.setForeground(Color.GREEN);
  421. status_menu.addActionListener(new ActionListener() {
  422. public void actionPerformed(ActionEvent e) {
  423. }
  424. });
  425. status_menu.setForeground(Color.GREEN);
  426. status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  427. status_menu.setBackground(Color.BLACK);
  428. toolBar.add(status_menu);
  429. JLabel space_1 = new JLabel(" ");
  430. toolBar.add(space_1);
  431. JLabel heart_beat_status_label = new JLabel("心跳:");
  432. heart_beat_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  433. heart_beat_status_label.setForeground(Color.BLACK);
  434. heart_beat_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  435. heart_beat_status_label.setBackground(Color.LIGHT_GRAY);
  436. toolBar.add(heart_beat_status_label);
  437. heart_beat_menu = new JButton("2024-02-20 23:20:10");
  438. heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
  439. heart_beat_menu.setForeground(Color.GREEN);
  440. heart_beat_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  441. heart_beat_menu.setBackground(Color.BLACK);
  442. toolBar.add(heart_beat_menu);
  443. JLabel space_2 = new JLabel(" ");
  444. toolBar.add(space_2);
  445. JLabel user_status_label = new JLabel("登录用户:");
  446. user_status_label.setHorizontalAlignment(SwingConstants.CENTER);
  447. user_status_label.setForeground(Color.BLACK);
  448. user_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  449. user_status_label.setBackground(Color.LIGHT_GRAY);
  450. toolBar.add(user_status_label);
  451. user_menu = new JButton("JinJuShi");
  452. user_menu.setForeground(Color.GREEN);
  453. user_menu.setFont(new Font("微软雅黑", Font.PLAIN, 22));
  454. user_menu.setBackground(Color.BLACK);
  455. toolBar.add(user_menu);
  456. JLabel space_3 = new JLabel(" ");
  457. toolBar.add(space_3);
  458. JLabel space_4 = new JLabel(" ");
  459. toolBar.add(space_4);
  460. tabbedPane = new JTabbedPane(JTabbedPane.TOP);
  461. tabbedPane.setMinimumSize(new Dimension(400, 50));
  462. tabbedPane.setFont(new Font("宋体", Font.BOLD, 15));
  463. contentPane.add(tabbedPane);
  464. // ==================== 工作面板 1 (Index 0) ====================
  465. JPanel indexPanelA = new JPanel();
  466. indexScrollPaneA = new JScrollPane(indexPanelA);
  467. indexPanelA.setLayout(new BorderLayout(10, 10));
  468. JPanel topContainer = new JPanel();
  469. topContainer.setLayout(new BoxLayout(topContainer, BoxLayout.Y_AXIS));
  470. // 1. 设置加工模式区域 (原本的第二行,现在先加,排在最上面)
  471. JPanel modeRow = new JPanel(new FlowLayout(FlowLayout.CENTER, 50, 10)); // 增加了垂直间距
  472. modeRow.setBorder(new EmptyBorder(10, 0, 0, 0)); // 顶部留一点边距,避免顶格
  473. btnNormal = new JButton("正常检查");
  474. btnNormal.setFont(new Font("微软雅黑", Font.BOLD, 24));
  475. btnNormal.setPreferredSize(new Dimension(220, 60));
  476. btnNormal.setEnabled(false);
  477. btnNormal.setBackground(Color.GREEN); //默认为绿色
  478. btnRepair = new JButton("返修检查");
  479. btnRepair.setFont(new Font("微软雅黑", Font.BOLD, 24));
  480. btnRepair.setPreferredSize(new Dimension(220, 60));
  481. btnRepair.setEnabled(false);
  482. btnNormal.addActionListener(e -> {
  483. startInspection(0);
  484. });
  485. btnRepair.addActionListener(e -> {
  486. startInspection(1);
  487. });
  488. modeRow.add(btnNormal);
  489. modeRow.add(btnRepair);
  490. // 2. 设置扫码区域 (原本的第一行,现在后加,排在下面)
  491. JPanel scanRow = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 20));
  492. product_sn = new JTextField(30);
  493. product_sn.setHorizontalAlignment(SwingConstants.CENTER);
  494. product_sn.setEditable(false);
  495. product_sn.setFont(new Font("微软雅黑", Font.PLAIN, 28));
  496. product_sn.setPreferredSize(new Dimension(600, 70));
  497. scanRow.add(product_sn);
  498. f_scan_data_bt_1 = new JButton("扫码");
  499. f_scan_data_bt_1.addActionListener(new ActionListener() {
  500. public void actionPerformed(ActionEvent e) {
  501. scan_type = 1;
  502. scanBarcode();
  503. }
  504. });
  505. f_scan_data_bt_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
  506. f_scan_data_bt_1.setFont(new Font("微软雅黑", Font.PLAIN, 32));
  507. f_scan_data_bt_1.setPreferredSize(new Dimension(198, 70));
  508. scanRow.add(f_scan_data_bt_1);
  509. topContainer.add(modeRow); // 按钮出现在最上方
  510. topContainer.add(scanRow); // 扫码框出现在下方
  511. indexPanelA.add(topContainer, BorderLayout.NORTH);
  512. // 中间面板:漏点按钮和返修标签
  513. JPanel centerPanel1 = new JPanel();
  514. centerPanel1.setLayout(new BorderLayout(10, 10));
  515. centerPanel1.setBorder(new EmptyBorder(10, 20, 10, 20));
  516. // 3. 漏点按钮 1-58 (数组下标 0-57)
  517. JPanel weldPanel1 = new JPanel();
  518. weldPanel1.setLayout(new GridLayout(8, 8, 10, 10)); // 8行8列
  519. weldPanel1.setOpaque(false);
  520. addWeldButtonsToPanel(weldPanel1, 0, 58); // 调用辅助方法
  521. centerPanel1.add(weldPanel1, BorderLayout.CENTER);
  522. // 4. 返修标签
  523. fxlabel = new JLabel("该工件为返修件,请仔细检查");
  524. fxlabel.setFont(new Font("微软雅黑", Font.PLAIN, 38));
  525. fxlabel.setForeground(Color.RED);
  526. fxlabel.setHorizontalAlignment(SwingConstants.CENTER);
  527. fxlabel.setPreferredSize(new Dimension(810, 70));
  528. fxlabel.setVisible(false);
  529. centerPanel1.add(fxlabel, BorderLayout.SOUTH);
  530. indexPanelA.add(centerPanel1, BorderLayout.CENTER);
  531. // 底部面板:下一步按钮
  532. JPanel bottomPanel1 = new JPanel();
  533. bottomPanel1.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10));
  534. bottomPanel1.setBorder(new EmptyBorder(10, 10, 20, 10));
  535. // 5. 下一步按钮 (跳转到面板2 - Tab Index 1)
  536. nextBtn1 = new JButton("下一步");
  537. nextBtn1.setFont(new Font("微软雅黑", Font.PLAIN, 24));
  538. nextBtn1.setPreferredSize(new Dimension(200, 60));
  539. nextBtn1.addActionListener(new ActionListener() {
  540. @Override
  541. public void actionPerformed(ActionEvent e) {
  542. tabbedPane.setSelectedIndex(1); // 跳转到第二个标签页
  543. }
  544. });
  545. bottomPanel1.add(nextBtn1);
  546. indexPanelA.add(bottomPanel1, BorderLayout.SOUTH);
  547. // 添加面板1到Tab
  548. tabbedPane.addTab("工作面板1-58", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA, null);
  549. // ==================== 工作面板 2 (Index 1) ====================
  550. JPanel indexPanelA2 = new JPanel();
  551. JScrollPane indexScrollPaneA2 = new JScrollPane(indexPanelA2);
  552. indexPanelA2.setLayout(new BorderLayout(10, 10));
  553. // 1. 漏点按钮 59-116 (数组下标 58-115)
  554. JPanel weldPanel2 = new JPanel();
  555. weldPanel2.setLayout(new GridLayout(8, 8, 10, 10));
  556. weldPanel2.setOpaque(false);
  557. weldPanel2.setBorder(new EmptyBorder(20, 20, 20, 20));
  558. addWeldButtonsToPanel(weldPanel2, 58, 116);
  559. indexPanelA2.add(weldPanel2, BorderLayout.CENTER);
  560. // 2. 底部按钮面板
  561. JPanel bottomPanel2 = new JPanel();
  562. bottomPanel2.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 10));
  563. bottomPanel2.setBorder(new EmptyBorder(10, 10, 20, 10));
  564. // 上一步按钮 (跳转到面板1 - Tab Index 0)
  565. prevBtn2 = new JButton("上一步");
  566. prevBtn2.setFont(new Font("微软雅黑", Font.PLAIN, 24));
  567. prevBtn2.setPreferredSize(new Dimension(200, 60));
  568. prevBtn2.addActionListener(new ActionListener() {
  569. @Override
  570. public void actionPerformed(ActionEvent e) {
  571. tabbedPane.setSelectedIndex(0);
  572. }
  573. });
  574. bottomPanel2.add(prevBtn2);
  575. // OK 按钮
  576. finish_ok_bt = new JButton("OK");
  577. finish_ok_bt.setEnabled(false);
  578. finish_ok_bt.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ok_bg.png")));
  579. finish_ok_bt.setFont(new Font("微软雅黑", Font.PLAIN, 32));
  580. finish_ok_bt.setPreferredSize(new Dimension(240, 80));
  581. finish_ok_bt.addActionListener(new ActionListener() {
  582. public void actionPerformed(ActionEvent e) {
  583. if(work_status == 1 && check_quality_result){
  584. String sn = product_sn.getText();
  585. if(sn == null || sn.trim().isEmpty()){
  586. MesClient.setMenuStatus("工件码为空,请重试",-1);
  587. return;
  588. }
  589. if(!getWeldTrueIndexes().isEmpty()){
  590. MesClient.setMenuStatus("提交漏点,请点NG",-1);
  591. return;
  592. }
  593. getUser();
  594. String result = "OK";
  595. JSONObject retObj = DataUtil.pcResult(sn,user20,"",result,isRepair);
  596. if (retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) {
  597. MesClient.resetScanA();
  598. MesClient.setMenuStatus("结果上传成功,请扫下一件", 0);
  599. MesClient.scan_type = 1;
  600. MesClient.scanBarcode();
  601. } else {
  602. MesClient.setMenuStatus("结果上传失败,请重试", -1);
  603. return;
  604. }
  605. }
  606. }
  607. });
  608. bottomPanel2.add(finish_ok_bt);
  609. // NG 按钮
  610. finish_ng_bt = new JButton("NG");
  611. finish_ng_bt.setEnabled(false);
  612. finish_ng_bt.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ng_bg.png")));
  613. finish_ng_bt.setFont(new Font("微软雅黑", Font.PLAIN, 32));
  614. finish_ng_bt.setPreferredSize(new Dimension(240, 80));
  615. finish_ng_bt.addActionListener(new ActionListener() {
  616. public void actionPerformed(ActionEvent e) {
  617. if(work_status == 1 && check_quality_result){
  618. String sn = product_sn.getText();
  619. if(sn == null || sn.trim().isEmpty()){
  620. MesClient.setMenuStatus("工件码为空,请重试",-1);
  621. return;
  622. }
  623. if(getWeldTrueIndexes().isEmpty()){
  624. MesClient.setMenuStatus("请选择漏点,进行NG提交",-1);
  625. return;
  626. }
  627. getUser();
  628. String result = "NG";
  629. JSONObject retObj = DataUtil.pcResult(sn,user20,getWeldTrueIndexes(),result,isRepair);
  630. if (retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) {
  631. MesClient.resetScanA();
  632. MesClient.setMenuStatus("结果上传成功,请扫下一件", 0);
  633. MesClient.scan_type = 1;
  634. MesClient.scanBarcode();
  635. } else {
  636. MesClient.setMenuStatus("结果上传失败,请重试", -1);
  637. return;
  638. }
  639. }
  640. }
  641. });
  642. bottomPanel2.add(finish_ng_bt);
  643. indexPanelA2.add(bottomPanel2, BorderLayout.SOUTH);
  644. // 添加面板2到Tab
  645. tabbedPane.addTab("工作面板59-116", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA2, null);
  646. tabbedPane.setEnabledAt(0, true);
  647. tabbedPane.setEnabledAt(1, true);
  648. // searchScrollPane = new JScrollPane((Component) null);
  649. indexPanelC = new JPanel();
  650. searchScrollPaneDj = new JScrollPane(indexPanelC);
  651. indexPanelC.setLayout(null);
  652. // tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
  653. // ========== 工作记录 Tab(改造:当前工位Tab + 所有工位Tab) ==========
  654. // 旧代码已注释:
  655. // indexPanelB = new JPanel();
  656. // searchScrollPane = new JScrollPane(indexPanelB);
  657. // indexPanelB.setLayout(null);
  658. // tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
  659. // 创建工作记录的子 TabbedPane
  660. JTabbedPane workRecordTabbedPane = new JTabbedPane(JTabbedPane.TOP);
  661. workRecordTabbedPane.setFont(new Font("微软雅黑", Font.PLAIN, 14));
  662. // OP80 工位:当前工位 + 所有工位
  663. WorkRecordPanel[] workRecordPanels = new WorkRecordPanel[2];
  664. // 当前工位Tab(使用配置文件中的 mes.gw)
  665. workRecordPanels[0] = new WorkRecordPanel(mes_gw, mes_line_sn);
  666. workRecordTabbedPane.addTab(mes_gw, null, workRecordPanels[0], "查询" + mes_gw + "的工作记录");
  667. // 所有工位Tab(查询整条产线所有工位)
  668. workRecordPanels[1] = new WorkRecordPanel(null, mes_line_sn);
  669. workRecordTabbedPane.addTab("所有工位", null, workRecordPanels[1], "查询整条产线所有工位的工作记录");
  670. // 切换子Tab时自动刷新数据
  671. workRecordTabbedPane.addChangeListener(e -> {
  672. int selectedIdx = workRecordTabbedPane.getSelectedIndex();
  673. if (selectedIdx >= 0 && selectedIdx < workRecordPanels.length) {
  674. workRecordPanels[selectedIdx].refreshData();
  675. }
  676. });
  677. // 将子 TabbedPane 添加到主 TabbedPane
  678. tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), workRecordTabbedPane, null);
  679. tabbedPane.addChangeListener(new ChangeListener() {
  680. @Override
  681. public void stateChanged(ChangeEvent e) {
  682. JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
  683. int selectedIndex = tabbedPane.getSelectedIndex();
  684. System.out.println("selectedIndex:"+selectedIndex);
  685. if(selectedIndex == 1){
  686. }
  687. }
  688. });
  689. ImagePanel hfPanel = new ImagePanel("/bg/zl.png");
  690. // 设置背景色(可选,比如设置为白色或灰色背景)
  691. hfPanel.setBackground(Color.WHITE);
  692. // 添加到 TabbedPane
  693. // 第二个参数是图标,这里复用了 menu_data_preprocess.png,您也可以换成其他图标
  694. tabbedPane.addTab("查看漏点", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), hfPanel, "查看漏点图片");
  695. }
  696. public static void setMenuStatus(String msg,int error){
  697. if(error == 0){
  698. MesClient.status_menu.setForeground(Color.GREEN);
  699. }else{
  700. MesClient.status_menu.setForeground(Color.RED);
  701. }
  702. MesClient.status_menu.setText(msg);
  703. }
  704. public static void getMaterailData(){
  705. try{
  706. JSONObject retObj = DataUtil.getBindMaterail();
  707. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  708. java.util.List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  709. int i = 0;
  710. rowData = new Object[arrs.size()][7];
  711. for (BindMaterialResp bindMaterialResp:arrs){
  712. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  713. rowData[i][1] = bindMaterialResp.getBatchSn();
  714. rowData[i][2] = bindMaterialResp.getLastTimes();
  715. rowData[i][3] = "";
  716. rowData[i][4] = bindMaterialResp.getCraft();
  717. rowData[i][5] = bindMaterialResp.getMaterialId();
  718. rowData[i][6] = bindMaterialResp.getType();
  719. i++;
  720. }
  721. bindBatchPanel();
  722. }
  723. }catch (Exception e){
  724. log.info(e.getMessage());
  725. }
  726. }
  727. public static void updateMaterailData(){
  728. try{
  729. JSONObject retObj = DataUtil.getBindMaterail();
  730. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  731. List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  732. int i = 0;
  733. for (BindMaterialResp bindMaterialResp:arrs){
  734. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  735. rowData[i][1] = bindMaterialResp.getBatchSn();
  736. rowData[i][2] = bindMaterialResp.getLastTimes();
  737. rowData[i][3] = "";
  738. rowData[i][4] = bindMaterialResp.getCraft();
  739. rowData[i][5] = bindMaterialResp.getMaterialId();
  740. rowData[i][6] = bindMaterialResp.getType();
  741. i++;
  742. }
  743. MesClient.table.repaint();
  744. }
  745. }catch (Exception e){
  746. log.info(e.getMessage());
  747. }
  748. }
  749. // 绑定物料批次码
  750. public static void scanBatchSn(BindMaterialResp bindMaterialResp) {
  751. //弹窗扫工件码
  752. String scanBarcodeTitle = "请扫物料:"+bindMaterialResp.getMaterialTitle();
  753. String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
  754. if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
  755. JSONObject retObj = DataUtil.saveBindMaterail(scanBarcode,bindMaterialResp.getCraft(),bindMaterialResp.getMaterialId(),bindMaterialResp.getType());
  756. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  757. MesClient.setMenuStatus("扫物料:"+bindMaterialResp.getMaterialTitle()+"成功",0);
  758. updateMaterailData();
  759. }else{
  760. if(retObj.get("result")==null){
  761. MesClient.setMenuStatus("请求失败,请重试",-1);
  762. }else{
  763. if(retObj.get("result").toString().equalsIgnoreCase("false")){
  764. MesClient.setMenuStatus(retObj.getString("message"),-1);
  765. }
  766. }
  767. }
  768. }
  769. }
  770. public static void bindBatchPanel(){
  771. JPanel indexPanelBB = new JPanel();
  772. JPanel panel = new JPanel();
  773. panel.setBounds(0, 0, 990, 550);
  774. // panel.setBounds(81, 50, 810, 479);
  775. indexPanelBB.add(panel);
  776. panel.setLayout(new GridLayout(0, 1, 0, 0));
  777. table = new JTable(rowData, columnNames){
  778. public boolean isCellEditable(int row, int column) {
  779. if(column == 3){
  780. return true;
  781. }
  782. return false;
  783. }
  784. };
  785. table.setRowHeight(40);
  786. table.setEnabled(true);
  787. table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
  788. table.getColumnModel().getColumn(3).setCellRenderer(new TableCellRendererButton());
  789. table.getColumnModel().getColumn(3).setCellEditor(new TableCellEditorButton());
  790. JScrollPane scrollPane = new JScrollPane(table);
  791. panel.add(scrollPane);
  792. JScrollPane indexScrollPaneB = new JScrollPane(indexPanelBB);
  793. indexPanelBB.setLayout(null);
  794. tabbedPane.addTab("绑定物料", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), indexScrollPaneB, null);
  795. }
  796. // 开启发送结果定时任务
  797. public static void startUpdateQualityTimer(){
  798. // 创建异步线程池
  799. ExecutorService executorService = Executors.newSingleThreadExecutor();
  800. // 提交任务
  801. executorService.submit(() -> {
  802. log.info("异步任务执行中...");
  803. // 模拟耗时操作
  804. try {
  805. while (true){
  806. try {
  807. // 确保连接已经打开
  808. if (JdbcUtils.conn == null || JdbcUtils.conn.isClosed()) {
  809. JdbcUtils.openConnection();
  810. }
  811. Statement statement = JdbcUtils.conn.createStatement();
  812. String selectSql = "SELECT id, bw FROM submit_record\n" +
  813. "WHERE state = 0 ORDER BY id DESC LIMIT 10";
  814. String updateSql = "UPDATE submit_record \n" +
  815. "SET state = '1'\n" +
  816. "WHERE id = ";
  817. ResultSet rs = statement.executeQuery(selectSql);
  818. while(rs.next()){
  819. int id = rs.getInt("id");
  820. String bw = rs.getString("bw");
  821. // 发送请求
  822. String url = "http://"+MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/updateQualityByTiming";
  823. log.info("质量:"+bw);
  824. String s = HttpUtils.sendPostRequestJson(url, bw );
  825. log.info("结果:"+s);
  826. Boolean result = JSONObject.parseObject(s).getBoolean("result");
  827. if(result) {
  828. // 更改状态为 1
  829. statement.executeUpdate(updateSql + id);
  830. }
  831. }
  832. rs.close();
  833. statement.close();
  834. } catch (Exception e) {
  835. log.info(e.getMessage());
  836. }
  837. try {
  838. Thread.sleep(2000);
  839. }catch (Exception e){
  840. log.info(e.getMessage());
  841. }
  842. }
  843. } catch (Exception e) {
  844. log.info(e.getMessage());
  845. }
  846. log.info("异步任务执行完毕");
  847. });
  848. }
  849. // 检测漏点是否全部点击完成
  850. public static void checkWeldCompletion() {
  851. boolean allClicked = true;
  852. for (boolean state : weldClickStates) {
  853. if (!state) {
  854. allClicked = false;
  855. break;
  856. }
  857. }
  858. }
  859. //开启漏点按钮
  860. public static void startWeldButton(){
  861. for (int i = 0; i < weldButtons.length; i++) {
  862. weldButtons[i].setEnabled(true);
  863. weldClickStates[i] = false; // 重置状态
  864. }
  865. if(nextBtn1 != null) nextBtn1.setEnabled(true);
  866. if(prevBtn2 != null) prevBtn2.setEnabled(true);
  867. }
  868. // 关闭漏点按钮和下一步,上一步按钮
  869. public static void closeWeldButton(){
  870. for (int i = 0; i < weldButtons.length; i++) {
  871. weldClickStates[i] = false; // 重置状态
  872. weldButtons[i].setBackground(null); // 重置颜色
  873. weldButtons[i].setEnabled(false);
  874. }
  875. // 关闭下一步,上一步按钮
  876. if(nextBtn1 != null) nextBtn1.setEnabled(false);
  877. if(prevBtn2 != null) prevBtn2.setEnabled(false);
  878. }
  879. //获取按钮下标
  880. public static String getWeldTrueIndexes() {
  881. StringBuilder sb = new StringBuilder();
  882. boolean first = true;
  883. for (int i = 0; i < weldClickStates.length; i++) {
  884. // 直接判断布尔值
  885. if (weldClickStates[i]) {
  886. if (!first) {
  887. sb.append(",");
  888. }
  889. sb.append(i+1);
  890. first = false;
  891. }
  892. }
  893. return sb.toString();
  894. }
  895. // 自定义面板,用于同比例缩放显示图片
  896. public class ImagePanel extends JPanel {
  897. private Image image;
  898. public ImagePanel(String imagePath) {
  899. // 加载图片资源
  900. try {
  901. ImageIcon icon = new ImageIcon(MesClient.class.getResource(imagePath));
  902. this.image = icon.getImage();
  903. } catch (Exception e) {
  904. log.error("加载图片失败: " + imagePath);
  905. }
  906. }
  907. @Override
  908. protected void paintComponent(Graphics g) {
  909. super.paintComponent(g);
  910. if (image != null) {
  911. // 获取面板的宽高
  912. int panelWidth = getWidth();
  913. int panelHeight = getHeight();
  914. // 获取图片的原始宽高
  915. int imageWidth = image.getWidth(this);
  916. int imageHeight = image.getHeight(this);
  917. if (imageWidth > 0 && imageHeight > 0) {
  918. // 计算缩放比例,保持长宽比
  919. double widthRatio = (double) panelWidth / imageWidth;
  920. double heightRatio = (double) panelHeight / imageHeight;
  921. double ratio = Math.min(widthRatio, heightRatio);
  922. // 计算新的绘制宽高
  923. int newWidth = (int) (imageWidth * ratio);
  924. int newHeight = (int) (imageHeight * ratio);
  925. // 计算居中位置
  926. int x = (panelWidth - newWidth) / 2;
  927. int y = (panelHeight - newHeight) / 2;
  928. // 绘制缩放后的图片
  929. g.drawImage(image, x, y, newWidth, newHeight, this);
  930. }
  931. }
  932. }
  933. }
  934. /**
  935. * 辅助方法:批量添加漏点按钮到指定面板
  936. * @param panel 目标面板
  937. * @param start 按钮起始索引(包含)
  938. * @param end 按钮结束索引(不包含)
  939. */
  940. private void addWeldButtonsToPanel(JPanel panel, int start, int end) {
  941. for (int i = start; i < end; i++) {
  942. // 防止数组越界 (安全检查)
  943. if (i >= weldButtons.length) break;
  944. int index = i; // 供内部类使用
  945. weldButtons[i] = new JButton("漏点" + (i + 1));
  946. weldButtons[i].setFont(new Font("微软雅黑", Font.PLAIN, 13));
  947. weldButtons[i].setEnabled(false); // 初始时禁用
  948. // 添加点击事件
  949. weldButtons[i].addActionListener(new ActionListener() {
  950. @Override
  951. public void actionPerformed(ActionEvent e) {
  952. JButton btn = (JButton) e.getSource();
  953. // 判断是否选中
  954. if (weldClickStates[index]) {
  955. // 取消选中
  956. btn.setBackground(null);
  957. weldClickStates[index] = false;
  958. log.info("已取消按钮: 漏点" + (index + 1));
  959. } else {
  960. // 选中
  961. btn.setBackground(Color.GREEN);
  962. weldClickStates[index] = true;
  963. log.info("已选中按钮: 漏点" + (index + 1));
  964. }
  965. }
  966. });
  967. panel.add(weldButtons[i]);
  968. }
  969. }
  970. /**
  971. * 密码验证后退出系统
  972. */
  973. private static void confirmLogout() {
  974. // 弹出密码输入对话框
  975. JPasswordField pwdField = new JPasswordField();
  976. Object[] message = {
  977. "请输入退出密码:",
  978. pwdField
  979. };
  980. pwdField.setFocusable(true);
  981. // 关键:添加层级监听器,监听密码框是否被加入对话框窗口
  982. pwdField.addHierarchyListener(new HierarchyListener() {
  983. @Override
  984. public void hierarchyChanged(HierarchyEvent evt) {
  985. // 检测:窗口已显示 + 组件可显示 + 焦点未被获取
  986. if ((evt.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) != 0
  987. && pwdField.isShowing()) {
  988. // 强制抢焦点(优先级最高)
  989. SwingUtilities.invokeLater(() -> {
  990. pwdField.requestFocus();
  991. pwdField.requestFocusInWindow();
  992. pwdField.grabFocus();
  993. pwdField.setCaretPosition(0);
  994. // 可选:禁用焦点遍历(防止焦点跳回按钮)
  995. pwdField.setFocusTraversalPolicyProvider(true);
  996. });
  997. }
  998. }
  999. });
  1000. int option = JOptionPane.showConfirmDialog(
  1001. mesClientFrame,
  1002. message,
  1003. "退出确认",
  1004. JOptionPane.OK_CANCEL_OPTION,
  1005. JOptionPane.QUESTION_MESSAGE
  1006. );
  1007. // 如果用户点击了确定按钮
  1008. if (option == JOptionPane.OK_OPTION) {
  1009. String inputPassword = new String(pwdField.getPassword());
  1010. // 验证密码
  1011. if (validatePassword(inputPassword)) {
  1012. // 密码正确,退出系统
  1013. // 执行清理操作
  1014. cleanupBeforeExit();
  1015. // 退出应用程序
  1016. System.exit(0);
  1017. } else {
  1018. // 密码错误,显示错误提示
  1019. JOptionPane.showMessageDialog(
  1020. mesClientFrame,
  1021. "密码错误,退出操作被拒绝",
  1022. "错误",
  1023. JOptionPane.ERROR_MESSAGE
  1024. );
  1025. }
  1026. }
  1027. }
  1028. /**
  1029. * 验证用户输入的密码
  1030. * @param inputPassword 用户输入的密码
  1031. * @return 验证结果
  1032. */
  1033. private static boolean validatePassword(String inputPassword) {
  1034. // 固定退出密码为503833
  1035. return "503833".equals(inputPassword);
  1036. }
  1037. /**
  1038. * 退出前的清理操作
  1039. */
  1040. private static void cleanupBeforeExit() {
  1041. // 关闭TCP连接
  1042. if(nettyClient != null) {
  1043. // nettyClient.close(); // 根据NettyClient的关闭方法调整
  1044. }
  1045. // 停止定时器
  1046. if(MesClient.heartBeatTimer != null) {
  1047. MesClient.heartBeatTimer.cancel();
  1048. }
  1049. if(MesClient.heartBeatIconTimer != null) {
  1050. MesClient.heartBeatIconTimer.cancel();
  1051. }
  1052. // 关闭数据库连接
  1053. try {
  1054. if(JdbcUtils.conn != null && !JdbcUtils.conn.isClosed()) {
  1055. JdbcUtils.conn.close();
  1056. }
  1057. } catch (Exception e) {
  1058. log.error("关闭数据库连接失败", e);
  1059. }
  1060. }
  1061. //开启加工返修按钮
  1062. public static void startRepairButton() {
  1063. MesClient.btnNormal.setEnabled(true);
  1064. MesClient.btnRepair.setEnabled(true);
  1065. }
  1066. //重置加工返修按钮
  1067. public static void closeRepairButton() {
  1068. MesClient.btnNormal.setEnabled(false);
  1069. MesClient.btnRepair.setEnabled(false);
  1070. }
  1071. }