liuwei 3 هفته پیش
کامیت
2179738a16
100فایلهای تغییر یافته به همراه3909 افزوده شده و 0 حذف شده
  1. 25 0
      .classpath
  2. 7 0
      .gitignore
  3. 0 0
      .lock
  4. 17 0
      .project
  5. 2 0
      image/.gitignore
  6. BIN
      image/background.png
  7. BIN
      image/bg/a_side.png
  8. BIN
      image/bg/b_side.png
  9. BIN
      image/bg/bar_add.png
  10. BIN
      image/bg/bar_bookmark.png
  11. BIN
      image/bg/bar_cmd_go.png
  12. BIN
      image/bg/bar_edit.png
  13. BIN
      image/bg/bar_pause.png
  14. BIN
      image/bg/bar_sampling.png
  15. BIN
      image/bg/bar_setting.png
  16. BIN
      image/bg/bar_stop.png
  17. BIN
      image/bg/close_bt.png
  18. BIN
      image/bg/company_setting_logo.png
  19. BIN
      image/bg/delete.png
  20. BIN
      image/bg/department_setting_logo.png
  21. BIN
      image/bg/download.png
  22. BIN
      image/bg/equipment_setting_logo.png
  23. BIN
      image/bg/gj_001_1_20.png
  24. BIN
      image/bg/gj_001_21_40.png
  25. BIN
      image/bg/gj_001_41_60.png
  26. BIN
      image/bg/green_dot.png
  27. BIN
      image/bg/grey_dot.png
  28. BIN
      image/bg/icon.png
  29. BIN
      image/bg/inductance_logo.png
  30. BIN
      image/bg/insulation_logo.png
  31. BIN
      image/bg/login.png
  32. BIN
      image/bg/logo.png
  33. BIN
      image/bg/logoff.png
  34. BIN
      image/bg/menu_data_analysis.png
  35. BIN
      image/bg/menu_data_preprocess.png
  36. BIN
      image/bg/menu_file.png
  37. BIN
      image/bg/menu_setting.png
  38. BIN
      image/bg/min_bt.png
  39. BIN
      image/bg/ng_bg.png
  40. BIN
      image/bg/ok_bg.png
  41. BIN
      image/bg/open_file.png
  42. BIN
      image/bg/refresh.png
  43. BIN
      image/bg/reset_logo.png
  44. BIN
      image/bg/resistance_logo.png
  45. BIN
      image/bg/save_bg.png
  46. BIN
      image/bg/scan_barcode.png
  47. BIN
      image/bg/tree_folder_icon.png
  48. BIN
      image/bg/tree_leaf_icon.png
  49. BIN
      image/bg/user.png
  50. BIN
      image/bg/vertical_line.png
  51. BIN
      image/bg/zoom_in.png
  52. BIN
      image/bg/zoom_out.png
  53. BIN
      image/close_bt.png
  54. 0 0
      image/cmd.txt
  55. BIN
      image/icon.ico
  56. BIN
      image/info_bt.png
  57. BIN
      image/min_bt.png
  58. BIN
      lib/commons-codec-1.15.jar
  59. BIN
      lib/fastjson2-2.0.16.jar
  60. BIN
      lib/gson-2.10.jar
  61. BIN
      lib/iot-communication-1.4.4.jar
  62. BIN
      lib/jfreechart-1.5.4.jar
  63. BIN
      lib/jshortcut-0.4-oberzalek.jar
  64. BIN
      lib/kotlin-stdlib-1.8.10.jar
  65. BIN
      lib/logback-classic-1.2.13.jar
  66. BIN
      lib/logback-core-1.2.13.jar
  67. BIN
      lib/netty-all-4.1.48.Final.jar
  68. BIN
      lib/okhttp-4.10.0.jar
  69. BIN
      lib/okio-jvm-3.3.0.jar
  70. BIN
      lib/s7connector-2.1.jar
  71. BIN
      lib/slf4j-api-1.7.36.jar
  72. BIN
      lib/sqlite-jdbc-3.36.0.3.jar
  73. 10 0
      src/com/mes/component/CallFromJs.java
  74. 57 0
      src/com/mes/component/MesRadio.java
  75. 44 0
      src/com/mes/component/MesWebView.java
  76. 30 0
      src/com/mes/component/MyDialog.java
  77. 90 0
      src/com/mes/netty/MesMsgUtils.java
  78. 63 0
      src/com/mes/netty/NettyClient.java
  79. 82 0
      src/com/mes/netty/NettyClientHandler.java
  80. 73 0
      src/com/mes/netty/ProtocolParam.java
  81. 168 0
      src/com/mes/netty/XDecoder.java
  82. 58 0
      src/com/mes/ui/BindMaterialResp.java
  83. 495 0
      src/com/mes/ui/DataUtil.java
  84. 53 0
      src/com/mes/ui/ErrorMsg.java
  85. 85 0
      src/com/mes/ui/LockUtil.java
  86. 206 0
      src/com/mes/ui/LoginFarme.java
  87. 950 0
      src/com/mes/ui/MesClient.java
  88. 115 0
      src/com/mes/ui/MesRevice.java
  89. 236 0
      src/com/mes/ui/ModbusUtil.java
  90. 67 0
      src/com/mes/ui/OprnoUtil.java
  91. 194 0
      src/com/mes/ui/PlcUtil.java
  92. 148 0
      src/com/mes/ui/ProdReq.java
  93. 43 0
      src/com/mes/ui/TableCellEditorButton.java
  94. 14 0
      src/com/mes/ui/TableCellRendererButton.java
  95. 61 0
      src/com/mes/ui/WorkRecordData.java
  96. 404 0
      src/com/mes/ui/WorkRecordPanel.java
  97. 63 0
      src/com/mes/ui/WorkRecordResp.java
  98. 15 0
      src/com/mes/util/Base64Utils.java
  99. 34 0
      src/com/mes/util/DateLocalUtils.java
  100. 0 0
      src/com/mes/util/ErrorMsg.java

+ 25 - 0
.classpath

@@ -0,0 +1,25 @@
+<?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"/>
+	<classpathentry kind="lib" path="lib/iot-communication-1.4.4.jar"/>
+</classpath>

+ 7 - 0
.gitignore

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

+ 0 - 0
.lock


+ 17 - 0
.project

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>mesclient-op220</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>

+ 2 - 0
image/.gitignore

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

BIN
image/background.png


BIN
image/bg/a_side.png


BIN
image/bg/b_side.png


BIN
image/bg/bar_add.png


BIN
image/bg/bar_bookmark.png


BIN
image/bg/bar_cmd_go.png


BIN
image/bg/bar_edit.png


BIN
image/bg/bar_pause.png


BIN
image/bg/bar_sampling.png


BIN
image/bg/bar_setting.png


BIN
image/bg/bar_stop.png


BIN
image/bg/close_bt.png


BIN
image/bg/company_setting_logo.png


BIN
image/bg/delete.png


BIN
image/bg/department_setting_logo.png


BIN
image/bg/download.png


BIN
image/bg/equipment_setting_logo.png


BIN
image/bg/gj_001_1_20.png


BIN
image/bg/gj_001_21_40.png


BIN
image/bg/gj_001_41_60.png


BIN
image/bg/green_dot.png


BIN
image/bg/grey_dot.png


BIN
image/bg/icon.png


BIN
image/bg/inductance_logo.png


BIN
image/bg/insulation_logo.png


BIN
image/bg/login.png


BIN
image/bg/logo.png


BIN
image/bg/logoff.png


BIN
image/bg/menu_data_analysis.png


BIN
image/bg/menu_data_preprocess.png


BIN
image/bg/menu_file.png


BIN
image/bg/menu_setting.png


BIN
image/bg/min_bt.png


BIN
image/bg/ng_bg.png


BIN
image/bg/ok_bg.png


BIN
image/bg/open_file.png


BIN
image/bg/refresh.png


BIN
image/bg/reset_logo.png


BIN
image/bg/resistance_logo.png


BIN
image/bg/save_bg.png


BIN
image/bg/scan_barcode.png


BIN
image/bg/tree_folder_icon.png


BIN
image/bg/tree_leaf_icon.png


BIN
image/bg/user.png


BIN
image/bg/vertical_line.png


BIN
image/bg/zoom_in.png


BIN
image/bg/zoom_out.png


BIN
image/close_bt.png


+ 0 - 0
image/cmd.txt


BIN
image/icon.ico


BIN
image/info_bt.png


BIN
image/min_bt.png


BIN
lib/commons-codec-1.15.jar


BIN
lib/fastjson2-2.0.16.jar


BIN
lib/gson-2.10.jar


BIN
lib/iot-communication-1.4.4.jar


BIN
lib/jfreechart-1.5.4.jar


BIN
lib/jshortcut-0.4-oberzalek.jar


BIN
lib/kotlin-stdlib-1.8.10.jar


BIN
lib/logback-classic-1.2.13.jar


BIN
lib/logback-core-1.2.13.jar


BIN
lib/netty-all-4.1.48.Final.jar


BIN
lib/okhttp-4.10.0.jar


BIN
lib/okio-jvm-3.3.0.jar


BIN
lib/s7connector-2.1.jar


BIN
lib/slf4j-api-1.7.36.jar


BIN
lib/sqlite-jdbc-3.36.0.3.jar


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

@@ -0,0 +1,10 @@
+package com.mes.component;
+
+import com.mes.ui.MesClient;
+
+public class CallFromJs {
+    public String callFromJs(String info){
+        System.out.print("ss:"+info);
+        return MesClient.sessionid+":java:" + info;
+    }
+}

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

@@ -0,0 +1,57 @@
+package com.mes.component;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class MesRadio extends JPanel {
+
+    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;
+                    System.out.println("选择:"+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;
+    }
+}

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

@@ -0,0 +1,44 @@
+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 java.util.Date;
+
+public class MesWebView extends JFXPanel {
+
+    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();
+            System.out.print(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);
+    }
+}

+ 90 - 0
src/com/mes/netty/MesMsgUtils.java

