Sfoglia il codice sorgente

refactor: op40 镭雕客户端改造为拉铆流转卡打印代理

变化:
- 集成 mes-print 模块 (PrintHelper 封装)
- 主界面重写为极简监控面板: 状态灯 + 队列 5 行 + 自动/手动模式 + 手动重打
- LaserFlowManager 保留骨架 (轮询/单线程打印/内存去重), 去掉建档逻辑
- DataUtil 精简为只保留 listPendingPrint / ackPrint / isServerReachable
- 队列区分待打印/已打印/打印失败三态, 失败行显示错误消息
- 重打按钮点击立即置灰 + 内存原子拦截, 三层防重复
- 打印失败后立即触发 poll, UI 不用等下一轮 3s 自动刷新
- 启动兜底: cwd/config/print.properties 不存在时自动创建
- 新增"打印机设置"按钮, 弹出 mes-print 自带的 PrinterSettingDialog
- 异步预热 PDF 模板 + 300dpi 底图, 首次打印从 55s 降到 1s 内

清理:
- 删除 netty / ModbusRtu / PLC / MesRevice / LoginFarme / 老 UI 组件等 20+ 文件
- lib 精简: 22 个 jar → 8 个 (只保留 mes-print / pdfbox / zxing / fastjson2 等)
- 源码从 31 文件 5000+ 行 → 7 文件 1300 行

配置:
- config/print.properties: printer.type/name/paper
- resources/config/config.properties: mes.server_ip/port + mes.rivet.poll_*
wangxichen 1 settimana fa
parent
commit
37171f2626
44 ha cambiato i file con 526 aggiunte e 5286 eliminazioni
  1. 4 17
      .classpath
  2. BIN
      lib/commons-codec-1.15.jar
  3. BIN
      lib/gson-2.10.jar
  4. BIN
      lib/iot-communication-1.4.4.jar
  5. BIN
      lib/jSerialComm-2.6.2.jar
  6. BIN
      lib/jfreechart-1.5.4.jar
  7. BIN
      lib/jlibmodbus-1.2.9.2.jar
  8. BIN
      lib/jshortcut-0.4-oberzalek.jar
  9. BIN
      lib/kotlin-stdlib-1.8.10.jar
  10. BIN
      lib/netty-all-4.1.48.Final.jar
  11. BIN
      lib/okhttp-4.10.0.jar
  12. BIN
      lib/okio-jvm-3.3.0.jar
  13. BIN
      lib/s7connector-2.1.jar
  14. BIN
      lib/slf4j-api-2.0.6.jar
  15. BIN
      lib/sqlite-jdbc-3.36.0.3.jar
  16. 0 10
      src/com/mes/component/CallFromJs.java
  17. 0 57
      src/com/mes/component/MesRadio.java
  18. 0 44
      src/com/mes/component/MesWebView.java
  19. 0 30
      src/com/mes/component/MyDialog.java
  20. 0 84
      src/com/mes/component/SwitchButton.java
  21. 0 311
      src/com/mes/laser/LaserCardPrintUtil.java
  22. 108 152
      src/com/mes/laser/LaserFlowManager.java
  23. 0 91
      src/com/mes/netty/MesMsgUtils.java
  24. 0 63
      src/com/mes/netty/NettyClient.java
  25. 0 85
      src/com/mes/netty/NettyClientHandler.java
  26. 0 67
      src/com/mes/netty/ProtocolParam.java
  27. 0 168
      src/com/mes/netty/XDecoder.java
  28. 0 58
      src/com/mes/ui/BindMaterialResp.java
  29. 78 387
      src/com/mes/ui/DataUtil.java
  30. 0 244
      src/com/mes/ui/LoginFarme.java
  31. 328 1385
      src/com/mes/ui/MesClient.java
  32. 0 150
      src/com/mes/ui/MesRevice.java
  33. 0 242
      src/com/mes/ui/ModbusRtu.java
  34. 0 54
      src/com/mes/ui/OprnoUtil.java
  35. 0 101
      src/com/mes/ui/RoundedComponentStyle.java
  36. 0 43
      src/com/mes/ui/TableCellEditorButton.java
  37. 0 14
      src/com/mes/ui/TableCellRendererButton.java
  38. 0 1001
      src/com/mes/ui/VisualUiEditorPanel.java
  39. 0 15
      src/com/mes/util/Base64Utils.java
  40. 0 34
      src/com/mes/util/DateLocalUtils.java
  41. 0 49
      src/com/mes/util/ErrorMsg.java
  42. 0 131
      src/com/mes/util/HttpUtils.java
  43. 0 171
      src/com/mes/util/JdbcUtils.java
  44. 8 28
      src/resources/config/config.properties

+ 4 - 17
.classpath

@@ -5,28 +5,15 @@
 			<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/mes-print.jar"/>
 	<classpathentry kind="lib" path="lib/fastjson2-2.0.16.jar"/>
-	<classpathentry kind="lib" path="lib/jlibmodbus-1.2.9.2.jar"/>
-	<classpathentry kind="lib" path="lib/jSerialComm-2.6.2.jar"/>
-	<classpathentry kind="lib" path="lib/core-3.5.1.jar"/>
-	<classpathentry kind="lib" path="lib/javase-3.5.1.jar"/>
 	<classpathentry kind="lib" path="lib/pdfbox-2.0.30.jar"/>
 	<classpathentry kind="lib" path="lib/fontbox-2.0.30.jar"/>
 	<classpathentry kind="lib" path="lib/commons-logging-1.2.jar"/>
-	<classpathentry kind="lib" path="lib/mes-print.jar"/>
+	<classpathentry kind="lib" path="lib/core-3.5.1.jar"/>
+	<classpathentry kind="lib" path="lib/javase-3.5.1.jar"/>
+	<classpathentry kind="lib" path="lib/snmp4j-3.7.7.jar"/>
 </classpath>

BIN
lib/commons-codec-1.15.jar


BIN
lib/gson-2.10.jar


BIN
lib/iot-communication-1.4.4.jar


BIN
lib/jSerialComm-2.6.2.jar


BIN
lib/jfreechart-1.5.4.jar


BIN
lib/jlibmodbus-1.2.9.2.jar


BIN
lib/jshortcut-0.4-oberzalek.jar


BIN
lib/kotlin-stdlib-1.8.10.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-2.0.6.jar


BIN
lib/sqlite-jdbc-3.36.0.3.jar


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

@@ -1,10 +0,0 @@
-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;
-    }
-}

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

@@ -1,57 +0,0 @@
-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;
-    }
-}

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

@@ -1,44 +0,0 @@
-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();
-    }
-}

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

@@ -1,30 +0,0 @@
-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);
-    }
-}

+ 0 - 84
src/com/mes/component/SwitchButton.java

@@ -1,84 +0,0 @@
-package com.mes.component;
-
-import javax.swing.*;
-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.util.ArrayList;
-import java.util.List;
-
-/**
- * 左右拨动的开关组件。绿色=开,灰色=关。
- * 用法:new SwitchButton() → addActionListener(...) → isSelected() 查状态
- * @author hzd
- */
-public class SwitchButton extends JComponent {
-
-    private boolean on = false;
-    private final Color colorOn = new Color(46, 160, 67);   // 绿色
-    private final Color colorOff = new Color(190, 190, 190); // 灰色
-    private final Color knob = Color.WHITE;
-    private final List<ActionListener> listeners = new ArrayList<>();
-
-    public SwitchButton(boolean initialOn) {
-        this.on = initialOn;
-        setPreferredSize(new Dimension(80, 40));
-        setOpaque(false);
-        setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
-        addMouseListener(new MouseAdapter() {
-            @Override
-            public void mouseClicked(MouseEvent e) {
-                setSelected(!on);
-                fireAction();
-            }
-        });
-    }
-
-    public boolean isSelected() {
-        return on;
-    }
-
-    /** 静默设置状态,不触发 ActionListener */
-    public void setSelected(boolean on) {
-        if (this.on == on) return;
-        this.on = on;
-        repaint();
-    }
-
-    public void addActionListener(ActionListener l) {
-        if (l != null) listeners.add(l);
-    }
-
-    private void fireAction() {
-        ActionEvent evt = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "toggle");
-        for (ActionListener l : new ArrayList<>(listeners)) l.actionPerformed(evt);
-    }
-
-    @Override
-    protected void paintComponent(Graphics g) {
-        Graphics2D g2 = (Graphics2D) g.create();
-        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-        int w = getWidth();
-        int h = getHeight();
-        // 圆角背景
-        g2.setColor(on ? colorOn : colorOff);
-        g2.fillRoundRect(0, 0, w, h, h, h);
-        // 圆钮
-        int d = h - 8;
-        int x = on ? (w - d - 4) : 4;
-        g2.setColor(knob);
-        g2.fillOval(x, 4, d, d);
-        // 文字 ON / OFF
-        g2.setFont(new Font("微软雅黑", Font.BOLD, 13));
-        g2.setColor(Color.WHITE);
-        String text = on ? "ON" : "OFF";
-        FontMetrics fm = g2.getFontMetrics();
-        int tw = fm.stringWidth(text);
-        int textX = on ? 10 : (w - tw - 10);
-        int textY = (h + fm.getAscent()) / 2 - 3;
-        g2.drawString(text, textX, textY);
-        g2.dispose();
-    }
-}

+ 0 - 311
src/com/mes/laser/LaserCardPrintUtil.java

