瀏覽代碼

初始化+隐藏中转车

liuwei 2 周之前
當前提交
dcd1da622d
共有 100 個文件被更改,包括 3724 次插入 和 0 次删除
  1. 24 0
      .classpath
  2. 7 0
      .gitignore
  3. 17 0
      .project
  4. 0 0
      README.md
  5. 2 0
      image/.gitignore
  6. 二進制
      image/background.png
  7. 二進制
      image/bg/a_side.png
  8. 二進制
      image/bg/b_side.png
  9. 二進制
      image/bg/bar_add.png
  10. 二進制
      image/bg/bar_bookmark.png
  11. 二進制
      image/bg/bar_cmd_go.png
  12. 二進制
      image/bg/bar_edit.png
  13. 二進制
      image/bg/bar_pause.png
  14. 二進制
      image/bg/bar_sampling.png
  15. 二進制
      image/bg/bar_setting.png
  16. 二進制
      image/bg/bar_stop.png
  17. 二進制
      image/bg/close_bt.png
  18. 二進制
      image/bg/company_setting_logo.png
  19. 二進制
      image/bg/delete.png
  20. 二進制
      image/bg/department_setting_logo.png
  21. 二進制
      image/bg/download.png
  22. 二進制
      image/bg/equipment_setting_logo.png
  23. 二進制
      image/bg/gj_001_1_20.png
  24. 二進制
      image/bg/gj_001_21_40.png
  25. 二進制
      image/bg/gj_001_41_60.png
  26. 二進制
      image/bg/green_dot.png
  27. 二進制
      image/bg/grey_dot.png
  28. 二進制
      image/bg/icon.png
  29. 二進制
      image/bg/inductance_logo.png
  30. 二進制
      image/bg/insulation_logo.png
  31. 二進制
      image/bg/login.png
  32. 二進制
      image/bg/logo.png
  33. 二進制
      image/bg/logoff.png
  34. 二進制
      image/bg/menu_data_analysis.png
  35. 二進制
      image/bg/menu_data_preprocess.png
  36. 二進制
      image/bg/menu_file.png
  37. 二進制
      image/bg/menu_setting.png
  38. 二進制
      image/bg/min_bt.png
  39. 二進制
      image/bg/ng_bg.png
  40. 二進制
      image/bg/ok_bg.png
  41. 二進制
      image/bg/open_file.png
  42. 二進制
      image/bg/refresh.png
  43. 二進制
      image/bg/reset_logo.png
  44. 二進制
      image/bg/resistance_logo.png
  45. 二進制
      image/bg/save_bg.png
  46. 二進制
      image/bg/scan_barcode.png
  47. 二進制
      image/bg/tree_folder_icon.png
  48. 二進制
      image/bg/tree_leaf_icon.png
  49. 二進制
      image/bg/user.png
  50. 二進制
      image/bg/vertical_line.png
  51. 二進制
      image/bg/zoom_in.png
  52. 二進制
      image/bg/zoom_out.png
  53. 二進制
      image/close_bt.png
  54. 0 0
      image/cmd.txt
  55. 二進制
      image/icon.ico
  56. 二進制
      image/info_bt.png
  57. 二進制
      image/min_bt.png
  58. 二進制
      lib/bcpkix-jdk15on-1.69.jar
  59. 二進制
      lib/bcprov-jdk15on-1.70.jar
  60. 二進制
      lib/bcutil-jdk15on-1.69.jar
  61. 二進制
      lib/commons-codec-1.15.jar
  62. 二進制
      lib/core-3.5.1.jar
  63. 二進制
      lib/failureaccess-1.0.1.jar
  64. 二進制
      lib/fastjson2-2.0.16.jar
  65. 二進制
      lib/gson-2.10.jar
  66. 二進制
      lib/guava-31.0.1-jre.jar
  67. 二進制
      lib/iot-communication-1.4.4.jar
  68. 二進制
      lib/javase-3.5.1.jar
  69. 二進制
      lib/jfreechart-1.5.4.jar
  70. 二進制
      lib/jshortcut-0.4-oberzalek.jar
  71. 二進制
      lib/kotlin-stdlib-1.8.10.jar
  72. 二進制
      lib/logback-classic-1.2.13.jar
  73. 二進制
      lib/logback-core-1.2.13.jar
  74. 二進制
      lib/netty-all-4.1.48.Final.jar
  75. 二進制
      lib/netty-channel-fsm-0.8.jar
  76. 二進制
      lib/okhttp-4.10.0.jar
  77. 二進制
      lib/okio-jvm-3.3.0.jar
  78. 二進制
      lib/s7connector-2.1.jar
  79. 二進制
      lib/sdk-client-0.6.9.jar
  80. 二進制
      lib/sdk-core-0.6.9.jar
  81. 二進制
      lib/slf4j-api-1.7.36.jar
  82. 二進制
      lib/sqlite-jdbc-3.36.0.3.jar
  83. 二進制
      lib/stack-client-0.6.9.jar
  84. 二進制
      lib/stack-core-0.6.9.jar
  85. 二進制
      lib/strict-machine-0.6.jar
  86. 3 0
      src/META-INF/MANIFEST.MF
  87. 13 0
      src/com/mes/component/CallFromJs.java
  88. 62 0
      src/com/mes/component/MesRadio.java
  89. 48 0
      src/com/mes/component/MesWebView.java
  90. 30 0
      src/com/mes/component/MyDialog.java
  91. 286 0
      src/com/mes/component/PlcSignalMonitor.java
  92. 861 0
      src/com/mes/component/WorkJPanelOP150.java
  93. 58 0
      src/com/mes/ui/BindMaterialResp.java
  94. 89 0
      src/com/mes/ui/CacheData.java
  95. 71 0
      src/com/mes/ui/CncParamReq.java
  96. 318 0
      src/com/mes/ui/DataUtil.java
  97. 214 0
      src/com/mes/ui/LoginFarme.java
  98. 1563 0
      src/com/mes/ui/MesClient.java
  99. 58 0
      src/com/mes/ui/ParamReq.java
  100. 0 0
      src/com/mes/ui/TableCellEditorButton.java

+ 24 - 0
.classpath

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="module" value="true"/>
+		</attributes>
+	</classpathentry>
+    <classpathentry kind="src" path="image"/>
+	<classpathentry excluding="resources/" kind="src" path="src"/>
+	<classpathentry kind="src" path="src/resources"/>
+	<classpathentry kind="output" path="bin"/>
+	<classpathentry kind="lib" path="lib/s7connector-2.1.jar"/>
+	<classpathentry kind="lib" path="lib/slf4j-api-2.0.6.jar"/>
+	<classpathentry kind="lib" path="lib/okhttp-4.10.0.jar"/>
+	<classpathentry kind="lib" path="lib/kotlin-stdlib-1.8.10.jar"/>
+	<classpathentry kind="lib" path="lib/okio-jvm-3.3.0.jar"/>
+	<classpathentry kind="lib" path="lib/gson-2.10.jar"/>
+	<classpathentry kind="lib" path="lib/jfreechart-1.5.4.jar"/>
+	<classpathentry kind="lib" path="lib/jshortcut-0.4-oberzalek.jar"/>
+	<classpathentry kind="lib" path="lib/netty-all-4.1.48.Final.jar"/>
+	<classpathentry kind="lib" path="lib/sqlite-jdbc-3.36.0.3.jar"/>
+	<classpathentry kind="lib" path="lib/commons-codec-1.15.jar"/>
+	<classpathentry kind="lib" path="lib/fastjson2-2.0.16.jar"/>
+</classpath>

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+.idea
+.settings
+classes
+bin
+out
+*.db
+*.iml

+ 17 - 0
.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mesclient</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>

+ 0 - 0
README.md


+ 2 - 0
image/.gitignore

@@ -0,0 +1,2 @@
+META-INF
+_system~.ini

二進制
image/background.png


二進制
image/bg/a_side.png


二進制
image/bg/b_side.png


二進制
image/bg/bar_add.png


二進制
image/bg/bar_bookmark.png


二進制
image/bg/bar_cmd_go.png


二進制
image/bg/bar_edit.png


二進制
image/bg/bar_pause.png


二進制
image/bg/bar_sampling.png


二進制
image/bg/bar_setting.png


二進制
image/bg/bar_stop.png


二進制
image/bg/close_bt.png


二進制
image/bg/company_setting_logo.png


二進制
image/bg/delete.png


二進制
image/bg/department_setting_logo.png


二進制
image/bg/download.png


二進制
image/bg/equipment_setting_logo.png


二進制
image/bg/gj_001_1_20.png


二進制
image/bg/gj_001_21_40.png


二進制
image/bg/gj_001_41_60.png


二進制
image/bg/green_dot.png


二進制
image/bg/grey_dot.png


二進制
image/bg/icon.png


二進制
image/bg/inductance_logo.png


二進制
image/bg/insulation_logo.png


二進制
image/bg/login.png


二進制
image/bg/logo.png


二進制
image/bg/logoff.png


二進制
image/bg/menu_data_analysis.png


二進制
image/bg/menu_data_preprocess.png


二進制
image/bg/menu_file.png


二進制
image/bg/menu_setting.png


二進制
image/bg/min_bt.png


二進制
image/bg/ng_bg.png


二進制
image/bg/ok_bg.png


二進制
image/bg/open_file.png


二進制
image/bg/refresh.png


二進制
image/bg/reset_logo.png


二進制
image/bg/resistance_logo.png


二進制
image/bg/save_bg.png


二進制
image/bg/scan_barcode.png


二進制
image/bg/tree_folder_icon.png


二進制
image/bg/tree_leaf_icon.png


二進制
image/bg/user.png


二進制
image/bg/vertical_line.png


二進制
image/bg/zoom_in.png