@@ -0,0 +1,90 @@
+package com.mes.netty;
+
+public class MesMsgUtils {
+
+    public static int SYNR_LEN = 46;
+    public static int AXTW_LEN = 46;
+    public static int ACLW_LEN = 46;
+    public static int MCJW_LEN = 96;
+    public static int AQDW_LEN = 96;
+    public static int MBDW_LEN = 96;
+    public static int MJBW_LEN = 96;
+    public static int MQDW_LEN = 96;
+    public static int MKSW_LEN = 96;
+    public static int MSBW_LEN = 96;
+    public static int MCSW_LEN = 96;
+    public static int AQRW_LEN = 96;
+
+    public static String MSG_TYPE[] = {
+        "SYNR",
+        "AXTW",
+        "ACLW",
+        "MCJW",
+        "AQDW",
+        "MBDW",
+        "MJBW",
+        "MQDW",
+        "MKSW",
+        "MSBW",
+        "MCSW",
+        "AQRW",
+    };
+
+    public static int isMsgContentOK(String msg, String msg_type) {
+        //ret=0OK,1 空内容,2 长度不符
+        int ret = 0;
+        if(msg==null||msg.equalsIgnoreCase("")) {
+            ret = 1;
+            return ret;
+        }
+
+        int len = msg.length();
+        //System.out.println("len="+len);
+        switch(msg_type) {
+            case "SYNR":
+            case "AXTW":
+            case "ACLW":
+                if(len==SYNR_LEN) {
+                    ret = 0;
+                }else {
+                    ret = 2;
+                }
+                break;
+            default:
+                if(len==AQDW_LEN) {
+                    ret = 0;
+                }else {
+                    ret = 2;
+                }
+                break;
+        }
+        return ret;
+    }
+
+    // 判断报文类型是否在清单里
+    public static boolean isMsgTypeOk(String msg_type) {
+        for (String str : MSG_TYPE) {
+            if (str.equals(msg_type)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // 处理报文数据
+    public static String processMsg(String msg, String msg_type) {
+        String processMsgRet = "";
+        if(msg_type.equalsIgnoreCase("SYNR")) {
+
+        }else if(msg_type.equalsIgnoreCase("AXTW")) {
+
+        }else if(msg_type.equalsIgnoreCase("ACLW")) {
+
+        }else{
+            processMsgRet = ProtocolParam.getResult(msg);
+        }
+        return processMsgRet;
+    }
+
+
+}

+ 63 - 0
src/com/mes/netty/NettyClient.java

@@ -0,0 +1,63 @@
+package com.mes.netty;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.*;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.string.StringEncoder;
+import java.util.concurrent.TimeUnit;
+
+import com.mes.ui.MesClient;
+
+public class NettyClient {
+    public SocketChannel socketChannel;
+    public static ChannelFuture future;
+
+    public  void run(Object msg){
+        //配置线程组
+        EventLoopGroup group = new NioEventLoopGroup();
+        //创建服务启动器
+        Bootstrap bootstrap = new Bootstrap();
+
+        //配置参数
+        bootstrap.group(group)
+                .channel(NioSocketChannel.class)
+                .option(ChannelOption.TCP_NODELAY,true)
+                .handler(new ChannelInitializer<SocketChannel>() {
+                    protected void initChannel(SocketChannel socketChannel) throws Exception {
+                        socketChannel.pipeline()
+                                .addLast(new XDecoder())
+                                .addLast(new StringEncoder())
+//                                    .addLast(new StringDecoder())
+                                .addLast(new NettyClientHandler());
+                    }
+                })
+                .remoteAddress(MesClient.mes_server_ip,MesClient.mes_tcp_port);
+
+        //连接
+        future = bootstrap.connect();
+        System.out.println("客户端正在连接服务端...");
+        //客户端断线重连逻辑
+        future.addListener((ChannelFutureListener) future1 -> {
+            if (future1.isSuccess()) {
+                //tcp连接成功
+                MesClient.tcp_connect_flag = true;
+                //设置TCP请求状态
+                MesClient.connect_request_flag = false;
+                System.out.println("连接Netty服务端成功");
+                future.channel().writeAndFlush(msg);
+            } else {
+                //tcp连接失败
+                MesClient.tcp_connect_flag = false;
+                MesClient.connect_request_flag = true;
+                System.out.println("连接失败,进行断线重连");
+                future1.channel().eventLoop().schedule(() -> run(msg), 10, TimeUnit.SECONDS);
+            }
+            //设置tcp连接状态
+            MesClient.setTcpStatus();
+        });
+        socketChannel = (SocketChannel) future.channel();
+
+    }
+}

+ 82 - 0
src/com/mes/netty/NettyClientHandler.java

@@ -0,0 +1,82 @@
+package com.mes.netty;
+
+import com.mes.ui.MesClient;
+import com.mes.ui.MesRevice;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class NettyClientHandler extends ChannelInboundHandlerAdapter {
+
+    private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    public static byte[] responseByte;
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        System.out.println("mes connecting:" + sdf.format(new Date()));
+    }
+
+    @Override
+    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
+        Channel channel = ctx.channel();
+        System.err.println("close tcp, ip:" + channel.remoteAddress());
+        MesClient.tcp_connect_flag = false;
+        MesClient.setTcpStatus();
+        // 关闭通道
+        channel.close();
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        System.out.println("msg:"+msg);
+
+        String mes_msg = formatResult(msg.toString());
+        if(mes_msg == null || mes_msg.isEmpty()){ // error msg
+            return;
+        }
+
+        String msg_type = ProtocolParam.getMsgType(mes_msg);
+        System.out.println("msg_type="+msg_type);
+
+        String processMsgRet = MesMsgUtils.processMsg(mes_msg, msg_type);
+        System.out.println("processMsgRet="+processMsgRet);
+        switch(msg_type) {
+            case "AQDW": // 查询质量
+                MesRevice.checkQualityRevice(processMsgRet,mes_msg);
+                break;
+            case "MKSW":
+                MesRevice.startRevice(processMsgRet,mes_msg);
+                break;
+            case "MBDW":
+                MesRevice.bindRevice(processMsgRet,mes_msg);
+                break;
+            case "MJBW":
+                MesRevice.unbindRevice(processMsgRet,mes_msg);
+                break;
+            case "MQDW":
+                MesRevice.updateResultRevice(processMsgRet,mes_msg);
+                break;
+        }
+
+
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+        ctx.close();
+    }
+
+    private String formatResult(String msg){
+        System.err.println("length:" + msg.length() + " content:" + msg);
+        String msgType = msg.substring(0,2).trim();
+        if(msgType.equals("OK")){
+            return msg.substring(3,msg.length());
+        }else{
+            return "";
+        }
+    }
+
+}

+ 73 - 0
src/com/mes/netty/ProtocolParam.java

@@ -0,0 +1,73 @@
+package com.mes.netty;
+
+
+// 固定格式报文各参数获取方法
+public class ProtocolParam {
+    // bbbbfffffARWAQDWGWOP100 GY100000ID151245P00000106200123062900001      RSOKDA2023-09-07ZT10:16:58
+    public static Integer fixedLength = 96; // 固定长度
+
+    // 获取消息类型  所有报文都可使用
+    public static String getMsgType(String msg){
+        System.out.print(msg);
+        if(msg.length() < 16){
+            return "";
+        }
+        return msg.substring(12,16);
+    }
+
+    // 获取工位号
+    public static String getOprno(String msg){
+        if(msg.length() < 24){
+            return "";
+        }
+        return msg.substring(18,24);
+    }
+
+    // 获取工艺号
+    public static String getCraft(String msg){
+        if(msg.length() < 32){
+            return "";
+        }
+        return msg.substring(26,32);
+    }
+
+    // 获取镭雕码或设备报警故障代码
+    public static String getSn(String msg){
+        if(msg.length() < 70){
+            return "";
+        }
+        return msg.substring(34,70);
+    }
+
+    public static String getLx(String msg){
+        if(msg.length() < 72){
+            return "";
+        }
+        return msg.substring(70,72);
+    }
+
+    // 获取结果
+    public static String getResult(String msg){
+        if(msg.length() < 74){
+            return "";
+        }
+        return msg.substring(72,74);
+    }
+
+    // 获取日期
+    public static String getDay(String msg){
+        if(msg.length() < 86){
+            return "";
+        }
+        return msg.substring(76,86);
+    }
+
+    // 获取时间
+    public static String getTime(String msg){
+        if(msg.length() < 96){
+            return "";
+        }
+        return msg.substring(88,96);
+    }
+
+}

+ 168 - 0
src/com/mes/netty/XDecoder.java

@@ -0,0 +1,168 @@
+package com.mes.netty;
+
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufUtil;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.ByteToMessageDecoder;
+
+import java.util.List;
+
+public class XDecoder extends ByteToMessageDecoder {
+    static final int PACKET_SIZE = 46; // 最短包长度
+    static final int PACKET_MAX_SIZE = 1000; // 最长包长度
+
+    // 用来临时保留没有处理过的请求报文
+    ByteBuf tempMsg = Unpooled.buffer();
+
+    /**
+     * @param ctx
+     * @param in 请求的数据
+     * @param out 将粘在一起的报文拆分后的结果保留起来
+     * @throws Exception
+     */
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
+        System.out.println(Thread.currentThread() + "收到了一次数据包,长度是:" + in.readableBytes());
+        String content = hexStringToAscii(ByteBufUtil.hexDump(in));
+        System.out.println("接收包内容:" + hexStringToAscii(ByteBufUtil.hexDump(in)));
+
+        // 合并报文
+        ByteBuf message = null;
+        int tmpMsgSize = tempMsg.readableBytes();
+        // 如果暂存有上一次余下的请求报文,则合并
+        if (tmpMsgSize > 0) {
+            message = Unpooled.buffer();
+            message.writeBytes(tempMsg);
+            message.writeBytes(in);
+            System.out.println("合并:上一数据包余下的长度为:" + tmpMsgSize + ",合并后长度为:" + message.readableBytes());
+            System.out.println("合并后包内容:" + hexStringToAscii(ByteBufUtil.hexDump(message)));
+        } else {
+            message = in;
+        }
+
+//        System.out.println(Thread.currentThread() + "收到了一次数据包,长度是:" + message.readableBytes());
+        int size = 0;
+        String split = "bbbbfffffARW";
+
+        while (true){
+            size = message.readableBytes();
+            if(size >= PACKET_SIZE){
+                String retType = "NG:";
+                int qcsize = 0;
+                String str = hexStringToAscii(ByteBufUtil.hexDump(message));
+                String[] lists = str.split(split);
+
+                if(lists.length == 1 && size > PACKET_MAX_SIZE){ // 大于最大包长度
+                    byte[] request = new byte[size - PACKET_MAX_SIZE];
+                    // 每次从总的消息中读取n个字节的数据
+                    message.readBytes(request);
+                    // 将拆分后的结果放入out列表中,交由后面的业务逻辑去处理
+                    out.add(retType+hexStringToAscii(ByteBufUtil.hexDump(Unpooled.copiedBuffer(request))));
+                    break;
+                }
+
+                if(lists[0].length() > 0){
+                    byte[] request = new byte[lists[0].length()];
+                    // 每次从总的消息中读取n个字节的数据
+                    message.readBytes(request);
+                    // 将拆分后的结果放入out列表中,交由后面的业务逻辑去处理
+                    out.add(retType+hexStringToAscii(ByteBufUtil.hexDump(Unpooled.copiedBuffer(request))));
+                }else{
+                    if(lists.length > 1){
+                        String ss = lists[1];
+                        if(ss.length() <= 4){
+                            qcsize += ss.length();
+                        }else{
+                            String msgType = ProtocolParam.getMsgType(split+ss);
+                            if(!MesMsgUtils.isMsgTypeOk(msgType)){
+                                qcsize += split.length() + ss.length();
+                            }else{
+                                Integer ppsize = checkResultSize(ss,msgType,split);
+                                if(ppsize > 0){
+                                    qcsize = ppsize;
+                                    retType = "OK:";
+                                }else{
+                                    qcsize += split.length() + ss.length();
+                                }
+                            }
+                        }
+                    }
+                }
+
+
+                if(qcsize > 0){
+                    byte[] request = new byte[qcsize];
+                    // 每次从总的消息中读取n个字节的数据
+                    message.readBytes(request);
+                    // 将拆分后的结果放入out列表中,交由后面的业务逻辑去处理
+                    out.add(retType+hexStringToAscii(ByteBufUtil.hexDump(Unpooled.copiedBuffer(request))));
+                }
+            }else{
+                break;
+            }
+        }
+
+        // 多余的报文存起来
+        // 第一个报文: i+  暂存
+        // 第二个报文: 1 与第一次
+        size = message.readableBytes();
+        if (size != 0) {
+            System.out.println("多余的数据长度:" + size);
+            // 剩下来的数据放到tempMsg暂存
+            tempMsg.clear();
+            tempMsg.writeBytes(message.readBytes(size));
+        }
+    }
+
+    private Integer checkResultSize(String str, String msg_type, String split){
+        String oldstr = str;
+        str = split+str;
+        int tpsize = 0;
+        switch(msg_type) {
+            case "SYNR": // 同步
+                if(str.length() >= MesMsgUtils.SYNR_LEN){
+                    tpsize = MesMsgUtils.SYNR_LEN;
+                }
+                break;
+            case "AXTW": // 心跳
+                if(str.length() >= MesMsgUtils.AXTW_LEN){
+                    tpsize = MesMsgUtils.AXTW_LEN;
+                }
+                break;
+            case "ACLW": // 重连
+                if(str.length() >= MesMsgUtils.ACLW_LEN){
+                    tpsize = MesMsgUtils.ACLW_LEN;
+                }
+                break;
+            case "MCJW":
+            case "AQDW":
+            case "MBDW":
+            case "MJBW":
+            case "MQDW":
+            case "MKSW":
+            case "MSBW":
+            case "MCSW":
+            case "AQRW":
+            default: // 默认新报文
+                if(str.length() >= ProtocolParam.fixedLength){ // 大于固定长度
+                    tpsize = ProtocolParam.fixedLength;
+                }
+                break;
+        }
+
+        return tpsize;
+    }
+
+    // 16字符串转Ascii
+    private String hexStringToAscii(String hexString) {
+        StringBuilder sbuilder = new StringBuilder();
+        for (int i = 0; i < hexString.length(); i += 2) {
+            String hexByte = hexString.substring(i, i + 2);
+            int byteValue = Integer.parseInt(hexByte, 16);
+            char c = (char) byteValue;
+            sbuilder.append(c);
+        }
+        return sbuilder.toString();
+    }
+}

+ 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;
+    }
+}

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

