|
|
@@ -0,0 +1,756 @@
|
|
|
+package com.mes.ui;
|
|
|
+
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.mes.component.MesWebView;
|
|
|
+import com.mes.util.PLCUtils;
|
|
|
+import com.mes.util.StationConfig;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+
|
|
|
+import javax.swing.*;
|
|
|
+import javax.swing.border.TitledBorder;
|
|
|
+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.LinkedHashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Timer;
|
|
|
+import java.util.TimerTask;
|
|
|
+
|
|
|
+public class WorkStationPanel extends JPanel {
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(WorkStationPanel.class);
|
|
|
+ private static final long PLC_STATUS_REFRESH_INTERVAL_MS = 3000L;
|
|
|
+ private static final long PLC_STATUS_RETRY_BACKOFF_MS = 10000L;
|
|
|
+ private static final long PLC_STATUS_WARN_INTERVAL_MS = 30000L;
|
|
|
+ private static final long PLC_WORKFLOW_WARN_INTERVAL_MS = 30000L;
|
|
|
+ private String gw;
|
|
|
+ private String gwDes;
|
|
|
+ private String lineSn;
|
|
|
+ private String serverIp;
|
|
|
+
|
|
|
+ private String allowStart;
|
|
|
+ private String allowDown;
|
|
|
+ private String startMethod;
|
|
|
+ private String stopMethod;
|
|
|
+ private StationConfig stationConfig;
|
|
|
+
|
|
|
+ public int workStatus = 0;
|
|
|
+ public int plcStatus = 0;
|
|
|
+ public boolean checkQualityResult = false;
|
|
|
+ private String currentUser = "system";
|
|
|
+ private String lastWeldingParamContent = "";
|
|
|
+ private PLCUtils.WeldingParamSampler weldingParamSampler;
|
|
|
+
|
|
|
+ public static List<String> hjparams = new ArrayList<>();
|
|
|
+
|
|
|
+ public JTextField productSnField;
|
|
|
+ public JButton scanButton;
|
|
|
+ public JButton finishOkButton;
|
|
|
+ public JButton finishNgButton;
|
|
|
+ private JLabel statusLabel;
|
|
|
+ private JLabel heartBeatLabel;
|
|
|
+ private JLabel fxLabel;
|
|
|
+ private final Map<String, JLabel> plcStatusDots = new LinkedHashMap<>();
|
|
|
+ private final Map<String, Boolean> plcStatusValues = new LinkedHashMap<>();
|
|
|
+ public static Object[][] rowData = null;
|
|
|
+
|
|
|
+ private Timer heartBeatTimer;
|
|
|
+ private Timer getSnBeatTimer;
|
|
|
+ private Timer plcStatusTimer;
|
|
|
+ private int plcStatusReadFailCount = 0;
|
|
|
+ private long nextPlcStatusReadTime = 0L;
|
|
|
+ private long lastPlcStatusWarnTime = 0L;
|
|
|
+ private int plcWorkflowFailCount = 0;
|
|
|
+ private long lastPlcWorkflowWarnTime = 0L;
|
|
|
+ private long nextPlcWorkflowTime = 0L;
|
|
|
+
|
|
|
+ private boolean iconREDFlag = true;
|
|
|
+
|
|
|
+ public WorkStationPanel(String gw, String gwDes, String lineSn, String serverIp, String allowStart, String allowDown, String startMethod, String stopMethod) {
|
|
|
+ this.gw = gw;
|
|
|
+ this.gwDes = gwDes;
|
|
|
+ this.lineSn = lineSn;
|
|
|
+ this.serverIp = serverIp;
|
|
|
+ this.allowStart = allowStart;
|
|
|
+ this.allowDown = allowDown;
|
|
|
+ this.startMethod = startMethod;
|
|
|
+ this.stopMethod = stopMethod;
|
|
|
+ initUI();
|
|
|
+ startHeartBeatTimer();
|
|
|
+ startPlcStatusTimer();
|
|
|
+ startGetCurSn();
|
|
|
+ }
|
|
|
+
|
|
|
+ public WorkStationPanel(StationConfig stationConfig) {
|
|
|
+ this.gw = stationConfig.getGw();
|
|
|
+ this.gwDes = stationConfig.getGwDes();
|
|
|
+ this.lineSn = stationConfig.getLineSn();
|
|
|
+ this.serverIp = stationConfig.getServerIp();
|
|
|
+ this.allowStart = stationConfig.getAllowStart();
|
|
|
+ this.allowDown = stationConfig.getAllowDown();
|
|
|
+ this.startMethod = stationConfig.getStartMethod();
|
|
|
+ this.stopMethod = stationConfig.getStopMethod();
|
|
|
+ this.stationConfig = stationConfig;
|
|
|
+ initUI();
|
|
|
+ startHeartBeatTimer();
|
|
|
+ startPlcStatusTimer();
|
|
|
+ startGetCurSn();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void initUI() {
|
|
|
+ setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLACK),
|
|
|
+ gw + " - " + gwDes,
|
|
|
+ TitledBorder.CENTER,
|
|
|
+ TitledBorder.TOP,
|
|
|
+ new Font("微软雅黑", Font.BOLD, 20),
|
|
|
+ Color.BLUE));
|
|
|
+
|
|
|
+ setLayout(new BorderLayout(5, 5));
|
|
|
+ setBackground(Color.WHITE);
|
|
|
+
|
|
|
+ JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
|
|
|
+ topPanel.setBackground(Color.WHITE);
|
|
|
+
|
|
|
+ statusLabel = new JLabel("等待扫码");
|
|
|
+ statusLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
|
|
|
+ statusLabel.setForeground(Color.RED);
|
|
|
+ topPanel.add(statusLabel);
|
|
|
+
|
|
|
+ heartBeatLabel = new JLabel(new ImageIcon(getClass().getResource("/bg/grey_dot.png")));
|
|
|
+ topPanel.add(heartBeatLabel);
|
|
|
+
|
|
|
+ add(topPanel, BorderLayout.NORTH);
|
|
|
+
|
|
|
+ JPanel centerPanel = new JPanel();
|
|
|
+ centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
|
|
|
+ centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
|
|
+
|
|
|
+ fxLabel = new JLabel("该工件为返修件,请仔细检查");
|
|
|
+ fxLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
|
|
|
+ fxLabel.setForeground(Color.RED);
|
|
|
+ fxLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
+ fxLabel.setVisible(false);
|
|
|
+ centerPanel.add(fxLabel);
|
|
|
+
|
|
|
+ productSnField = new JTextField();
|
|
|
+ productSnField.setHorizontalAlignment(SwingConstants.CENTER);
|
|
|
+ productSnField.setEditable(false);
|
|
|
+ productSnField.setFont(new Font("微软雅黑", Font.BOLD, 15));
|
|
|
+ productSnField.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
|
|
|
+ productSnField.setColumns(15);
|
|
|
+ productSnField.setPreferredSize(new Dimension(100, 30));
|
|
|
+ scanButton = new JButton("扫码");
|
|
|
+// scanButton.setIcon(new ImageIcon(getClass().getResource("/bg/scan_barcode.png")));
|
|
|
+ scanButton.setFont(new Font("微软雅黑", Font.PLAIN, 15));
|
|
|
+ scanButton.setPreferredSize(new Dimension(70, 30));
|
|
|
+ scanButton.addActionListener(new ActionListener() {
|
|
|
+ @Override
|
|
|
+ public void actionPerformed(ActionEvent e) {
|
|
|
+ try {
|
|
|
+ JSONObject result = DataUtil.getCurSn(gw, serverIp, lineSn);
|
|
|
+
|
|
|
+ if (result == null) {
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, "获取工件码失败", "错误", JOptionPane.ERROR_MESSAGE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检查是否需要登录
|
|
|
+ if (result.containsKey("result") && "login".equalsIgnoreCase(result.getString("result"))) {
|
|
|
+ String message = result.containsKey("message") ? result.getString("message") : "";
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, "登录超时,请重新登录!\n" + message, "登录提示", JOptionPane.WARNING_MESSAGE);
|
|
|
+ // 切换到登录窗口
|
|
|
+ if (MultiStationClient.welcomeWin != null) {
|
|
|
+ MultiStationClient.welcomeWin.setVisible(true);
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 正常处理结果
|
|
|
+ if (result.containsKey("data")) {
|
|
|
+ String data = result.getString("data");
|
|
|
+ if (data != null && !data.isEmpty()) {
|
|
|
+ productSnField.setText(data);
|
|
|
+ checkQuality(data);
|
|
|
+ } else {
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, "获取工件码为空", "提示", JOptionPane.INFORMATION_MESSAGE);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, result.get("message"), "错误", JOptionPane.ERROR_MESSAGE);
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, "扫码异常: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ JPanel linePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 1, 0));
|
|
|
+ linePanel.add(productSnField);
|
|
|
+ linePanel.add(scanButton);
|
|
|
+ centerPanel.add(linePanel);
|
|
|
+
|
|
|
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10));
|
|
|
+ buttonPanel.setBackground(Color.WHITE);
|
|
|
+ finishOkButton = new JButton("OK");
|
|
|
+ finishOkButton.setIcon(new ImageIcon(getClass().getResource("/bg/ok_bg.png")));
|
|
|
+ finishOkButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
|
|
|
+ finishOkButton.setPreferredSize(new Dimension(120, 30));
|
|
|
+ finishOkButton.setEnabled(false);
|
|
|
+ finishOkButton.addActionListener(new ActionListener() {
|
|
|
+ @Override
|
|
|
+ public void actionPerformed(ActionEvent e) {
|
|
|
+ submitResult("OK");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ buttonPanel.add(finishOkButton);
|
|
|
+
|
|
|
+ // NG按钮
|
|
|
+ finishNgButton = new JButton("NG");
|
|
|
+ finishNgButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
|
|
|
+ finishNgButton.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ng_bg.png")));
|
|
|
+ finishNgButton.setPreferredSize(new Dimension(120, 30));
|
|
|
+ finishNgButton.setEnabled(false);
|
|
|
+ finishNgButton.addActionListener(new ActionListener() {
|
|
|
+ @Override
|
|
|
+ public void actionPerformed(ActionEvent e) {
|
|
|
+ submitResult("NG");
|
|
|
+// resetScanA();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ buttonPanel.add(finishNgButton);
|
|
|
+
|
|
|
+ centerPanel.add(buttonPanel);
|
|
|
+
|
|
|
+ JPanel plcStatusPanel = createPlcStatusPanel();
|
|
|
+ centerPanel.add(plcStatusPanel);
|
|
|
+
|
|
|
+ add(centerPanel, BorderLayout.CENTER);
|
|
|
+
|
|
|
+ JPanel bottomPanel = new JPanel(new BorderLayout());
|
|
|
+ bottomPanel.setBackground(Color.WHITE);
|
|
|
+ bottomPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
|
|
+
|
|
|
+ JButton checkRecordButton = new JButton("点检记录");
|
|
|
+ checkRecordButton.setFont(new Font("微软雅黑", Font.PLAIN, 15));
|
|
|
+ checkRecordButton.setPreferredSize(new Dimension(100, 30));
|
|
|
+ checkRecordButton.addActionListener(new ActionListener() {
|
|
|
+ @Override
|
|
|
+ public void actionPerformed(ActionEvent e) {
|
|
|
+ showCheckRecordDialog();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ JButton workRecordButton = new JButton("工作记录");
|
|
|
+ workRecordButton.setFont(new Font("微软雅黑", Font.PLAIN, 15));
|
|
|
+ workRecordButton.setPreferredSize(new Dimension(100, 30));
|
|
|
+ workRecordButton.addActionListener(new ActionListener() {
|
|
|
+ @Override
|
|
|
+ public void actionPerformed(ActionEvent e) {
|
|
|
+ showWorkRecordDialog();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ JPanel leftBottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
|
|
|
+ leftBottomPanel.setBackground(Color.WHITE);
|
|
|
+ leftBottomPanel.add(checkRecordButton);
|
|
|
+
|
|
|
+ JPanel rightBottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
|
|
|
+ rightBottomPanel.setBackground(Color.WHITE);
|
|
|
+ rightBottomPanel.add(workRecordButton);
|
|
|
+
|
|
|
+ bottomPanel.add(leftBottomPanel, BorderLayout.WEST);
|
|
|
+ bottomPanel.add(rightBottomPanel, BorderLayout.EAST);
|
|
|
+ add(bottomPanel, BorderLayout.SOUTH);
|
|
|
+ }
|
|
|
+
|
|
|
+ private JPanel createPlcStatusPanel() {
|
|
|
+ JPanel plcStatusPanel = new JPanel(new GridLayout(3, 1, 0, 3));
|
|
|
+ plcStatusPanel.setBackground(Color.WHITE);
|
|
|
+ plcStatusPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
|
|
|
+
|
|
|
+ JPanel firstLine = createPlcStatusLine();
|
|
|
+ addPlcStatusItem(firstLine, "allowStart", "允许启动", true);
|
|
|
+ addPlcStatusItem(firstLine, "allowDown", "允许下料", true);
|
|
|
+ plcStatusPanel.add(firstLine);
|
|
|
+
|
|
|
+ JPanel secondLine = createPlcStatusLine();
|
|
|
+ addPlcStatusItem(secondLine, "start", "开始加工", false);
|
|
|
+ addPlcStatusItem(secondLine, "finish", "加工结束", false);
|
|
|
+ plcStatusPanel.add(secondLine);
|
|
|
+
|
|
|
+ JPanel thirdLine = createPlcStatusLine();
|
|
|
+ addPlcStatusItem(thirdLine, "fault", "故障", false);
|
|
|
+ plcStatusPanel.add(thirdLine);
|
|
|
+ return plcStatusPanel;
|
|
|
+ }
|
|
|
+
|
|
|
+ private JPanel createPlcStatusLine() {
|
|
|
+ JPanel linePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 14, 0));
|
|
|
+ linePanel.setBackground(Color.WHITE);
|
|
|
+ return linePanel;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addPlcStatusItem(JPanel parent, final String key, String title, boolean clickable) {
|
|
|
+ JPanel itemPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 0));
|
|
|
+ itemPanel.setBackground(Color.WHITE);
|
|
|
+
|
|
|
+ JLabel titleLabel = new JLabel(title);
|
|
|
+ titleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
|
|
|
+ titleLabel.setPreferredSize(new Dimension(62, 20));
|
|
|
+ titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
|
|
|
+ itemPanel.add(titleLabel);
|
|
|
+
|
|
|
+ JLabel dotLabel = new JLabel(greyDotIcon());
|
|
|
+ dotLabel.setPreferredSize(new Dimension(20, 20));
|
|
|
+ if (clickable) {
|
|
|
+ dotLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
|
+ titleLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
|
+ MouseAdapter adapter = new MouseAdapter() {
|
|
|
+ @Override
|
|
|
+ public void mouseClicked(MouseEvent e) {
|
|
|
+ toggleWritablePlcStatus(key);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ dotLabel.addMouseListener(adapter);
|
|
|
+ titleLabel.addMouseListener(adapter);
|
|
|
+ }
|
|
|
+ itemPanel.add(dotLabel);
|
|
|
+
|
|
|
+ plcStatusDots.put(key, dotLabel);
|
|
|
+ plcStatusValues.put(key, false);
|
|
|
+ parent.add(itemPanel);
|
|
|
+ }
|
|
|
+
|
|
|
+ private ImageIcon greenDotIcon() {
|
|
|
+ return new ImageIcon(getClass().getResource("/bg/green_dot.png"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private ImageIcon greyDotIcon() {
|
|
|
+ return new ImageIcon(getClass().getResource("/bg/grey_dot.png"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void toggleWritablePlcStatus(final String key) {
|
|
|
+ if (stationConfig == null) {
|
|
|
+ JOptionPane.showMessageDialog(this, "未加载PLC工位配置,无法切换状态", "提示", JOptionPane.WARNING_MESSAGE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ final boolean newValue = !Boolean.TRUE.equals(plcStatusValues.get(key));
|
|
|
+ String statusName = "allowStart".equals(key) ? "允许启动" : "允许下料";
|
|
|
+ String actionName = newValue ? "开启" : "关闭";
|
|
|
+ int confirm = JOptionPane.showConfirmDialog(
|
|
|
+ this,
|
|
|
+ "确定要" + actionName + "【" + statusName + "】吗?",
|
|
|
+ "确认更改",
|
|
|
+ JOptionPane.YES_NO_OPTION,
|
|
|
+ JOptionPane.QUESTION_MESSAGE);
|
|
|
+ if (confirm != JOptionPane.YES_OPTION) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ setPlcStatusDot(key, newValue);
|
|
|
+
|
|
|
+ SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
|
|
|
+ @Override
|
|
|
+ protected Boolean doInBackground() {
|
|
|
+ if ("allowStart".equals(key)) {
|
|
|
+ return PLCUtils.writeAllowStart(stationConfig, newValue);
|
|
|
+ }
|
|
|
+ if ("allowDown".equals(key)) {
|
|
|
+ return PLCUtils.writeAllowDown(stationConfig, newValue);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void done() {
|
|
|
+ try {
|
|
|
+ if (!get()) {
|
|
|
+ setPlcStatusDot(key, !newValue);
|
|
|
+ }
|
|
|
+ } catch (Exception ex) {
|
|
|
+ setPlcStatusDot(key, !newValue);
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, "PLC状态切换失败:" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ worker.execute();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setPlcStatusDot(String key, boolean value) {
|
|
|
+ plcStatusValues.put(key, value);
|
|
|
+ JLabel dot = plcStatusDots.get(key);
|
|
|
+ if (dot != null) {
|
|
|
+ dot.setIcon(value ? greenDotIcon() : greyDotIcon());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void checkQuality(String sn) {
|
|
|
+ JSONObject retObj = DataUtil.checkQuality(sn, currentUser, gw, lineSn, serverIp);
|
|
|
+ if (retObj != null && "true".equalsIgnoreCase(retObj.getString("result"))) {
|
|
|
+ statusLabel.setForeground(Color.GREEN);
|
|
|
+ statusLabel.setText("该工件可以加工");
|
|
|
+ checkQualityResult = true;
|
|
|
+ workStatus = 1;
|
|
|
+ finishOkButton.setEnabled(true);
|
|
|
+ finishNgButton.setEnabled(true);
|
|
|
+
|
|
|
+ if ("1".equals(retObj.getString("fx"))) {
|
|
|
+ fxLabel.setVisible(true);
|
|
|
+ } else {
|
|
|
+ fxLabel.setVisible(false);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ statusLabel.setForeground(Color.RED);
|
|
|
+ String msg = (retObj != null && retObj.containsKey("message")) ? retObj.getString("message") : "检查失败";
|
|
|
+ statusLabel.setText(msg);
|
|
|
+ checkQualityResult = false;
|
|
|
+ workStatus = 0;
|
|
|
+ fxLabel.setVisible(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void submitResult(String result) {
|
|
|
+ if (workStatus == 1 && checkQualityResult) {
|
|
|
+ String sn = productSnField.getText().trim();
|
|
|
+ if (sn.isEmpty()) {
|
|
|
+ statusLabel.setForeground(Color.RED);
|
|
|
+ statusLabel.setText("工件码为空,请重试");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject retObj = DataUtil.sendQuality(sn, result, currentUser, gw, lineSn, serverIp);
|
|
|
+ if (retObj != null && "true".equalsIgnoreCase(retObj.getString("result"))) {
|
|
|
+ resetState();
|
|
|
+ statusLabel.setForeground(Color.GREEN);
|
|
|
+ statusLabel.setText("结果提交成功,请扫下一件");
|
|
|
+ finishNgButton.setEnabled(false);
|
|
|
+ } else {
|
|
|
+ statusLabel.setForeground(Color.RED);
|
|
|
+ String msg = (retObj != null && retObj.containsKey("message")) ? retObj.getString("message") : "提交失败";
|
|
|
+ statusLabel.setText(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void resetState() {
|
|
|
+ workStatus = 0;
|
|
|
+ plcStatus = 0;
|
|
|
+ checkQualityResult = false;
|
|
|
+ productSnField.setText("");
|
|
|
+ finishOkButton.setEnabled(false);
|
|
|
+ fxLabel.setVisible(false);
|
|
|
+ lastWeldingParamContent = "";
|
|
|
+ stopWeldingParamSampler();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void resetScanA() {
|
|
|
+ JSONObject retObj = DataUtil.delCurSn(gw, serverIp, lineSn);
|
|
|
+ if (retObj.get("result")!=null && retObj.get("result").toString().equalsIgnoreCase("true")) {
|
|
|
+ this.workStatus = 0;
|
|
|
+ this.checkQualityResult = false;
|
|
|
+ finishOkButton.setEnabled(false);
|
|
|
+// finishNgButton.setEnabled(false);
|
|
|
+ productSnField.setText("");
|
|
|
+ fxLabel.setVisible(false);
|
|
|
+ lastWeldingParamContent = "";
|
|
|
+ stopWeldingParamSampler();
|
|
|
+ PLCUtils.writeStartfalseMethod(stationConfig);
|
|
|
+ scanButton.setEnabled(true);
|
|
|
+ statusLabel.setText("请扫工件码");
|
|
|
+// MesClient.setMenuStatus("开班点检,请先进行OKNG样件测试",-1);
|
|
|
+
|
|
|
+ updateMaterailData();
|
|
|
+// shiftUserCheck();
|
|
|
+ } else {
|
|
|
+ statusLabel.setText("刷新失败");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ public static void updateMaterailData(){
|
|
|
+ try{
|
|
|
+ JSONObject retObj = DataUtil.getBindMaterail();
|
|
|
+ if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
|
|
|
+ List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
|
|
|
+
|
|
|
+ int i = 0;
|
|
|
+ for (BindMaterialResp bindMaterialResp:arrs){
|
|
|
+ rowData[i][0] = bindMaterialResp.getMaterialTitle();
|
|
|
+ rowData[i][1] = bindMaterialResp.getBatchSn();
|
|
|
+ rowData[i][2] = bindMaterialResp.getLastTimes();
|
|
|
+ rowData[i][3] = "";
|
|
|
+ rowData[i][4] = bindMaterialResp.getCraft();
|
|
|
+ rowData[i][5] = bindMaterialResp.getMaterialId();
|
|
|
+ rowData[i][6] = bindMaterialResp.getType();
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+
|
|
|
+// MesClient.table.repaint();
|
|
|
+ }
|
|
|
+ }catch (Exception e){
|
|
|
+ log.info(e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ private void startHeartBeatTimer() {
|
|
|
+ if (heartBeatTimer != null) {
|
|
|
+ heartBeatTimer.cancel();
|
|
|
+ }
|
|
|
+
|
|
|
+ heartBeatTimer = new Timer();
|
|
|
+ heartBeatTimer.schedule(new TimerTask() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ if (iconREDFlag) {
|
|
|
+ heartBeatLabel.setIcon(new ImageIcon(getClass().getResource("/bg/grey_dot.png")));
|
|
|
+ iconREDFlag = false;
|
|
|
+ } else {
|
|
|
+ heartBeatLabel.setIcon(new ImageIcon(getClass().getResource("/bg/green_dot.png")));
|
|
|
+ iconREDFlag = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }, 100, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void startPlcStatusTimer() {
|
|
|
+ if (plcStatusTimer != null) {
|
|
|
+ plcStatusTimer.cancel();
|
|
|
+ }
|
|
|
+ plcStatusTimer = new Timer();
|
|
|
+ long initialDelay = 500L + Math.abs(gw == null ? 0 : gw.hashCode() % 2000);
|
|
|
+ plcStatusTimer.schedule(new TimerTask() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ refreshPlcStatus();
|
|
|
+ }
|
|
|
+ }, initialDelay, PLC_STATUS_REFRESH_INTERVAL_MS);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void refreshPlcStatus() {
|
|
|
+ if (stationConfig == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ if (now < nextPlcStatusReadTime) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ final PLCUtils.StationStatus status = PLCUtils.readStationStatus(stationConfig);
|
|
|
+ plcStatusReadFailCount = 0;
|
|
|
+ nextPlcStatusReadTime = 0L;
|
|
|
+ SwingUtilities.invokeLater(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ setPlcStatusDot("allowStart", status.isAllowStart());
|
|
|
+ setPlcStatusDot("allowDown", status.isAllowDown());
|
|
|
+ setPlcStatusDot("start", status.isStart());
|
|
|
+ setPlcStatusDot("finish", status.isFinish());
|
|
|
+ setPlcStatusDot("fault", status.isFault());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (Exception e) {
|
|
|
+ plcStatusReadFailCount++;
|
|
|
+ nextPlcStatusReadTime = now + PLC_STATUS_RETRY_BACKOFF_MS;
|
|
|
+ if (now - lastPlcStatusWarnTime >= PLC_STATUS_WARN_INTERVAL_MS) {
|
|
|
+ lastPlcStatusWarnTime = now;
|
|
|
+ log.warn("读取PLC状态失败,工位={},连续失败{}次,{}ms后重试", gw, plcStatusReadFailCount, PLC_STATUS_RETRY_BACKOFF_MS, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void startGetCurSn(){
|
|
|
+ if (getSnBeatTimer != null) {
|
|
|
+ getSnBeatTimer.cancel();
|
|
|
+ }
|
|
|
+ getSnBeatTimer = new Timer();
|
|
|
+ getSnBeatTimer.schedule(new TimerTask() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ runWorkFlowSafely();
|
|
|
+ }
|
|
|
+
|
|
|
+ }, 100, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void runWorkFlowSafely() {
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ if (now < nextPlcWorkflowTime) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ runWorkFlow();
|
|
|
+ plcWorkflowFailCount = 0;
|
|
|
+ nextPlcWorkflowTime = 0L;
|
|
|
+ } catch (Exception e) {
|
|
|
+ handleWorkflowException(e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void runWorkFlow() {
|
|
|
+ if (workStatus == 1) {
|
|
|
+ if (plcStatus == 0){
|
|
|
+ // 等待扫码
|
|
|
+ String sn = productSnField.getText().trim();
|
|
|
+ if (!sn.isEmpty()) {
|
|
|
+ plcStatus = 1;
|
|
|
+ }
|
|
|
+ } else if (plcStatus == 1) {
|
|
|
+ // 质量检查合格后,发送允许启动信号。
|
|
|
+ Boolean ret = PLCUtils.writeStartMethod(stationConfig);
|
|
|
+ if (ret) {
|
|
|
+ statusLabel.setForeground(Color.GREEN);
|
|
|
+ statusLabel.setText("已允许启动,等待开始加工");
|
|
|
+ plcStatus = 2;
|
|
|
+ }
|
|
|
+ } else if (plcStatus == 2) {
|
|
|
+ // 等待开始加工信号为 true,收到后将允许启动置为 false。
|
|
|
+ Boolean ret = PLCUtils.readStartMethod(stationConfig);
|
|
|
+ System.out.println("开始加工信号"+stationConfig.getGw()+ret);
|
|
|
+ if (ret){
|
|
|
+ boolean ret2 = PLCUtils.writeStopMethod(stationConfig);
|
|
|
+ if (ret2) {
|
|
|
+ startWeldingParamSampler();
|
|
|
+ statusLabel.setForeground(Color.GREEN);
|
|
|
+ statusLabel.setText("加工中,等待加工结束");
|
|
|
+ plcStatus = 3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (plcStatus ==3) {
|
|
|
+ // 等待加工结束信号为 true,提交结果后发送允许下料信号。
|
|
|
+ Boolean ret = PLCUtils.readStopMethod(stationConfig);
|
|
|
+ if (ret){
|
|
|
+ // 发送结果
|
|
|
+ String sn = productSnField.getText().trim();
|
|
|
+ if (lastWeldingParamContent == null || lastWeldingParamContent.trim().isEmpty()) {
|
|
|
+ lastWeldingParamContent = stopWeldingParamSamplerAndGetContent();
|
|
|
+ log.info("PLC中读取"+lastWeldingParamContent);
|
|
|
+ }
|
|
|
+ JSONObject retObj = DataUtil.sendQuality( sn,"OK", currentUser, gw, lineSn, serverIp);
|
|
|
+ if (retObj != null && "true".equalsIgnoreCase(retObj.getString("result"))) {
|
|
|
+ if (lastWeldingParamContent != null && !lastWeldingParamContent.trim().isEmpty()) {
|
|
|
+ JSONObject saveParamRet = DataUtil.saveWeldingParams(sn, gw, lineSn, serverIp, lastWeldingParamContent);
|
|
|
+ if (saveParamRet == null || !"true".equalsIgnoreCase(saveParamRet.getString("result"))) {
|
|
|
+ log.warn("焊接参数上传失败,工位={}, 工件码={}", gw, sn);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Boolean downRet = PLCUtils.writeDownMethod(stationConfig);
|
|
|
+ if (downRet) {
|
|
|
+ statusLabel.setForeground(Color.GREEN);
|
|
|
+ statusLabel.setText("已允许下料,等待加工结束信号复位");
|
|
|
+ finishOkButton.setEnabled(false);
|
|
|
+ finishNgButton.setEnabled(false);
|
|
|
+ plcStatus = 4;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ statusLabel.setForeground(Color.RED);
|
|
|
+ String msg = (retObj != null && retObj.containsKey("message")) ? retObj.getString("message") : "提交失败";
|
|
|
+ statusLabel.setText(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }else if (plcStatus == 4){
|
|
|
+ // 等待加工结束信号为 false,收到后将允许下料置为 false。
|
|
|
+ Boolean ret = PLCUtils.readStopMethod(stationConfig);
|
|
|
+ if (!ret){
|
|
|
+ PLCUtils.writeDownStopMethod(stationConfig);
|
|
|
+ resetState();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
+ } else if (workStatus == 0) {
|
|
|
+ JSONObject result = DataUtil.getCurSn(gw, serverIp, lineSn);
|
|
|
+ // 正常处理结果
|
|
|
+ if (result.containsKey("data")) {
|
|
|
+ String data = result.getString("data");
|
|
|
+ if (data != null && !data.isEmpty()) {
|
|
|
+ productSnField.setText(data);
|
|
|
+ checkQuality(data);
|
|
|
+ } else {
|
|
|
+ JOptionPane.showMessageDialog(WorkStationPanel.this, "获取工件码为空", "提示", JOptionPane.INFORMATION_MESSAGE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void handleWorkflowException(Exception e) {
|
|
|
+ plcWorkflowFailCount++;
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
+ long retryDelay = Math.min(30000L, 3000L * plcWorkflowFailCount);
|
|
|
+ nextPlcWorkflowTime = now + retryDelay;
|
|
|
+ if (now - lastPlcWorkflowWarnTime >= PLC_WORKFLOW_WARN_INTERVAL_MS) {
|
|
|
+ lastPlcWorkflowWarnTime = now;
|
|
|
+ log.warn("PLC自动流程执行失败,工位={},流程状态={},连续失败{}次,下次继续等待", gw, plcStatus, plcWorkflowFailCount, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void startWeldingParamSampler() {
|
|
|
+ if (stationConfig == null || weldingParamSampler != null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ lastWeldingParamContent = "";
|
|
|
+ weldingParamSampler = PLCUtils.startWeldingParamSampler(stationConfig);
|
|
|
+ log.info("start welding param sampler, gw={}", gw);
|
|
|
+ }
|
|
|
+
|
|
|
+ private String stopWeldingParamSamplerAndGetContent() {
|
|
|
+ PLCUtils.WeldingParamSampler sampler = weldingParamSampler;
|
|
|
+ weldingParamSampler = null;
|
|
|
+ String content;
|
|
|
+ if (sampler == null) {
|
|
|
+ content = PLCUtils.getWeldingParamContent(stationConfig);
|
|
|
+ } else {
|
|
|
+ content = sampler.stopAndGetContent();
|
|
|
+ }
|
|
|
+ hjparams = new ArrayList<>();
|
|
|
+ if (content != null && !content.trim().isEmpty()) {
|
|
|
+ hjparams.add(content);
|
|
|
+ }
|
|
|
+ log.info("stop welding param sampler, gw={}, contentLength={}", gw, content == null ? 0 : content.length());
|
|
|
+ return content;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void stopWeldingParamSampler() {
|
|
|
+ PLCUtils.WeldingParamSampler sampler = weldingParamSampler;
|
|
|
+ weldingParamSampler = null;
|
|
|
+ if (sampler != null) {
|
|
|
+ sampler.stopAndGetContent();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setCurrentUser(String user) {
|
|
|
+ this.currentUser = user;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void showCheckRecordDialog() {
|
|
|
+ JDialog dialog = new JDialog((Frame) SwingUtilities.getWindowAncestor(this),
|
|
|
+ gw + " - 点检记录", true);
|
|
|
+ dialog.setSize(1000, 600);
|
|
|
+ dialog.setLocationRelativeTo(this);
|
|
|
+
|
|
|
+ String url = "http://" + serverIp + ":8980/js/a/mes/mesProcessCheckRecord/ulist?ucode=" + currentUser + "&oprno=" + gw + "&lineSn=" + lineSn;
|
|
|
+ MesWebView checkPanel = new MesWebView(url);
|
|
|
+ checkPanel.setSize(990, 550);
|
|
|
+ dialog.add(checkPanel);
|
|
|
+
|
|
|
+ dialog.setVisible(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void showWorkRecordDialog() {
|
|
|
+ JDialog dialog = new JDialog((Frame) SwingUtilities.getWindowAncestor(this),
|
|
|
+ gw + " - 工作记录", true);
|
|
|
+ dialog.setSize(1000, 600);
|
|
|
+ dialog.setLocationRelativeTo(this);
|
|
|
+
|
|
|
+ String url = "http://" + serverIp + ":8980/js/a/mes/mesProductRecord/work?oprno=" + gw + "&lineSn=" + lineSn;
|
|
|
+ MesWebView workRecordPanel = new MesWebView(url);
|
|
|
+ workRecordPanel.setSize(990, 550);
|
|
|
+ dialog.add(workRecordPanel);
|
|
|
+
|
|
|
+ dialog.setVisible(true);
|
|
|
+ }
|
|
|
+}
|