二進制
image/bg/zoom_out.png


二進制
image/close_bt.png


+ 0 - 0
image/cmd.txt


二進制
image/icon.ico


二進制
image/info_bt.png


二進制
image/min_bt.png


二進制
lib/bcpkix-jdk15on-1.69.jar


二進制
lib/bcprov-jdk15on-1.70.jar


二進制
lib/bcutil-jdk15on-1.69.jar


二進制
lib/commons-codec-1.15.jar


二進制
lib/core-3.5.1.jar


二進制
lib/failureaccess-1.0.1.jar


二進制
lib/fastjson2-2.0.16.jar


二進制
lib/gson-2.10.jar


二進制
lib/guava-31.0.1-jre.jar


二進制
lib/iot-communication-1.4.4.jar


二進制
lib/javase-3.5.1.jar


二進制
lib/jfreechart-1.5.4.jar


二進制
lib/jshortcut-0.4-oberzalek.jar


二進制
lib/kotlin-stdlib-1.8.10.jar


二進制
lib/logback-classic-1.2.13.jar


二進制
lib/logback-core-1.2.13.jar


二進制
lib/netty-all-4.1.48.Final.jar


二進制
lib/netty-channel-fsm-0.8.jar


二進制
lib/okhttp-4.10.0.jar


二進制
lib/okio-jvm-3.3.0.jar


二進制
lib/s7connector-2.1.jar


二進制
lib/sdk-client-0.6.9.jar


二進制
lib/sdk-core-0.6.9.jar


二進制
lib/slf4j-api-1.7.36.jar


二進制
lib/sqlite-jdbc-3.36.0.3.jar


二進制
lib/stack-client-0.6.9.jar


二進制
lib/stack-core-0.6.9.jar


二進制
lib/strict-machine-0.6.jar


+ 3 - 0
src/META-INF/MANIFEST.MF

@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: com.mes.ui.MesClient
+

+ 13 - 0
src/com/mes/component/CallFromJs.java

@@ -0,0 +1,13 @@
+package com.mes.component;
+
+import com.mes.ui.MesClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CallFromJs {
+    public static final Logger log =  LoggerFactory.getLogger(CallFromJs.class);
+    public String callFromJs(String info){
+        log.info("ss:"+info);
+        return MesClient.sessionid+":java:" + info;
+    }
+}

+ 62 - 0
src/com/mes/component/MesRadio.java

@@ -0,0 +1,62 @@
+package com.mes.component;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class MesRadio extends JPanel {
+
+    public static final Logger log =  LoggerFactory.getLogger(MesRadio.class);
+
+    private String result = "";
+    private Integer i = 0;
+
+    public MesRadio(String[] radioTitles,String[] radioVals){
+        this.setLayout(new FlowLayout());
+        ButtonGroup group = new ButtonGroup();
+        i = 0;
+        for (String title:radioTitles){
+            JRadioButton radioButton = new JRadioButton(title);
+            radioButton.setFont(new Font("微软雅黑", Font.PLAIN, 28));
+
+            String val = radioVals[i];
+            radioButton.setName(val);
+
+            this.add(radioButton);
+            group.add(radioButton);
+
+            radioButton.addActionListener(new ActionListener() {
+                @Override
+                public void actionPerformed(ActionEvent e) {
+                    result = val;
+                    log.info("选择:"+result);
+                }
+            });
+            i++;
+        }
+    }
+
+    public void setResult(String ret){
+        this.result = "";
+        Component[] components = this.getComponents();
+        for (Component jRadioButton:components){
+            if(jRadioButton instanceof JRadioButton){
+                JRadioButton jRadioButtonParam = (JRadioButton)jRadioButton;
+                if(ret.equals(jRadioButtonParam.getName())){
+                    jRadioButtonParam.setSelected(true);
+                    this.result = jRadioButtonParam.getName();
+                }else{
+                    jRadioButtonParam.setSelected(false);
+                }
+            }
+        }
+    }
+
+    public String getResult(){
+        return this.result;
+    }
+}

+ 48 - 0
src/com/mes/component/MesWebView.java

@@ -0,0 +1,48 @@
+package com.mes.component;
+
+import javafx.application.Platform;
+import javafx.beans.value.ObservableValue;
+import javafx.concurrent.Worker;
+import javafx.embed.swing.JFXPanel;
+import javafx.scene.Scene;
+import javafx.scene.web.WebEngine;
+import javafx.scene.web.WebView;
+import netscape.javascript.JSObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+
+public class MesWebView extends JFXPanel {
+
+    public static final Logger log =  LoggerFactory.getLogger(MesWebView.class);
+
+    public static WebEngine engine = null;
+
+    public MesWebView(String url){
+
+        Platform.runLater(() -> {
+            WebView webView = new WebView();
+            setScene(new Scene(webView));
+            Date date = new Date();
+//            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesQuality/check?__sid="+sessionid+"&oprno="+mes_gw+"&t="+date.getTime();
+            log.info(url);
+            engine = webView.getEngine();
+            CallFromJs bridge = new CallFromJs();
+            engine.getLoadWorker().stateProperty().addListener(
+                    (ObservableValue<? extends Worker.State> ov, Worker.State oldState, Worker.State newState) -> {
+                        if (newState == Worker.State.SUCCEEDED) {
+                            JSObject window = (JSObject) engine.executeScript("window");
+                            window.setMember("apps", bridge);
+                            window.setMember("sout", System.out);
+                        }
+                    }
+            );
+            engine.load(url);
+        });
+    }
+
+    public void reloadWeb(){
+        engine.reload();
+    }
+}

+ 30 - 0
src/com/mes/component/MyDialog.java

@@ -0,0 +1,30 @@
+package com.mes.component;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class MyDialog extends JDialog {
+
+    public MyDialog(Frame owner, String title, String msg){
+        super(owner, title);
+        init(msg);
+    }
+
+    private void init(String msg){
+        Container container = this.getContentPane();
+        container.setLayout(null);
+        container.setBackground(Color.BLACK);
+        this.setSize(800,220);
+        this.setLocationRelativeTo(null);
+
+        JLabel tslabel = new JLabel(msg);
+        tslabel.setHorizontalAlignment(SwingConstants.CENTER);
+        tslabel.setForeground(Color.RED);
+        tslabel.setFont(new Font("微软雅黑", Font.PLAIN,48));
+        tslabel.setBounds(0,30,800,100);
+
+        container.add(tslabel);
+        this.setModal(true);
+        this.setVisible(true);
+    }
+}

+ 286 - 0
src/com/mes/component/PlcSignalMonitor.java