@@ -0,0 +1,495 @@
+package com.mes.ui;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.mes.netty.NettyClient;
+import com.mes.util.DateLocalUtils;
+import com.mes.util.JdbcUtils;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Properties;
+import java.util.ArrayList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.alibaba.fastjson2.JSONArray;
+
+public class DataUtil {
+
+    public static final Logger log = LoggerFactory.getLogger(DataUtil.class);
+
+
+    /**
+     * 查询工作记录
+     * @param oprno 工位号(空则查所有工位)
+     * @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);
+            }
+            // 注意:不传auto参数,这样"所有工位"查询时会返回整条产线所有工位的数据
+            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 Boolean synrTcp(NettyClient nettyClient,String mes_gw){
+        try{
+            //TCP连接后,直接先发同步报文
+            String start = "aaaabbbbbABW";
+            String msgType = "SYNR";
+            String gw = "GW"+DataUtil.rightPad(mes_gw, 6);
+            String da = "DA" + DateLocalUtils.getCurrentDate();
+            String zt = "ZT" + DateLocalUtils.getCurrentTimeHMS();
+            String synr_str = start + msgType + gw + da + zt;
+            //插入报文本地数据
+            String gy = "";
+            String sn = "";
+            JdbcUtils.insertData(gw, gy, synr_str, msgType, sn);
+
+            nettyClient.run(synr_str);
+
+            return true;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean heartBeat(NettyClient nettyClient,String mes_gw){
+        try{
+            //TCP连接后,直接先发同步报文
+            String start = "aaaabbbbbABW";
+            String msgType = "AXTW";
+            String gw = "GW"+DataUtil.rightPad(mes_gw, 6);
+            String da = "DA" + DateLocalUtils.getCurrentDate();
+            String zt = "ZT" + DateLocalUtils.getCurrentTimeHMS();
+            String axtw_str = start + msgType + gw + da + zt;
+            //插入报文本地数据
+            String gy = "";
+            String sn = "";
+            JdbcUtils.insertData(gw, gy, axtw_str, msgType, sn);
+            nettyClient.future.channel().writeAndFlush(axtw_str);
+
+            return true;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean checkQuality(NettyClient nettyClient, String sn, String user){
+        try{
+            String msgType = "AQDW";
+            String gy = "100000";
+            Boolean aqdw_str = sendMessage(nettyClient,msgType,gy,"",sn,"",user,"00","");
+            return aqdw_str;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean startWork(NettyClient nettyClient,String sn,String user){
+        try{
+            String msgType = "MKSW";
+            String gy = "";
+            Boolean aqdw_str = sendMessage(nettyClient,msgType,gy,"",sn,"",user,"00","");
+            return aqdw_str;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean bindUser(NettyClient nettyClient,String sn,String user){
+        try{
+            String msgType = "MBDW";
+            String gy = "400001";
+            String param = rightPad(user, 36);
+            Boolean aqdw_str = sendMessage(nettyClient,msgType,gy,"",sn,"",user,"01",param);
+            return aqdw_str;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean bindWarehouse(NettyClient nettyClient,String sn,String wsn,String user,String craft){
+        try{
+            String msgType = "MBDW";
+            String param = rightPad(wsn, 36);
+            Boolean aqdw_str = sendMessage(nettyClient,msgType,craft,"",sn,"",user,"01",param);
+            return aqdw_str;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean unBindWarehouse(NettyClient nettyClient,String sn,String wsn,String user,String craft){
+        try{
+            String msgType = "MJBW";
+            String param = rightPad(wsn, 36);
+            Boolean aqdw_str = sendMessage(nettyClient,msgType,craft,"",sn,"",user,"01",param);
+            return aqdw_str;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean sendQuality(NettyClient nettyClient,String sn,String ret,String user){
+        try{
+            String msgType = "MQDW";
+            String gy = "100000";
+            String param = "";
+            Boolean aqdw_str = sendMessage(nettyClient,msgType,gy,"",sn,ret,user,"00",param);
+            return aqdw_str;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static Boolean sendMessage(NettyClient nettyClient,String msgType,String craft,String lx,String sn,String result,String user,String paramNums,String params){
+        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 gw = "GW"+rightPad(pro.getProperty("mes.gw"), 6);
+            String start = "aaaabbbbbABW";
+            String gy = "GY" + rightPad(craft, 6);
+            String reslx = "LX" + rightPad(lx, 2);
+            String id = pro.getProperty("mes.line_sn") + rightPad(sn, 36);
+            String rs = "RS"+ rightPad(result, 2);
+            String da = "DA" + DateLocalUtils.getCurrentDate();
+            String zt = "ZT" + DateLocalUtils.getCurrentTimeHMS();
+            String yh = "YH" + rightPad(user, 20);
+            String aqdw_str = start + msgType + gw + gy + reslx + id + rs + da + zt + yh + paramNums + params;
+            System.out.println("message="+aqdw_str);
+            JdbcUtils.insertData(gw, gy, aqdw_str, msgType, sn);
+            nettyClient.future.channel().writeAndFlush(aqdw_str);
+            return true;
+        }catch (Exception e){
+            return false;
+        }
+    }
+
+    public static String rightPad(final String str, final int size) {
+        if (str == null) {
+            return null;
+        }
+
+        String strret = str;
+        if(str.length() > size){
+            strret = str.substring(0,size);
+        }
+        return String.format("%-"+size+"s", strret);
+    }
+
+    public static JSONObject getBindMaterail() {
+        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 oprno = pro.getProperty("mes.gw").trim();
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesLineProcessMaterial/materials";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn;
+            System.out.println("params="+params);
+            String result = doPost(url,params);
+            System.out.println("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            return null;
+        }
+    }
+
+    public static JSONObject saveBindMaterail(String batchSn,String craft,String materialId,String type) {
+        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 oprno = pro.getProperty("mes.gw").trim();
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesMaterialPrebind/bind";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&batchSn="+batchSn+"&craft="+craft+"&materialId="+materialId+"&type="+type;
+            System.out.println("params="+params);
+            String result = doPost(url,params);
+            System.out.println("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            return null;
+        }
+    }
+
+    public static JSONObject upParams(String upparams) {
+        try{
+            String mes_server_ip = MesClient.mes_server_ip;
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesProductProd/batchsave";
+            String params = "__ajax=json&oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn+"&params="+upparams;
+            System.out.println("params="+params);
+            String result = doPost(url,params);
+            System.out.println("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            return null;
+        }
+    }
+
+    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(60000);
+            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;
+    }
+
+    public static JSONObject upAlarm(String sn,String ucode) {
+        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 oprno = pro.getProperty("mes.gw").trim();
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String url = "http://"+mes_server_ip+":8980/js/a/mes/mesProcessAlarm/add";
+            String params = "__ajax=json&oprno="+oprno+"&lineSn="+lineSn+"&sn="+sn+"&ucode="+ucode;
+            System.out.println("params="+params);
+            String result = doPost(url,params);
+            System.out.println("result="+result);
+
+            if(result.equalsIgnoreCase("false")) {
+                return null;
+            }else {
+                return JSONObject.parseObject(result);
+            }
+        }catch (Exception e){
+            return null;
+        }
+    }
+
+
+    public static JSONObject pcCheck(String sn, String userCode) {
+        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 oprno = pro.getProperty("mes.gw").trim();
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String gy = "100000";
+            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesProductRecord/pccheck";
+
+            String params = "__ajax=json"
+                    + "&sn=" + sn
+                    + "&oprno=" + oprno
+                    + "&lineSn=" + lineSn
+                    + "&ucode=" + userCode;
+
+            System.out.println("params=" + params);
+
+            // 5. 发送 POST 请求
+            String resultParams = doPost(url, params);
+            System.out.println("resultParam=" + resultParams);
+
+            // 6. 处理返回结果
+            if(resultParams == null || resultParams.trim().isEmpty() || resultParams.equalsIgnoreCase("false")) {
+                return null;
+            } else {
+                return JSONObject.parseObject(resultParams);
+            }
+        } catch (Exception e) {
+            e.printStackTrace(); // 建议打印堆栈以便调试
+            return null;
+        }
+    }
+
+    public static JSONObject pcResult(String sn, String userCode,String ldFlag,String result) {
+        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 oprno = pro.getProperty("mes.gw").trim();
+            String lineSn = pro.getProperty("mes.line_sn").trim();
+            String gy = "100000";
+            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesProductRecord/pcresult";
+
+            String params = "__ajax=json"
+                    + "&sn=" + sn
+                    + "&oprno=" + oprno
+                    + "&lineSn=" + lineSn
+                    + "&ldFlag=" + ldFlag
+                    + "&ucode=" + userCode
+                    + "&result=" + result
+                    + "&craft="
+                    + "&remark="
+                    + "&ps=";
+
+            System.out.println("params=" + params);
+
+            // 5. 发送 POST 请求
+            String resultParams = doPost(url, params);
+            System.out.println("resultParam=" + resultParams);
+
+            // 6. 处理返回结果
+            if(resultParams == null || resultParams.trim().isEmpty() || resultParams.equalsIgnoreCase("false")) {
+                return null;
+            } else {
+                return JSONObject.parseObject(resultParams);
+            }
+        } catch (Exception e) {
+            e.printStackTrace(); // 建议打印堆栈以便调试
+            return null;
+        }
+    }
+
+
+
+}

+ 53 - 0
src/com/mes/ui/ErrorMsg.java

@@ -0,0 +1,53 @@
+package com.mes.ui;
+
+import com.mes.netty.MesMsgUtils;
+import com.mes.netty.ProtocolParam;
+
+public class ErrorMsg {
+    public static void setErrorMsg(String mes_msg){
+        try{
+            String msg_type = ProtocolParam.getMsgType(mes_msg);
+            String processMsgRet = MesMsgUtils.processMsg(mes_msg, msg_type);
+            String lmsg = "该工件本工位不可加工";
+            if(processMsgRet.equalsIgnoreCase("OK")||processMsgRet.equalsIgnoreCase("NG")) {
+                lmsg = "该工件本工位已加工,结果:"+processMsgRet;
+            }else if(processMsgRet.equalsIgnoreCase("NE")) {
+                lmsg = "该工件未录入系统";
+            }else if(processMsgRet.equalsIgnoreCase("NN")) {
+                lmsg = "该工件跳过该工位";
+            }else if(processMsgRet.equalsIgnoreCase("QN")) {
+                lmsg = "该工件OP"+ ProtocolParam.getLx(mes_msg)+"0加工NG";
+            }else if(processMsgRet.equalsIgnoreCase("QD")) {
+                lmsg = "该工件OP"+ ProtocolParam.getLx(mes_msg)+"0未加工";
+            }else if(processMsgRet.equalsIgnoreCase("NF")) {
+                lmsg = "该工件已合格下线";
+            }else if(processMsgRet.equalsIgnoreCase("NR")) {
+                lmsg = "该工件离线返修中";
+            }else if(processMsgRet.equalsIgnoreCase("NB")) {
+                lmsg = "该工件已报废";
+            }else if(processMsgRet.equalsIgnoreCase("ND")) {
+                lmsg = "该工件NG待处理";
+            }else if(processMsgRet.equalsIgnoreCase("FN")) {
+                lmsg = "首件检查工件不合格停机";
+            }else if(processMsgRet.equalsIgnoreCase("GN")) {
+                lmsg = "更换配件首件检查不合格停机";
+            }else if(processMsgRet.equalsIgnoreCase("DJ")) {
+                lmsg = "未进行开班点检";
+            }else if(processMsgRet.equalsIgnoreCase("BM")) {
+                lmsg = "未绑定物料";
+            }else if(processMsgRet.equalsIgnoreCase("PL")) {
+                lmsg = "配件寿命不足";
+            }else if(processMsgRet.equalsIgnoreCase("QM")) {
+                lmsg = "两次气密必须间隔15分钟";
+            }else if(processMsgRet.equalsIgnoreCase("GS")) {
+                lmsg = "工件码格式不正确";
+            }else if(processMsgRet.equalsIgnoreCase("CF")) {
+                lmsg = "工件码重复";
+            }
+
+            MesClient.setMenuStatus(lmsg,-1);
+        }catch (Exception e){
+            MesClient.setMenuStatus("未知错误",-1);
+        }
+    }
+}

+ 85 - 0
src/com/mes/ui/LockUtil.java

@@ -0,0 +1,85 @@
+package com.mes.ui;
+
+import java.io.File;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+
+public class LockUtil {
+    private FileChannel channel;
+
+    private FileLock lock;
+
+    private File file;
+
+    private static LockUtil instance = null;
+
+    /**
+     * 获取唯一进程限制的实例
+     * @Title: getInstance
+     * @return  唯一进程实例
+     */
+    public static LockUtil getInstance(){
+        if(instance == null){
+            instance = new LockUtil();
+        }
+        return instance;
+    }
+
+    /**
+     * 进程是否正在运行
+     * @Title: isAppActive
+     * @return  运行与否
+     */
+    public boolean isAppActive() {
+        File file = new File(".lock");
+        try {
+            channel = new RandomAccessFile(file, "rw").getChannel();
+            try {
+                lock = channel.tryLock();
+
+            } catch (OverlappingFileLockException e) {
+                closeLock();
+                return true;
+            }
+            if (lock == null) {
+                closeLock();
+                return true;
+            }
+            Runtime.getRuntime().addShutdownHook(new Thread() {
+                public void run() {
+                    closeLock();
+                    deleteFile();
+                }
+            });
+            return false;
+        } catch (Exception e) {
+            closeLock();
+            return true;
+        }
+    }
+
+    protected void deleteFile() {
+        try {
+            file.delete();
+        } catch (Exception e) {
+
+        }
+
+    }
+
+    private void closeLock() {
+        try {
+            lock.release();
+        } catch (Exception e) {
+
+        }
+
+        try {
+            channel.close();
+        } catch (Exception e) {
+
+        }
+    }
+}

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

@@ -0,0 +1,206 @@
+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 javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class LoginFarme extends JFrame {
+    //登录模块组件
+    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系统客户端:"+MesClient.mes_gw+" - "+MesClient.mes_gw_des);
+
+        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);
+        System.out.println("&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, "请扫码工牌二维码");
+        System.out.println("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);
+            System.out.println("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);
+            System.out.println("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) {
+                    //初始化tcp连接,发送同步报文
+//                    MesClient.initTcpConnection();
+                    //启动timer心跳包
+                    MesClient.startHeartBeatTimer();
+
+                    //1操作工人,2管理员
+                    //登录成功
+                    MesClient.user_menu.setText(user_id);
+                    MesClient.welcomeWin.setVisible(false);
+                    MesClient.mesClientFrame.setVisible(true);
+
+//                    if(MesClient.jfxPanel == null){
+//                        String url = "http://"+ MesClient.mes_server_ip+":8980/js/a/mes/mesProductRecord/work?__sid="+MesClient.sessionid+"&oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn;
+//                        MesClient.jfxPanel = new MesWebView(url);
+//                        MesClient.jfxPanel.setSize(990, 550);
+//                        MesClient.indexPanelB.add(MesClient.jfxPanel);
+//                    }
+
+                    if(MesClient.jfxPanel2 == null){
+                        String url = "http://"+ MesClient.mes_server_ip+":8980/js/a/mes/mesProcessCheckRecord/ulist?__sid="+MesClient.sessionid+"&oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn;
+                        MesClient.jfxPanel2 = new MesWebView(url);
+                        MesClient.jfxPanel2.setSize(990, 550);
+                        MesClient.indexPanelC.add(MesClient.jfxPanel2);
+                    }
+
+                    MesClient.initWarehouseData();
+                }
+
+            }
+
+        }else {
+            JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录失败,用户名或密码错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }
+    }
+}

+ 950 - 0
src/com/mes/ui/MesClient.java