@@ -1,311 +0,0 @@
-package com.mes.laser;
-
-import com.google.zxing.BarcodeFormat;
-import com.google.zxing.EncodeHintType;
-import com.google.zxing.WriterException;
-import com.google.zxing.common.BitMatrix;
-import com.google.zxing.qrcode.QRCodeWriter;
-import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
-import org.apache.pdfbox.pdmodel.PDDocument;
-import org.apache.pdfbox.rendering.ImageType;
-import org.apache.pdfbox.rendering.PDFRenderer;
-
-import javax.imageio.ImageIO;
-import javax.print.PrintService;
-import javax.print.PrintServiceLookup;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.awt.print.PageFormat;
-import java.awt.print.Paper;
-import java.awt.print.Printable;
-import java.awt.print.PrinterJob;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * 流转卡打印:以 PDF 模板为底图,叠加二维码 + 两行动态文字。
- *
- * 三个动态元素坐标(从 PDF 里精确提取,单位 pt,A5 纵向 419.5x595.25):
- * - 左上二维码方框:x=194.5 y=65.4 w=35.7 h=34.6
- * - 「钢印明码:」冒号后 baseline:x=291.5 y=85.5
- * - 「二 维 码:」冒号后 baseline:x=291.5 y=96.4
- *
- * 打印时按打印页面可用区域等比缩放,PDF 内容居中。
- * @author hzd
- */
-public class LaserCardPrintUtil {
-
-    // PDF 模板尺寸(A5 纵向 148x210mm)
-    private static final float PDF_PAGE_W_PT = 419.5f;
-    private static final float PDF_PAGE_H_PT = 595.25f;
-
-    // 三个动态元素在 PDF 坐标系里的位置(pt,左上原点)
-    private static final float QR_X = 194.5f;
-    private static final float QR_Y = 65.4f;
-    private static final float QR_W = 35.7f;
-    private static final float QR_H = 34.6f;
-
-    // 文字 baseline(Graphics2D.drawString 的 y 参数)
-    private static final float STEEL_TEXT_X = 291.5f;
-    private static final float STEEL_TEXT_Y = 85.5f;
-    private static final float SN_TEXT_X = 291.5f;
-    private static final float SN_TEXT_Y = 96.4f;
-
-    private static final int TEXT_FONT_SIZE = 8;
-
-    // 中文字体候选,按顺序找到系统里第一个可用的
-    private static final String[] FONT_CANDIDATES = {"SimSun", "宋体", "Microsoft YaHei", "微软雅黑", Font.SANS_SERIF};
-
-    // 打印用的底图 DPI;越高越清晰但内存/耗时越大,300 是常规打印标准
-    private static final float PRINT_TEMPLATE_DPI = 300f;
-
-    // 模板 PDF 缓存,程序生命周期内加载一次
-    private static volatile PDDocument templateDoc;
-    private static volatile PDFRenderer templateRenderer;
-    // 预渲染好的底图:Java Print 的 Graphics2D 跟 PDFRenderer.renderPageToGraphics 兼容性差
-    // (会出现整页涂黑),所以打印时改用这张 BufferedImage 直接 drawImage
-    private static volatile BufferedImage templateImage;
-    private static final Object LOCK = new Object();
-
-    /**
-     * 打印一张流转卡(新方案入口,模板从 config.properties 的 mes.laser.card_template_path 读取)
-     * @param printerName 打印机名,空则用默认打印机
-     * @param steelSn 钢印码
-     * @param customerSn 客户码(21位,二维码内容)
-     * @return true=打印任务已提交
-     */
-    public static boolean printCard(String printerName, String steelSn, String customerSn) {
-        return printCard(printerName, null, steelSn, customerSn);
-    }
-
-    public static boolean printCard(String printerName, String templatePath, String steelSn, String customerSn) {
-        try {
-            BufferedImage bgImage = getTemplateImage(templatePath);
-            BufferedImage qr = generateQrCode(customerSn, 600);
-            if (qr == null) {
-                System.out.println("[流转卡] 二维码生成失败 customerSn=" + customerSn);
-                return false;
-            }
-
-            PrinterJob job = PrinterJob.getPrinterJob();
-            PrintService svc = findPrintService(printerName);
-            if (svc != null) {
-                job.setPrintService(svc);
-            }
-
-            PageFormat pf = buildA5Portrait(job);
-            job.setPrintable(new CardPrintable(bgImage, qr, steelSn, customerSn), pf);
-            job.print();
-
-            System.out.println("[流转卡] 打印完成 steelSn=" + steelSn + " customerSn=" + customerSn);
-            return true;
-        } catch (Exception e) {
-            System.out.println("[流转卡] 打印失败:" + e.getMessage());
-            e.printStackTrace();
-            return false;
-        }
-    }
-
-    /** 本地预览(不接打印机也能看效果),dpi 建议 300 */
-    public static boolean previewToPng(String templatePath, String steelSn, String customerSn, String outPath, float dpi) {
-        try {
-            PDFRenderer renderer = getRenderer(templatePath);
-            BufferedImage img = renderer.renderImageWithDPI(0, dpi, ImageType.RGB);
-
-            Graphics2D g2 = img.createGraphics();
-            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
-
-            // 坐标切换到 pt 单位
-            double s = dpi / 72.0;
-            g2.scale(s, s);
-
-            drawDynamic(g2, generateQrCode(customerSn, 600), steelSn, customerSn);
-            g2.dispose();
-
-            File out = new File(outPath);
-            if (out.getParentFile() != null) {
-                out.getParentFile().mkdirs();
-            }
-            ImageIO.write(img, "PNG", out);
-            System.out.println("[流转卡预览] 已输出 " + out.getAbsolutePath()
-                    + " size=" + img.getWidth() + "x" + img.getHeight());
-            return true;
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-    }
-
-    // ==== 内部实现 ====
-
-    private static PDFRenderer getRenderer(String templatePath) throws IOException {
-        if (templateRenderer != null) return templateRenderer;
-        synchronized (LOCK) {
-            if (templateRenderer == null) {
-                String path = (templatePath == null || templatePath.trim().isEmpty())
-                        ? "config/liuzhuanka_template.pdf" : templatePath.trim();
-                File pdfFile = extractToTemp(path);
-                PDDocument doc = PDDocument.load(pdfFile);
-                templateDoc = doc;
-                templateRenderer = new PDFRenderer(doc);
-                System.out.println("[流转卡] 已加载模板:" + pdfFile.getAbsolutePath());
-            }
-        }
-        return templateRenderer;
-    }
-
-    /** 打印用底图:把 PDF 预渲染成 BufferedImage 缓存起来,避免 renderPageToGraphics 在打印机 Graphics 上崩掉 */
-    private static BufferedImage getTemplateImage(String templatePath) throws IOException {
-        if (templateImage != null) return templateImage;
-        synchronized (LOCK) {
-            if (templateImage == null) {
-                PDFRenderer r = getRenderer(templatePath);
-                templateImage = r.renderImageWithDPI(0, PRINT_TEMPLATE_DPI, ImageType.RGB);
-                System.out.println("[流转卡] 底图已预渲染 " + templateImage.getWidth() + "x" + templateImage.getHeight()
-                        + " @" + PRINT_TEMPLATE_DPI + "dpi");
-            }
-        }
-        return templateImage;
-    }
-
-    private static File extractToTemp(String cpPath) throws IOException {
-        File direct = new File(cpPath);
-        if (direct.isFile()) {
-            return direct;
-        }
-        try (InputStream is = ClassLoader.getSystemResourceAsStream(cpPath)) {
-            if (is == null) {
-                throw new IOException("找不到流转卡模板:" + cpPath);
-            }
-            Path tmp = Files.createTempFile("liuzhuanka_template_", ".pdf");
-            tmp.toFile().deleteOnExit();
-            Files.copy(is, tmp, StandardCopyOption.REPLACE_EXISTING);
-            return tmp.toFile();
-        }
-    }
-
-    private static PageFormat buildA5Portrait(PrinterJob job) {
-        PageFormat pf = job.defaultPage();
-        Paper paper = new Paper();
-        double wPt = 148 * 72.0 / 25.4;   // ≈ 419.53
-        double hPt = 210 * 72.0 / 25.4;   // ≈ 595.28
-        paper.setSize(wPt, hPt);
-        double margin = 4 * 72.0 / 25.4;  // 4mm 边距
-        paper.setImageableArea(margin, margin, wPt - 2 * margin, hPt - 2 * margin);
-        pf.setPaper(paper);
-        pf.setOrientation(PageFormat.PORTRAIT);
-        return job.validatePage(pf);
-    }
-
-    private static PrintService findPrintService(String printerName) {
-        if (printerName == null || printerName.trim().isEmpty()) return null;
-        PrintService[] all = PrintServiceLookup.lookupPrintServices(null, null);
-        PrintService s = Arrays.stream(all)
-                .filter(p -> p.getName().equalsIgnoreCase(printerName.trim()))
-                .findFirst().orElse(null);
-        if (s == null) {
-            System.out.println("[流转卡] 未找到打印机 " + printerName + ",改用系统默认");
-        }
-        return s;
-    }
-
-    private static void drawDynamic(Graphics2D g2, BufferedImage qr, String steelSn, String customerSn) {
-        // 白底盖一下原模板上的二维码占位图
-        g2.setColor(Color.WHITE);
-        g2.fill(new java.awt.geom.Rectangle2D.Float(QR_X, QR_Y, QR_W, QR_H));
-        g2.drawImage(qr, (int) QR_X, (int) QR_Y, (int) QR_W, (int) QR_H, null);
-
-        g2.setColor(Color.BLACK);
-        g2.setFont(pickChineseFont(TEXT_FONT_SIZE));
-        if (steelSn != null) {
-            g2.drawString(steelSn, STEEL_TEXT_X, STEEL_TEXT_Y);
-        }
-        if (customerSn != null) {
-            g2.drawString(customerSn, SN_TEXT_X, SN_TEXT_Y);
-        }
-    }
-
-    private static Font pickChineseFont(int size) {
-        String[] available = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
-        for (String name : FONT_CANDIDATES) {
-            for (String a : available) {
-                if (a.equalsIgnoreCase(name)) {
-                    return new Font(name, Font.BOLD, size);
-                }
-            }
-        }
-        return new Font(Font.SANS_SERIF, Font.BOLD, size);
-    }
-
-    private static BufferedImage generateQrCode(String content, int pixelSize) {
-        try {
-            Map<EncodeHintType, Object> hints = new HashMap<>();
-            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
-            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
-            hints.put(EncodeHintType.MARGIN, 0);
-
-            BitMatrix bm = new QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, pixelSize, pixelSize, hints);
-            BufferedImage img = new BufferedImage(pixelSize, pixelSize, BufferedImage.TYPE_INT_RGB);
-            for (int x = 0; x < pixelSize; x++) {
-                for (int y = 0; y < pixelSize; y++) {
-                    img.setRGB(x, y, bm.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
-                }
-            }
-            return img;
-        } catch (WriterException e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    /** 打印任务:底图(预渲染 BufferedImage) + 二维码 + 两行文字 */
-    private static class CardPrintable implements Printable {
-        private final BufferedImage bg;
-        private final BufferedImage qr;
-        private final String steelSn;
-        private final String customerSn;
-
-        CardPrintable(BufferedImage bg, BufferedImage qr, String steelSn, String customerSn) {
-            this.bg = bg;
-            this.qr = qr;
-            this.steelSn = steelSn;
-            this.customerSn = customerSn;
-        }
-
-        @Override
-        public int print(Graphics g, PageFormat pf, int page) {
-            if (page > 0) return NO_SUCH_PAGE;
-            Graphics2D g2 = (Graphics2D) g;
-
-            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
-            g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
-
-            // 把 PDF 页面尺寸(pt)等比缩放到打印区域,居中
-            double sx = pf.getImageableWidth() / PDF_PAGE_W_PT;
-            double sy = pf.getImageableHeight() / PDF_PAGE_H_PT;
-            double scale = Math.min(sx, sy);
-            double tx = pf.getImageableX() + (pf.getImageableWidth() - PDF_PAGE_W_PT * scale) / 2.0;
-            double ty = pf.getImageableY() + (pf.getImageableHeight() - PDF_PAGE_H_PT * scale) / 2.0;
-
-            g2.translate(tx, ty);
-            g2.scale(scale, scale);
-
-            // 底图 BufferedImage 是 A5 @ 300dpi ≈ 1747x2480 像素,drawImage 到 pt 坐标 419.5x595.25
-            // 会自动做高质量重采样,避免 PDFBox 直接渲染到打印 Graphics 时出现的黑屏问题
-            g2.drawImage(bg, 0, 0, (int) Math.ceil(PDF_PAGE_W_PT), (int) Math.ceil(PDF_PAGE_H_PT), null);
-
-            drawDynamic(g2, qr, steelSn, customerSn);
-            return PAGE_EXISTS;
-        }
-    }
-}

+ 108 - 152
src/com/mes/laser/LaserFlowManager.java

@@ -2,11 +2,14 @@ package com.mes.laser;
 
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
+import com.mes.print.PrintHelper;
 import com.mes.ui.DataUtil;
 
 import java.io.BufferedReader;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
@@ -16,82 +19,87 @@ import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 /**
- * 镭雕流程管理器 —— 新方案:客户端不再联动镭雕机,改为定时轮询 mescloud
- * 拉取本产线待打印列表 → 建档 → 打印流转卡 → 上报 ack
+ * 拉铆流转卡打印代理 —— 定时轮询服务端 pendingPrint,
+ * 拿到一条就走 PrintHelper 打印,成功后 ackPrint OK,失败 ackPrint NG
  *
- * 类名和公共 API 保持与旧版一致,MesClient.java 里的调用点不用改。
- * 旧的"获取镭雕码 / 完成回调 / 模拟"等语义在新流程下已经没有意义,
- * 相关方法保留但退化为空操作或转发到轮询开关。
+ * 数据流:
+ *   定时器 → GET /mesLaser/pendingPrint → 内存 Set 去重 → 单线程消费
+ *          → PrintHelper.printFlowCard → POST /mesLaser/printAck
  *
- * 数据流:定时器 → GET /mesLaser/pendingPrint → 内存 Set 去重 → 单线程消费
- *        → onSubmitResult 建档(走 sendCreate 报文)→ LaserCardPrintUtil.printCard
- *        → POST /mesLaser/printAck
- * @author hzd
+ * 状态语义(服务端表 mes_product_laser.rivet_print_status):
+ *   0 = 无需打印
+ *   1 = 待打印  ← 代理拉取
+ *   2 = 已打印  ← ack OK
+ *   3 = 打印失败 ← ack NG
  */
 public class LaserFlowManager {
 
     public interface UiCallback {
         /** 状态栏提示,error=true 走错误样式 */
         void onStatus(String msg, boolean error);
-        /** 打印开始/结束时的按钮锁定信号,UI 用来防止操作员打印进行中重复点击 */
+        /** 打印进行中/结束的按钮锁定信号,UI 用来防止重复点击 */
         void onLockButton(boolean lock);
-        /** 客户码回显到扫码框 */
-        void onCodeReceived(String code);
-        /** 客户端建档回调(走 op040 sendCreate 报文),true=建档成功 */
-        boolean onSubmitResult(String customerSn, String qret);
-        /** 待打印数量变化通知,UI 用来更新 pending label */
+        /** 待打印数量变化通知 */
         void onPendingCount(int count);
         /**
-         * 队列快照更新:3 行队列
-         * rows[0] = 最近打完的一条(done=true,UI 显示绿框),首次启动没打过时为 null
-         * rows[1..N] = 服务端 pending 最早几条(done=false,UI 显示灰框)
+         * 队列快照:5 行
+         * rows[0] = 最近打完的一条(done=true 绿框),首次启动为 null
+         * rows[1..N] = 服务端 pending 最早几条(done=false 灰框)
          */
-        void onQueueUpdated(java.util.List<QueueRow> rows);
+        void onQueueUpdated(List<QueueRow> rows);
     }
 
-    /** 队列行数据:钢印码 + 客户码 + 是否已打印 */
+    /** 队列行数据 */
     public static class QueueRow {
+        /** 状态: 1=待打印, 2=已打印, 3=打印失败 */
+        public final int status;
         public final String steelSn;
         public final String customerSn;
-        public final boolean done;
-        public QueueRow(String steelSn, String customerSn, boolean done) {
+        public final String errMsg;
+
+        public QueueRow(int status, String steelSn, String customerSn, String errMsg) {
+            this.status = status;
             this.steelSn = steelSn;
             this.customerSn = customerSn;
-            this.done = done;
+            this.errMsg = errMsg;
         }
+        public boolean isDone()    { return status == 2; }
+        public boolean isPending() { return status == 1; }
+        public boolean isFailed()  { return status == 3; }
     }
 
     private final UiCallback uiCallback;
     private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(r -> {
-        Thread t = new Thread(r, "LaserPoll-Scheduler");
+        Thread t = new Thread(r, "RivetPoll-Scheduler");
         t.setDaemon(true);
         return t;
     });
-    // 单线程打印,避免并发抢打印机队列,也保证扫码框回显顺序
+    // 单线程打印,避免并发抢打印机队列
     private final ExecutorService printerExecutor = Executors.newSingleThreadExecutor(r -> {
-        Thread t = new Thread(r, "LaserPoll-Printer");
+        Thread t = new Thread(r, "RivetPoll-Printer");
         t.setDaemon(true);
         return t;
     });
-    // 内存去重:已经在处理(打印中/待 ack)的客户码,防止 ack 之前被同一次拉取的下一批重复消费
+    // 内存去重:在处理(打印中/待 ack)的客户码,防止同一次拉取的下一批重复消费
     private final Set<String> processing = ConcurrentHashMap.newKeySet();
 
-    // 队列快照:最近打完的一条 + 上次轮询拿到的 pending 列表
+    // 队列快照
     private volatile QueueRow lastPrintedRow = null;
-    private volatile java.util.List<QueueRow> lastPending = new java.util.ArrayList<>();
+    private volatile List<QueueRow> lastPending = new ArrayList<>();
 
-    // paused = true 等价于手动模式(轮询定时器空转)
+    // paused=true 等价于手动模式(轮询定时器空转,只更新队列 UI 不打印
     private volatile boolean paused = false;
     private volatile boolean running = false;
 
+    // 累计计数
+    private int totalPrinted = 0;
+    private int totalFailed = 0;
+
     // ==== 配置项 ====
-    private String lineSn = "T9";
-    private String prodCode = "T09";
     private long pollIntervalMs = 3000;
     private int batchSize = 10;
-    private String printerName = "";
-    // 启动时默认模式:auto=自动轮询打印,manual=只在点击后打印一次
-    private String defaultMode = "manual";
+    /** 启动默认模式:auto=自动轮询打印,manual=只更新 UI 不自动打 */
+    private String defaultMode = "auto";
 
     public LaserFlowManager(UiCallback uiCallback) {
         this.uiCallback = uiCallback;
@@ -105,111 +113,63 @@ public class LaserFlowManager {
             try (BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
                 pro.load(br);
             }
-            lineSn = pro.getProperty("mes.line_sn", "T9").trim();
-            prodCode = pro.getProperty("mes.prod_code", "T09").trim();
-            pollIntervalMs = Long.parseLong(pro.getProperty("mes.laser.poll_interval", "3000").trim());
-            batchSize = Integer.parseInt(pro.getProperty("mes.laser.poll_batch_size", "10").trim());
-            printerName = pro.getProperty("mes.laser.printer_name", "").trim();
-            defaultMode = pro.getProperty("mes.laser.print_mode", "manual").trim().toLowerCase();
+            pollIntervalMs = Long.parseLong(pro.getProperty("mes.rivet.poll_interval", "3000").trim());
+            batchSize = Integer.parseInt(pro.getProperty("mes.rivet.poll_batch_size", "10").trim());
+            defaultMode = pro.getProperty("mes.rivet.print_mode", "auto").trim().toLowerCase();
             paused = "manual".equals(defaultMode);
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
-    // ==== 对外 API(兼容 MesClient.java 原调用点)====
+    // ==== 对外 API ====
 
-    /** 应用启动时调一次。旧名字沿用,实际启动的是轮询定时器 */
-    public void startCompleteServer() {
+    public void start() {
         if (running) return;
         running = true;
         scheduler.scheduleWithFixedDelay(this::pollOnce, 500, pollIntervalMs, TimeUnit.MILLISECONDS);
-        String mode = paused ? "手动模式(点按钮打一次)" : "自动模式(间隔 " + pollIntervalMs + " ms)";
-        uiCallback.onStatus("镭雕轮询已启动 - " + mode, false);
+        uiCallback.onStatus("轮询已启动 - " + (paused ? "手动模式" : "自动模式(间隔" + pollIntervalMs + "ms)"), false);
     }
 
-    /** 应用关闭时调一次 */
-    public void stopCompleteServer() {
+    public void stop() {
         running = false;
         scheduler.shutdownNow();
         printerExecutor.shutdown();
     }
 
-    /**
-     * 旧 UI 用来判断"镭雕进行中"以禁用按钮。新方案下轮询是常态、单件打印是异步,
-     * 直接返回是否有正在处理的记录即可。为了不误锁 UI,保守返回 false。
-     */
-    public boolean isWaitingComplete() {
-        return false;
-    }
-
-    /** 设置自动打印开关:true=开启定时轮询自动打印,false=只更新 UI 不自动打(靠队列行按钮打) */
+    /** 自动打印开关 */
     public void setAutoMode(boolean auto) {
         paused = !auto;
-        uiCallback.onStatus(auto ? "自动打印:开" : "自动打印:关", false);
+        uiCallback.onStatus(auto ? "自动打印: 开" : "自动打印: 关(仅刷新队列)", false);
     }
 
     public boolean isAutoMode() {
         return !paused;
     }
 
-    /** 提交钢印码并打印,独立于轮询队列。操作员手工输入 steelSn 后调用 */
-    public void submitAndPrint(String steelSn) {
-        if (steelSn == null || steelSn.trim().isEmpty()) {
-            uiCallback.onStatus("请输入钢印码", true);
+    /** 手动重打指定一条 */
+    public void reprint(String customerSn, String steelSn) {
+        if (customerSn == null || customerSn.isEmpty() || steelSn == null || steelSn.isEmpty()) {
+            uiCallback.onStatus("参数缺失,无法打印", true);
             return;
         }
-        final String ss = steelSn.trim();
-        printerExecutor.submit(() -> {
-            uiCallback.onLockButton(true);
-            try {
-                uiCallback.onStatus("正在提交钢印码到服务端:" + ss, false);
-                JSONObject resp = DataUtil.submitSteelSn(prodCode, ss);
-                if (resp == null || resp.get("result") == null
-                        || !"true".equalsIgnoreCase(resp.get("result").toString())) {
-                    String msg = resp != null && resp.get("message") != null
-                            ? resp.get("message").toString() : "服务端无响应";
-                    uiCallback.onStatus("提交失败:" + msg, true);
-                    return;
-                }
-                JSONObject data = resp.getJSONObject("data");
-                String customerSn = data == null ? null : data.getString("customerSn");
-                if (customerSn == null || customerSn.isEmpty()) {
-                    uiCallback.onStatus("服务端未返回客户码,无法打印", true);
-                    return;
-                }
-                // 回显客户码到扫码框
-                uiCallback.onCodeReceived(customerSn);
-                uiCallback.onStatus("已入库,正在建档并打印:" + customerSn, false);
-
-                // 直接打印(此时已在 printerExecutor 单线程里,直接 printOne 串行执行)
-                if (!processing.add(customerSn)) return;
-                try {
-                    printOne(customerSn, ss);
-                } finally {
-                    processing.remove(customerSn);
-                }
-            } finally {
-                uiCallback.onLockButton(false);
-            }
-        });
+        submitPrintJob(customerSn, steelSn);
     }
 
+    public int getTotalPrinted() { return totalPrinted; }
+    public int getTotalFailed() { return totalFailed; }
 
+    /** UI 查询某条 SN 是否正在打印中,用于按钮置灰 */
+    public boolean isProcessing(String customerSn) {
+        return customerSn != null && processing.contains(customerSn);
+    }
 
     // ==== 内部实现 ====
 
-    /** 定时器每 pollIntervalMs 触发一次。无论开关状态都拉数据更新 UI,只有开关 ON 时才自动打印 */
+    /** 定时器每 pollIntervalMs 触发一次:拉取列表并更新 UI,自动模式下逐条打印 */
     private void pollOnce() {
-        pollBatch(batchSize, !paused);
-    }
-
-    /**
-     * 拉待打印列表并更新 UI 队列;printAll=true 时把拉到的每一条都送去打印(仅自动模式用)
-     */
-    private void pollBatch(int limit, boolean printAll) {
         try {
-            JSONObject resp = DataUtil.listPendingPrint(lineSn, limit);
+            JSONObject resp = DataUtil.listPendingPrint(batchSize);
             if (resp == null || resp.get("result") == null
                     || !"true".equalsIgnoreCase(resp.get("result").toString())) {
                 return;
@@ -217,98 +177,94 @@ public class LaserFlowManager {
             Object dataObj = resp.get("data");
             if (!(dataObj instanceof JSONArray)) return;
             JSONArray list = (JSONArray) dataObj;
-            uiCallback.onPendingCount(list.size());
-            // 更新 pending 快照供 UI 展示:取前 5 条足够填 5 行 UI(即使 Row0 让给了 lastPrinted)
-            java.util.List<QueueRow> newPending = new java.util.ArrayList<>();
-            for (int i = 0; i < Math.min(5, list.size()); i++) {
+            // 拉到的记录包含 status=1(待打印) 和 status=3(失败)
+            int pendingCnt = 0;
+            List<QueueRow> newPending = new ArrayList<>();
+            for (int i = 0; i < list.size(); i++) {
                 JSONObject r = list.getJSONObject(i);
-                newPending.add(new QueueRow(r.getString("steel_sn"), r.getString("customer_sn"), false));
+                Integer st = r.getInteger("rivet_print_status");
+                int status = st == null ? 1 : st;
+                if (status == 1) pendingCnt++;
+                if (newPending.size() < 5) {
+                    newPending.add(new QueueRow(
+                            status,
+                            r.getString("steel_sn"),
+                            r.getString("customer_sn"),
+                            r.getString("print_msg")));
+                }
             }
+            uiCallback.onPendingCount(pendingCnt);
             lastPending = newPending;
             pushQueueSnapshot();
 
-            if (!printAll || list.isEmpty()) return;
+            if (paused || list.isEmpty()) return;
 
-            // 自动模式:把拉到的每一条都送去打印(内存 processing 去重防止重复)
+            // 自动模式:仅打 status=1;status=3(失败) 只在 UI 展示,等人工点重打
             for (int i = 0; i < list.size(); i++) {
                 JSONObject row = list.getJSONObject(i);
-                submitPrintJob(row.getString("customer_sn"), row.getString("steel_sn"));
+                Integer st = row.getInteger("rivet_print_status");
+                if (st != null && st == 1) {
+                    submitPrintJob(row.getString("customer_sn"), row.getString("steel_sn"));
+                }
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
     }
 
-    /** 打印指定的一条:队列 UI 行点「打印」按钮走这里 */
-    public void printSpecific(String customerSn, String steelSn) {
-        if (customerSn == null || customerSn.isEmpty() || steelSn == null || steelSn.isEmpty()) {
-            uiCallback.onStatus("参数缺失,无法打印", true);
-            return;
-        }
-        submitPrintJob(customerSn, steelSn);
-    }
-
-    /** 把一次打印任务塞到单线程 executor,内存去重防止同一 sn 并发打两次 */
+    /** 把一次打印任务塞到单线程 executor */
     private void submitPrintJob(String customerSn, String steelSn) {
         if (customerSn == null || steelSn == null) return;
-        if (!processing.add(customerSn)) return;
+        if (!processing.add(customerSn)) return; // 已在处理,跳过
+        // 立即通知 UI 刷新(这条会显示"打印中")
+        pushQueueSnapshot();
         printerExecutor.submit(() -> {
             try {
                 uiCallback.onLockButton(true);
-                uiCallback.onCodeReceived(customerSn);
-                uiCallback.onStatus("正在建档并打印:" + customerSn, false);
+                uiCallback.onStatus("正在打印: " + customerSn, false);
                 printOne(customerSn, steelSn);
             } finally {
                 processing.remove(customerSn);
                 uiCallback.onLockButton(false);
+                // 任务收尾再刷新一次,让按钮从"打印中"恢复
+                pushQueueSnapshot();
             }
         });
     }
 
+    /** 单条打印:调 PrintHelper → ack → 更新计数和 UI */
     private void printOne(String customerSn, String steelSn) {
-        // 1. 建档(走 op040 现有 sendCreate 报文)
-        boolean buildOk = uiCallback.onSubmitResult(customerSn, "OK");
-        if (!buildOk) {
-            uiCallback.onStatus("建档失败:" + customerSn + ",下次继续重试", true);
-            DataUtil.ackPrint(customerSn, "NG", "客户端建档失败");
-            return;
-        }
-        // 2. 打印流转卡(PrinterJob.print 返回 = 任务提交系统队列成功 = 视为完成)
-        boolean printOk = LaserCardPrintUtil.printCard(printerName, steelSn, customerSn);
-        // 3. ack:让服务端把 print_status 从 0 更新为 1
+        boolean printOk = PrintHelper.printFlowCard(customerSn, steelSn);
         if (printOk) {
             boolean ackOk = DataUtil.ackPrint(customerSn, "OK", null);
             if (ackOk) {
-                uiCallback.onStatus("打印完成并已入库:" + customerSn, false);
+                totalPrinted++;
+                uiCallback.onStatus("打印完成: " + customerSn, false);
             } else {
-                uiCallback.onStatus("打印完成但 ack 失败(服务端会保留待打印状态):" + customerSn, true);
+                uiCallback.onStatus("打印完成但 ack 失败(下次会重打): " + customerSn, true);
             }
-            // 顶部绿框显示刚打完的这条
-            lastPrintedRow = new QueueRow(steelSn, customerSn, true);
-            // 先清空 lastPending 里跟刚打完这条重复的记录,避免 UI 出现 "已打印+待打印" 两行内容一样
-            java.util.List<QueueRow> filtered = new java.util.ArrayList<>();
+            lastPrintedRow = new QueueRow(2, steelSn, customerSn, null);
+            // 清掉 pending 里跟刚打完这条重复的
+            List<QueueRow> filtered = new ArrayList<>();
             for (QueueRow r : lastPending) {
                 if (r != null && !customerSn.equals(r.customerSn)) filtered.add(r);
             }
             lastPending = filtered;
             pushQueueSnapshot();
-            // 立即触发一次刷新(printAll=false 只更新 UI 不打印,避免重复打)
-            scheduler.execute(() -> pollBatch(batchSize, false));
         } else {
             DataUtil.ackPrint(customerSn, "NG", "客户端打印失败");
-            uiCallback.onStatus("打印失败:" + customerSn, true);
+            totalFailed++;
+            uiCallback.onStatus("打印失败: " + customerSn, true);
+            // 立即触发一次拉取,UI 能看到该条被服务端标记为 status=3
+            scheduler.execute(this::pollOnce);
         }
     }
 
-    /**
-     * 合成 5 行队列推给 UI。策略:
-     *   有 lastPrinted:Row 0 = lastPrinted(绿框),Row 1-4 = pending[0..3]
-     *   没有:Row 0-4 全部是 pending[0..4]("只有 1 条就在第一行")
-     */
+    /** 合成 5 行队列推给 UI */
     private void pushQueueSnapshot() {
         final int total = 5;
-        java.util.List<QueueRow> rows = new java.util.ArrayList<>(total);
-        java.util.List<QueueRow> p = lastPending;
+        List<QueueRow> rows = new ArrayList<>(total);
+        List<QueueRow> p = lastPending;
         if (lastPrintedRow != null) {
             rows.add(lastPrintedRow);
             for (int i = 0; i < total - 1; i++) {

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

@@ -1,91 +0,0 @@
-package com.mes.netty;
-
-public class MesMsgUtils {
-
-    // 协议 v2(2026-06-29):oprno 字段从 6 字符扩到 8 字符,所有长度 +2
-    public static int SYNR_LEN = 48;
-    public static int AXTW_LEN = 48;
-    public static int ACLW_LEN = 48;
-    public static int MCJW_LEN = 98;
-    public static int AQDW_LEN = 98;
-    public static int MBDW_LEN = 98;
-    public static int MJBW_LEN = 98;
-    public static int MQDW_LEN = 98;
-    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;
-    }
-
-
-}

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

@@ -1,63 +0,0 @@
-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();
-
-    }
-}

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

@@ -1,85 +0,0 @@
-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;
-            case "MCJW":
-                MesRevice.createRevice(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 "";
-        }
-    }
-
-}

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

@@ -1,67 +0,0 @@
-package com.mes.netty;
-
-
-// 固定格式报文各参数获取方法
-// 协议 v2(2026-06-29 修订):oprno 字段从 6 字符扩到 8 字符,后续字段偏移整体 +2
-public class ProtocolParam {
-    // bbbbfffffARWAQDWGWOP100   GY100000ID151245P00000106200123062900001      RSOKDA2023-09-07ZT10:16:58
-    public static Integer fixedLength = 98;
-
-    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() < 26){
-            return "";
-        }
-        return msg.substring(18,26);
-    }
-
-    public static String getCraft(String msg){
-        if(msg.length() < 34){
-            return "";
-        }
-        return msg.substring(28,34);
-    }
-
-    public static String getSn(String msg){
-        if(msg.length() < 72){
-            return "";
-        }
-        return msg.substring(36,72);
-    }
-
-    public static String getLx(String msg){
-        if(msg.length() < 74){
-            return "";
-        }
-        return msg.substring(72,74);
-    }
-
-    public static String getResult(String msg){
-        if(msg.length() < 76){
-            return "";
-        }
-        return msg.substring(74,76);
-    }
-
-    public static String getDay(String msg){
-        if(msg.length() < 88){
-            return "";
-        }
-        return msg.substring(78,88);
-    }
-
-    public static String getTime(String msg){
-        if(msg.length() < 98){
-            return "";
-        }
-        return msg.substring(90,98);
-    }
-
-}

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

@@ -1,168 +0,0 @@
-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();
-    }
-}

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

@@ -1,58 +0,0 @@
-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;
-    }
-}

+ 78 - 387
src/com/mes/ui/DataUtil.java

@@ -1,294 +1,39 @@
 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.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.Properties;
 
+/**
+ * 服务端通信工具类(极简版,只保留打印相关接口)
+ *
+ * 支持接口:
+ *   1. pendingPrint  拉取拉铆待打印列表
+ *   2. printAck      回写打印结果
+ */
 public class DataUtil {
 
-    public static Boolean synrTcp(NettyClient nettyClient,String mes_gw){
-        try{
-            //TCP连接后,直接先发同步报文
-            String start = "aaaabbbbbABW";
-            String msgType = "SYNR";
-            String gw = "GW"+DataUtil.rightPad(mes_gw, 8);
-            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);
+    private static final String MES_URL_PREFIX = loadServerPrefix();
 
-            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, 8);
-            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 sendCreate(NettyClient nettyClient,String sn,String ret,String user){
-        try{
-            String msgType = "MCJW";
-            String gy = "100000";
-//            String param = rightPad("Y"+sn2, 36);
-            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"), 8);
-            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 getCheckResult() {
-        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/mesProcessCheckRecord/check";
-            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 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;
-        }
-    }
-
-    // Manual submit steelSn (same interface as PDA), server generates customerSn and enqueues for printing
-    public static JSONObject submitSteelSn(String prodCode, String steelSn) {
-        try {
-            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
-            Properties pro = new Properties();
-            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-            pro.load(br);
-            String mes_server_ip = pro.getProperty("mes.server_ip");
-            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesLaser/submitSteelSn";
-            String params = "__ajax=json&prodCode=" + prodCode + "&steelSn=" + steelSn;
-            System.out.println("[submitSteelSn] " + params);
-            String result = doPost(url, params);
-            System.out.println("[submitSteelSn] resp=" + result);
-            if (result == null || result.equalsIgnoreCase("false")) {
-                return null;
-            }
-            return JSONObject.parseObject(result);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    // Poll pending print queue from mescloud (OP040 new flow)
-    public static JSONObject listPendingPrint(String lineSn, int limit) {
+    /**
+     * 拉取拉铆待打印列表
+     * 服务端 SQL: WHERE rivet_print_status = 1 ORDER BY create_date ASC LIMIT ?
+     *
+     * @return { "result":"true", "data":[{customer_sn, steel_sn, ...}, ...] } 或 null
+     */
+    public static JSONObject listPendingPrint(int limit) {
         try {
-            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
-            Properties pro = new Properties();
-            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-            pro.load(br);
-            String mes_server_ip = pro.getProperty("mes.server_ip");
-            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesLaser/pendingPrint";
-            String params = "__ajax=json&lineSn=" + lineSn + "&limit=" + limit;
+            String url = MES_URL_PREFIX + "/js/a/mes/mesLaser/pendingPrint";
+            String params = "__ajax=json&limit=" + limit;
             String result = doPost(url, params);
-            // 日常轮询不打日志,避免噪音
-            if (result == null || result.equalsIgnoreCase("false")) {
+            if (result == null || "false".equalsIgnoreCase(result)) {
                 return null;
             }
             return JSONObject.parseObject(result);
@@ -298,19 +43,17 @@ public class DataUtil {
         }
     }
 
-    // Ack print result to mescloud, result = OK / NG
+    /**
+     * 回写打印结果
+     * OK → rivet_print_status=2, rivet_print_time=NOW()
+     * NG → rivet_print_status=3, print_msg=msg
+     */
     public static boolean ackPrint(String customerSn, String result, String msg) {
         try {
-            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
-            Properties pro = new Properties();
-            BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
-            pro.load(br);
-            String mes_server_ip = pro.getProperty("mes.server_ip");
-            String url = "http://" + mes_server_ip + ":8980/js/a/mes/mesLaser/printAck";
-            // customerSn 里带 '+' 号,form-urlencoded 传输时 '+' 会被服务端解码成空格,
-            // 必须 URL 编码后再拼接
-            String encSn = java.net.URLEncoder.encode(customerSn, "UTF-8");
-            String encMsg = msg == null ? "" : java.net.URLEncoder.encode(msg, "UTF-8");
+            String url = MES_URL_PREFIX + "/js/a/mes/mesLaser/printAck";
+            // customerSn 带 '+' 号,form-urlencoded 传输时 '+' 会被解码为空格,必须编码
+            String encSn = URLEncoder.encode(customerSn, "UTF-8");
+            String encMsg = msg == null ? "" : URLEncoder.encode(msg, "UTF-8");
             String params = "__ajax=json&customerSn=" + encSn + "&result=" + result + "&msg=" + encMsg;
             System.out.println("[ackPrint] " + params);
             String resp = doPost(url, params);
@@ -325,118 +68,66 @@ public class DataUtil {
         }
     }
 
-    // 调用mescloud生成客户编码并绑定钢印码(镭雕OP040专用)
-    // prodCode: 产品标识 T09/T68;steelSn: 镭雕软件回传的钢印码
-    public static JSONObject genCustomerSn(String prodCode,String steelSn){
-        try{
-            String enconding = "UTF-8";
-            InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties");
+    /** 从配置文件读服务端 IP,拼成 URL 前缀,只加载一次 */
+    private static String loadServerPrefix() {
+        try (InputStream is = ClassLoader.getSystemResourceAsStream("config/config.properties")) {
+            if (is == null) return "http://127.0.0.1:8980";
             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/mesLaser/genCustomerSn";
-            String params = "__ajax=json&prodCode="+prodCode+"&steelSn="+steelSn+"&oprno="+oprno+"&lineSn="+lineSn;
-            System.out.println("params="+params);
-            String result = doPost(url,params);
-            System.out.println("result="+result);
-
-            if(result==null||result.equalsIgnoreCase("false")) {
-                return null;
-            }else {
-                return JSONObject.parseObject(result);
+            try (BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"))) {
+                pro.load(br);
             }
-        }catch (Exception e){
+            String ip = pro.getProperty("mes.server_ip", "127.0.0.1").trim();
+            String port = pro.getProperty("mes.server_port", "8980").trim();
+            return "http://" + ip + ":" + port;
+        } catch (Exception e) {
             e.printStackTrace();
-            return null;
+            return "http://127.0.0.1:8980";
         }
     }
 
-    public static JSONObject unbindSteelSn(String steelSn){
-        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/mesLaser/unbindSteelSn";
-            String params = "__ajax=json&steelSn="+steelSn+"&oprno="+oprno+"&lineSn="+lineSn;
-            System.out.println("params="+params);
-            String result = doPost(url,params);
-            System.out.println("result="+result);
-
-            if(result==null||result.equalsIgnoreCase("false")) {
-                return null;
-            }else {
-                return JSONObject.parseObject(result);
-            }
-        }catch (Exception e){
-            e.printStackTrace();
-            return null;
+    /** 服务端在线探活 */
+    public static boolean isServerReachable() {
+        try {
+            URL url = new URL(MES_URL_PREFIX);
+            HttpURLConnection c = (HttpURLConnection) url.openConnection();
+            c.setConnectTimeout(2000);
+            c.setReadTimeout(2000);
+            c.setRequestMethod("HEAD");
+            int code = c.getResponseCode();
+            return code >= 200 && code < 500; // 4xx 也算联通
+        } catch (Exception e) {
+            return false;
         }
     }
+
+    /** 通用 POST,返回响应体字符串 */
     public static String doPost(String httpUrl, String param) {
-        HttpURLConnection connection = null;
-        InputStream is = null;
-        OutputStream os = null;
-        BufferedReader br = null;
-        String result = null;
+        HttpURLConnection conn = 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();
+            conn = (HttpURLConnection) url.openConnection();
+            conn.setRequestMethod("POST");
+            conn.setConnectTimeout(5000);
+            conn.setReadTimeout(15000);
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+            conn.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
+            try (OutputStream os = conn.getOutputStream()) {
+                os.write(param.getBytes("UTF-8"));
             }
-        } catch (MalformedURLException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
+            if (conn.getResponseCode() != 200) return null;
+            try (BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"))) {
+                StringBuilder sb = new StringBuilder();
+                String line;
+                while ((line = br.readLine()) != null) sb.append(line);
+                return sb.toString();
+            }
+        } catch (Exception e) {
             e.printStackTrace();
+            return null;
         } 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();
+            if (conn != null) conn.disconnect();
         }
-        return result;
     }
 }

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

@@ -1,244 +0,0 @@
-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 com.mes.util.AppLog;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.time.LocalDateTime;
-
-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.DO_NOTHING_ON_CLOSE);
-        addWindowListener(new WindowAdapter() {
-            @Override
-            public void windowClosing(WindowEvent e) {
-                if (MesClient.confirmClose(LoginFarme.this)) {
-                    AppLog.markUserClose();
-                    System.exit(0);
-                }
-            }
-        });
-        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("")) {
-            AppLog.login(user_str, "用户名密码", false);
-            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")) {
-            AppLog.login(user_str, "用户名密码", 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 {
-                AppLog.login(user_str, "用户名密码", false);
-                //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("")) {
-            AppLog.scan("工牌", scanContent);
-            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")) {
-                AppLog.login(scanContent, "扫码", 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 {
-                    AppLog.login(scanContent, "扫码", false);
-                    JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录失败,用户名或密码错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-                    return;
-                }
-            }
-        }else {
-            AppLog.login("", "扫码", false);
-            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) {
-                    AppLog.login(user_id, "权限校验", false);
-                    //无权限登录
-                    JOptionPane.showMessageDialog(MesClient.mesClientFrame,"您无权登录该工位","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-                    return;
-                }else if(MesClient.mes_auth==1||MesClient.mes_auth==2) {
-                    AppLog.login(user_id, "权限校验", true);
-                    // 获取等于所处时间-当前小时
-                    LocalDateTime now = LocalDateTime.now();
-                    MesClient.userLoginHours = now.getHour();
-
-                    //初始化tcp连接,发送同步报文
-                    MesClient.initTcpConnection();
-                    //启动timer心跳包
-                    MesClient.startHeartBeatTimer();
-
-                    //1操作工人,2管理员
-                    //登录成功
-                    MesClient.user_menu.setText(user_id);
-                    MesClient.welcomeWin.setVisible(false);
-                    // Apply the maximized state when the main window is actually shown after login.
-                    MesClient.mesClientFrame.setExtendedState(JFrame.MAXIMIZED_BOTH);
-                    MesClient.mesClientFrame.setVisible(true);
-                    MesClient.mesClientFrame.revalidate();
-                    MesClient.mesClientFrame.repaint();
-
-                    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.jfxPanel3 == null){
-                        String url = "http://"+ MesClient.mes_server_ip+":8980/js/a/mes/mesProductLaser/list?__sid="+MesClient.sessionid+"&oprno="+MesClient.mes_gw+"&lineSn="+MesClient.mes_line_sn+"#钢印码和客户码对应关系";
-                        MesClient.jfxPanel3 = new MesWebView(url);
-                        MesClient.jfxPanel3.setSize(990, 550);
-                        MesClient.indexPanelD.add(MesClient.jfxPanel3);
-                    }
-
-                    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 {
-            AppLog.login(user_id, "权限校验", false);
-            JOptionPane.showMessageDialog(MesClient.mesClientFrame,"登录失败,用户名或密码错误","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-            return;
-        }
-    }
-}

File diff suppressed because it is too large
+ 328 - 1385
src/com/mes/ui/MesClient.java


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

@@ -1,150 +0,0 @@
-package com.mes.ui;
-
-import com.mes.netty.ProtocolParam;
-import com.mes.component.MyDialog;
-import com.mes.util.ErrorMsg;
-
-import javax.swing.*;
-import java.awt.*;
-
-public class MesRevice {
-
-    //创建
-    public static void createRevice(String processMsgRet,String mes_msg){
-        try{
-            if(processMsgRet.equalsIgnoreCase("OK")) {
-               MesClient.resetScanA();
-               MesClient.setMenuStatus("结果已上传MES,请继续",0);
-            }else if(processMsgRet.equalsIgnoreCase("CF")){
-                MesClient.setMenuStatus("工件码重复提交失败",1);
-            }else if(processMsgRet.equalsIgnoreCase("BM")){
-                MesClient.setMenuStatus("物料未绑定或已失效",1);
-            }else if(processMsgRet.equalsIgnoreCase("GS")){
-                MesClient.setMenuStatus("工件码格式不正确",1);
-            }else if(processMsgRet.equalsIgnoreCase("DJ")){
-                MesClient.setMenuStatus("未进行开班点检",1);
-            }else{
-                MesClient.setMenuStatus("结果上传MES失败,请重试",1);
-            }
-        }catch (Exception e){
-            e.printStackTrace();
-            MesClient.setMenuStatus("结果上传MES失败,请重试",1);
-        }
-    }
-
-    // 质量查询
-    public static void checkQualityRevice(String processMsgRet,String mes_msg){
-        try{
-//            String lmsg = "该工件本工位不可加工";
-//            MesClient.status_menu.setText(lmsg);
-//            new MyDialog(MesClient.mesClientFrame,"提示",lmsg);
-            if(processMsgRet.equalsIgnoreCase("UD")) {
-                MesClient.status_menu.setForeground(Color.GREEN);
-                MesClient.check_quality_result = true;//质量合格,可以绑定加工
-                MesClient.status_menu.setText("该工件可以加工");
-                if(MesClient.work_status == 0 ){
-                    String barcode36 = MesClient.getBarcode(MesClient.product_sn.getText());//处理36为码
-                    MesClient.getUser();
-                    DataUtil.startWork(MesClient.nettyClient,barcode36,MesClient.user20);
-                }
-            }else {
-                MesClient.check_quality_result = false;
-
-                String lmsg = ErrorMsg.getErrorMsg(processMsgRet, ProtocolParam.getLx(mes_msg));
-
-                MesClient.status_menu.setText(lmsg);
-                new MyDialog(MesClient.mesClientFrame,"提示",lmsg);
-            }
-            if(MesClient.check_quality_result){
-                if(MesClient.work_status == 0){
-                    MesClient.finish_ok_bt.setEnabled(false);
-                    MesClient.finish_ng_bt.setEnabled(false);
-                }else{
-                    MesClient.finish_ok_bt.setEnabled(true);
-                    MesClient.finish_ng_bt.setEnabled(true);
-                }
-            }else{
-                MesClient.finish_ok_bt.setEnabled(false);
-                MesClient.finish_ng_bt.setEnabled(false);
-            }
-        }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);
-
-                String sn = MesClient.getBarcode(MesClient.product_sn.getText());
-                MesClient.getUser();
-                DataUtil.bindUser(MesClient.nettyClient,sn,MesClient.user20);
-
-                MesClient.finish_ok_bt.setEnabled(true);
-                MesClient.finish_ng_bt.setEnabled(true);
-
-                /*String qret = "OK";
-                Boolean sendret = DataUtil.sendQuality(MesClient.nettyClient,sn,qret,MesClient.user20);
-                if(!sendret){
-//                    MesClient.finish_ok_bt.setEnabled(true);
-//                    MesClient.finish_ng_bt.setEnabled(true);
-                    MesClient.status_menu.setText("结果提交失败,请重试");
-                    JOptionPane.showMessageDialog(MesClient.mesClientFrame,"结果提交失败,请重试","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-                    return;
-                }*/
-            }
-        }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.scan_type = 1;
-                MesClient.scanBarcode();
-
-            }else{
-                MesClient.status_menu.setText("结果提交失败,请重试");
-                JOptionPane.showMessageDialog(MesClient.mesClientFrame,"结果提交失败,请重试","提示窗口", JOptionPane.INFORMATION_MESSAGE);
-                return;
-            }
-        }catch (Exception e){
-            e.printStackTrace();
-        }
-    }
-}

+ 0 - 242
src/com/mes/ui/ModbusRtu.java

@@ -1,242 +0,0 @@
-package com.mes.ui;
-
-import com.fazecast.jSerialComm.*;
-
-import java.math.BigInteger;
-
-public class ModbusRtu {
-    public static SerialPort connect(){
-        try{
-            SerialPort serialPort = SerialPort.getCommPort("COM2"); // 替换为你的端口名
-            serialPort.setComPortParameters(38400, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); // 设置端口参数
-            serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);
-
-            if (serialPort.openPort()) {
-                System.out.println("Port opened successfully.");
-                return serialPort;
-            } else {
-               return null;
-            }
-        }catch (Exception e){
-            e.printStackTrace();
-            return null;
-        }
-    }
-
-    public static void disconnect(SerialPort serialPort) {
-        if (serialPort != null && serialPort.isOpen()) {
-            serialPort.closePort();
-        }
-    }
-
-    public static SerialPort reconnect(SerialPort serialPort) {
-        disconnect(serialPort);
-        return connect();
-    }
-
-    public static void openDevice(SerialPort serialPort) {
-        System.out.println("isOpen:");
-        if(serialPort ==null || !serialPort.isOpen()){
-            serialPort = reconnect(serialPort);
-        }
-        if(serialPort == null){
-            // 串口设备不存在(如COM2未接硬件),跳过操作,避免NPE刷屏
-            System.out.println("Modbus设备未连接,跳过openDevice");
-            return;
-        }
-
-        try {
-            String writeString = "010600000000"; // 关
-            String crc = getCRC16_Modbus_Str(writeString);
-            byte[] writeBuffer = hexStringToByteArray(writeString+crc);
-            serialPort.writeBytes(writeBuffer, writeBuffer.length);
-
-            // 接收数据
-            byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度
-            int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
-            System.out.println("Read " + numRead + " bytes.");
-
-            // 将读取的字节转换为十六进制字符串
-            StringBuilder data = new StringBuilder();
-            for (int i = 0; i < numRead; i++) {
-                data.append(String.format("%02X", readBuffer[i]));
-            }
-            String revStr = data.toString();
-//            String ret = revStr.substring(6,8);
-            System.out.println("Received data: " + revStr);
-//            System.out.println("ret data: " + ret);
-
-        } catch (Exception e) {
-            e.printStackTrace();
-            serialPort.closePort();
-        } finally {
-
-        }
-    }
-
-    public static void closeDevice(SerialPort serialPort) {
-        if(serialPort ==null || !serialPort.isOpen()){
-            serialPort = reconnect(serialPort);
-        }
-        if(serialPort == null){
-            // 串口设备不存在(如COM2未接硬件),跳过操作,避免NPE刷屏
-            System.out.println("Modbus设备未连接,跳过closeDevice");
-            return;
-        }
-        try {
-            String writeString = "010600000001"; // 开
-            String crc = getCRC16_Modbus_Str(writeString);
-            byte[] writeBuffer = hexStringToByteArray(writeString+crc);
-            serialPort.writeBytes(writeBuffer, writeBuffer.length);
-
-            // 接收数据
-            byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度
-            int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
-            System.out.println("Read " + numRead + " bytes.");
-
-            // 将读取的字节转换为十六进制字符串
-            StringBuilder data = new StringBuilder();
-            for (int i = 0; i < numRead; i++) {
-                data.append(String.format("%02X", readBuffer[i]));
-            }
-            String revStr = data.toString();
-//            String ret = revStr.substring(6,8);
-            System.out.println("Received data: " + revStr);
-//            System.out.println("ret data: " + ret);
-
-        } catch (Exception e) {
-            e.printStackTrace();
-            serialPort.closePort();
-        } finally {
-
-        }
-    }
-
-    public static Boolean readCoil(SerialPort serialPort,int pos) {
-        if(serialPort ==null || !serialPort.isOpen()){
-            serialPort = reconnect(serialPort);
-        }
-        if(serialPort == null){
-            // 串口设备不存在(如COM2未接硬件),跳过操作,避免NPE刷屏
-            System.out.println("Modbus设备未连接,跳过readCoil");
-            return false;
-        }
-        try {
-            String writeString = "010100000"+pos+"01"; // 线圈地址 0/1,目前只有2路
-            String crc = getCRC16_Modbus_Str(writeString);
-            byte[] writeBuffer = hexStringToByteArray(writeString+crc);
-            serialPort.writeBytes(writeBuffer, writeBuffer.length);
-
-            // 接收数据
-            byte[] readBuffer = new byte[512]; // 调整数组大小以适应预期的响应长度
-            int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
-            System.out.println("Read " + numRead + " bytes.");
-
-            // 将读取的字节转换为十六进制字符串
-            StringBuilder data = new StringBuilder();
-            for (int i = 0; i < numRead; i++) {
-                data.append(String.format("%02X", readBuffer[i]));
-            }
-            String revStr = data.toString();
-            String ret = revStr.substring(6,8);
-            System.out.println("Received data: " + revStr);
-            System.out.println("ret data: " + ret);
-
-            if(ret.equals("01")){
-                MesClient.setMenuStatus("当前结果为:true",0);
-                return true;
-            }else{
-                MesClient.setMenuStatus("当前结果为:false",0);
-                return false;
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            MesClient.setMenuStatus("串口断线",0);
-            serialPort.closePort();
-            return false;
-        }
-    }
-
-
-    /**
-     * CRC16(modbus)校验
-     * 获取crc16校验码,参数data中不能有空格
-     * @param data
-     * @return
-     */
-    public static String getCRC16_Modbus_Str(String data) {
-        data = data.replace(" ", "");
-        int len = data.length();
-        if (!(len % 2 == 0)) {
-            return "0000";
-        }
-        int num = len / 2;
-        byte[] para = new byte[num];
-        for (int i = 0; i < num; i++) {
-            int value = Integer.valueOf(data.substring(i * 2, 2 * (i + 1)), 16);
-            para[i] = (byte) value;
-        }
-        return getCRC(para);
-    }
-
-    /**
-     * 计算CRC16校验码
-     * @param bytes
-     *            字节数组
-     * @return {@link String} 校验码
-     * @since 1.0
-     */
-    public static String getCRC(byte[] bytes) {
-        // CRC寄存器全为1
-        int CRC = 0x0000ffff;
-        // 多项式校验值
-        int POLYNOMIAL = 0x0000a001;
-        int i, j;
-        for (i = 0; i < bytes.length; i++) {
-            CRC ^= ((int) bytes[i] & 0x000000ff);
-            for (j = 0; j < 8; j++) {
-                if ((CRC & 0x00000001) != 0) {
-                    CRC >>= 1;
-                    CRC ^= POLYNOMIAL;
-                } else {
-                    CRC >>= 1;
-                }
-            }
-        }
-        // 结果转换为16进制
-        String result = Integer.toHexString(CRC).toUpperCase();
-        if (result.length() != 4) {
-            StringBuffer sb = new StringBuffer("0000");
-            result = sb.replace(4 - result.length(), 4, result).toString();
-        }
-        //高位在前地位在后
-        //return result.substring(2, 4) + " " + result.substring(0, 2);
-        // 交换高低位,低位在前高位在后
-        return result.substring(2, 4) +  result.substring(0, 2);
-    }
-
-    public static byte[] hexStringToByteArray(String hexString) {
-        // 去除字符串前后的空格
-        hexString = hexString.trim();
-
-        // 确保字符串的长度是偶数
-        if (hexString.length() % 2 != 0) {
-            throw new IllegalArgumentException("Invalid hex string");
-        }
-
-        // 将字符串转换为BigInteger对象
-        BigInteger bigInt = new BigInteger(hexString, 16);
-
-        // 获取BigInteger表示的字节数组
-        byte[] byteArray = bigInt.toByteArray();
-
-        // 处理符号位,如果数组的长度大于字符串的长度,则将符号位字节去除
-        if (byteArray.length > hexString.length() / 2) {
-            byte[] trimmedArray = new byte[hexString.length() / 2];
-            System.arraycopy(byteArray, 1, trimmedArray, 0, trimmedArray.length);
-            return trimmedArray;
-        }
-
-        return byteArray;
-    }
-}

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

@@ -1,54 +0,0 @@
-package com.mes.ui;
-
-/**
- * 工位描述工具:硬编码工位列表,避免每台客户端都依赖服务端接口
- * 数据来源 2026-06-24:T09 产线 mesLineProcess(lineSn=T9)
- */
-public class OprnoUtil {
-
-    /** T9 产线工位号(按 sorts 排序) */
-    public static String[] t9oprnos = new String[]{
-            "OP040", "OP050", "OP060", "OP070", "INSP030",
-            "OP090", "OP100", "OP120", "OP130", "INSP050",
-            "INSP060", "OP170", "OP190", "OP200", "INSP080",
-            "OP230", "INSP090", "INSP100", "INSP130", "INSP110"
-    };
-
-    /** T9 产线工位名(与 t9oprnos 一一对应) */
-    public static String[] t9oprnodes = new String[]{
-            "激光打码", "框架总成焊接1", "框架总成焊接2", "人工补焊1", "框架气密",
-            "框架激光切割正面", "框架激光切割反面", "套筒焊接", "人工补焊2", "总成检具检验",
-            "黑件入库", "紧固件装配正面/反面", "框架涂胶", "冷板装配", "半成品气密",
-            "安装密封垫底护板", "整包气密", "液冷板气密", "等电位电阻测试", "CCD检测"
-    };
-
-    /**
-     * 根据工位号查工位描述
-     * 子工位号自动转父工位(OP040A → OP040、INSP030A → INSP030)
-     * 注:lineSn 已不再区分,此客户端固定为 T09 产线
-     */
-    public static String getGwDes(String lineSn, String oprno) {
-        if (oprno == null) return "";
-        String code = formatOprno(oprno);
-        for (int i = 0; i < t9oprnos.length; i++) {
-            if (t9oprnos[i].equals(code)) return t9oprnodes[i];
-        }
-        return "";
-    }
-
-    /**
-     * 子工位号 → 父工位号
-     * 规则:去除末尾连续字母(前提是字母前是数字),如 OP040A → OP040、INSP030B → INSP030
-     * 不动 OP/INSP 这种前缀字母
-     */
-    public static String formatOprno(String oprno) {
-        if (oprno == null) return "";
-        int len = oprno.length();
-        while (len > 1
-                && Character.isLetter(oprno.charAt(len - 1))
-                && Character.isDigit(oprno.charAt(len - 2))) {
-            len--;
-        }
-        return oprno.substring(0, len);
-    }
-}

+ 0 - 101
src/com/mes/ui/RoundedComponentStyle.java

@@ -1,101 +0,0 @@
-package com.mes.ui;
-
-import javax.swing.AbstractButton;
-import javax.swing.BorderFactory;
-import javax.swing.JComponent;
-import javax.swing.JTextField;
-import javax.swing.border.AbstractBorder;
-import javax.swing.plaf.basic.BasicButtonUI;
-import javax.swing.plaf.basic.BasicTextFieldUI;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.Insets;
-import java.awt.RenderingHints;
-
-/** Applies a restrained, consistent rounded treatment to client controls. */
-public final class RoundedComponentStyle {
-    private static final int ARC = 8;
-    private static final Color BORDER_COLOR = new Color(170, 170, 170);
-
-    private RoundedComponentStyle() {
-    }
-
-    public static void apply(Component component) {
-        if (component instanceof AbstractButton) {
-            styleButton((AbstractButton) component);
-        } else if (component instanceof JTextField) {
-            styleTextField((JTextField) component);
-        }
-
-        if (component instanceof Container) {
-            for (Component child : ((Container) component).getComponents()) {
-                apply(child);
-            }
-        }
-    }
-
-    public static void styleButton(AbstractButton button) {
-        button.setUI(new RoundedButtonUI());
-        button.setBorder(BorderFactory.createEmptyBorder(2, 8, 2, 8));
-        button.setOpaque(false);
-    }
-
-    public static void styleTextField(JTextField textField) {
-        textField.setUI(new RoundedTextFieldUI());
-        textField.setBorder(BorderFactory.createCompoundBorder(
-                new RoundedBorder(BORDER_COLOR, ARC),
-                BorderFactory.createEmptyBorder(2, 7, 2, 7)));
-        textField.setOpaque(false);
-    }
-
-    private static class RoundedButtonUI extends BasicButtonUI {
-        @Override
-        public void update(Graphics graphics, JComponent component) {
-            Graphics2D g2 = (Graphics2D) graphics.create();
-            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g2.setColor(component.isEnabled() ? component.getBackground() : new Color(230, 230, 230));
-            g2.fillRoundRect(0, 0, component.getWidth() - 1, component.getHeight() - 1, ARC, ARC);
-            g2.dispose();
-            paint(graphics, component);
-        }
-    }
-
-    private static class RoundedTextFieldUI extends BasicTextFieldUI {
-        @Override
-        public void update(Graphics graphics, JComponent component) {
-            Graphics2D g2 = (Graphics2D) graphics.create();
-            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g2.setColor(component.getBackground());
-            g2.fillRoundRect(0, 0, component.getWidth() - 1, component.getHeight() - 1, ARC, ARC);
-            g2.dispose();
-            paint(graphics, component);
-        }
-    }
-
-    private static class RoundedBorder extends AbstractBorder {
-        private final Color color;
-        private final int arc;
-
-        RoundedBorder(Color color, int arc) {
-            this.color = color;
-            this.arc = arc;
-        }
-
-        @Override
-        public void paintBorder(Component component, Graphics graphics, int x, int y, int width, int height) {
-            Graphics2D g2 = (Graphics2D) graphics.create();
-            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-            g2.setColor(color);
-            g2.drawRoundRect(x, y, width - 1, height - 1, arc, arc);
-            g2.dispose();
-        }
-
-        @Override
-        public Insets getBorderInsets(Component component) {
-            return new Insets(1, 1, 1, 1);
-        }
-    }
-}

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

@@ -1,43 +0,0 @@
-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;
-    }
-}

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

@@ -1,14 +0,0 @@
-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;
-    }
-}

File diff suppressed because it is too large
+ 0 - 1001
src/com/mes/ui/VisualUiEditorPanel.java


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

@@ -1,15 +0,0 @@
-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;
-	}
-}

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

@@ -1,34 +0,0 @@
-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 - 49
src/com/mes/util/ErrorMsg.java

@@ -1,49 +0,0 @@
-package com.mes.util;
-
-public class ErrorMsg {
-    public static String getErrorMsg(String processMsgRet,String lx){
-        String lmsg = "该工件本工位不可加工";
-        try{
-            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"+ lx+"0加工NG";
-            }else if(processMsgRet.equalsIgnoreCase("QD")) {
-                lmsg = "该工件OP"+ lx+"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("CS")) {
-                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 = "工件码重复";
-            }else if(processMsgRet.equalsIgnoreCase("SB")) {
-                lmsg = "设备信息不存在";
-            }
-        }catch (Exception e){ }
-        return lmsg;
-    }
-}

+ 0 - 131
src/com/mes/util/HttpUtils.java

@@ -1,131 +0,0 @@
-package com.mes.util;
-
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.net.HttpURLConnection;
-import java.net.URISyntaxException;
-import java.net.URL;
-
-public class HttpUtils {
-	/**
-	 * HTTP请求,正确报文解析,并保存数据到生产记录数据
-	 * @return 
-	 * @throws URISyntaxException
-	 */
-    //http post请求
-    public static String sendRequest(String urlParam) {
-		String requestType = "POST";
-        //根据接收内容返回数据结果
-    	String ret = "";
-    	System.out.println(urlParam);
-        HttpURLConnection con = null;
-        BufferedReader buffer = null;
-        StringBuffer resultBuffer = null;
-        try {
-            URL url = new URL(urlParam);
-            //得到连接对象
-            con = (HttpURLConnection) url.openConnection();
-            //设置请求类型
-            con.setRequestMethod(requestType);
-            //设置请求需要返回的数据类型和字符集类型
-            con.setRequestProperty("Content-Type", "application/json;charset=GBK");  
-            //允许写出
-            con.setDoOutput(true);
-            //允许读入
-            con.setDoInput(true);
-            //不使用缓存
-            con.setUseCaches(false);
-            //得到响应码
-            int responseCode = con.getResponseCode();
-            System.out.println("responseCode="+responseCode);
-            if(responseCode == HttpURLConnection.HTTP_OK){
-                //得到响应流
-                InputStream inputStream = con.getInputStream();
-                //将响应流转换成字符串
-                resultBuffer = new StringBuffer();
-                String line;
-                buffer = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
-                while ((line = buffer.readLine()) != null) {
-                    resultBuffer.append(line);
-                }
-                System.out.println(resultBuffer.toString());
-                ret = resultBuffer.toString();
-            }else {
-            	//ret = String.valueOf(responseCode);
-            	ret = "false";
-            }
-            con.disconnect();
-        }catch(Exception e) {
-        	//ret = false;
-        	//System.out.println("e.toString()="+e.toString());
-        	//return e.toString();
-            //e.printStackTrace();
-        	ret = "false";
-        }
-        return ret;
-    }
-
-
-    public static String sendPostRequest(String urlParam, String params) {
-        String requestType = "POST";
-        //根据接收内容返回数据结果
-        String ret = "";
-        System.out.println(urlParam);
-        HttpURLConnection con = null;
-        BufferedReader buffer = null;
-        StringBuffer resultBuffer = null;
-        try {
-            URL url = new URL(urlParam);
-            //得到连接对象
-            con = (HttpURLConnection) url.openConnection();
-            //设置请求类型
-            con.setRequestMethod(requestType);
-            //设置请求需要返回的数据类型和字符集类型
-            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=GBK");
-            //允许写出
-            con.setDoOutput(true);
-            //允许读入
-            con.setDoInput(true);
-            //不使用缓存
-            con.setUseCaches(false);
-
-            // 获取URLConnection对象对应的输出流
-            OutputStreamWriter out = new OutputStreamWriter( con.getOutputStream(),"UTF-8");// utf-8编码
-            // 发送请求参数
-            out.write(params);
-
-            //得到响应码
-            int responseCode = con.getResponseCode();
-            System.out.println("responseCode="+responseCode);
-            if(responseCode == HttpURLConnection.HTTP_OK){
-                //得到响应流
-                InputStream inputStream = con.getInputStream();
-                //将响应流转换成字符串
-                resultBuffer = new StringBuffer();
-                String line;
-                buffer = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
-                while ((line = buffer.readLine()) != null) {
-                    resultBuffer.append(line);
-                }
-                System.out.println(resultBuffer.toString());
-                ret = resultBuffer.toString();
-            }else {
-                //ret = String.valueOf(responseCode);
-                ret = "false";
-            }
-            con.disconnect();
-        }catch(Exception e) {
-            //ret = false;
-            //System.out.println("e.toString()="+e.toString());
-            //return e.toString();
-            //e.printStackTrace();
-            ret = "false";
-        }
-        return ret;
-    }
-
-	
-
-}

+ 0 - 171
src/com/mes/util/JdbcUtils.java

@@ -1,171 +0,0 @@
-package com.mes.util;
-
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.SQLException;
-import java.sql.Statement;
-
-public class JdbcUtils {
-	//通过上面的工具就可以获取到properties文件中的键值从而可以加载驱动 获取链接 从而 可以增删改查
-	public static Connection conn = null;
-    public static String Drivde="org.sqlite.JDBC";
-    
-    public static Connection getConn(){
-        try {
-            Class.forName(Drivde);// 加载驱动,连接sqlite的jdbc
-            conn = DriverManager.getConnection("jdbc:sqlite:mes_db.db");//连接数据库zhou.db,不存在则创建
-            System.out.println("连接到SQLite数据库成功!");
-            create_bw_record();//初始化结构表
-            //create_measure_data();//初始化测试数据表
-        } catch (Exception e) {
-            // TODO Auto-generated catch block
-        	close();//关闭数据库连接
-            e.printStackTrace();
-        }
-        return conn;
-    }
-    
-    public static void create_bw_record() throws SQLException {
-    	Statement statement=conn.createStatement();   //创建连接对象,是Java的一个操作数据库的重要接口
-        //设备结构数据库
-        String sqlEquipment = "CREATE TABLE if not exists bw_record("
-        		+ "id INTEGER PRIMARY KEY AUTOINCREMENT,gw VARCHAR(20),gy VARCHAR(20),message_type VARCHAR(20),sn VARCHAR(48),bw VARCHAR(1000),record_time DATETIME,"
-        		+ "info_01 VARCHAR(200),info_02 VARCHAR(200),info_03 VARCHAR(200))";
-        statement.executeUpdate("drop table if exists bw_record");//判断是否有表tables的存在。有则删除
-        statement.executeUpdate(sqlEquipment);
-        System.out.println("表创建成功!");
-        
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (1, '第一电厂', '第一电厂', '', 1, 0,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (2, '第一电厂-设备管理部', '第一电厂-设备管理部', '第一电厂', 2, 0,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (3, '第一电厂-设备管理部-电机1', '第一电厂-设备管理部-电机1', '第一电厂-设备管理部', 3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (4, '第一电厂-设备管理部-电机2', '第一电厂-设备管理部-电机2', '第一电厂-设备管理部', 3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (5, '第一电厂-设备管理部-电机3', '第一电厂-设备管理部-发电机组-电机3', '第一电厂-设备管理部', 3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (6, '第一电厂-设备管理部-电机4', '第一电厂-设备管理部-发电机组-电机4', '第一电厂-设备管理部', 3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (7, '第一电厂-设备管理部-电机5', '第一电厂-设备管理部-发电机组-电机5', '第一电厂-设备管理部',3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (9, '第一电厂-设备管理部-电机6', '第一电厂-设备管理部-发电机组-电机6', '第一电厂-设备管理部',3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (10, '第二电厂', '第二电厂', '', 1, 0,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (11, '第二电厂-设备管理部', '第二电厂-设备管理部', '第二电厂', 2, 0,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (12, '第二电厂-设备管理部-电机1', '第二电厂-设备管理部-电机1', '第二电厂-设备管理部', 3, 1,'','','','','','')");//向数据库中插入数据
-//        statement.executeUpdate("INSERT INTO tree_structure VALUES (13, '第二电厂-设备管理部-电机2', '第二电厂-设备管理部-电机2', '第二电厂-设备管理部', 3, 1,'','','','','','')");//向数据库中插入数据
-//        System.out.println(sqlEquipment);
-//        ResultSet rSet=statement.executeQuery("select * from bw_record");//搜索数据库,将搜索的放入数据集ResultSet中
-//        while (rSet.next()) {            //遍历这个数据集
-//            System.out.println("gw:"+rSet.getString(1));//依次输出 也可以这样写 rSet.getString("name")
-//            //System.out.println("密码:"+rSet.getString("pwd"));
-//        }
-//        rSet.close();//关闭数据集
-        statement.close();
-    }
-    
-    //插入数据
-    public static boolean insertData(String gw, String gy, String bw, String message_type, String sn) {
-    	boolean ret = false;
-    	String record_time = DateLocalUtils.getCurrentTime();
-    	if(conn==null) {
-    		ret = false;
-    	}else {
-    		try {
-    			//创建连接对象,是Java的一个操作数据库的重要接口
-				Statement statement=conn.createStatement();
-				statement.executeUpdate("INSERT INTO bw_record (gw,gy,bw,record_time,message_type,sn) VALUES"
-						+ " ('"+gw+"', '"+gy+"', '"+bw+"', '"+record_time+"','"+message_type+"','"+sn+"')");//向数据库中插入数据
-				statement.close();
-				ret = true;
-			} catch (SQLException e) {
-				// TODO Auto-generated catch block
-				//e.printStackTrace();
-				ret = false;
-			}   
-    	}
-    	
-    	return ret;
-    }
-    
-    public static void create_measure_data() throws SQLException {
-    	Statement statement=conn.createStatement();   //创建连接对象,是Java的一个操作数据库的重要接口
-    	//statement.executeUpdate("drop table if exists measure_data");//判断是否有表tables的存在。有则删除
-    	//设备结构数据库
-        String sqlEquipment = "CREATE TABLE if not exists measure_data("
-        		+ "id INTEGER PRIMARY KEY AUTOINCREMENT,function_location VARCHAR(200),description VARCHAR(200),"
-        		+ "data_item VARCHAR(100),measure_time DATETIME,data_type INT(3)," //data_type=1电阻校准数据,2电感校准数据,3绝缘电阻校准数据
-        		+ "data_01 double(30),data_02 double(30),data_03 double(30),data_04 double(30),data_05 double(30),"
-        		+ "data_06 double(30),data_07 double(30),data_08 double(30),data_09 double(30),data_10 double(30),"
-        		+ "data_11 double(30),data_12 double(30),data_13 double(30),data_14 double(30),data_15 double(30),"
-        		+ "data_16 double(30),data_17 double(30),data_18 double(30),data_19 double(30),data_20 double(30)"
-        		+ ")";
-        statement.executeUpdate(sqlEquipment);
-//        statement.executeUpdate("INSERT INTO measure_data VALUES (1, '第一电厂-设备管理部-电机1',  '第一电厂-设备管理部-电机1', '2022-03-22 15:16:18', '2022-03-22 15:16:18',1,"
-//        		+ "0.05, 0.82, 3, 80, 130, 180, 402, 502, 809, 1103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)");//向数据库中插入数据        
-//        ResultSet rSet=statement.executeQuery("select * from measure_data");//搜索数据库,将搜索的放入数据集ResultSet中
-//        while (rSet.next()) {            //遍历这个数据集
-//            System.out.println("function_location:"+rSet.getString(2));//依次输出 也可以这样写 rSet.getString(“name”)
-//            System.out.println("data_01:"+rSet.getString(4));
-//        }
-//        rSet.close();//关闭数据集
-        statement.close();
-    }
-    
-    public static void close(){
-    	System.out.println("SQLite数据库连接关闭!");
-        try {
-        	if(conn!=null) {
-        		conn.close();
-        	}
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
-    }
-    
-    
-  //设备结构数据库
-//    String sqlEquipment = "CREATE TABLE if not exists tree_structure(id INTEGER PRIMARY KEY AUTOINCREMENT,function_location VARCHAR(200),description VARCHAR(200),sup_fl VARCHAR(200),level INT(3)," +
-//            "isleaf INT(3))";
-//    statement.executeUpdate("drop table if exists tree_structure");//判断是否有表tables的存在。有则删除
-//    statement.executeUpdate(sqlEquipment);
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (1, '第一电厂', '第一电厂', NULL, 1, 0)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (2, '第一电厂-设备管理部', '第一电厂-设备管理部', '第一电厂', 2, 0)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (3, '第一电厂-设备管理部-发电机组', '第一电厂-设备管理部-发电机组', '第一电厂-设备管理部', 3, 0)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (4, '第一电厂-设备管理部-发电机组-电机1', '第一电厂-设备管理部-发电机组-电机1', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (5, '第一电厂-设备管理部-发电机组-电机2', '第一电厂-设备管理部-发电机组-电机2', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (6, '第二电厂', '第二电厂', NULL, 1, 0)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (7, '第二电厂-设备管理部', '第二电厂-设备管理部', '第二电厂', 2, 0)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (8, '第一电厂-设备管理部-发电机组-电机3', '第一电厂-设备管理部-发电机组-电机3', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (10, '第一电厂-设备管理部-发电机组-电机4', '第一电厂-设备管理部-发电机组-电机4', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (11, '第一电厂-设备管理部-发电机组-电机5', '第一电厂-设备管理部-发电机组-电机5', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (12, '第一电厂-设备管理部-发电机组-电机8', '第一电厂-设备管理部-发电机组-电机8', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (13, '第一电厂-设备管理部-发电机组-电机6', '第一电厂-设备管理部-发电机组-电机6', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (14, '第一电厂-设备管理部-发电机组-电机7', '第一电厂-设备管理部-发电机组-电机7', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (15, '第一电厂-设备管理部-发电机组-电机9', '第一电厂-设备管理部-发电机组-电机9', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    statement.executeUpdate("INSERT INTO tree_structure VALUES (16, '第一电厂-设备管理部-发电机组-电机10', '第一电厂-设备管理部-发电机组-电机10', '第一电厂-设备管理部-发电机组', 4, 1)");//向数据库中插入数据
-//    ResultSet rSet=statement.executeQuery("select * from tree_structure");//搜索数据库,将搜索的放入数据集ResultSet中
-    
-//    /**
-//    * 通过用户名到数据库中获取凭证密码
-//    * @param userName
-//    * @return
-//    */
-//    private static String getPasswordByUserName(String userName) {
-//    //SQL语句  
-//    String sql = "select password from users where username = " +"'" + userName+"'";
-//        Connection conn = JdbcUtils.getConn();
-//        Statement stmt=null; 
-//        ResultSet ret = null;  
-//        String password=null;
-//    try {
-//    stmt = conn.createStatement();
-//    //执行语句,得到结果集  
-//    ret = stmt.executeQuery(sql);
-//                while (ret.next()) {  
-//                //这里只查询的密码
-//                password = ret.getString(1);  
-//                }
-//                ret.close();  
-//                conn.close();//关闭连接  
-//    } catch (SQLException e1) {
-//    e1.printStackTrace();
-//    }  
-//    return password;
-//    }
-}
- 
-

+ 8 - 28
src/resources/config/config.properties

@@ -1,31 +1,11 @@
-mes.gw=OP040A
-#mes.server_ip=127.0.0.1
+# mescloud 服务端
 mes.server_ip=192.168.114.99
-mes.tcp_port=3000
-mes.heart_beat_cycle=60
-mes.line_sn=XT
-
-# prodCode: T09/T68, used for customer sn prefix, independent from mes.line_sn(XT)
-mes.prod_code=T09
-
-# 拉取待打印的轮询间隔(毫秒)
-mes.laser.poll_interval=3000
+mes.server_port=8980
 
+# 拉铆待打印轮询配置
+# 轮询间隔(毫秒)
+mes.rivet.poll_interval=3000
 # 单次拉取条数上限
-mes.laser.poll_batch_size=10
-
-# 启动默认打印模式:auto=自动轮询打印,manual=只在点击后打印一次
-mes.laser.print_mode=manual
-
-# 打印机名,空则使用系统默认打印机
-mes.laser.printer_name=
-
-# 流转卡 PDF 模板路径(classpath 内相对路径)
-mes.laser.card_template_path=config/liuzhuanka_template.pdf
-
-# true=只生成预览 PNG 到 preview_path 不真打印,false=送打印机
-mes.laser.preview_only=false
-mes.laser.preview_path=logs/card_preview.png
-
-# UI design panel password, triggered by triple-clicking time status bar
-mes.ui.design.password=mes123
+mes.rivet.poll_batch_size=10
+# 启动默认打印模式:auto=自动轮询打印,manual=只更新 UI 不自动打
+mes.rivet.print_mode=auto