@@ -0,0 +1,286 @@
+package com.mes.component;
+
+import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * PLC信号监控组件
+ * 可复用的信号监控面板,支持显示PLC信号状态和详细对话框
+ */
+public class PlcSignalMonitor {
+
+    private static final Logger log = LoggerFactory.getLogger(PlcSignalMonitor.class);
+
+    private S7PLC s7PLC;
+    private String plcDb;
+    private String stationName;
+    private JFrame parentFrame;
+
+    // 信号标签(用于对话框中的实时更新)
+    private JLabel signal_feeding;
+    private JLabel signal_blanking;
+    private JLabel signal_running;
+    private JLabel signal_deviceStatus;
+    private JLabel signal_allowFeeding;
+    private JLabel signal_allowBlanking;
+    private JLabel signal_heart;
+    private JLabel signal_toDevice; // 保留:上料到设备
+
+    /**
+     * 构造函数
+     * @param s7PLC PLC连接对象
+     * @param plcDb DB块名称(如 DB7000)
+     * @param stationName 工位名称(如 OP040A)
+     * @param parentFrame 父窗口
+     */
+    public PlcSignalMonitor(S7PLC s7PLC, String plcDb, String stationName, JFrame parentFrame) {
+        this.s7PLC = s7PLC;
+        this.plcDb = plcDb;
+        this.stationName = stationName;
+        this.parentFrame = parentFrame;
+    }
+
+    /**
+     * 创建信号监控按钮(放在工位面板中)
+     * @return 信号监控按钮
+     */
+    public JButton createSignalButton() {
+        JButton signalBtn = new JButton("PLC信号");
+        signalBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
+        signalBtn.setForeground(new Color(0, 102, 204));
+        signalBtn.setToolTipText("点击查看PLC信号详情");
+        signalBtn.addActionListener(e -> showSignalDialog());
+        return signalBtn;
+    }
+
+    /**
+     * 创建信号标签
+     */
+    private JLabel createSignalLabel(String text, boolean active) {
+        JLabel label = new JLabel(text);
+        label.setOpaque(true);
+        label.setFont(new Font("微软雅黑", Font.PLAIN, 11));
+        label.setHorizontalAlignment(SwingConstants.CENTER);
+        label.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
+        label.setPreferredSize(new Dimension(50, 18));
+        updateSignalLabel(label, active);
+        return label;
+    }
+
+    /**
+     * 更新信号标签状态
+     */
+    private void updateSignalLabel(JLabel label, boolean active) {
+        if (active) {
+            label.setBackground(new Color(0, 200, 0));
+            label.setForeground(Color.WHITE);
+        } else {
+            label.setBackground(new Color(200, 200, 200));
+            label.setForeground(Color.DARK_GRAY);
+        }
+    }
+
+    /**
+     * 显示信号监控对话框
+     */
+    public void showSignalDialog() {
+        JDialog dialog = new JDialog(parentFrame, stationName + " - PLC信号监控", false);
+        dialog.setSize(550, 400);
+        dialog.setLocationRelativeTo(parentFrame);
+
+        JPanel panel = new JPanel();
+        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
+
+        // 标题
+        JLabel title = new JLabel("PLC信号实时监控");
+        title.setFont(new Font("微软雅黑", Font.BOLD, 16));
+        title.setAlignmentX(Component.CENTER_ALIGNMENT);
+        panel.add(title);
+        panel.add(Box.createVerticalStrut(10));
+
+        // 工位信息
+        JLabel stationInfo = new JLabel("工位: " + stationName + " | DB块: " + plcDb);
+        stationInfo.setFont(new Font("微软雅黑", Font.PLAIN, 12));
+        stationInfo.setForeground(Color.GRAY);
+        stationInfo.setAlignmentX(Component.CENTER_ALIGNMENT);
+        panel.add(stationInfo);
+        panel.add(Box.createVerticalStrut(15));
+
+        // 信号详情面板
+        JPanel signalPanel = createSignalDetailPanel();
+        panel.add(signalPanel);
+
+        panel.add(Box.createVerticalStrut(15));
+
+        // 刷新按钮
+        JButton refreshBtn = new JButton("刷新信号");
+        refreshBtn.setFont(new Font("微软雅黑", Font.PLAIN, 12));
+        refreshBtn.setAlignmentX(Component.CENTER_ALIGNMENT);
+        refreshBtn.addActionListener(e -> updateSignalDisplay());
+        panel.add(refreshBtn);
+
+        dialog.add(panel);
+
+        // 首次显示时更新信号
+        updateSignalDisplay();
+
+        dialog.setVisible(true);
+    }
+
+    /**
+     * 创建信号详情面板
+     */
+    private JPanel createSignalDetailPanel() {
+        String[][] signals = {
+                {"请求扫码", plcDb + ".0.0", "PLC→MES"},
+                {"下料信号", plcDb + ".0.1", "PLC→MES"},
+                {"设备运行", plcDb + ".0.2", "PLC→MES"},
+                {"设备通讯", plcDb + ".0.3", "PLC状态"},
+                {"MES允许上料", plcDb + ".0.4", "MES→PLC"},
+                {"MES允许下料", plcDb + ".0.5", "MES→PLC"},
+                {"心跳信号", plcDb + ".0.6", "MES→PLC"},
+                {"上料到设备", plcDb + ".0.7", "PLC→MES"}  // 保留了 0.7 信号
+        };
+
+        JPanel panel = new JPanel(new GridLayout(signals.length + 1, 4, 5, 5));
+        panel.setBorder(BorderFactory.createTitledBorder(stationName + " 信号状态"));
+
+        // 表头
+        panel.add(createHeaderLabel("信号名称"));
+        panel.add(createHeaderLabel("地址"));
+        panel.add(createHeaderLabel("方向"));
+        panel.add(createHeaderLabel("状态"));
+
+        // 初始化信号标签
+        signal_feeding = createStatusLabel();
+        signal_blanking = createStatusLabel();
+        signal_running = createStatusLabel();
+        signal_deviceStatus = createStatusLabel();
+        signal_allowFeeding = createStatusLabel();
+        signal_allowBlanking = createStatusLabel();
+        signal_heart = createStatusLabel();
+        signal_toDevice = createStatusLabel(); // 保留
+
+        JLabel[] statusLabels = {
+                signal_feeding, signal_blanking, signal_running, signal_deviceStatus,
+                signal_allowFeeding, signal_allowBlanking, signal_heart,
+                signal_toDevice
+        };
+
+        // 添加信号行
+        for (int i = 0; i < signals.length; i++) {
+            panel.add(new JLabel(signals[i][0], SwingConstants.CENTER));
+            panel.add(new JLabel(signals[i][1], SwingConstants.CENTER));
+            panel.add(new JLabel(signals[i][2], SwingConstants.CENTER));
+            panel.add(statusLabels[i]);
+        }
+
+        return panel;
+    }
+
+    /**
+     * 创建表头标签
+     */
+    private JLabel createHeaderLabel(String text) {
+        JLabel label = new JLabel(text, SwingConstants.CENTER);
+        label.setFont(new Font("微软雅黑", Font.BOLD, 12));
+        return label;
+    }
+
+    /**
+     * 创建状态标签
+     */
+    private JLabel createStatusLabel() {
+        JLabel label = new JLabel("--", SwingConstants.CENTER);
+        label.setOpaque(true);
+        label.setBackground(Color.LIGHT_GRAY);
+        label.setFont(new Font("微软雅黑", Font.PLAIN, 11));
+        return label;
+    }
+
+    /**
+     * 更新信号显示
+     */
+    private void updateSignalDisplay() {
+        try {
+            if (s7PLC == null) {
+                log.warn("[{}] PLC连接为空,无法读取信号", stationName);
+                showConnectionError();
+                return;
+            }
+
+            // 读取所有信号
+            boolean feeding = s7PLC.readBoolean(plcDb + ".0.0");
+            boolean blanking = s7PLC.readBoolean(plcDb + ".0.1");
+            boolean running = s7PLC.readBoolean(plcDb + ".0.2");
+            boolean deviceStatus = s7PLC.readBoolean(plcDb + ".0.3");
+            boolean allowFeeding = s7PLC.readBoolean(plcDb + ".0.4");
+            boolean allowBlanking = s7PLC.readBoolean(plcDb + ".0.5");
+            boolean heart = s7PLC.readBoolean(plcDb + ".0.6");
+            boolean toDevice = s7PLC.readBoolean(plcDb + ".0.7"); // 读取 0.7 信号
+
+            // 在EDT线程中更新UI
+            SwingUtilities.invokeLater(() -> {
+                updateStatusLabel(signal_feeding, feeding);
+                updateStatusLabel(signal_blanking, blanking);
+                updateStatusLabel(signal_running, running);
+                updateStatusLabel(signal_deviceStatus, deviceStatus);
+                updateStatusLabel(signal_allowFeeding, allowFeeding);
+                updateStatusLabel(signal_allowBlanking, allowBlanking);
+                updateStatusLabel(signal_heart, heart);
+                updateStatusLabel(signal_toDevice, toDevice); // 更新 0.7 信号 UI
+            });
+
+        } catch (Exception e) {
+            String errorMsg = e.getMessage();
+            if (errorMsg != null && errorMsg.contains("connect timed out")) {
+                log.warn("[{}] PLC连接超时,请检查网络连接", stationName);
+            } else {
+                log.error("[{}] 读取PLC信号异常: {}", stationName, errorMsg);
+            }
+            // 在UI上显示错误提示
+            SwingUtilities.invokeLater(this::showConnectionError);
+        }
+    }
+
+    /**
+     * 显示连接错误提示
+     */
+    private void showConnectionError() {
+        JLabel[] labels = {
+                signal_feeding, signal_blanking, signal_running, signal_deviceStatus,
+                signal_allowFeeding, signal_allowBlanking, signal_heart,
+                signal_toDevice
+        };
+
+        for (JLabel label : labels) {
+            if (label != null) {
+                label.setText("ERR");
+                label.setBackground(Color.ORANGE);
+                label.setForeground(Color.WHITE);
+            }
+        }
+    }
+
+    /**
+     * 更新状态标签
+     */
+    private void updateStatusLabel(JLabel label, boolean active) {
+        if (label != null) {
+            if (active) {
+                label.setText("ON");
+                label.setBackground(new Color(0, 200, 0));
+                label.setForeground(Color.WHITE);
+            } else {
+                label.setText("OFF");
+                label.setBackground(new Color(200, 200, 200));
+                label.setForeground(Color.DARK_GRAY);
+            }
+        }
+    }
+}

+ 861 - 0
src/com/mes/component/WorkJPanelOP150.java