@@ -0,0 +1,950 @@
+package com.mes.ui;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
+import com.github.xingshuangs.iot.protocol.s7.enums.EPlcType;
+import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
+import com.mes.component.MesRadio;
+import com.mes.component.MesWebView;
+import com.mes.netty.NettyClient;
+import com.mes.util.DateLocalUtils;
+import com.mes.util.JdbcUtils;
+import javafx.embed.swing.JFXPanel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.*;
+import java.util.List;
+import java.util.Timer;
+
+public class MesClient extends JFrame {
+
+    public static final Logger log = LoggerFactory.getLogger(MesClient.class);
+    private static String Drivde = "org.sqlite.JDBC";
+
+    public static int mes_auth = 0; // 权限级别 0=无权限 1=操作工人 2=管理员
+    public static String mes_gw = ""; // 工位号
+    public static String mes_gw_des = ""; // 工位名称
+    public static String mes_server_ip = ""; // 服务器IP地址
+    public static int mes_tcp_port = 3000; // TCP服务端口
+    public static int mes_heart_beat_cycle = 10; // 心跳周期
+    public static int mes_heart_icon_cycle = 1;
+    public static String mes_line_sn = ""; // 产线编号
+    public static Boolean flag = false;
+    //TCP连接
+    public static NettyClient nettyClient;
+    //TCP连接状态
+    public static boolean tcp_connect_flag = true;
+    //TCP连接请求
+    public static boolean connect_request_flag = false;
+
+    //session
+    public static String sessionid = "";
+
+    public static JPanel contentPane;
+    public static MesClient mesClientFrame;
+    public static JTabbedPane tabbedPane;
+    public static JScrollPane indexScrollPaneA;
+//    public static JScrollPane searchScrollPane;
+    public static JScrollPane searchScrollPaneDj;
+
+
+    public static Boolean check_quality_result = false;
+    public static Integer work_status = 0;
+
+    public static JButton heart_beat_menu;
+    public static JButton status_menu;
+    public static JButton user_menu;
+
+    public static int scan_type = 0;
+    public static JButton finish_ok_bt;
+    public static JButton finish_ng_bt;
+    public static JTextField product_sn;
+    public static JButton f_scan_data_bt_1;
+
+    public static String user20 = "";
+
+    public static JFrame welcomeWin;
+
+//    public static JPanel indexPanelB;
+    public static MesWebView jfxPanel = null;
+    public static JPanel indexPanelC;
+    public static MesWebView jfxPanel2 = null;
+    public static MesRadio mesRadioHj;
+
+    public static JTextField param1;
+    public static JTextField param2;
+    public static JTextField param3;
+    public static JTextField param4;
+
+    public static S7PLC plcA = new S7PLC( EPlcType.S1200,"192.168.0.200");
+
+    public static Timer cjTimer;
+
+    public static Timer cjTimer2;
+
+    public static Timer cjTimer3;
+
+    public static int aSetNum = 20;
+    public static int sortA = 0;
+    public static int aMax = 0;
+    public static Short aFinish = 0;
+    public static List<Map> alist = new ArrayList<>();
+    public static int bSetNum = 42;
+    public static int sortB = 0;
+    public static int bMax = 0;
+    public static Short bFinish = 0;
+    public static List<Map> blist = new ArrayList<>();
+    public static Short deviceControl = 0; // 0=本地 1=远程
+    public static Integer tjStatus = 0; // 1=提交失败
+
+    public static String tjFlagTextErr = "结果上传MES失败,请重试";
+
+    public static String curSn = "";
+
+    public static JTable table;
+    public static Object[] columnNames = { "物料名称", "绑定批次", "剩余次数", "操作" };
+    public static Object[][] rowData = null;
+
+    public static void main(String[] args) {
+        if (LockUtil.getInstance().isAppActive() == true){
+//            JOptionPane.showMessageDialog(null, "已有一个程序在运行,程序退出");
+            return;
+        }
+        EventQueue.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                try{
+                    //读文件配置
+                    readProperty();
+
+                    // 显示界面
+                    mesClientFrame = new MesClient();
+                    mesClientFrame.setVisible(false);
+
+                    JdbcUtils.getConn();
+
+                    welcomeWin = new LoginFarme();
+                    welcomeWin.setVisible(true);
+
+                    getPlcParam();
+
+                    upParams();
+
+                    setDeviceStart();
+
+                    getMaterailData();
+
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    public static java.util.Timer cjTimer4;
+    public static void setDeviceStart() {
+        if(cjTimer4!=null) {
+            cjTimer4.cancel();
+        }
+        cjTimer4 = new Timer();
+        cjTimer4.schedule(new TimerTask() {
+            public void run() {
+                try{
+                    if(work_status == 1){
+                        if(MesClient.flag) {   //Mes允许
+//                            PlcUtil.setTask(plcA, MesClient.aSetNum, MesClient.bSetNum);
+                            MesClient.flag = false;
+                        }
+                    }else{
+                        PlcUtil.setPowerOffA(plcA);
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        }, 1000,1000);
+    }
+
+    //读配置文件
+    private static void readProperty() throws IOException{
+        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);
+        mes_gw =  pro.getProperty("mes.gw");
+
+//        mes_gw_des = pro.getProperty("mes.gw_des");
+        mes_server_ip = pro.getProperty("mes.server_ip");
+        mes_tcp_port = Integer.parseInt(pro.getProperty("mes.tcp_port"));
+        mes_heart_beat_cycle = Integer.parseInt(pro.getProperty("mes.heart_beat_cycle"));
+        mes_line_sn = pro.getProperty("mes.line_sn");
+
+        mes_gw_des = OprnoUtil.getGwDes(mes_line_sn,mes_gw);
+
+        System.out.println(mes_gw + ";" + mes_gw_des + ";" + mes_server_ip + ";" + mes_tcp_port + ";" + mes_heart_beat_cycle);
+    }
+
+    public static void getPlcParam() {
+        if(cjTimer!=null) {
+            cjTimer.cancel();
+        }
+        cjTimer = new Timer();
+        cjTimer.schedule(new TimerTask() {
+            public void run() {
+                try{
+                    if(work_status == 1){
+                        PlcUtil.getDataA(plcA);
+                    }
+
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+
+            }
+        }, 1000,500);
+    }
+
+    public static void upParams() {
+        if(cjTimer2!=null) {
+            cjTimer2.cancel();
+        }
+        cjTimer2 = new Timer();
+        cjTimer2.schedule(new TimerTask() {
+            public void run() {
+                try{
+                    List<ProdReq> prods = JdbcUtils.getProds();
+                    System.out.println("prods:"+ JSON.toJSONString(prods));
+                    if(prods.size() > 0){
+                        // 定时上传参数
+                        JSONObject retObj = DataUtil.upParams(JSON.toJSONString(prods));
+                        if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                            // 更新sqlite已同步
+                            for(ProdReq prodReq:prods){
+                                JdbcUtils.updateProdSync(prodReq.getId(),1);
+                            }
+                        }
+                    }
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        }, 1000,30*1000);
+    }
+
+    // 初始化TCP
+//    public static void initTcpConnection() {
+//        try {
+//            if(nettyClient==null) {
+//                //初始化TCP连接
+//                nettyClient = new NettyClient();
+//                //TCP连接状态
+//                tcp_connect_flag = false;
+//                //设置TCP请求状态
+//                connect_request_flag = true;
+//
+//                DataUtil.synrTcp(nettyClient,mes_gw);
+//            }
+//        } catch (Exception e) {
+//            // TODO Auto-generated catch block
+//            e.printStackTrace();
+//        }
+//    }
+
+    //启动心跳包程序
+    public static java.util.Timer heartBeatTimer;
+    public static java.util.Timer heartBeatIconTimer;
+    public static boolean iconREDFlag = true;
+    public static void startHeartBeatTimer() {
+        if(heartBeatTimer!=null) {
+            heartBeatTimer.cancel();
+        }
+
+        //心跳显示图标
+        if(heartBeatIconTimer!=null) {
+            heartBeatIconTimer.cancel();
+        }
+        heartBeatIconTimer = new Timer();
+        heartBeatIconTimer.schedule(new TimerTask() {
+            public void run() {
+                if(iconREDFlag) {
+                    heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
+                    iconREDFlag = false;
+                }else {
+                    heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
+                    iconREDFlag = true;
+                }
+                heart_beat_menu.setText(DateLocalUtils.getCurrentTime());
+                heart_beat_menu.repaint();
+            }
+        }, 100,mes_heart_icon_cycle*1000);
+    }
+
+    //设置tcp连接状态显示
+    public static void setTcpStatus() {
+        status_menu.setText("已连接MES服务器");
+        heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/grey_dot.png")));
+        heart_beat_menu.repaint();
+    }
+
+    public static void initWarehouseData(){
+        resetScanA();
+    }
+
+    public static void resetScanA() {
+        work_status = 0;
+        check_quality_result = false;
+        MesClient.finish_ok_bt.setEnabled(false);
+        MesClient.finish_ng_bt.setEnabled(false);
+        product_sn.setText("");
+        curSn = "";
+        tjStatus = 0;
+
+        MesClient.f_scan_data_bt_1.setEnabled(true);
+        MesClient.setMenuStatus("请扫工件码",0);
+
+        MesClient.aMax = 0;
+        MesClient.bMax = 0;
+        MesClient.aFinish = 0;
+        MesClient.bFinish = 0;
+        MesClient.alist = new ArrayList<>();
+        MesClient.blist = new ArrayList<>();
+        MesClient.sortB = 0;
+        MesClient.sortA = 0;
+        MesClient.param1.setText("");
+        MesClient.param2.setText("");
+//        MesClient.param3.setText("3");
+//        MesClient.param4.setText("4");
+
+
+//        PlcUtil.setPowerOff(MesClient.plcA); // 远程关机
+//        PlcUtil.setTask(MesClient.plcA,MesClient.aSetNum,MesClient.bSetNum);
+
+        //关闭任务,重置预设值和实际值
+        PlcUtil.setPowerOffA(MesClient.plcA);
+        updateMaterailData();
+        flag = false;  //Mes关闭
+    }
+
+    public static void resetScanB() {
+
+    }
+
+    //获取用户20位
+    public static void getUser() {
+        user20 = user_menu.getText().toString();
+        String space_tmp1 = "";
+        if(user20.length()<20) {
+            for(int i=0;i<20-user20.length();i++) {
+                space_tmp1 = space_tmp1 + " ";
+            }
+        }
+        user20 = user20 + space_tmp1;
+    }
+
+    //获取barcode内容36位
+    public static String getBarcode(String barcodeTmp) {
+        String barcodeRet = barcodeTmp;
+        if(barcodeTmp.equalsIgnoreCase("")) {
+            return "";
+        }else {
+            if(barcodeTmp.length()<36) {
+                String space = "";
+                for(int i=0;i<36-barcodeTmp.length();i++) {
+                    space = space + " ";
+                }
+                barcodeRet = barcodeTmp + space;
+            }
+        }
+        return barcodeRet;
+    }
+
+    public static void scanBarcode() {
+//        if(work_status == 1){
+//            JOptionPane.showMessageDialog(mesClientFrame,"工作中,勿扫码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+//            return;
+//        }
+        String scanBarcodeTitle = "";
+        switch(scan_type) {
+            case 1:
+                product_sn.setText("");
+                scanBarcodeTitle = "请扫工件码";
+                break;
+        }
+
+        //弹窗扫工件码
+        String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
+        if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
+            //获取用户
+            getUser();
+            //获取扫码内容36位
+            String barcode36 = getBarcode(scanBarcode);//处理36为码
+            //工位号
+            String gw = "";
+            switch(scan_type) {
+                case 1:
+                    product_sn.setText(scanBarcode);
+                    curSn = scanBarcode;
+                    break;
+            }
+            //刷新界面
+            mesClientFrame.repaint();
+
+
+            // 查询工件质量
+            JSONObject retObj = DataUtil.pcCheck(barcode36,user20);
+            if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                MesClient.status_menu.setForeground(Color.GREEN);
+                MesClient.check_quality_result = true;//质量合格,可以绑定加工
+                MesClient.setMenuStatus("该工件可以加工",0);
+
+                MesClient.work_status = 1;
+                MesClient.f_scan_data_bt_1.setEnabled(false);
+                MesClient.tjStatus = 0;
+                MesClient.flag  = true;
+
+                PlcUtil.setTask(MesClient.plcA,MesClient.aSetNum,MesClient.bSetNum);  //只设置任务A
+                PlcUtil.setPowerOnA(MesClient.plcA); // 远程开机
+
+            }else{
+                if(retObj.get("result")==null){
+                    MesClient.setMenuStatus("请求失败,请重试",-1);
+                }else{
+                    if(retObj.get("result").toString().equalsIgnoreCase("false")){
+                        MesClient.setMenuStatus(retObj.getString("message"),-1);
+                    }
+                }
+                MesClient.check_quality_result = false;
+                PlcUtil.setPowerOffA(MesClient.plcA); // 远程开机
+            }
+        }else {
+            JOptionPane.showMessageDialog(mesClientFrame,"请扫工件码","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+            return;
+        }
+    }
+
+    public static void logoff() {
+        welcomeWin.setVisible(true);
+        mesClientFrame.setVisible(false);
+
+        nettyClient = null;
+//        if(heartBeatTimer!=null) {
+//            heartBeatTimer.cancel();
+//        }
+//        if(heartBeatIconTimer!=null) {
+//            heartBeatIconTimer.cancel();
+//        }
+        tcp_connect_flag = false;
+        connect_request_flag = false;
+    }
+
+    public MesClient() {
+        setIconImage(Toolkit.getDefaultToolkit().getImage(MesClient.class.getResource("/bg/logo.png")));
+        setTitle("MES系统客户端:"+mes_gw + "- " + mes_gw_des);
+        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        setBounds(0, 0, 1024, 768);
+
+        JMenuBar menuBar = new JMenuBar();
+        menuBar.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 26));
+        setJMenuBar(menuBar);
+        JMenu fileMenu = new JMenu("用户");
+        fileMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/user.png")));
+        fileMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        menuBar.add(fileMenu);
+
+        JMenuItem exitMenuItem = new JMenuItem("退出");
+        exitMenuItem.setIcon(new ImageIcon(MesClient.class.getResource("/bg/logoff.png")));
+        exitMenuItem.setFont(new Font("微软雅黑", Font.PLAIN, 22));
+        fileMenu.add(exitMenuItem);
+        exitMenuItem.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {//只能检测到mousePressed事件
+                super.mouseClicked(e);
+                //dispose();
+                logoff();
+            }
+        });
+
+        JMenu settingMenu = new JMenu("设置");
+        //settingMenu.setVisible(false);
+        settingMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/menu_setting.png")));
+        settingMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        menuBar.add(settingMenu);
+
+        JMenuItem resetTcpMenu = new JMenuItem("\u91CD\u8FDEMES");
+        resetTcpMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
+        resetTcpMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        resetTcpMenu.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                super.mouseClicked(e);
+                //重连mes
+                nettyClient.future.channel().close();
+            }
+        });
+        settingMenu.add(resetTcpMenu);
+
+        JMenuItem resetTcpMenu_1 = new JMenuItem("刷新工件");
+        resetTcpMenu_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
+        resetTcpMenu_1.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        resetTcpMenu_1.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                super.mouseClicked(e);
+                log.info("刷新工件:"+MesClient.product_sn.getText());
+                resetScanA();
+            }
+        });
+        settingMenu.add(resetTcpMenu_1);
+
+        JMenuItem resetTcpMenu_12 = new JMenuItem("手动提交");
+        resetTcpMenu_12.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
+        resetTcpMenu_12.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        resetTcpMenu_12.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mousePressed(MouseEvent e) {
+                super.mouseClicked(e);
+                if(MesClient.work_status == 1){
+                    log.info("手动提交:"+MesClient.product_sn.getText());
+                    MesClient.finish_ok_bt.setEnabled(true);
+                    MesClient.finish_ng_bt.setEnabled(true);
+                }
+            }
+        });
+        settingMenu.add(resetTcpMenu_12);
+
+        contentPane = new JPanel();
+        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
+        setContentPane(contentPane);
+        contentPane.setLayout(new BorderLayout(0, 0));
+
+        JToolBar toolBar = new JToolBar();
+        contentPane.add(toolBar, BorderLayout.NORTH);
+
+        JLabel equipment_statu_label = new JLabel("状态:");
+        equipment_statu_label.setHorizontalAlignment(SwingConstants.CENTER);
+        equipment_statu_label.setForeground(Color.BLACK);
+        equipment_statu_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        equipment_statu_label.setBackground(Color.LIGHT_GRAY);
+        toolBar.add(equipment_statu_label);
+
+        status_menu = new JButton("设备未连接MES服务器");
+        status_menu.setText("已连接MES服务器");
+        status_menu.setForeground(Color.GREEN);
+        status_menu.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+            }
+        });
+        status_menu.setForeground(Color.GREEN);
+        status_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        status_menu.setBackground(Color.BLACK);
+        toolBar.add(status_menu);
+
+        JLabel space_1 = new JLabel("    ");
+        toolBar.add(space_1);
+
+        JLabel heart_beat_status_label = new JLabel("心跳:");
+        heart_beat_status_label.setHorizontalAlignment(SwingConstants.CENTER);
+        heart_beat_status_label.setForeground(Color.BLACK);
+        heart_beat_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        heart_beat_status_label.setBackground(Color.LIGHT_GRAY);
+        toolBar.add(heart_beat_status_label);
+
+        heart_beat_menu = new JButton("2024-02-20 23:20:10");
+        heart_beat_menu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/green_dot.png")));
+        heart_beat_menu.setForeground(Color.GREEN);
+        heart_beat_menu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        heart_beat_menu.setBackground(Color.BLACK);
+        toolBar.add(heart_beat_menu);
+
+        JLabel space_2 = new JLabel("    ");
+        toolBar.add(space_2);
+
+        JLabel user_status_label = new JLabel("登录用户:");
+        user_status_label.setHorizontalAlignment(SwingConstants.CENTER);
+        user_status_label.setForeground(Color.BLACK);
+        user_status_label.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        user_status_label.setBackground(Color.LIGHT_GRAY);
+        toolBar.add(user_status_label);
+
+        user_menu = new JButton("JinJuShi");
+        user_menu.setForeground(Color.GREEN);
+        user_menu.setFont(new Font("微软雅黑", Font.PLAIN, 22));
+        user_menu.setBackground(Color.BLACK);
+        toolBar.add(user_menu);
+
+        JLabel space_3 = new JLabel("    ");
+        toolBar.add(space_3);
+
+        JLabel space_4 = new JLabel("    ");
+        toolBar.add(space_4);
+
+        tabbedPane = new JTabbedPane(JTabbedPane.TOP);
+        tabbedPane.setMinimumSize(new Dimension(400, 50));
+        tabbedPane.setFont(new Font("宋体", Font.BOLD, 22));
+        contentPane.add(tabbedPane);
+
+        //首页
+        JPanel indexPanelA = new JPanel();
+        indexScrollPaneA = new JScrollPane(indexPanelA);
+        indexPanelA.setLayout(null);
+
+        product_sn = new JTextField();
+        product_sn.setHorizontalAlignment(SwingConstants.CENTER);
+        product_sn.setEditable(false);
+        product_sn.setFont(new Font("微软雅黑", Font.PLAIN, 28));
+        product_sn.setBounds(81, 70, 602, 70);
+        indexPanelA.add(product_sn);
+        product_sn.setColumns(10);
+
+        f_scan_data_bt_1 = new JButton("扫码");
+        f_scan_data_bt_1.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                scan_type = 1;
+                scanBarcode();
+            }
+        });
+        f_scan_data_bt_1.setIcon(new ImageIcon(MesClient.class.getResource("/bg/scan_barcode.png")));
+        f_scan_data_bt_1.setFont(new Font("微软雅黑", Font.PLAIN, 32));
+        f_scan_data_bt_1.setBounds(693, 70, 198, 70);
+        indexPanelA.add(f_scan_data_bt_1);
+
+//        String[] hjtitles = new String[]{"焊机1","焊机2","焊机3"};
+//        String[] hjvals = new String[]{"HJ001","HJ002","HJ003"};
+//        mesRadioHj = new MesRadio(hjtitles,hjvals);
+//        mesRadioHj.setSize(500,50);
+//        mesRadioHj.setBounds(190,170,500,50);
+//        indexPanelA.add(mesRadioHj);
+
+        finish_ok_bt = new JButton("OK");
+        finish_ok_bt.setEnabled(false);
+        finish_ok_bt.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if(work_status == 1 && check_quality_result){
+
+                    String sn = getBarcode(product_sn.getText());
+                    getUser();
+
+                    String qret = "OK";
+
+                    JSONObject retObj = DataUtil.pcResult(MesClient.product_sn.getText(),MesClient.user20,"",qret);
+                    if (retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) {
+                        MesClient.resetScanA();
+                        MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
+                        MesClient.scan_type = 1;
+                        MesClient.scanBarcode();
+                    } else {
+//                    MesClient.setMenuStatus(MesClient.tjFlagTextErr,-1);
+                        MesClient.setMenuStatus("结果提交失败,请重试",-1);
+                        return;
+                    }
+                }
+            }
+        });
+        finish_ok_bt.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ok_bg.png")));
+        finish_ok_bt.setFont(new Font("微软雅黑", Font.PLAIN, 32));
+//        finish_ok_bt.setBounds(185, 291, 240, 80);
+        finish_ok_bt.setBounds(185, 371, 240, 80);
+        finish_ok_bt.setEnabled(false);
+        indexPanelA.add(finish_ok_bt);
+
+        finish_ng_bt = new JButton("NG");
+        finish_ng_bt.setEnabled(false);
+        finish_ng_bt.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                if(work_status == 1 && check_quality_result){
+
+                    String sn = getBarcode(product_sn.getText());
+                    getUser();
+                    String qret = "NG";
+                    JSONObject retObj = DataUtil.pcResult(MesClient.product_sn.getText(),MesClient.user20,"",qret);
+                    if (retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) {
+                        MesClient.resetScanA();
+                        MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
+                        MesClient.scan_type = 1;
+                        MesClient.scanBarcode();
+                    } else {
+//                    MesClient.setMenuStatus(MesClient.tjFlagTextErr,-1);
+                        MesClient.setMenuStatus("结果提交失败,请重试",-1);
+                    }
+                }
+            }
+        });
+        finish_ng_bt.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ng_bg.png")));
+        finish_ng_bt.setFont(new Font("微软雅黑", Font.PLAIN, 32));
+        finish_ng_bt.setBounds(508, 371, 240, 80);
+        finish_ng_bt.setEnabled(false);
+        indexPanelA.add(finish_ng_bt);
+
+        JLabel lblNewLabel = new JLabel("A\u67AA");
+        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        lblNewLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+        lblNewLabel.setBounds(384, 186, 166, 28);
+        indexPanelA.add(lblNewLabel);
+
+        JLabel lblNewLabel_1 = new JLabel("\u9884\u8BBE\u6570\u91CF");
+        lblNewLabel_1.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        lblNewLabel_1.setBounds(384, 241, 83, 34);
+        indexPanelA.add(lblNewLabel_1);
+
+        param1 = new JTextField();
+        param1.setHorizontalAlignment(SwingConstants.CENTER);
+        param1.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        param1.setText("0");
+        param1.setEditable(false);
+        param1.setBounds(468, 241, 83, 34);
+        indexPanelA.add(param1);
+        param1.setColumns(10);
+
+        JLabel lblNewLabel_1_1 = new JLabel("\u5B8C\u6210\u6570\u91CF");
+        lblNewLabel_1_1.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        lblNewLabel_1_1.setBounds(384, 285, 83, 34);
+        indexPanelA.add(lblNewLabel_1_1);
+
+        param2 = new JTextField();
+        param2.setHorizontalAlignment(SwingConstants.CENTER);
+        param2.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+        param2.setText("0");
+        param2.setEditable(false);
+        param2.setColumns(10);
+        param2.setBounds(468, 285, 83, 34);
+        indexPanelA.add(param2);
+
+//        JLabel lblB = new JLabel("B\u67AA");
+//        lblB.setHorizontalAlignment(SwingConstants.CENTER);
+//        lblB.setFont(new Font("微软雅黑", Font.PLAIN, 20));
+//        lblB.setBounds(525, 186, 166, 28);
+//        indexPanelA.add(lblB);
+
+//        JLabel lblNewLabel_1_2 = new JLabel("\u9884\u8BBE\u6570\u91CF");
+//        lblNewLabel_1_2.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+//        lblNewLabel_1_2.setBounds(525, 241, 83, 34);
+//        indexPanelA.add(lblNewLabel_1_2);
+
+//        param3 = new JTextField();
+//        param3.setText("0");
+//        param3.setHorizontalAlignment(SwingConstants.CENTER);
+//        param3.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+//        param3.setEditable(false);
+//        param3.setColumns(10);
+//        param3.setBounds(608, 241, 83, 34);
+//        indexPanelA.add(param3);
+
+//        JLabel lblNewLabel_1_1_1 = new JLabel("\u5B8C\u6210\u6570\u91CF");
+//        lblNewLabel_1_1_1.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+//        lblNewLabel_1_1_1.setBounds(525, 285, 83, 34);
+//        indexPanelA.add(lblNewLabel_1_1_1);
+
+//        param4 = new JTextField();
+//        param4.setText("0");
+//        param4.setHorizontalAlignment(SwingConstants.CENTER);
+//        param4.setFont(new Font("微软雅黑", Font.PLAIN, 18));
+//        param4.setEditable(false);
+//        param4.setColumns(10);
+//        param4.setBounds(608, 285, 83, 34);
+//        indexPanelA.add(param4);
+
+        tabbedPane.addTab("工作面板", new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), indexScrollPaneA, null);
+        tabbedPane.setEnabledAt(0, true);
+
+//		searchScrollPane = new JScrollPane((Component) null);
+
+        indexPanelC = new JPanel();
+        searchScrollPaneDj = new JScrollPane(indexPanelC);
+        indexPanelC.setLayout(null);
+
+        tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPaneDj, null);
+
+
+        // ========== 工作记录 Tab(改造:当前工位Tab + 所有工位Tab) ==========
+        // 旧代码已注释:
+        // indexPanelB = new JPanel();
+        // searchScrollPane = new JScrollPane(indexPanelB);
+        // indexPanelB.setLayout(null);
+        // tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), searchScrollPane, null);
+
+        // 创建工作记录的子 TabbedPane
+        JTabbedPane workRecordTabbedPane = new JTabbedPane(JTabbedPane.TOP);
+        workRecordTabbedPane.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+
+        // OP80 工位:当前工位 + 所有工位
+        WorkRecordPanel[] workRecordPanels = new WorkRecordPanel[2];
+
+        // 当前工位Tab(使用配置文件中的 mes.gw)
+        workRecordPanels[0] = new WorkRecordPanel(mes_gw, mes_line_sn);
+        workRecordTabbedPane.addTab(mes_gw, null, workRecordPanels[0], "查询" + mes_gw + "的工作记录");
+
+        // 所有工位Tab(查询整条产线所有工位)
+        workRecordPanels[1] = new WorkRecordPanel(null, mes_line_sn);
+        workRecordTabbedPane.addTab("所有工位", null, workRecordPanels[1], "查询整条产线所有工位的工作记录");
+
+        // 切换子Tab时自动刷新数据
+        workRecordTabbedPane.addChangeListener(e -> {
+            int selectedIdx = workRecordTabbedPane.getSelectedIndex();
+            if (selectedIdx >= 0 && selectedIdx < workRecordPanels.length) {
+                workRecordPanels[selectedIdx].refreshData();
+            }
+        });
+
+        // 将子 TabbedPane 添加到主 TabbedPane
+        tabbedPane.addTab("工作记录", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), workRecordTabbedPane, null);
+
+		tabbedPane.addChangeListener(new ChangeListener() {
+            @Override
+            public void stateChanged(ChangeEvent e) {
+                JTabbedPane tabbedPane = (JTabbedPane) e.getSource();
+                int selectedIndex = tabbedPane.getSelectedIndex();
+                System.out.println("selectedIndex:"+selectedIndex);
+
+                if(selectedIndex == 1){
+
+                }
+            }
+        });
+    }
+
+    public static void setMenuStatus(String msg,int error){
+        if(error == 0){
+            MesClient.status_menu.setForeground(Color.GREEN);
+        }else{
+            MesClient.status_menu.setForeground(Color.RED);
+        }
+        MesClient.status_menu.setText(msg);
+    }
+
+    public static void getMaterailData(){
+        JSONObject retObj = DataUtil.getBindMaterail();
+        if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+            java.util.List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
+            int i = 0;
+            rowData = new Object[arrs.size()][7];
+            for (BindMaterialResp bindMaterialResp:arrs){
+                rowData[i][0] = bindMaterialResp.getMaterialTitle();
+                rowData[i][1] = bindMaterialResp.getBatchSn();
+                rowData[i][2] = bindMaterialResp.getLastTimes();
+                rowData[i][3] = "";
+                rowData[i][4] = bindMaterialResp.getCraft();
+                rowData[i][5] = bindMaterialResp.getMaterialId();
+                rowData[i][6] = bindMaterialResp.getType();
+                i++;
+            }
+            bindBatchPanel();
+        }
+    }
+
+    public static void updateMaterailData(){
+        JSONObject retObj = DataUtil.getBindMaterail();
+        if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+            List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
+
+            int i = 0;
+            for (BindMaterialResp bindMaterialResp:arrs){
+                rowData[i][0] = bindMaterialResp.getMaterialTitle();
+                rowData[i][1] = bindMaterialResp.getBatchSn();
+                rowData[i][2] = bindMaterialResp.getLastTimes();
+                rowData[i][3] = "";
+                rowData[i][4] = bindMaterialResp.getCraft();
+                rowData[i][5] = bindMaterialResp.getMaterialId();
+                rowData[i][6] = bindMaterialResp.getType();
+                i++;
+            }
+
+            MesClient.table.repaint();
+        }
+    }
+
+    // 绑定物料批次码
+    public static void scanBatchSn(BindMaterialResp bindMaterialResp) {
+        //弹窗扫工件码
+        String scanBarcodeTitle = "请扫物料:"+bindMaterialResp.getMaterialTitle();
+        String scanBarcode = JOptionPane.showInputDialog(null, scanBarcodeTitle);
+        if(scanBarcode!=null&&!scanBarcode.equalsIgnoreCase("")) {
+
+            JSONObject retObj = DataUtil.saveBindMaterail(scanBarcode,bindMaterialResp.getCraft(),bindMaterialResp.getMaterialId(),bindMaterialResp.getType());
+            if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
+                MesClient.setMenuStatus("扫物料:"+bindMaterialResp.getMaterialTitle()+"成功",0);
+                updateMaterailData();
+            }else{
+                if(retObj.get("result")==null){
+                    MesClient.setMenuStatus("请求失败,请重试",-1);
+                }else{
+                    if(retObj.get("result").toString().equalsIgnoreCase("false")){
+                        MesClient.setMenuStatus(retObj.getString("message"),-1);
+                    }
+                }
+            }
+        }
+    }
+
+    public static void bindBatchPanel(){
+        JPanel indexPanelBB = new JPanel();
+        JPanel panel = new JPanel();
+        panel.setBounds(0, 0, 990, 550);
+//        panel.setBounds(81, 50, 810, 479);
+        indexPanelBB.add(panel);
+
+        panel.setLayout(new GridLayout(0, 1, 0, 0));
+        table = new JTable(rowData, columnNames){
+            public boolean isCellEditable(int row, int column) {
+                if(column == 3){
+                    return true;
+                }
+                return false;
+            }
+        };
+        table.setRowHeight(40);
+        table.setEnabled(true);
+        table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
+
+        table.getColumnModel().getColumn(3).setCellRenderer(new TableCellRendererButton());
+        table.getColumnModel().getColumn(3).setCellEditor(new TableCellEditorButton());
+
+
+        JScrollPane scrollPane = new JScrollPane(table);
+        panel.add(scrollPane);
+
+        JScrollPane indexScrollPaneB = new JScrollPane(indexPanelBB);
+        indexPanelBB.setLayout(null);
+        tabbedPane.addTab("绑定物料", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")), indexScrollPaneB, null);
+    }
+
+    // 检查工件属于哪个版本
+    public static void checkSnType(String sn) {
+        if(sn.length() < 20){
+            return;
+        }
+        String xwd = sn.substring(0,14);
+        switch (xwd){
+            case "000020015308-0":// 国内长续航
+            case "000020015305-0":// 国内超长续航
+            case "000020020155-0":// 国内长续航
+            case "000020020156-0":// 国内超长续航
+            case "000020017939-0":// 中亚长续航
+            case "000020017933-0":// 中亚超长续航
+                bSetNum = 42;
+                break;
+            case "000020018302-0":// 海外长续航
+            case "000020018301-0":// 海外超长续航
+            case "000020020890-0":// 海外长续航
+            case "000020020889-0":// 海外超长续航
+                bSetNum = 46;
+                break;
+        }
+    }
+
+}