@@ -0,0 +1,861 @@
+package com.mes.component;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
+import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
+import com.mes.ui.CacheData;
+import com.mes.ui.DataUtil;
+import com.mes.ui.MesClient;
+import com.mes.util.JdbcUtils;
+import com.mes.util.TCPClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+public class WorkJPanelOP150 extends JPanel {
+
+    public static final Logger log =  LoggerFactory.getLogger(WorkJPanelOP150.class);
+
+    public String oprno = "OP150";
+
+    public String pos = "A";
+
+    public String lastSn = ""; // 最近的码
+
+    public String lineSn = "XT";
+
+    public JLabel feedinglabel;
+
+    public JLabel feedingmeslabel;
+
+    public JLabel runlabel; //运行反馈,
+
+    public JLabel blankinglabel; // 下料反馈
+
+    public JLabel blankingmeslabel; // 下料MES反馈
+
+    public JLabel feedingtodevicelabel; // 上料到设备
+
+    public JLabel feedingtotransferlabel; // 上料到中转车
+
+    public JLabel transfertodevicelabel; // 上料到中转车
+
+    public JButton scanBtn;
+
+    public JTextField productSn;
+
+    public JTextField productSnFeeding;
+
+    public JButton status_menu;
+
+    public JButton resetBtn;
+
+    public JButton resetFeedingBtn;
+
+    public ImageIcon imageGreen;
+
+    public ImageIcon imageGray;
+
+    public String plcIp12 = "192.168.90.92"; // plc92
+    public String plcIp13 = "192.168.90.93"; // plc93
+
+    public S7PLC s7PLC = null;
+
+    public Integer workWidth = 470;
+    public Integer workHeight = 300;
+
+    public String plcDb = "";
+
+    public Integer tjFeedingFlag = 0; // 上料状态标识
+    public Integer tjFlag = 0; // 1=可加工 2=设备运行中 3=加工结束
+    public Integer tjStatus = 0; // 提交标识
+    public Boolean toDevice = false;
+    public Boolean toTransfer = false;
+    public Boolean transferToDevice = false;
+    public Integer tjScan = 0;
+
+    public Boolean plcHeart = false;
+
+    public Integer isLocal = 0; // 0=正式 1=本地
+
+    public String cncDeviceName = "";
+
+    public JLabel oprnoLabel2;
+
+    public JButton signalBtn; // 信号监控按钮
+
+    public PlcSignalMonitor signalMonitor; // 信号监控组件
+
+    public CacheData cacheData = null;
+    public String cacheName = "";
+
+    public WorkJPanelOP150(String position){
+        this.setLayout(null);
+        this.setBackground(Color.WHITE);
+        this.pos = position;
+
+        cacheName = "cache_"+oprno+pos;
+        cacheData = JdbcUtils.getCache(cacheName);
+        if(cacheData == null){
+            cacheData = new CacheData();
+            cacheData.setLastSn("");
+            cacheData.setSn("");
+            cacheData.setFeedingSn("");
+            cacheData.setTjStatus(0);
+            cacheData.setTjFlag(0);
+            cacheData.setError(-1);
+            cacheData.setMsg("");
+            JdbcUtils.setCache(cacheName, JSON.toJSONString(cacheData));
+        }
+
+        if(position.equals("A") || position.equals("B") || position.equals("C") || position.equals("D") || position.equals("E")){
+            s7PLC = new S7PLC(EPlcType.S1500, plcIp12);
+        }else{
+            s7PLC = new S7PLC(EPlcType.S1500, plcIp13);
+        }
+
+        s7PLC.setReceiveTimeout(1000);
+        s7PLC.setConnectTimeout(1000);
+
+        switch (position){
+            case "A":
+                plcDb = "DB7000";
+                cncDeviceName = "东侧一号机";
+                break;
+            case "B":
+                plcDb = "DB7001";
+                cncDeviceName = "东侧二号机";
+                break;
+            case "C":
+                plcDb = "DB7002";
+                cncDeviceName = "东侧三号机";
+                break;
+            case "D":
+                plcDb = "DB7003";
+                cncDeviceName = "东侧四号机";
+                break;
+            case "E":
+                plcDb = "DB7004";
+                cncDeviceName = "东侧五号机";
+                break;
+            case "F":
+                plcDb = "DB7000";
+                cncDeviceName = "东侧六号机";
+                break;
+            case "G":
+                plcDb = "DB7001";
+                cncDeviceName = "东侧七号机";
+                break;
+            case "H":
+                plcDb = "DB7002";
+                cncDeviceName = "东侧八号机";
+                break;
+            case "I":
+                plcDb = "DB7003";
+                cncDeviceName = "东侧九号机";
+                break;
+            case "J":
+                plcDb = "DB7004";
+                cncDeviceName = "东侧十号机";
+                break;
+        }
+
+        JLabel oprnoLabel = new JLabel(oprno+pos);
+        oprnoLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        oprnoLabel.setForeground(Color.BLACK);
+        oprnoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        oprnoLabel.setBounds(0, 0, workWidth/5, 40);
+        this.add(oprnoLabel);
+
+        oprnoLabel2 = new JLabel(cncDeviceName);
+        oprnoLabel2.setHorizontalAlignment(SwingConstants.CENTER);
+        oprnoLabel2.setForeground(Color.BLACK);
+        oprnoLabel2.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+        oprnoLabel2.setBounds(0, 17, workWidth / 5, 40);
+        this.add(oprnoLabel2);
+
+        status_menu = new JButton("等待请求扫码");
+        status_menu.setBounds(workWidth/5, 0, workWidth*4/5, 40);
+        status_menu.setForeground(Color.GREEN);
+        status_menu.setForeground(Color.GREEN);
+        status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+        status_menu.setBackground(Color.BLACK);
+        this.add(status_menu);
+
+        JLabel oprnoLabelFeeding = new JLabel("上料");
+        oprnoLabelFeeding.setHorizontalAlignment(SwingConstants.CENTER);
+        oprnoLabelFeeding.setForeground(Color.BLACK);
+        oprnoLabelFeeding.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        oprnoLabelFeeding.setBounds(0, 50, workWidth/5, 40);
+        this.add(oprnoLabelFeeding);
+
+        productSnFeeding = new JTextField("");
+        productSnFeeding.setHorizontalAlignment(SwingConstants.CENTER);
+        productSnFeeding.setForeground(Color.BLACK);
+        productSnFeeding.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+        productSnFeeding.setEditable(false);
+        productSnFeeding.setBounds(workWidth/5, 50, workWidth*3/5, 40);
+        productSnFeeding.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                String sn = productSnFeeding.getText().trim();
+                if(!sn.isEmpty()){
+                    MesClient.createQRCode(productSnFeeding.getText(),oprno+pos);
+                }
+            }
+        });
+        this.add(productSnFeeding);
+
+        JLabel oprnoLabelWork = new JLabel("加工");
+        oprnoLabelWork.setHorizontalAlignment(SwingConstants.CENTER);
+        oprnoLabelWork.setForeground(Color.BLACK);
+        oprnoLabelWork.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        oprnoLabelWork.setBounds(0, 100, workWidth/5, 40);
+        this.add(oprnoLabelWork);
+
+        productSn = new JTextField("");
+        productSn.setHorizontalAlignment(SwingConstants.CENTER);
+        productSn.setForeground(Color.BLACK);
+        productSn.setFont(new Font("微软雅黑", Font.PLAIN, 16));
+        productSn.setEditable(false);
+        productSn.setBounds(workWidth/5, 100, workWidth*3/5, 40);
+        productSn.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                String sn = productSn.getText().trim();
+                if(!sn.isEmpty()){
+                    MesClient.createQRCode(productSn.getText(),oprno+pos);
+                }
+            }
+        });
+        this.add(productSn);
+
+
+//        scanBtn = new JButton("扫码");
+//        scanBtn.addActionListener(new ActionListener() {
+//            public void actionPerformed(ActionEvent e) {
+//                log.info("test2:"+productSn.getText());
+//                barCode();
+//            }
+//        });
+//        scanBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
+//        scanBtn.setFont(new Font("微软雅黑", Font.PLAIN, 32));
+//        scanBtn.setBounds(0, 160, workWidth/2 - 5, 50);
+//        this.add(scanBtn);
+
+        resetFeedingBtn = new JButton("刷新");
+        resetFeedingBtn.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                resetFeeding();
+//                scanQrcode();
+//                MesClient.scanQrcode1();
+            }
+        });
+//        resetFeedingBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
+        resetFeedingBtn.setFont(new Font("微软雅黑", Font.PLAIN, 22));
+        resetFeedingBtn.setBounds(workWidth*4/5 + 10, 50, workWidth/5 - 10, 40);
+        this.add(resetFeedingBtn);
+
+        resetBtn = new JButton("刷新");
+        resetBtn.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+//                log.info("test2:"+productSn.getText());
+               resetBlanking();
+            }
+        });
+//        resetBtn.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
+        resetBtn.setFont(new Font("微软雅黑", Font.PLAIN, 22));
+        resetBtn.setBounds(workWidth*4/5 + 10, 100, workWidth/5 - 10, 40);
+        this.add(resetBtn);
+
+        imageGreen = new ImageIcon(MesClient.class.getResource("/bg/green_dot.png"));
+        imageGreen.setImage(imageGreen.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH));
+
+        imageGray = new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png"));
+        imageGray.setImage(imageGray.getImage().getScaledInstance(20, 20, Image.SCALE_SMOOTH));
+
+        feedinglabel = new JLabel("请求扫码");
+        feedinglabel.setHorizontalAlignment(SwingConstants.LEFT);
+        feedinglabel.setIcon(imageGreen);
+        feedinglabel.setForeground(Color.BLACK);
+        feedinglabel.setBounds(0, 150, workWidth/3, 30);
+        this.add(feedinglabel);
+
+        feedingmeslabel = new JLabel("MES扫码反馈");
+        feedingmeslabel.setHorizontalAlignment(SwingConstants.LEFT);
+        feedingmeslabel.setIcon(imageGreen);
+        feedingmeslabel.setForeground(Color.BLACK);
+        feedingmeslabel.setBounds(workWidth/3, 150, workWidth/3, 30);
+        feedingmeslabel.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                boolean ret = readAllowFeeding();
+                int choice = JOptionPane.showConfirmDialog(null, "确定修改MES扫码反馈结果为"+(ret?"false":"true")+"吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+                if (choice == JOptionPane.YES_OPTION) {
+                    writeAllowFeeding(!ret);
+                }
+            }
+        });
+        this.add(feedingmeslabel);
+
+        runlabel = new JLabel("设备运行中");
+        runlabel.setHorizontalAlignment(SwingConstants.LEFT);
+        runlabel.setIcon(imageGreen);
+        runlabel.setForeground(Color.BLACK);
+        runlabel.setBounds(workWidth*2/3, 150, workWidth/3, 30);
+        this.add(runlabel);
+
+        blankinglabel = new JLabel("下料请求");
+        blankinglabel.setHorizontalAlignment(SwingConstants.LEFT);
+        blankinglabel.setIcon(imageGreen);
+        blankinglabel.setForeground(Color.BLACK);
+        blankinglabel.setBounds(0, 190, workWidth/3, 30);
+        this.add(blankinglabel);
+
+        blankingmeslabel = new JLabel("MES下料反馈");
+        blankingmeslabel.setHorizontalAlignment(SwingConstants.LEFT);
+        blankingmeslabel.setIcon(imageGreen);
+        blankingmeslabel.setForeground(Color.BLACK);
+        blankingmeslabel.setBounds(workWidth/3, 190, workWidth/3, 30);
+        this.add(blankingmeslabel);
+        blankingmeslabel.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                boolean ret = readAllowBlanking();
+                int choice = JOptionPane.showConfirmDialog(null, "确定修改MES下料反馈结果为"+(ret?"false":"true")+"吗?", "操作确认", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
+                if (choice == JOptionPane.YES_OPTION) {
+                    writeAllowBlanking(!ret);
+                }
+            }
+        });
+
+        feedingtodevicelabel = new JLabel("上料到设备");
+        feedingtodevicelabel.setHorizontalAlignment(SwingConstants.LEFT);
+        feedingtodevicelabel.setIcon(imageGreen);
+        feedingtodevicelabel.setForeground(Color.BLACK);
+        feedingtodevicelabel.setBounds(workWidth*2/3, 190, workWidth/3, 30);
+        this.add(feedingtodevicelabel);
+
+        feedingtotransferlabel = new JLabel("上料到中转车");
+        feedingtotransferlabel.setHorizontalAlignment(SwingConstants.LEFT);
+        feedingtotransferlabel.setIcon(imageGreen);
+        feedingtotransferlabel.setForeground(Color.BLACK);
+        feedingtotransferlabel.setBounds(0, 230, workWidth/3, 30);
+//        this.add(feedingtotransferlabel);
+
+        transfertodevicelabel = new JLabel("中转车上料到设备");
+        transfertodevicelabel.setHorizontalAlignment(SwingConstants.LEFT);
+        transfertodevicelabel.setIcon(imageGreen);
+        transfertodevicelabel.setForeground(Color.BLACK);
+        transfertodevicelabel.setBounds(workWidth/3, 230, workWidth/3, 30);
+//        this.add(transfertodevicelabel);
+
+
+        formatElementUI();
+
+        this.startOprnoTimer();
+        heartData();
+
+//        resetScanA();
+
+        // 信号监控按钮
+        signalMonitor = new PlcSignalMonitor(s7PLC, plcDb, oprno + pos, MesClient.mesClientFrame);
+        signalBtn = signalMonitor.createSignalButton();
+        signalBtn.setBounds(workWidth*2/3 + 63, 230, 90, 26);
+        this.add(signalBtn);
+    }
+
+    public void formatElementUI(){
+        cacheData = JdbcUtils.getCache(cacheName);
+        if(cacheData == null){
+            return;
+        }
+        String msg = cacheData.getMsg();
+        int error = cacheData.getError();
+        String sn = cacheData.getSn();
+        productSn.setText(sn);
+
+        String feedingSn = cacheData.getFeedingSn();
+        productSnFeeding.setText(feedingSn);
+
+        tjFlag = cacheData.getTjFlag();
+        lastSn = cacheData.getLastSn();
+
+        setMenuStatus(msg,error);
+
+        this.repaint();
+    }
+
+    public void setMenuStatus(String msg,int error){
+        if(error == 0){
+            this.status_menu.setForeground(Color.GREEN);
+        }else{
+            this.status_menu.setForeground(Color.RED);
+        }
+        this.status_menu.setText(msg);
+
+        cacheData.setMsg(msg);
+        cacheData.setError(error);
+        cacheData.setTjFlag(tjFlag);
+        cacheData.setTjStatus(tjStatus);
+        cacheData.setLastSn(lastSn);
+        cacheData.setSn(productSn.getText());
+        cacheData.setFeedingSn(productSnFeeding.getText());
+        JdbcUtils.setCache(cacheName, JSON.toJSONString(cacheData));
+    }
+
+    // 定时任务 -----------------------------------------------------------------------------------------------------
+
+    public Timer cjTimerText2;
+    public void heartData() {
+        if(cjTimerText2!=null) {
+            cjTimerText2.cancel();
+        }
+        cjTimerText2 = new Timer();
+        cjTimerText2.schedule(new TimerTask() {
+            public void run() {
+                if(MesClient.isLogin == 1 && isLocal == 0){
+                    plcHeart = !plcHeart;
+                    writeBoolean(plcDb+".0.6",plcHeart);
+                }
+            }
+        }, 1000,1000);
+    }
+
+    public Timer oprnoTimer;
+    public void startOprnoTimer() {
+
+        //心跳显示图标
+        if(oprnoTimer!=null) {
+            oprnoTimer.cancel();
+        }
+        oprnoTimer = new Timer();
+        oprnoTimer.schedule(new TimerTask() {
+            public void run() {
+                try{
+
+                    if(MesClient.isLogin == 1){
+                        Boolean retFeeding = readFeeding();
+//                        Boolean retFeeding = true;
+                        feedinglabel.setIcon(retFeeding?imageGreen:imageGray);
+
+                        transferToDevice = readFeedingTransferToDevice();
+                        transfertodevicelabel.setIcon(transferToDevice?imageGreen:imageGray);
+
+                        Boolean retFeedingAllow = readAllowFeeding();
+                        feedingmeslabel.setIcon(retFeedingAllow?imageGreen:imageGray);
+
+                        if(!retFeeding && retFeedingAllow){
+                            writeAllowFeeding(false);
+                        }
+
+                        Boolean retBlanking = readBlanking();
+                        blankinglabel.setIcon(retBlanking?imageGreen:imageGray);
+
+                        Boolean retAllowBlanking = readAllowBlanking();
+                        blankingmeslabel.setIcon(retAllowBlanking?imageGreen:imageGray);
+
+                        toDevice = readFeedingToDevice();
+                        feedingtodevicelabel.setIcon(toDevice?imageGreen:imageGray);
+
+                        toTransfer = readFeedingToTransfer();
+                        feedingtotransferlabel.setIcon(toTransfer?imageGreen:imageGray);
+
+                        Boolean retRunning = readRunning();
+                        runlabel.setIcon(retRunning?imageGreen:imageGray);
+
+                        if(retBlanking && productSn.getText().isEmpty()){
+                            writeAllowBlanking(true);
+                        }
+
+                        if(tjFeedingFlag == 0){
+                            if(retFeeding){
+                                barCode();
+                            }
+
+                        }else if(tjFeedingFlag == 1){
+                            // 中转车已隐藏:不再走 toTransfer 存码,统一按去设备处理
+//                            if(toDevice){ // 去设备
+                                if(tjFlag == 0 && retRunning){
+                                    tjFlag = 1;
+                                    productSn.setText(productSnFeeding.getText());
+//                                    resetBtn.setEnabled(false);
+                                    resetFeeding();
+                                }
+//                            }
+//                            if(toTransfer){ // 去中转台
+//                                int transferSn = readTransferNo();
+//                                int transferFloor = readTransferFloor();
+//                                if(transferSn > 0 && transferFloor > 0){
+//                                    if(tjStatus == 0) {
+//                                        tjStatus = 1;
+//                                        JSONObject retObj = DataUtil.saveSn(oprno+pos,productSnFeeding.getText().trim(),transferSn,transferFloor,MesClient.user_menu.getText());
+//                                        if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+//                                            resetFeeding();
+//                                        }else{
+//                                            if(retObj.get("result")==null){
+//                                                setMenuStatus("请求失败,请重试",-1);
+//                                            }else{
+//                                                if(retObj.get("result").toString().equalsIgnoreCase("false")){
+//                                                    setMenuStatus(retObj.getString("message"),-1);
+//                                                }
+//                                            }
+//                                        }
+//                                    }
+//                                }
+//                            }
+                        }
+
+                        if(tjFlag == 0 && !retBlanking){
+                            writeAllowBlanking(false);
+                        }
+
+                        if(tjFlag == 1){
+                            // 中转车已隐藏:不再走 toTransfer 存码,统一按去设备处理
+//                            if(toDevice){ // 去设备
+                                if(retRunning){
+                                    tjFlag = 2;
+                                    setMenuStatus("工件加工中", 0);
+                                    // 运行中清除下料反馈
+                                    writeAllowBlanking(false);
+                                }
+//                            }
+//                            if(toTransfer){ // 去中转台
+//                                int transferSn = readTransferNo();
+//                                int transferFloor = readTransferFloor();
+//                                if(transferSn > 0 && transferFloor > 0){
+//                                    if(tjStatus == 0) {
+//                                        tjStatus = 1;
+//                                        JSONObject retObj = DataUtil.saveSn(oprno+pos,productSn.getText().trim(),transferSn,transferFloor,MesClient.user_menu.getText());
+//                                        if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+//                                            resetFeeding();
+//                                        }else{
+//                                            if(retObj.get("result")==null){
+//                                                setMenuStatus("请求失败,请重试",-1);
+//                                            }else{
+//                                                if(retObj.get("result").toString().equalsIgnoreCase("false")){
+//                                                    setMenuStatus(retObj.getString("message"),-1);
+//                                                }
+//                                            }
+//                                        }
+//                                    }
+//                                }
+//                            }
+                        }else if(tjFlag == 2){
+                            if(retBlanking){
+                                tjFlag = 3;
+                                setMenuStatus("工件加工结束,结果上传中", 0);
+
+                                if(tjStatus == 0){
+                                    tjStatus = 1;
+
+                                    // 异步执行上传任务,防止阻塞
+                                    ExecutorService executor = Executors.newCachedThreadPool();
+                                    executor.submit(() -> {
+                                        // 你的异步任务代码
+                                        log.info("["+oprno+pos+"]质量上传任务开始");
+                                        try {
+                                            JSONObject retObj = DataUtil.sendQuality(productSn.getText(),oprno+pos,"OK",MesClient.user_menu.getText());
+                                            if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                                                resetBlanking();
+                                            }else{
+                                                if(retObj.get("result")==null){
+                                                    setMenuStatus("请求失败,请重试",-1);
+                                                }else{
+                                                    if(retObj.get("result").toString().equalsIgnoreCase("false")){
+                                                        setMenuStatus(retObj.getString("message"),-1);
+                                                    }
+                                                }
+                                            }
+                                        } catch (Exception e) {
+                                            Thread.currentThread().interrupt();
+                                        }
+                                        log.info("["+oprno+pos+"]质量上传任务结束");
+                                    });
+                                    // 关闭ExecutorService,不再接受新任务,等待已提交的任务完成
+                                    executor.shutdown();
+                                }
+                            }
+                        }
+                    }
+
+
+
+                }catch (Exception e) {
+                    log.error(e.getMessage());
+                }
+            }
+        }, 100,3000);
+    }
+
+    public void barCode(){
+        if(!productSnFeeding.getText().isEmpty()){
+            return;
+        }
+        String sn = readQrcode();
+        if(sn.equals("")){
+            if(productSnFeeding.getText().isEmpty()){
+                this.setMenuStatus("扫码结果为空", -1);
+            }
+        }else{
+            productSnFeeding.setText(sn);
+            lastSn = sn;
+            // 查询工件质量
+            JSONObject retObj = DataUtil.checkQuality(sn,oprno+pos,MesClient.user_menu.getText());
+            if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                tjFeedingFlag = 1;//可加工
+                setMenuStatus("工件可以加工", 0);
+                writeAllowFeeding(true);
+//                resetFeedingBtn.setEnabled(false);
+            }else{
+                writeAllowFeeding(false);
+                resetFeedingBtn.setEnabled(true);
+                if(retObj.get("result")==null){
+                    setMenuStatus("请求失败,请重试",-1);
+                }else{
+                    if(retObj.get("result").toString().equalsIgnoreCase("false")){
+                        setMenuStatus(retObj.getString("message"),-1);
+                    }
+                }
+            }
+        }
+    }
+
+    public void resetBlanking() {
+        tjFlag = 0;
+        tjStatus = 0;
+        productSn.setText("");
+        setMenuStatus("工件结果已提交,等待下一件",0);
+        resetBtn.setEnabled(true);
+//        writeAllowFeeding(false);
+//        writeAllowBlanking(false);
+    }
+
+    public void resetFeeding() {
+        tjScan = 0;
+        productSnFeeding.setText("");
+        tjFeedingFlag = 0;
+        setMenuStatus("等待请求扫码",0);
+        resetFeedingBtn.setEnabled(true);
+        writeAllowFeeding(false);
+    }
+
+    public void resetScanA() {
+        tjFeedingFlag = 0;
+        tjFlag = 0;
+        tjStatus = 0;
+        productSn.setText("");
+        productSnFeeding.setText("");
+        setMenuStatus("等待请求扫码",0);
+        resetBtn.setEnabled(true);
+        resetFeedingBtn.setEnabled(true);
+        writeAllowFeeding(false);
+        writeAllowBlanking(false);
+    }
+    // 与设备交互-----------------------------------------------------------------------------------------
+
+    // 请求扫码
+    public boolean readFeeding(){
+        if(isLocal == 1){
+            return false;
+        }else{
+            return readBoolean(plcDb+".0.0");
+        }
+    }
+
+    // 读取上料到设备
+    public boolean readFeedingToDevice(){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return readBoolean(plcDb+".0.7");
+        }
+    }
+
+    // 读取上料到中转车
+    public boolean readFeedingToTransfer(){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return readBoolean(plcDb+".1.0");
+        }
+    }
+
+    // 读取中转车上料到设备
+    public boolean readFeedingTransferToDevice(){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return readBoolean(plcDb+".1.1");
+        }
+    }
+
+    // 读取下料信号
+    public boolean readBlanking(){
+        if(isLocal == 1){
+            return false;
+        }else{
+            return readBoolean(plcDb+".0.1");
+        }
+    }
+
+    // 读取设备运行信号
+    public boolean readRunning(){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return readBoolean(plcDb+".0.2");
+        }
+    }
+
+    // 读取设备通讯状态
+    public boolean readDeviceStatus(){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return readBoolean(plcDb+".0.3");
+        }
+    }
+
+    // 读取MES允许上料信号
+    public boolean readAllowFeeding(){
+        if(isLocal == 1){
+            return false;
+        }else{
+            return readBoolean(plcDb+".0.4");
+        }
+    }
+
+    // 写入MES允许上料信号
+    public boolean writeAllowFeeding(Boolean b){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return writeBoolean(plcDb+".0.4",b);
+        }
+    }
+
+    // 读取MES允许下料信号
+    public boolean readAllowBlanking(){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return readBoolean(plcDb+".0.5");
+        }
+    }
+
+    // 写入MES允许下料信号
+    public boolean writeAllowBlanking(Boolean b){
+        if(isLocal == 1){
+            return true;
+        }else{
+            return writeBoolean(plcDb+".0.5",b);
+        }
+    }
+
+    // 读取中转车号
+    public int readTransferNo(){
+        if(isLocal == 1){
+            return 1;
+        }else{
+            return s7PLC.readInt16(plcDb+".2.0");
+        }
+    }
+
+    // 读取中转车层数
+    public int readTransferFloor(){
+        if(isLocal == 1){
+            return 1;
+        }else{
+            return s7PLC.readInt16(plcDb+".4.0");
+        }
+    }
+
+    // 控制扫码枪读取二维码
+    public String readQrcode(){
+        String sn = "";
+        if(isLocal == 1){
+            return "";
+        }else{
+            try{
+                // 中转车已隐藏:不再从中转车取码,统一走扫码枪
+//                if(transferToDevice){ // 中转车上料到设备
+//                    int transferSn = readTransferNo();
+//                    int transferFloor = readTransferFloor();
+//                    JSONObject retObj = DataUtil.getSn(oprno+pos,transferSn,transferFloor,MesClient.user_menu.getText());
+//                    if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+//                        sn = retObj.getString("data");
+//                    }else{
+//                        writeAllowFeeding(false);
+//                        if(retObj.get("result")==null){
+//                            this.setMenuStatus("请求失败,请重试",-1);
+//                        }else{
+//                            if(retObj.get("result").toString().equalsIgnoreCase("false")){
+//                                this.setMenuStatus(retObj.getString("message"),-1);
+//                            }
+//                        }
+//                    }
+//                }else{
+                    int transferSn = readTransferNo();
+                    if(transferSn == 1){
+                        if(pos.equals("A") || pos.equals("B") || pos.equals("C") || pos.equals("D") || pos.equals("E")){
+                            sn = MesClient.scanQrcode1();
+                        }else{
+                            sn = MesClient.scanQrcode3();
+                        }
+                    }else{
+                        if(pos.equals("A") || pos.equals("B") || pos.equals("C") || pos.equals("D") || pos.equals("E")){
+                            sn = MesClient.scanQrcode2();
+                        }else{
+                            sn = MesClient.scanQrcode4();
+                        }
+                    }
+//                }
+            }catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        return sn;
+    }
+
+    public void scanQrcode(){
+        log.info("scanQrcode");
+        // 异步执行上传任务,防止阻塞
+        ExecutorService executor = Executors.newCachedThreadPool();
+        executor.submit(() -> {
+            MesClient.scanQrcode4();
+        });
+        // 关闭ExecutorService,不再接受新任务,等待已提交的任务完成
+        executor.shutdown();
+
+    }
+
+    public boolean readBoolean(String db){
+        boolean permit;
+        try {
+            permit = s7PLC.readBoolean(db);
+            log.info("<"+this.oprno+this.pos+">读取"+db+"-->成功,结果:{}", permit ? "true" : "false");
+        } catch (Exception e) {
+            log.error("<"+this.oprno+this.pos+">读取"+db+"-->失败", e);
+            return false;
+        }
+        return permit;
+    }
+
+    public boolean writeBoolean(String db, boolean permit){
+        try {
+            s7PLC.writeBoolean(db,permit);
+            // 心跳日志已关闭
+        } catch (Exception e) {
+            log.error("<"+this.oprno+this.pos+">写入"+db+"-->失败,写入内容:{}", permit ? "true" : "false");
+            log.error(e.getMessage(), e);
+            return false;
+        }
+        return true;
+    }
+}

+ 58 - 0
src/com/mes/ui/BindMaterialResp.java

@@ -0,0 +1,58 @@
+package com.mes.ui;
+
+public class BindMaterialResp {
+    private String materialId;
+    private String materialTitle;
+    private String craft;
+    private String batchSn;
+    private String lastTimes;
+    private String type;
+
+    public String getMaterialId() {
+        return materialId;
+    }
+
+    public void setMaterialId(String materialId) {
+        this.materialId = materialId;
+    }
+
+    public String getMaterialTitle() {
+        return materialTitle;
+    }
+
+    public void setMaterialTitle(String materialTitle) {
+        this.materialTitle = materialTitle;
+    }
+
+    public String getCraft() {
+        return craft;
+    }
+
+    public void setCraft(String craft) {
+        this.craft = craft;
+    }
+
+    public String getBatchSn() {
+        return batchSn;
+    }
+
+    public void setBatchSn(String batchSn) {
+        this.batchSn = batchSn;
+    }
+
+    public String getLastTimes() {
+        return lastTimes;
+    }
+
+    public void setLastTimes(String lastTimes) {
+        this.lastTimes = lastTimes;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+}

+ 89 - 0
src/com/mes/ui/CacheData.java

@@ -0,0 +1,89 @@
+package com.mes.ui;
+
+public class CacheData {
+    private Integer tjFlag;
+    private String msg;
+    private String sn;
+    private String feedingSn;
+    private String lastSn;
+    private Integer error;
+    private Integer tjStatus;
+    private String preSn;
+
+    public Integer getTjFlag() {
+        return tjFlag;
+    }
+
+    public void setTjFlag(Integer tjFlag) {
+        this.tjFlag = tjFlag;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Integer getError() {
+        return error;
+    }
+
+    public void setError(Integer error) {
+        this.error = error;
+    }
+
+    public String getLastSn() {
+        return lastSn;
+    }
+
+    public void setLastSn(String lastSn) {
+        this.lastSn = lastSn;
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public Integer getTjStatus() {
+        return tjStatus;
+    }
+
+    public void setTjStatus(Integer tjStatus) {
+        this.tjStatus = tjStatus;
+    }
+
+    public String getFeedingSn() {
+        return feedingSn;
+    }
+
+    public void setFeedingSn(String feedingSn) {
+        this.feedingSn = feedingSn;
+    }
+
+    public String getPreSn() {
+        return preSn;
+    }
+
+    public void setPreSn(String preSn) {
+        this.preSn = preSn;
+    }
+
+    @Override
+    public String toString() {
+        return "CacheData{" +
+                "tjFlag=" + tjFlag +
+                ", msg='" + msg + '\'' +
+                ", sn='" + sn + '\'' +
+                ", feedingSn='" + feedingSn + '\'' +
+                ", lastSn='" + lastSn + '\'' +
+                ", error=" + error +
+                ", tjStatus=" + tjStatus +
+                '}';
+    }
+}

+ 71 - 0
src/com/mes/ui/CncParamReq.java

@@ -0,0 +1,71 @@
+package com.mes.ui;
+
+/**
+ * CNC过程参数请求类
+ * 用于存储从OPC UA读取的CNC参数,并上传到服务端
+ */
+public class CncParamReq {
+    private Integer id;
+    private String oprno;       // 工位号
+    private String lineSn;      // 产线编号
+    private String sn;          // 工件码
+    private String deviceCode;  // 设备编号
+    private String content;     // JSON格式的完整参数
+    private Integer sync;       // 同步状态 0=未同步 1=已同步
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getOprno() {
+        return oprno;
+    }
+
+    public void setOprno(String oprno) {
+        this.oprno = oprno;
+    }
+
+    public String getLineSn() {
+        return lineSn;
+    }
+
+    public void setLineSn(String lineSn) {
+        this.lineSn = lineSn;
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getDeviceCode() {
+        return deviceCode;
+    }
+
+    public void setDeviceCode(String deviceCode) {
+        this.deviceCode = deviceCode;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Integer getSync() {
+        return sync;
+    }
+
+    public void setSync(Integer sync) {
+        this.sync = sync;
+    }
+}

+ 318 - 0
src/com/mes/ui/DataUtil.java

@@ -0,0 +1,318 @@
+package com.mes.ui;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.mes.util.DateLocalUtils;
+import com.mes.util.JdbcUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+
+public class DataUtil {
+
+    public static final Logger log =  LoggerFactory.getLogger(DataUtil.class);
+
+    public static JSONObject checkToResult(String sn,String oprno,String lineSn) {
+        try{
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesProductRecord/checkToResult";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&sn="+sn;
+            log.info("params="+params);
+            String result = doPost(url,params);
+            log.info("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            return null;
+        }
+    }
+
+    public static JSONObject checkQuality(String sn,String oprno, String user){
+        try{
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesProductRecord/pccheck";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&sn="+sn+"&ucode="+user;
+            log.info("params="+params);
+            String result = doPost(url,params);
+            log.info("result="+result);
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                JdbcUtils.insertData(oprno, "100000", params, "AQDW", sn);
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            log.info("e="+e.getMessage());
+            return null;
+        }
+    }
+
+    public static JSONObject sendQuality(String sn,String oprno,String ret,String user){
+        try{
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesProductRecord/pcresult";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&sn="+sn+"&result="+ret+"&ucode="+user;
+            log.info("params="+params);
+            String result = doPost(url,params);
+            log.info("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                JdbcUtils.insertData(oprno, "100000", params, "MQDW", sn);
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            log.info("e="+e.getMessage());
+            return null;
+        }
+    }
+
+    public static JSONObject getSn(String oprno,int transferSn,int transferFloor,String user){
+        try{
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesTransfer/getSn";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&transferSn="+transferSn+"&transferFloor="+transferFloor+"&ucode="+user;
+            log.info("params="+params);
+            String result = doPost(url,params);
+            log.info("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                JdbcUtils.insertData(oprno, "100000", params, "MQDW", "");
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            log.info("e="+e.getMessage());
+            return null;
+        }
+    }
+
+    public static JSONObject saveSn(String oprno,String sn,int transferSn,int transferFloor,String user){
+        try{
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesTransfer/saveSn";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&sn="+sn+"&transferSn="+transferSn+"&transferFloor="+transferFloor+"&ucode="+user;
+            log.info("params="+params);
+            String result = doPost(url,params);
+            log.info("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                JdbcUtils.insertData(oprno, "100000", params, "MQDW", "");
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            log.info("e="+e.getMessage());
+            return null;
+        }
+    }
+
+    public static JSONObject upCncParams(String upparams) {
+        try {
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesProductCncParam/batchsave";
+            String params = "__ajax=json&params=" + upparams;
+            log.info("上传CNC参数: params=" + params);
+            String result = doPost(url, params);
+            log.info("上传CNC参数结果: result=" + result);
+
+            if (result == null || result.equalsIgnoreCase("false")) {
+                return null;
+            } else {
+                return JSONObject.parseObject(result);
+            }
+        } catch (Exception e) {
+            log.error("上传CNC参数异常: " + e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 查询工作记录
+     * @param oprno 工位号(5位如OP150会查询所有子工位,空则查所有)
+     * @param sn 工件码(可选,用于搜索)
+     * @param pageNo 页码
+     * @param pageSize 每页条数
+     * @return 工作记录响应
+     */
+    public static WorkRecordResp getWorkRecordList(String oprno, String sn, int pageNo, int pageSize) {
+        WorkRecordResp resp = new WorkRecordResp();
+        try {
+            String enconding = "UTF-8";
+            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+            Properties pro = new Properties();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is, enconding));
+            pro.load(br);
+            String mes_server_ip = pro.getProperty("mes.server_ip");
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            
+            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesProductRecord/workData";
+            StringBuilder params = new StringBuilder();
+            params.append("__ajax=json");
+            params.append("&lineSn=").append(lineSn);
+            params.append("&pageNo=").append(pageNo);
+            params.append("&pageSize=").append(pageSize);
+            
+            if (oprno != null && !oprno.isEmpty()) {
+                params.append("&oprno=").append(oprno);
+            }
+            if (sn != null && !sn.isEmpty()) {
+                params.append("&sn=").append(sn);
+            }
+            
+            log.info("查询工作记录: url=" + url + ", params=" + params.toString());
+            String result = doPost(url, params.toString());
+            log.info("查询工作记录结果: result=" + result);
+            
+            if (result == null || result.trim().isEmpty()) {
+                resp.setResult(false);
+                resp.setMessage("请求返回空结果");
+                return resp;
+            }
+            
+            JSONObject jsonObj = JSONObject.parseObject(result);
+            if (jsonObj == null) {
+                resp.setResult(false);
+                resp.setMessage("解析响应失败");
+                return resp;
+            }
+            
+            resp.setResult(true);
+            resp.setPageNo(jsonObj.getIntValue("pageNo"));
+            resp.setPageSize(jsonObj.getIntValue("pageSize"));
+            resp.setCount(jsonObj.getLongValue("count"));
+            
+            List<WorkRecordData> list = new ArrayList<>();
+            JSONArray listArray = jsonObj.getJSONArray("list");
+            if (listArray != null) {
+                for (int i = 0; i < listArray.size(); i++) {
+                    JSONObject item = listArray.getJSONObject(i);
+                    WorkRecordData data = new WorkRecordData();
+                    data.setId(item.getString("id"));
+                    data.setSn(item.getString("sn"));
+                    data.setOprno(item.getString("oprno"));
+                    data.setUpdateBy(item.getString("updateBy"));
+                    data.setUpdateDate(item.getString("updateDate"));
+                    data.setContent(item.getString("content"));
+                    list.add(data);
+                }
+            }
+            resp.setList(list);
+            
+        } catch (Exception e) {
+            log.error("查询工作记录异常: " + e.getMessage());
+            e.printStackTrace();
+            resp.setResult(false);
+            resp.setMessage("查询异常: " + e.getMessage());
+        }
+        return resp;
+    }
+
+    public static String doPost(String httpUrl, String param) {
+        HttpURLConnection connection = null;
+        InputStream is = null;
+        OutputStream os = null;
+        BufferedReader br = null;
+        String result = null;
+        try {
+            URL url = new URL(httpUrl);
+            connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("POST");
+            connection.setConnectTimeout(15000);
+            connection.setReadTimeout(15000);
+            connection.setDoOutput(true);
+            connection.setDoInput(true);
+            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+            connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
+            os = connection.getOutputStream();
+            os.write(param.getBytes());
+            if (connection.getResponseCode() == 200) {
+                is = connection.getInputStream();
+                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
+                StringBuffer sbf = new StringBuffer();
+                String temp = null;
+                while ((temp = br.readLine()) != null) {
+                    sbf.append(temp);
+                    sbf.append("\r\n");
+                }
+                result = sbf.toString();
+            }
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (null != br) {
+                try {
+                    br.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (null != os) {
+                try {
+                    os.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (null != is) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            connection.disconnect();
+        }
+        return result;
+    }
+}

+ 214 - 0
src/com/mes/ui/LoginFarme.java

@@ -0,0 +1,214 @@
+package com.mes.ui;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.mes.component.MesRadio;
+import com.mes.component.MesWebView;
+import com.mes.util.Base64Utils;
+import com.mes.util.HttpUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.time.LocalDateTime;
+
+public class LoginFarme extends JFrame {
+
+    public static final Logger log =  LoggerFactory.getLogger(LoginFarme.class);
+    //登录模块组件
+    static JLabel userNameLabel= new JLabel("<html><body>用户名:</body></html>",JLabel.LEFT);//用户名
+    static JLabel userPasswordLabel= new JLabel("<html><body>密码:</body></html>",JLabel.LEFT);//用户名
+    public static JTextField userNameTxt;
+    public static JPasswordField userPasswordTxt;
+    static JButton loginButton = new JButton("用户密码登录");
+    static JButton scanLoginButton = new JButton("扫  码  登  录");
+
+    public LoginFarme(){
+        setTitle("MES系统客户端:OP150总成CNC");
+
+        ImageIcon bg = new ImageIcon(MesClient.class.getResource("/background.png"));
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        JLabel imgLabel = new JLabel(bg);//将背景图放在标签里。
+        getLayeredPane().add(imgLabel, new Integer(Integer.MIN_VALUE));//注意这里是关键,将背景标签添加到jfram的LayeredPane面板里。
+        imgLabel.setBounds(0,0,bg.getIconWidth(), bg.getIconHeight());//设置背景标签的位置
+        Container contentPane=getContentPane();
+        contentPane.setLayout(null);//布局,很重要
+        JPanel welcomePanel = new JPanel();
+        //welcomePanel.setLayout(new GridLayout(3, 1));
+        welcomePanel.setLayout(null);
+        //welcomeLable.setBounds(10, 5, 700, 100);
+        welcomePanel.setBounds(30, 330, 890, 300);
+        welcomePanel.setOpaque(false);//背景透明
+        contentPane.add(welcomePanel);
+
+        //登录页面
+        userNameLabel.setBounds(300, 100, 120, 40);
+        userNameLabel.setFont(new java.awt.Font("Dialog",   1,   16));
+        userPasswordLabel.setBounds(300, 150, 120, 40);
+        userPasswordLabel.setFont(new java.awt.Font("Dialog",   1,   16));
+        userNameTxt = new JTextField(20);
+        userNameTxt.setText("system");
+        userNameTxt.setBounds(400, 105, 150, 30);
+        userPasswordTxt = new JPasswordField(20);
+        userPasswordTxt.setBounds(400, 155, 150, 30);
+        userPasswordTxt.setText("Aa111111");
+        loginButton.setFont(new java.awt.Font("Dialog",   1,   16));
+        loginButton.setBounds(300, 200, 255, 40);
+        loginButton.setIcon(new ImageIcon(MesClient.class.getResource("/bg/user.png")));
+
+//        scanLoginButton.setVisible(false);
+        scanLoginButton.setFont(new java.awt.Font("Dialog",   1,   16));
+        scanLoginButton.setBounds(300, 250, 255, 40);
+        scanLoginButton.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
+
+        welcomePanel.add(userNameLabel);
+        welcomePanel.add(userPasswordLabel);
+        welcomePanel.add(userNameTxt);
+        welcomePanel.add(userPasswordTxt);
+        welcomePanel.add(loginButton);
+        welcomePanel.add(scanLoginButton);
+        loginButton.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                login();
+            }
+        });
+        scanLoginButton.addActionListener(new ActionListener(){
+            public void actionPerformed(ActionEvent e) {
+                scanLogin();
+            }
+        });
+
+        ((JPanel)contentPane).setOpaque(false); //注意这里,将内容面板设为透明。这样LayeredPane面板中的背景才能显示出来。
+        //welcomeWin.setSize(902,678);
+        setResizable(false);//禁止最大化
+        setIconImage(Toolkit.getDefaultToolkit().getImage(MesClient.class.getResource("/bg/logo.png")));
+
+        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
+        int width = 902;
+        int height = 678;
+        setBounds((d.width-width)/2, (d.height-height)/2-(d.height-height)/4, width, height);
+        /*****正常模式******/
+        setVisible(true);
+    }
+
+    //登录
+    public static void login() {
+        String user_str = userNameTxt.getText().toString();
+        String password_str = userPasswordTxt.getText().toString();
+        if(user_str.equalsIgnoreCase("")||password_str.equalsIgnoreCase("")) {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame,"用户名或密码不能为空","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }
+        String username = Base64Utils.getBase64(user_str);
+        String password = Base64Utils.getBase64(password_str);
+        log.info("&username=" + username + "&password=" + password);
+        String url = "http://"+MesClient.mes_server_ip+":8980/js/a/login?__ajax=json&username="+username+"&password="+password+"&validCode=&__sid=";
+        String loginResult = HttpUtils.sendRequest(url);
+        if(loginResult.equalsIgnoreCase("false")) {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录异常,请检查网络或联系网络管理员","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }else {
+            JSONObject retObj = JSONObject.parseObject(loginResult);
+            if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                //检查用户权限是否可登录界面
+                checkUserAuthority(retObj);
+            }else {
+                //ret = "msg save error";
+                //ret = false;
+                JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录失败,用户名或密码错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+                return;
+            }
+        }
+    }
+    //扫码登录
+    public static void scanLogin() {
+        //userNameTxt.setText("");
+        //userPasswordTxt.setText("");
+        String scanContent = JOptionPane.showInputDialog(null, "请扫码工牌二维码");
+        log.info("scanContent="+scanContent);
+        if(scanContent!=null&&!scanContent.equalsIgnoreCase("")) {
+            String url = "http://"+MesClient.mes_server_ip+":8980/js/a/mes/mesLogin/login?__login=true&__ajax=json&username="+scanContent;
+            String loginResult = HttpUtils.sendRequest(url);
+            log.info("loginResult="+loginResult);
+            if(loginResult.equalsIgnoreCase("false")) {
+                JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录异常,请检查网络或联系网络管理员","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+                return;
+            }else {
+                JSONObject retObj = JSONObject.parseObject(loginResult);
+                if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                    //检查用户权限是否可登录界面
+                    checkUserAuthority(retObj);
+                }else {
+                    JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录失败,用户名或密码错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }
+            }
+        }else {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame,"扫码内容错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }
+    }
+
+    //检查用户权限是否可登录界面
+    public static void checkUserAuthority(JSONObject retObj) {
+        //设置登录用户名
+        JSONObject userObj = JSONObject.parseObject(retObj.get("user").toString());
+        String user_id = userObj.getString("id").toString();
+
+        //获取sessionid,判断权限
+        MesClient.sessionid = retObj.get("sessionid").toString();
+        if(MesClient.sessionid!=null&&!MesClient.sessionid.equalsIgnoreCase("")) {
+            //请求权限
+            String url_authority = "http://"+MesClient.mes_server_ip+":8980/js/a/mes/mesLineProcess/userAuth?__ajax=json&type=0&__sid="+MesClient.sessionid+"&oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn;
+            String authorityResult = HttpUtils.sendRequest(url_authority);
+            log.info("authorityResult="+authorityResult);
+            JSONObject authorityObj = JSONObject.parseObject(authorityResult);
+            if(authorityObj.get("result")!=null&&authorityObj.get("result").toString().equalsIgnoreCase("true")) {
+                JSONObject authObjTmp = JSONObject.parseObject(authorityObj.get("data").toString());
+                MesClient.mes_auth = Integer.parseInt(authObjTmp.getString("auth").toString());
+                if(MesClient.mes_auth==0) {
+                    //无权限登录
+                    JOptionPane.showMessageDialog(MesClient.mesClientFrame,"您无权登录该工位","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+                    return;
+                }else if(MesClient.mes_auth==1||MesClient.mes_auth==2) {
+                    MesClient.isLogin = 1;
+                    //1操作工人,2管理员
+                    //登录成功
+                    MesClient.user_menu.setText(user_id);
+                    MesClient.welcomeWin.setVisible(false);
+                    MesClient.mesClientFrame.setVisible(true);
+
+                    // 工作记录已改用 WorkRecordPanel 实现,不再需要 WebView
+                    // if(MesClient.jfxPanel == null){
+                    //     String url = "http://"+ MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/work?oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn;
+                    //     MesClient.jfxPanel = new MesWebView(url);
+                    //     MesClient.jfxPanel.setSize(990, 550);
+                    //     MesClient.indexPanelWork.add(MesClient.jfxPanel);
+                    // }
+                    MesClient.initWarehouseData();
+
+                    // 异步初始化OPC UA连接和启动CNC监控
+                    new Thread(() -> {
+                        try {
+                            log.info("开始异步初始化OPC UA连接...");
+                            MesClient.initOpcUaConnection();
+                            MesClient.startCncParamUpload();  // 定时上传CNC参数到服务端
+                            MesClient.startCncParamRead(); // 定时采集CNC参数保存到本地
+                            MesClient.startCncDisplayRefresh(); // 启动CNC数据显示刷新
+                            log.info("OPC UA异步初始化完成");
+                        } catch (Exception e) {
+                            log.error("OPC UA异步初始化异常: {}", e.getMessage());
+                        }
+                    }, "OpcUa-Init-Thread").start();
+                }
+
+            }
+
+        }else {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录失败,用户名或密码错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }
+    }
+}

文件差異過大導致無法顯示
+ 1563 - 0
src/com/mes/ui/MesClient.java


+ 58 - 0
src/com/mes/ui/ParamReq.java

@@ -0,0 +1,58 @@
+package com.mes.ui;
+
+public class ParamReq {
+    private Integer id;
+    private String oprno;
+    private String lineSn;
+    private String sn;
+    private String content;
+    private Integer sync;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getOprno() {
+        return oprno;
+    }
+
+    public void setOprno(String oprno) {
+        this.oprno = oprno;
+    }
+
+    public String getLineSn() {
+        return lineSn;
+    }
+
+    public void setLineSn(String lineSn) {
+        this.lineSn = lineSn;
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Integer getSync() {
+        return sync;
+    }
+
+    public void setSync(Integer sync) {
+        this.sync = sync;
+    }
+}

+ 0 - 0
src/com/mes/ui/TableCellEditorButton.java


部分文件因文件數量過多而無法顯示