+ 115 - 0
src/com/mes/ui/MesRevice.java

@@ -0,0 +1,115 @@
+package com.mes.ui;
+
+import com.mes.netty.ProtocolParam;
+import com.mes.component.MyDialog;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class MesRevice {
+
+    // 质量查询
+    public static void checkQualityRevice(String processMsgRet,String mes_msg){
+        try{
+            String sn = ProtocolParam.getSn(mes_msg).trim();
+            MesClient.checkSnType(sn);
+
+            if(processMsgRet.equalsIgnoreCase("UD")) {
+                MesClient.status_menu.setForeground(Color.GREEN);
+                MesClient.check_quality_result = true;//质量合格,可以绑定加工
+                MesClient.setMenuStatus("该工件可以加工",0);
+
+                MesClient.work_status = 1;
+                MesClient.f_scan_data_bt_1.setEnabled(false);
+                MesClient.tjStatus = 0;
+
+//                PlcUtil.setPowerOn(MesClient.plcA); // 远程开机
+                PlcUtil.setTask(MesClient.plcA,MesClient.aSetNum,MesClient.bSetNum);
+
+            }else {
+                MesClient.check_quality_result = false;
+                ErrorMsg.setErrorMsg(mes_msg);
+
+//                PlcUtil.setPowerOff(MesClient.plcA);
+
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    // 开始回复处理
+    public static void startRevice(String processMsgRet,String mes_msg){
+        try{
+            if(processMsgRet.equalsIgnoreCase("OK")) {
+                MesClient.work_status = 1;
+                MesClient.f_scan_data_bt_1.setEnabled(false);
+                MesClient.tjStatus = 0;
+
+//                MesClient.deviceControl = ModbusUtil.getControlModel(MesClient.plcA);
+//                if(MesClient.deviceControl == 1){
+//
+//                }
+
+//                MesClient.plcA.writeCoil(3128,false);
+//                MesClient.plcB.writeCoil(3128,false);
+
+//                ModbusUtil.setPowerOn(MesClient.plcA); // 远程开机
+//                ModbusUtil.setPowerOn(MesClient.plcB); // 远程开机
+//
+//                ModbusUtil.setTask(MesClient.plcA,MesClient.aSetNum);
+//                ModbusUtil.setTask(MesClient.plcB,MesClient.bSetNum);
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    // 绑定
+    public static void bindRevice(String processMsgRet,String mes_msg){
+        try{
+            if(processMsgRet.equalsIgnoreCase("OK")) {
+
+            }else{
+
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    // 解绑
+    public static void unbindRevice(String processMsgRet,String mes_msg){
+        try{
+            if(processMsgRet.equalsIgnoreCase("OK")) {
+
+            }else{
+
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    // 上传质量
+    public static void updateResultRevice(String processMsgRet,String mes_msg){
+        try{
+            if(processMsgRet.equalsIgnoreCase("OK")) {
+
+                MesClient.resetScanA();
+//                MesClient.status_menu.setText("结果提交成功,请扫下一件");
+                MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
+                MesClient.scan_type = 1;
+                MesClient.scanBarcode();
+
+            }else{
+                MesClient.setMenuStatus("结果提交失败,请重试",-1);
+//                MesClient.status_menu.setText("结果提交失败,请重试");
+//                JOptionPane.showMessageDialog(MesClient.mesClientFrame,"结果提交失败,请重试","提示窗口", JOptionPane.INFORMATION_MESSAGE);
+//                return;
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+}

+ 236 - 0
src/com/mes/ui/ModbusUtil.java

@@ -0,0 +1,236 @@
+package com.mes.ui;
+
+import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
+import com.mes.util.JdbcUtils;
+
+import java.nio.charset.Charset;
+
+public class ModbusUtil {
+
+    public static void getDataA(ModbusTcp plc){
+
+        // 说明预设数量有变化不能修改
+        // 打钉数应按实际监听数算
+
+        // 41065=F-out  41066=S-out
+        // 41069=F-min  41071=S-min 41070=F-max  41072=S-max
+        // 预设数量=41129  完成数=41137
+
+        Short cur = plc.readInt16(1136);
+//        System.out.println("F-out:"+plc.readInt16(1064));
+//        System.out.println("S-out:"+plc.readInt16(1065));
+//        System.out.println("F-min:"+plc.readInt16(1068));
+//        System.out.println("S-min:"+plc.readInt16(1070));
+//        System.out.println("F-max:"+plc.readInt16(1069));
+//        System.out.println("S-max:"+plc.readInt16(1071));
+//        System.out.println("预设数量:"+plc.readInt16(1128));
+        //System.out.println("当前数量:"+cur);
+        if(MesClient.aMax <= 0){
+            MesClient.aMax = plc.readInt16(1128); // 任务数量
+            MesClient.param1.setText(String.valueOf(MesClient.aMax));
+        }
+
+        if(MesClient.sortA == cur - 1){
+            MesClient.sortA = cur;
+            MesClient.aFinish = plc.readInt16(1138);
+            String fout = plc.readInt16(1064)+"";
+            String sout = (float)plc.readInt16(1065)/1000+"";
+
+            String fmin = plc.readInt16(1068)+"";
+            String smin = (float)plc.readInt16(1070)/1000+"";
+
+            String fmax = plc.readInt16(1069)+"";
+            String smax = (float)plc.readInt16(1071)/1000+"";
+
+            MesClient.param2.setText(cur+"");
+            System.out.println("cur:"+cur);
+            if(!MesClient.product_sn.getText().isEmpty()){
+                JdbcUtils.insertProdData(MesClient.mes_gw, MesClient.mes_line_sn, MesClient.product_sn.getText(),"A",fout,sout,fmin,smin,fmax,smax,"1",cur+"", MesClient.user_menu.getText());
+            }
+        }
+
+        upResult();
+    }
+
+    public static void getDataB(ModbusTcp plc){
+
+        // 41065=F-out  41066=S-out
+        // 41069=F-min  41071=S-min 41070=F-max  41072=S-max
+        // 预设数量=41129  完成数=41137
+
+        Short cur = plc.readInt16(1136);
+//        System.out.println("F-out:"+plc.readInt16(1064));
+//        System.out.println("S-out:"+plc.readInt16(1065));
+//        System.out.println("F-min:"+plc.readInt16(1068));
+//        System.out.println("S-min:"+plc.readInt16(1070));
+//        System.out.println("F-max:"+plc.readInt16(1069));
+//        System.out.println("S-max:"+plc.readInt16(1071));
+//        System.out.println("set:"+plc.readInt16(1128));
+//        System.out.println("cur:"+cur);
+//        System.out.println("cur2:"+MesClient.sortB);
+
+        if(MesClient.bMax <= 0){
+            MesClient.bMax = plc.readInt16(1128);
+            MesClient.param3.setText(String.valueOf(MesClient.bMax));
+        }
+
+        if(MesClient.sortB == cur - 1){
+            MesClient.sortB = cur;
+            String fout = plc.readInt16(1064)+"";
+            String sout = (float)plc.readInt16(1065)/1000+"";
+
+            String fmin = plc.readInt16(1068)+"";
+            String smin = (float)plc.readInt16(1070)/1000+"";
+
+            String fmax = plc.readInt16(1069)+"";
+            String smax = (float)plc.readInt16(1071)/1000+"";
+
+            MesClient.param4.setText(cur+"");
+
+            System.out.println("cur:"+cur);
+            if(!MesClient.product_sn.getText().isEmpty()){
+               JdbcUtils.insertProdData(MesClient.mes_gw, MesClient.mes_line_sn, MesClient.product_sn.getText(),"B",fout,sout,fmin,smin,fmax,smax,"1",cur+"", MesClient.user_menu.getText());
+            }
+        }
+
+        upResult();
+
+    }
+
+    // 上传总结果
+    public static void upResult(){
+        if(!MesClient.curSn.isEmpty() && MesClient.aMax > 0 && MesClient.aMax == MesClient.sortA && MesClient.bMax > 0 && MesClient.bMax == MesClient.sortB){
+            MesClient.finish_ok_bt.setEnabled(true);
+            MesClient.finish_ng_bt.setEnabled(true);
+
+            if(MesClient.tjStatus == 0 && MesClient.check_quality_result){
+                MesClient.tjStatus = 1;
+                MesClient.getUser();
+                String retf = "OK";
+                if(MesClient.aFinish != MesClient.aMax){
+                    retf = "NG";
+                }
+                Boolean ret = DataUtil.sendQuality(MesClient.nettyClient, MesClient.product_sn.getText(),retf, MesClient.user20);
+                if(!ret){
+                    MesClient.setMenuStatus(MesClient.tjFlagTextErr,-1);
+                }
+            }
+
+        }
+    }
+
+    // 获取控制模式
+    public static short getControlModel(ModbusTcp plc){
+        short control = 0;
+        try{
+            control = plc.readInt16(1090);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+        return control;
+    }
+
+    // 获取二维码
+    public static String getSn(ModbusTcp plc){
+        String sn = "";
+        try{
+            sn = plc.readString(1216,40, Charset.forName("UTF8"));
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+        return splitIntoChunks(sn,2);
+    }
+
+    // 每两个字符分割,并反转
+    private static String splitIntoChunks(String str, int chunkSize) {
+        if (str == null || str.isEmpty() || chunkSize <= 0) {
+            return "";
+        }
+
+        int length = str.length();
+        int arraySize = (length + chunkSize - 1) / chunkSize;
+        String[] result = new String[arraySize];
+
+        for (int i = 0, j = 0; i < length; i += chunkSize, j++) {
+            int endIndex = Math.min(i + chunkSize, length);
+            String sttr = str.substring(i, endIndex);
+            StringBuilder sb = new StringBuilder(sttr);
+            String reversedStr = sb.reverse().toString(); // 字符串反转
+            result[j] = reversedStr;
+        }
+
+        return String.join("",result);
+    }
+
+    // 远程开机
+    public static Boolean setPowerOn(ModbusTcp plc){
+        Boolean ret = false;
+        try{
+            plc.writeCoil(3128,true);
+//            plc.writeCoil(3079,false);
+//            plc.writeCoil(3328,true); // 必须选关掉关机,开机才起左右
+            ret = true;
+        }catch (Exception e){
+            e.printStackTrace();
+            ret = false;
+        }
+
+        return ret;
+    }
+
+    // 远程关机
+    public static Boolean setPowerOff(ModbusTcp plc){
+        Boolean ret = false;
+        try{
+            plc.writeCoil(3128,false);
+//            plc.writeCoil(3328,false);
+//            plc.writeCoil(3079,true); // 关机
+            // 必须选关掉关机,开机才起左右
+            ret = true;
+        }catch (Exception e){
+            e.printStackTrace();
+            ret = false;
+        }
+
+        return ret;
+    }
+
+    // 重置任务
+    public static void setTask(ModbusTcp plc,Short setNum){
+        try{
+            // 设置模式 1=标记铆接模式
+            plc.writeInt16(1092,(short) 1);
+            // 设置任务
+            plc.writeInt16(1128,setNum);
+            plc.writeInt16(1136,(short) 0);
+            plc.writeInt16(1138,(short) 0);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+
+//        A枪说明 192.168.1.7
+//        plc.writeCoil(3079,false);
+//        plc.writeCoil(3328,true); // 必须选关掉关机,开机才起左右
+////        plc.writeCoil(3128,false);
+//        System.out.println("控制模式:"+plc.readInt16(1090)); // 1091 控制模式
+//        System.out.println("系统运行中:"+plc.readCoil(3128,1)); // 3129 系统运行中
+//        System.out.println("结束暂停:"+plc.readCoil(3132,1)); // 3133 系统运行中
+//        System.out.println("远程开机:"+plc.readCoil(3328,1)); // 3329 远程开机
+//        System.out.println("远程关机:"+plc.readCoil(3079,1)); // 3080 远程关机
+//        System.out.println("作业模式:"+plc.readInt16(1092)); // 1093 作业模式
+//        System.out.println("最大拉力:"+plc.readInt16(1064)); // 1065 最大拉力
+//        System.out.println("对应位移:"+plc.readInt16(1065)); // 1066 对应位移
+//        System.out.println("任务数量:"+plc.readInt16(1128)); // 1129 任务数量
+//        System.out.println("合格数量:"+plc.readInt16(1138)); // 1139 合格数量
+//        System.out.println("质量状态:"+plc.readInt16(1072)); // 1073 质量状态
+//        System.out.println("F-out:"+plc.readInt16(1064));
+//        System.out.println("S-out:"+plc.readInt16(1065));
+//        System.out.println("F-min:"+plc.readInt16(1068));
+//        System.out.println("S-min:"+plc.readInt16(1070));
+//        System.out.println("F-max:"+plc.readInt16(1069));
+//        System.out.println("S-max:"+plc.readInt16(1071));
+}

+ 67 - 0
src/com/mes/ui/OprnoUtil.java

@@ -0,0 +1,67 @@
+package com.mes.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class OprnoUtil {
+    public static String[] xtoprnos = new String[]{
+            "OP035", "OP040", "OP045", "OP050", "OP055", "OP060",
+            "OP065", "OP070", "OP075", "OP080", "OP085", "OP090",
+            "OP095", "OP100", "OP105", "OP110", "OP115", "OP120",
+            "OP125", "OP130", "OP135", "OP140", "OP145", "OP150",
+            "OP155", "OP160", "OP165", "OP170", "OP175", "OP180",
+            "OP185", "OP190", "OP195", "OP200", "OP205", "OP210",
+            "OP215", "OP220", "OP225", "OP230", "OP235", "OP240",
+            "OP245", "OP250", "OP255", "OP260", "OP265"
+    };
+    public static String[] xtoprnodes = new String[]{
+            "底板预拼+打码", "底板反面FSW", "底板反面打磨", "底板正面FSW", "CNC侧铣", "干冰清洁",
+            "封板预装+点焊", "封板正面FSW", "封板正面打磨", "封板反面FSW", "TIG手工焊", "打磨",
+            "检漏一序", "预拼锁付", "后膨胀梁打码", "弧焊一序", "弧焊二序", "TIG手工焊",
+            "打磨", "总成正面CNC", "总成反面CNC", "吹铝屑+刮毛刺+清洁", "检漏二序", "TIG手工焊",
+            "人工清洁", "抽芯拉铆", "拉铆", "螺套安装", "箱体气密一序", "水道气密一序",
+            "检具", "白件GP12", "喷粉前打包", "电泳", "箱体气密二序", "水道气密二序",
+            "氦检", "总成清洁", "支架、定位销安装", "涂胶", "全检", "GP12成品检验",
+            "CCD检测", "绝缘耐压测试", "成品打包", "入库", "出货"
+    };
+    public static String[] lboprnos = new String[]{};
+    public static String[] lboprnodes = new String[]{};
+    public static String getGwDes(String lineSn,String oprno){
+        String des = "";
+        oprno = formatOprno(oprno);
+        if(lineSn.equals("CZ060")){
+            int i = 0;
+            for (String gw:xtoprnos){
+                if(gw.equals(oprno)){
+                    des = xtoprnodes[i];
+                    break;
+                }
+                i++;
+            }
+        }else if(lineSn.equals("LB")){
+            int i = 0;
+            for (String gw:lboprnos){
+                if(gw.equals(oprno)){
+                    des = lboprnodes[i];
+                    break;
+                }
+                i++;
+            }
+        }
+        return des;
+    }
+
+    public static String formatOprno(String oprno){
+        List<String> lists = new ArrayList<>();
+
+        if(oprno.length() == 6){
+            String ysoprno = oprno.substring(0,5).trim();
+            if(!lists.contains(ysoprno)){
+                oprno = ysoprno;
+            }
+        }
+
+        return  oprno;
+    }
+}

+ 194 - 0
src/com/mes/ui/PlcUtil.java

@@ -0,0 +1,194 @@
+package com.mes.ui;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
+import com.github.xingshuangs.iot.protocol.s7.service.S7PLC;
+import com.mes.util.JdbcUtils;
+
+import java.nio.charset.Charset;
+import java.text.DecimalFormat;
+
+public class PlcUtil {
+
+    public static void getDataA(S7PLC plc){
+        int cur = plc.readInt32("DB1.184.0");   //实际数量
+        if(MesClient.aMax <= 0){
+            MesClient.aMax = plc.readInt32("DB1.38");
+            MesClient.param1.setText(String.valueOf(MesClient.aMax));  //预设数量
+            MesClient.param2.setText("0");
+        }
+
+        if(MesClient.sortA < cur){
+            MesClient.sortA = cur;
+
+            int fout = plc.readInt32("DB1.144.0");         //拉力
+            Float sout = plc.readFloat32("DB1.148.0");    //行程
+
+
+            int fjz = plc.readInt32("DB4.16");
+            Float sjz = plc.readFloat32("DB4.28.0");
+
+            int fmin = fjz - plc.readInt32("DB1.26.0");       //拉力下限
+            Float smin = sjz - plc.readFloat32("DB1.34.0");   //行程下限
+
+
+            int fmax = plc.readInt32("DB1.22.0") + fjz;        //拉力上限
+            Float smax = plc.readFloat32("DB1.30.0") + sjz;     //行程上限
+
+            String qty = "0";
+            //只记录实际值
+            if(getResultDingA(plc).equals("OK")){
+                MesClient.aFinish++;
+                qty = "1";
+            }
+
+            DecimalFormat decimalFormat = new DecimalFormat("#.###");
+            String soutstr = decimalFormat.format(sout);
+            String sminstr = decimalFormat.format(smin);
+            String smaxstr = decimalFormat.format(smax);
+            String foutstr = fout+"";
+            String fminstr = fmin+"";
+            String fmaxstr = fmax+"";
+
+            MesClient.param2.setText(cur+"");
+            System.out.println("cur:"+cur);
+            if(!MesClient.product_sn.getText().isEmpty()){
+                JdbcUtils.insertProdData(MesClient.mes_gw, MesClient.mes_line_sn, MesClient.product_sn.getText(),"A",foutstr,soutstr,fminstr,sminstr,fmaxstr,smaxstr,qty,cur+"", MesClient.user_menu.getText());
+            }
+        }
+
+        //如果达到完成数量,就关闭
+        if(MesClient.aMax <= MesClient.sortA){
+            PlcUtil.setPowerOffA(plc);
+        }
+
+        upResult();
+    }
+
+    // 上传总结果
+    public static void upResult(){
+        //如果达到完成数量,就上传结果
+        if(!MesClient.curSn.isEmpty() && MesClient.aMax > 0 && MesClient.aMax <= MesClient.sortA){
+            MesClient.finish_ok_bt.setEnabled(true);
+            MesClient.finish_ng_bt.setEnabled(true);
+
+            if(MesClient.tjStatus == 0 && MesClient.check_quality_result){
+                MesClient.tjStatus = 1;
+                MesClient.getUser();
+                String retf = "OK";
+                if(MesClient.aFinish != MesClient.aMax){
+                    retf = "NG";
+                }
+
+                JSONObject retObj = DataUtil.pcResult(MesClient.product_sn.getText(),MesClient.user20,"",retf);
+                if (retObj != null && retObj.get("result") != null && retObj.get("result").toString().equalsIgnoreCase("true")) {
+                        MesClient.resetScanA();
+                        MesClient.setMenuStatus("结果提交成功,请扫下一件",0);
+                        MesClient.scan_type = 1;
+                        MesClient.scanBarcode();
+                } else {
+//                    MesClient.setMenuStatus(MesClient.tjFlagTextErr,-1);
+                    MesClient.setMenuStatus("结果提交失败,请重试",-1);
+                }
+//                PlcUtil.setPowerOff(MesClient.plcA);
+//                Boolean ret = DataUtil.sendQuality(MesClient.nettyClient, MesClient.product_sn.getText(),retf, MesClient.user20);
+//                if(!ret){
+//                    MesClient.setMenuStatus(MesClient.tjFlagTextErr,-1);
+//                }
+
+
+
+            }
+
+        }
+    }
+
+    // 每两个字符分割,并反转
+    private static String splitIntoChunks(String str, int chunkSize) {
+        if (str == null || str.isEmpty() || chunkSize <= 0) {
+            return "";
+        }
+
+        int length = str.length();
+        int arraySize = (length + chunkSize - 1) / chunkSize;
+        String[] result = new String[arraySize];
+
+        for (int i = 0, j = 0; i < length; i += chunkSize, j++) {
+            int endIndex = Math.min(i + chunkSize, length);
+            String sttr = str.substring(i, endIndex);
+            StringBuilder sb = new StringBuilder(sttr);
+            String reversedStr = sb.reverse().toString(); // 字符串反转
+            result[j] = reversedStr;
+        }
+
+        return String.join("",result);
+    }
+
+
+    // 远程开机
+    public static Boolean setPowerOnA(S7PLC plc){
+        Boolean ret = false;
+        try{
+            plc.writeBoolean("DB4.0.1",true);
+            plc.writeBoolean("DB1.0.1",false); // 实际值清理关闭
+            ret = true;
+        }catch (Exception e){
+            e.printStackTrace();
+            ret = false;
+        }
+
+        return ret;
+    }
+
+    // 重置任务
+    public static void setTask(S7PLC plc,int setNumA,int setNumB){
+        try{
+            plc.writeBoolean("DB1.0.1",true); //实际值清0
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+    }
+
+    public static String getResultDingA(S7PLC plc){
+        String ret = "OK";
+        try{
+            //结果判断
+            boolean retang = plc.readBoolean("DB1.314.1");  //拉力NG
+            boolean retang2 = plc.readBoolean("DB1.314.3");   //位移Ng,有一个为true就记为NG
+            if(retang || retang2){
+                ret = "NG";
+            }
+        }catch (Exception e){
+            e.printStackTrace();
+            ret = "NG";
+        }
+        return ret;
+    }
+
+    public static Boolean setPowerOffA(S7PLC plc){
+        Boolean ret = false;
+        try{
+            plc.writeBoolean("DB4.0.1",false);
+            plc.writeBoolean("DB1.0.1",true); // 清零
+            ret = true;
+        }catch (Exception e){
+            e.printStackTrace();
+            ret = false;
+        }
+
+        return ret;
+    }
+
+    // MES开关   true = 开启
+    public static Boolean getMesTurn(S7PLC plc){
+        Boolean ret = false;
+        try{
+            ret = plc.readBoolean("DB1.3.0");
+        }catch (Exception e){
+            e.printStackTrace();
+            ret = false;
+        }
+
+        return ret;
+    }
+}

+ 148 - 0
src/com/mes/ui/ProdReq.java

@@ -0,0 +1,148 @@
+package com.mes.ui;
+
+public class ProdReq {
+    private Integer id;
+    private String gw;
+    private String lineSn;
+    private String type;
+    private String sn;
+    private String fout;
+    private String sout;
+    private String fmin;
+    private String smin;
+    private String fmax;
+    private String smax;
+    private String qty;
+    private String serialNumber;
+    private Integer sync;
+    private String recordTime;
+    private String ucode;
+
+    public String getUcode() {
+        return ucode;
+    }
+
+    public void setUcode(String ucode) {
+        this.ucode = ucode;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getGw() {
+        return gw;
+    }
+
+    public void setGw(String gw) {
+        this.gw = gw;
+    }
+
+    public String getLineSn() {
+        return lineSn;
+    }
+
+    public void setLineSn(String lineSn) {
+        this.lineSn = lineSn;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getFout() {
+        return fout;
+    }
+
+    public void setFout(String fout) {
+        this.fout = fout;
+    }
+
+    public String getSout() {
+        return sout;
+    }
+
+    public void setSout(String sout) {
+        this.sout = sout;
+    }
+
+    public String getFmin() {
+        return fmin;
+    }
+
+    public void setFmin(String fmin) {
+        this.fmin = fmin;
+    }
+
+    public String getSmin() {
+        return smin;
+    }
+
+    public void setSmin(String smin) {
+        this.smin = smin;
+    }
+
+    public String getFmax() {
+        return fmax;
+    }
+
+    public void setFmax(String fmax) {
+        this.fmax = fmax;
+    }
+
+    public String getSmax() {
+        return smax;
+    }
+
+    public void setSmax(String smax) {
+        this.smax = smax;
+    }
+
+    public String getQty() {
+        return qty;
+    }
+
+    public void setQty(String qty) {
+        this.qty = qty;
+    }
+
+    public String getSerialNumber() {
+        return serialNumber;
+    }
+
+    public void setSerialNumber(String serialNumber) {
+        this.serialNumber = serialNumber;
+    }
+
+    public Integer getSync() {
+        return sync;
+    }
+
+    public void setSync(Integer sync) {
+        this.sync = sync;
+    }
+
+    public String getRecordTime() {
+        return recordTime;
+    }
+
+    public void setRecordTime(String recordTime) {
+        this.recordTime = recordTime;
+    }
+}

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

@@ -0,0 +1,43 @@
+package com.mes.ui;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class TableCellEditorButton extends DefaultCellEditor {
+    private JButton btn;
+    public TableCellEditorButton() {
+        super(new JTextField());
+        //设置点击一次就激活,否则默认好像是点击2次激活。
+        this.setClickCountToStart(1);
+        btn = new JButton("扫码");
+        btn.addActionListener(new ActionListener() {
+
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                System.out.println("按钮事件触发----");
+                int selectedRow = MesClient.table.getSelectedRow();//获得选中行的索引
+//                MesClient.rowData[selectedRow][1] = (new Date()).getTime();
+//                MesClient.table.repaint(); //重绘
+
+//                MesClient.scan_type = selectedRow + 4;
+                BindMaterialResp bindMaterialResp = new BindMaterialResp();
+                bindMaterialResp.setMaterialTitle(MesClient.rowData[selectedRow][0] + "");
+                bindMaterialResp.setBatchSn(MesClient.rowData[selectedRow][1] + "");
+                bindMaterialResp.setLastTimes(MesClient.rowData[selectedRow][2] + "");
+                bindMaterialResp.setCraft(MesClient.rowData[selectedRow][4] + "");
+                bindMaterialResp.setMaterialId(MesClient.rowData[selectedRow][5] + "");
+                bindMaterialResp.setType(MesClient.rowData[selectedRow][6] + "");
+
+                MesClient.scanBatchSn(bindMaterialResp);
+            }
+        });
+
+    }
+    @Override
+    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+
+        return btn;
+    }
+}

+ 14 - 0
src/com/mes/ui/TableCellRendererButton.java

@@ -0,0 +1,14 @@
+package com.mes.ui;
+
+import javax.swing.*;
+import javax.swing.table.TableCellRenderer;
+import java.awt.*;
+
+public class TableCellRendererButton implements TableCellRenderer {
+    @Override
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+                                                   int row, int column) {
+        JButton button = new JButton("扫码");
+        return button;
+    }
+}

+ 61 - 0
src/com/mes/ui/WorkRecordData.java

@@ -0,0 +1,61 @@
+package com.mes.ui;
+
+/**
+ * 工作记录数据实体类
+ */
+public class WorkRecordData {
+    private String id;
+    private String sn;          // 工件码
+    private String oprno;       // 工位号
+    private String updateBy;    // 作业人员
+    private String updateDate;  // 日期
+    private String content;     // 工位结果
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getOprno() {
+        return oprno;
+    }
+
+    public void setOprno(String oprno) {
+        this.oprno = oprno;
+    }
+
+    public String getUpdateBy() {
+        return updateBy;
+    }
+
+    public void setUpdateBy(String updateBy) {
+        this.updateBy = updateBy;
+    }
+
+    public String getUpdateDate() {
+        return updateDate;
+    }
+
+    public void setUpdateDate(String updateDate) {
+        this.updateDate = updateDate;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}

+ 404 - 0
src/com/mes/ui/WorkRecordPanel.java

@@ -0,0 +1,404 @@
+package com.mes.ui;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.DefaultTableModel;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.util.List;
+
+/**
+ * 工作记录面板组件
+ * 支持分页查询和展示工作记录数据
+ * 适配 auto2 (OP040) 工位
+ */
+public class WorkRecordPanel extends JPanel {
+
+    private static final Logger log = LoggerFactory.getLogger(WorkRecordPanel.class);
+
+    // 表格列名
+    private static final String[] COLUMN_NAMES = {"工件码", "工位号", "工位结果", "作业人员", "日期"};
+
+    // 分页配置
+    private static final int PAGE_SIZE = 20;
+
+    // 查询条件
+    private String oprno;  // 工位号(null或空则查全部)
+    private String lineSn; // 产线编号
+    private boolean isAllStation; // 是否是"所有工位"模式
+
+    // 分页状态
+    private int pageNo = 1;
+    private long totalCount = 0;
+    private int totalPages = 0;
+
+    // UI组件
+    private JTable table;
+    private DefaultTableModel tableModel;
+    private JLabel pageLabel;
+    private JButton btnPrevious;
+    private JButton btnNext;
+    private JButton btnRefresh;
+    private JButton btnSearch;
+    private JLabel statusLabel;
+    private JTextField snSearchField;      // 工件码搜索框
+    private JTextField oprnoSearchField;   // 工位号搜索框(仅"所有工位"模式)
+    private JLabel snLabel;
+    private JLabel oprnoLabel;
+
+    /**
+     * 构造函数
+     * @param oprno 工位号(如OP040A查询该工位,null或空则查所有工位)
+     * @param lineSn 产线编号
+     */
+    public WorkRecordPanel(String oprno, String lineSn) {
+        this.oprno = oprno;
+        this.lineSn = lineSn;
+        this.isAllStation = (oprno == null || oprno.isEmpty());
+        initUI();
+    }
+
+    /**
+     * 初始化UI
+     */
+    private void initUI() {
+        setLayout(null);
+        setBackground(Color.WHITE);
+
+        // 顶部控制区
+        JPanel topPanel = new JPanel();
+        topPanel.setLayout(null);
+        topPanel.setBounds(0, 0, 1200, 50);
+        topPanel.setBackground(new Color(248, 248, 248));
+        add(topPanel);
+
+        int xPos = 10;
+
+        // 状态标签
+        String displayOprno = isAllStation ? "所有工位" : oprno;
+        statusLabel = new JLabel("工位:" + displayOprno);
+        statusLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        statusLabel.setBounds(xPos, 10, 160, 30);
+        topPanel.add(statusLabel);
+        xPos += 165;
+
+        // 工件码搜索
+        snLabel = new JLabel("工件码:");
+        snLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        snLabel.setBounds(xPos, 10, 50, 30);
+        topPanel.add(snLabel);
+        xPos += 52;
+
+        snSearchField = new JTextField();
+        snSearchField.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        snSearchField.setBounds(xPos, 10, 200, 30);
+        snSearchField.addActionListener(e -> doSearch()); // 回车搜索
+        topPanel.add(snSearchField);
+        xPos += 210;
+
+        // 工位号搜索(仅"所有工位"模式显示)
+        if (isAllStation) {
+            oprnoLabel = new JLabel("工位:");
+            oprnoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+            oprnoLabel.setBounds(xPos, 10, 40, 30);
+            topPanel.add(oprnoLabel);
+            xPos += 42;
+
+            oprnoSearchField = new JTextField();
+            oprnoSearchField.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+            oprnoSearchField.setBounds(xPos, 10, 100, 30);
+            oprnoSearchField.addActionListener(e -> doSearch()); // 回车搜索
+            topPanel.add(oprnoSearchField);
+            xPos += 110;
+        }
+
+        // 查询按钮
+        btnSearch = new JButton("查询");
+        btnSearch.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        btnSearch.setBounds(xPos, 10, 70, 30);
+        btnSearch.addActionListener(e -> doSearch());
+        topPanel.add(btnSearch);
+        xPos += 80;
+
+        // 刷新按钮
+        btnRefresh = new JButton("刷新");
+        btnRefresh.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        btnRefresh.setBounds(xPos, 10, 70, 30);
+        btnRefresh.addActionListener(e -> {
+            clearSearchFields();
+            refreshData();
+        });
+        topPanel.add(btnRefresh);
+        xPos += 80;
+
+        // 上一页按钮
+        btnPrevious = new JButton("上一页");
+        btnPrevious.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        btnPrevious.setBounds(xPos, 10, 80, 30);
+        btnPrevious.addActionListener(e -> {
+            if (pageNo > 1) {
+                pageNo--;
+                loadData();
+            }
+        });
+        topPanel.add(btnPrevious);
+        xPos += 85;
+
+        // 页码显示
+        pageLabel = new JLabel("0/0");
+        pageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        pageLabel.setHorizontalAlignment(SwingConstants.CENTER);
+        pageLabel.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
+        pageLabel.setBounds(xPos, 10, 70, 30);
+        topPanel.add(pageLabel);
+        xPos += 75;
+
+        // 下一页按钮
+        btnNext = new JButton("下一页");
+        btnNext.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        btnNext.setBounds(xPos, 10, 80, 30);
+        btnNext.addActionListener(e -> {
+            if (pageNo < totalPages) {
+                pageNo++;
+                loadData();
+            }
+        });
+        topPanel.add(btnNext);
+
+        // 表格面板
+        JPanel tablePanel = new JPanel();
+        tablePanel.setBounds(0, 50, 1200, 518);
+        tablePanel.setLayout(new GridLayout(1, 1, 0, 0));
+        add(tablePanel);
+
+        // 创建表格模型
+        tableModel = new DefaultTableModel(COLUMN_NAMES, 0) {
+            @Override
+            public boolean isCellEditable(int row, int column) {
+                return false;
+            }
+        };
+
+        // 创建表格
+        table = new JTable(tableModel);
+        table.setRowHeight(32);
+        table.setFont(new Font("微软雅黑", Font.PLAIN, 13));
+        table.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 14));
+        table.getTableHeader().setReorderingAllowed(false);
+
+        // 设置列宽
+        setColumnWidths();
+
+        // 设置居中渲染器
+        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
+        centerRenderer.setHorizontalAlignment(JLabel.CENTER);
+        for (int i = 0; i < table.getColumnCount(); i++) {
+            table.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
+        }
+
+        // 添加滚动面板
+        JScrollPane scrollPane = new JScrollPane(table);
+        tablePanel.add(scrollPane);
+
+        // 添加组件大小变化监听器
+        addComponentListener(new ComponentAdapter() {
+            @Override
+            public void componentResized(ComponentEvent e) {
+                int w = getWidth();
+                int h = getHeight();
+
+                // 调整顶部面板宽度
+                topPanel.setBounds(0, 0, w, 50);
+
+                // 调整表格面板
+                if (h > 50) {
+                    tablePanel.setBounds(0, 50, w, h - 50);
+                }
+
+                topPanel.revalidate();
+                tablePanel.revalidate();
+            }
+        });
+    }
+
+    /**
+     * 设置列宽
+     */
+    private void setColumnWidths() {
+        TableColumn column;
+        // 工件码
+        column = table.getColumnModel().getColumn(0);
+        column.setPreferredWidth(260);
+        // 工位号
+        column = table.getColumnModel().getColumn(1);
+        column.setPreferredWidth(90);
+        // 工位结果
+        column = table.getColumnModel().getColumn(2);
+        column.setPreferredWidth(70);
+        // 作业人员
+        column = table.getColumnModel().getColumn(3);
+        column.setPreferredWidth(100);
+        // 日期
+        column = table.getColumnModel().getColumn(4);
+        column.setPreferredWidth(150);
+    }
+
+    /**
+     * 清空搜索框
+     */
+    private void clearSearchFields() {
+        snSearchField.setText("");
+        if (oprnoSearchField != null) {
+            oprnoSearchField.setText("");
+        }
+    }
+
+    /**
+     * 执行搜索
+     */
+    private void doSearch() {
+        pageNo = 1;
+        loadData();
+    }
+
+    /**
+     * 刷新数据(重置到第一页)
+     */
+    public void refreshData() {
+        pageNo = 1;
+        loadData();
+    }
+
+    /**
+     * 加载数据
+     */
+    public void loadData() {
+        // 获取搜索条件
+        String searchSn = snSearchField.getText().trim();
+        String searchOprno = oprno; // 默认使用构造函数传入的工位号
+
+        // 如果是"所有工位"模式,检查是否有工位号搜索条件
+        if (isAllStation && oprnoSearchField != null) {
+            String inputOprno = oprnoSearchField.getText().trim();
+            if (!inputOprno.isEmpty()) {
+                searchOprno = inputOprno;
+            }
+        }
+
+        final String finalSearchOprno = searchOprno;
+        final String finalSearchSn = searchSn;
+
+        // 在后台线程中执行数据加载
+        SwingWorker<WorkRecordResp, Void> worker = new SwingWorker<WorkRecordResp, Void>() {
+            @Override
+            protected WorkRecordResp doInBackground() throws Exception {
+                // 更新状态
+                SwingUtilities.invokeLater(() -> {
+                    statusLabel.setText("正在加载...");
+                    setButtonsEnabled(false);
+                });
+
+                // 调用接口查询数据
+                return DataUtil.getWorkRecordList(finalSearchOprno, finalSearchSn, pageNo, PAGE_SIZE);
+            }
+
+            @Override
+            protected void done() {
+                try {
+                    WorkRecordResp resp = get();
+                    updateUI(resp, finalSearchOprno);
+                } catch (Exception e) {
+                    log.error("加载工作记录失败: {}", e.getMessage());
+                    updateUIError("加载失败: " + e.getMessage());
+                }
+            }
+        };
+        worker.execute();
+    }
+
+    /**
+     * 设置按钮启用状态
+     */
+    private void setButtonsEnabled(boolean enabled) {
+        btnSearch.setEnabled(enabled);
+        btnRefresh.setEnabled(enabled);
+        btnPrevious.setEnabled(enabled && pageNo > 1);
+        btnNext.setEnabled(enabled && pageNo < totalPages);
+    }
+
+    /**
+     * 更新UI显示数据
+     */
+    private void updateUI(WorkRecordResp resp, String queryOprno) {
+        // 清空表格
+        tableModel.setRowCount(0);
+
+        if (resp == null || !resp.isResult()) {
+            String msg = resp != null ? resp.getMessage() : "请求失败";
+            updateUIError(msg);
+            return;
+        }
+
+        // 更新分页信息
+        totalCount = resp.getCount();
+        totalPages = (int) Math.ceil((double) totalCount / PAGE_SIZE);
+        if (totalPages == 0) totalPages = 1;
+
+        // 更新页码显示
+        pageLabel.setText(pageNo + "/" + totalPages);
+
+        // 更新按钮状态
+        setButtonsEnabled(true);
+
+        // 更新状态标签
+        String oprnoDisplay;
+        if (isAllStation) {
+            oprnoDisplay = (queryOprno == null || queryOprno.isEmpty()) ? "所有工位" : queryOprno;
+        } else {
+            oprnoDisplay = oprno;
+        }
+        statusLabel.setText("工位:" + oprnoDisplay + " 共" + totalCount + "条");
+
+        // 填充表格数据
+        List<WorkRecordData> list = resp.getList();
+        if (list != null && !list.isEmpty()) {
+            for (WorkRecordData data : list) {
+                Object[] row = {
+                        data.getSn(),
+                        data.getOprno(),
+                        data.getContent(),
+                        data.getUpdateBy(),
+                        data.getUpdateDate()
+                };
+                tableModel.addRow(row);
+            }
+        }
+
+        // 刷新表格
+        table.repaint();
+    }
+
+    /**
+     * 更新UI显示错误信息
+     */
+    private void updateUIError(String message) {
+        statusLabel.setText("错误: " + message);
+        pageLabel.setText("0/0");
+        setButtonsEnabled(true);
+        btnPrevious.setEnabled(false);
+        btnNext.setEnabled(false);
+        tableModel.setRowCount(0);
+    }
+
+    /**
+     * 获取当前工位号
+     */
+    public String getOprno() {
+        return oprno;
+    }
+}

+ 63 - 0
src/com/mes/ui/WorkRecordResp.java

@@ -0,0 +1,63 @@
+package com.mes.ui;
+
+import java.util.List;
+
+/**
+ * 工作记录查询响应实体类
+ */
+public class WorkRecordResp {
+    private boolean result;
+    private String message;
+    private int pageNo;
+    private int pageSize;
+    private long count;
+    private List<WorkRecordData> list;
+
+    public boolean isResult() {
+        return result;
+    }
+
+    public void setResult(boolean result) {
+        this.result = result;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public int getPageNo() {
+        return pageNo;
+    }
+
+    public void setPageNo(int pageNo) {
+        this.pageNo = pageNo;
+    }
+
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(int pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public long getCount() {
+        return count;
+    }
+
+    public void setCount(long count) {
+        this.count = count;
+    }
+
+    public List<WorkRecordData> getList() {
+        return list;
+    }
+
+    public void setList(List<WorkRecordData> list) {
+        this.list = list;
+    }
+}

+ 15 - 0
src/com/mes/util/Base64Utils.java

@@ -0,0 +1,15 @@
+package com.mes.util;
+
+import org.apache.commons.codec.binary.Base64;
+
+public class Base64Utils {
+	public static String getBase64(String str) {
+		// 待编码的二进制数据
+        byte[] binaryData = str.getBytes();
+        // 使用Base64.encodeBase64String进行编码
+        String encodedString = Base64.encodeBase64String(binaryData);
+        // 输出编码后的结果
+        System.out.println("Base64编码结果: " + encodedString);
+        return encodedString;
+	}
+}

+ 34 - 0
src/com/mes/util/DateLocalUtils.java

@@ -0,0 +1,34 @@
+package com.mes.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateLocalUtils {
+	public static SimpleDateFormat DATA_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//璁剧疆鏃ユ湡鏍煎紡
+	public static SimpleDateFormat DATA_FORMAT1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+	
+	
+	public static String getCurrentTime() {
+		String currentTime = DATA_FORMAT.format(new Date());
+		return currentTime;
+	}
+	
+	public static String getCurrentTime1() {
+		String currentTime = DATA_FORMAT1.format(new Date());
+		return currentTime;
+	}
+	
+	//获取当前时间,年月日
+	public static SimpleDateFormat DATA_FORMAT2 = new SimpleDateFormat("yyyy-MM-dd");
+	public static String getCurrentDate() {
+		String currentTime = DATA_FORMAT2.format(new Date());
+		return currentTime;
+	}
+	
+	//获取当前时间,时分秒
+	public static SimpleDateFormat DATA_FORMAT3 = new SimpleDateFormat("HH:mm:ss");
+	public static String getCurrentTimeHMS() {
+		String currentTime = DATA_FORMAT3.format(new Date());
+		return currentTime;
+	}
+}

+ 0 - 0
src/com/mes/util/ErrorMsg.java


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است