WorkStationPanel.java 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. package com.mes.ui;
  2. import com.alibaba.fastjson2.JSONObject;
  3. import com.mes.component.MesWebView;
  4. import com.mes.device.DeviceStateReporter;
  5. import com.mes.util.PLCUtils;
  6. import com.mes.util.StationConfig;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import javax.swing.*;
  10. import javax.swing.border.TitledBorder;
  11. import java.awt.*;
  12. import java.awt.event.ActionEvent;
  13. import java.awt.event.ActionListener;
  14. import java.awt.event.MouseAdapter;
  15. import java.awt.event.MouseEvent;
  16. import java.util.ArrayList;
  17. import java.util.LinkedHashMap;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Timer;
  21. import java.util.TimerTask;
  22. public class WorkStationPanel extends JPanel {
  23. private static final Logger log = LoggerFactory.getLogger(WorkStationPanel.class);
  24. private static final long PLC_STATUS_REFRESH_INTERVAL_MS = 3000L;
  25. private static final long PLC_STATUS_RETRY_BACKOFF_MS = 10000L;
  26. private static final long PLC_STATUS_WARN_INTERVAL_MS = 30000L;
  27. private static final long PLC_WORKFLOW_WARN_INTERVAL_MS = 30000L;
  28. private String gw;
  29. private String gwDes;
  30. private String lineSn;
  31. private String serverIp;
  32. private String allowStart;
  33. private String allowDown;
  34. private String startMethod;
  35. private String stopMethod;
  36. private StationConfig stationConfig;
  37. public int workStatus = 0;
  38. public int plcStatus = 0;
  39. public boolean checkQualityResult = false;
  40. private String currentUser = "system";
  41. private String lastWeldingParamContent = "";
  42. private PLCUtils.WeldingParamSampler weldingParamSampler;
  43. public static List<String> hjparams = new ArrayList<>();
  44. public JTextField productSnField;
  45. public JButton scanButton;
  46. public JButton finishOkButton;
  47. public JButton finishNgButton;
  48. private JLabel statusLabel;
  49. private JLabel heartBeatLabel;
  50. private JLabel fxLabel;
  51. private final Map<String, JLabel> plcStatusDots = new LinkedHashMap<>();
  52. private final Map<String, Boolean> plcStatusValues = new LinkedHashMap<>();
  53. public static Object[][] rowData = null;
  54. private Timer heartBeatTimer;
  55. private Timer getSnBeatTimer;
  56. private Timer plcStatusTimer;
  57. private int plcStatusReadFailCount = 0;
  58. private long nextPlcStatusReadTime = 0L;
  59. private long lastPlcStatusWarnTime = 0L;
  60. private int plcWorkflowFailCount = 0;
  61. private long lastPlcWorkflowWarnTime = 0L;
  62. private long nextPlcWorkflowTime = 0L;
  63. private Boolean lastFaultSignal = null;
  64. private boolean iconREDFlag = true;
  65. public WorkStationPanel(String gw, String gwDes, String lineSn, String serverIp, String allowStart, String allowDown, String startMethod, String stopMethod) {
  66. this.gw = gw;
  67. this.gwDes = gwDes;
  68. this.lineSn = lineSn;
  69. this.serverIp = serverIp;
  70. this.allowStart = allowStart;
  71. this.allowDown = allowDown;
  72. this.startMethod = startMethod;
  73. this.stopMethod = stopMethod;
  74. initUI();
  75. startHeartBeatTimer();
  76. startPlcStatusTimer();
  77. startGetCurSn();
  78. }
  79. public WorkStationPanel(StationConfig stationConfig) {
  80. this.gw = stationConfig.getGw();
  81. this.gwDes = stationConfig.getGwDes();
  82. this.lineSn = stationConfig.getLineSn();
  83. this.serverIp = stationConfig.getServerIp();
  84. this.allowStart = stationConfig.getAllowStart();
  85. this.allowDown = stationConfig.getAllowDown();
  86. this.startMethod = stationConfig.getStartMethod();
  87. this.stopMethod = stationConfig.getStopMethod();
  88. this.stationConfig = stationConfig;
  89. initUI();
  90. startHeartBeatTimer();
  91. startPlcStatusTimer();
  92. startGetCurSn();
  93. }
  94. private void initUI() {
  95. setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLACK),
  96. gw + " - " + gwDes,
  97. TitledBorder.CENTER,
  98. TitledBorder.TOP,
  99. new Font("微软雅黑", Font.BOLD, 20),
  100. Color.BLUE));
  101. setLayout(new BorderLayout(5, 5));
  102. setBackground(Color.WHITE);
  103. JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 5));
  104. topPanel.setBackground(Color.WHITE);
  105. statusLabel = new JLabel("等待扫码");
  106. statusLabel.setFont(new Font("微软雅黑", Font.PLAIN, 20));
  107. statusLabel.setForeground(Color.RED);
  108. topPanel.add(statusLabel);
  109. heartBeatLabel = new JLabel(new ImageIcon(getClass().getResource("/bg/grey_dot.png")));
  110. topPanel.add(heartBeatLabel);
  111. add(topPanel, BorderLayout.NORTH);
  112. JPanel centerPanel = new JPanel();
  113. centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));
  114. centerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  115. fxLabel = new JLabel("该工件为返修件,请仔细检查");
  116. fxLabel.setFont(new Font("微软雅黑", Font.PLAIN, 16));
  117. fxLabel.setForeground(Color.RED);
  118. fxLabel.setHorizontalAlignment(SwingConstants.CENTER);
  119. fxLabel.setVisible(false);
  120. centerPanel.add(fxLabel);
  121. productSnField = new JTextField();
  122. productSnField.setHorizontalAlignment(SwingConstants.CENTER);
  123. productSnField.setEditable(false);
  124. productSnField.setFont(new Font("微软雅黑", Font.BOLD, 15));
  125. productSnField.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
  126. productSnField.setColumns(15);
  127. productSnField.setPreferredSize(new Dimension(100, 30));
  128. scanButton = new JButton("扫码");
  129. // scanButton.setIcon(new ImageIcon(getClass().getResource("/bg/scan_barcode.png")));
  130. scanButton.setFont(new Font("微软雅黑", Font.PLAIN, 15));
  131. scanButton.setPreferredSize(new Dimension(70, 30));
  132. scanButton.addActionListener(new ActionListener() {
  133. @Override
  134. public void actionPerformed(ActionEvent e) {
  135. try {
  136. JSONObject result = DataUtil.getCurSn(gw, serverIp, lineSn);
  137. if (result == null) {
  138. JOptionPane.showMessageDialog(WorkStationPanel.this, "获取工件码失败", "错误", JOptionPane.ERROR_MESSAGE);
  139. return;
  140. }
  141. // 检查是否需要登录
  142. if (result.containsKey("result") && "login".equalsIgnoreCase(result.getString("result"))) {
  143. String message = result.containsKey("message") ? result.getString("message") : "";
  144. JOptionPane.showMessageDialog(WorkStationPanel.this, "登录超时,请重新登录!\n" + message, "登录提示", JOptionPane.WARNING_MESSAGE);
  145. // 切换到登录窗口
  146. if (MultiStationClient.welcomeWin != null) {
  147. MultiStationClient.welcomeWin.setVisible(true);
  148. }
  149. return;
  150. }
  151. // 正常处理结果
  152. if (result.containsKey("data")) {
  153. String data = result.getString("data");
  154. if (data != null && !data.isEmpty()) {
  155. productSnField.setText(data);
  156. checkQuality(data);
  157. } else {
  158. JOptionPane.showMessageDialog(WorkStationPanel.this, "获取工件码为空", "提示", JOptionPane.INFORMATION_MESSAGE);
  159. }
  160. } else {
  161. JOptionPane.showMessageDialog(WorkStationPanel.this, result.get("message"), "错误", JOptionPane.ERROR_MESSAGE);
  162. }
  163. } catch (Exception ex) {
  164. JOptionPane.showMessageDialog(WorkStationPanel.this, "扫码异常: " + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  165. }
  166. }
  167. });
  168. JPanel linePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 1, 0));
  169. linePanel.add(productSnField);
  170. linePanel.add(scanButton);
  171. centerPanel.add(linePanel);
  172. JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 15, 10));
  173. buttonPanel.setBackground(Color.WHITE);
  174. finishOkButton = new JButton("OK");
  175. finishOkButton.setIcon(new ImageIcon(getClass().getResource("/bg/ok_bg.png")));
  176. finishOkButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
  177. finishOkButton.setPreferredSize(new Dimension(120, 30));
  178. finishOkButton.setEnabled(false);
  179. finishOkButton.addActionListener(new ActionListener() {
  180. @Override
  181. public void actionPerformed(ActionEvent e) {
  182. submitResult("OK");
  183. }
  184. });
  185. buttonPanel.add(finishOkButton);
  186. // NG按钮
  187. finishNgButton = new JButton("NG");
  188. finishNgButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
  189. finishNgButton.setIcon(new ImageIcon(MesClient.class.getResource("/bg/ng_bg.png")));
  190. finishNgButton.setPreferredSize(new Dimension(120, 30));
  191. finishNgButton.setEnabled(false);
  192. finishNgButton.addActionListener(new ActionListener() {
  193. @Override
  194. public void actionPerformed(ActionEvent e) {
  195. submitResult("NG");
  196. // resetScanA();
  197. }
  198. });
  199. buttonPanel.add(finishNgButton);
  200. centerPanel.add(buttonPanel);
  201. JPanel plcStatusPanel = createPlcStatusPanel();
  202. centerPanel.add(plcStatusPanel);
  203. add(centerPanel, BorderLayout.CENTER);
  204. JPanel bottomPanel = new JPanel(new BorderLayout());
  205. bottomPanel.setBackground(Color.WHITE);
  206. bottomPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
  207. JButton checkRecordButton = new JButton("点检记录");
  208. checkRecordButton.setFont(new Font("微软雅黑", Font.PLAIN, 15));
  209. checkRecordButton.setPreferredSize(new Dimension(100, 30));
  210. checkRecordButton.addActionListener(new ActionListener() {
  211. @Override
  212. public void actionPerformed(ActionEvent e) {
  213. showCheckRecordDialog();
  214. }
  215. });
  216. JButton workRecordButton = new JButton("工作记录");
  217. workRecordButton.setFont(new Font("微软雅黑", Font.PLAIN, 15));
  218. workRecordButton.setPreferredSize(new Dimension(100, 30));
  219. workRecordButton.addActionListener(new ActionListener() {
  220. @Override
  221. public void actionPerformed(ActionEvent e) {
  222. showWorkRecordDialog();
  223. }
  224. });
  225. JPanel leftBottomPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
  226. leftBottomPanel.setBackground(Color.WHITE);
  227. leftBottomPanel.add(checkRecordButton);
  228. JPanel rightBottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0));
  229. rightBottomPanel.setBackground(Color.WHITE);
  230. rightBottomPanel.add(workRecordButton);
  231. bottomPanel.add(leftBottomPanel, BorderLayout.WEST);
  232. bottomPanel.add(rightBottomPanel, BorderLayout.EAST);
  233. add(bottomPanel, BorderLayout.SOUTH);
  234. }
  235. private JPanel createPlcStatusPanel() {
  236. JPanel plcStatusPanel = new JPanel(new GridLayout(3, 1, 0, 3));
  237. plcStatusPanel.setBackground(Color.WHITE);
  238. plcStatusPanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 20));
  239. JPanel firstLine = createPlcStatusLine();
  240. addPlcStatusItem(firstLine, "allowStart", "允许启动", true);
  241. addPlcStatusItem(firstLine, "allowDown", "允许下料", true);
  242. plcStatusPanel.add(firstLine);
  243. JPanel secondLine = createPlcStatusLine();
  244. addPlcStatusItem(secondLine, "start", "开始加工", false);
  245. addPlcStatusItem(secondLine, "finish", "加工结束", false);
  246. plcStatusPanel.add(secondLine);
  247. JPanel thirdLine = createPlcStatusLine();
  248. addPlcStatusItem(thirdLine, "fault", "故障", false);
  249. plcStatusPanel.add(thirdLine);
  250. return plcStatusPanel;
  251. }
  252. private JPanel createPlcStatusLine() {
  253. JPanel linePanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 14, 0));
  254. linePanel.setBackground(Color.WHITE);
  255. return linePanel;
  256. }
  257. private void addPlcStatusItem(JPanel parent, final String key, String title, boolean clickable) {
  258. JPanel itemPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 0));
  259. itemPanel.setBackground(Color.WHITE);
  260. JLabel titleLabel = new JLabel(title);
  261. titleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14));
  262. titleLabel.setPreferredSize(new Dimension(62, 20));
  263. titleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
  264. itemPanel.add(titleLabel);
  265. JLabel dotLabel = new JLabel(greyDotIcon());
  266. dotLabel.setPreferredSize(new Dimension(20, 20));
  267. if (clickable) {
  268. dotLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
  269. titleLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
  270. MouseAdapter adapter = new MouseAdapter() {
  271. @Override
  272. public void mouseClicked(MouseEvent e) {
  273. toggleWritablePlcStatus(key);
  274. }
  275. };
  276. dotLabel.addMouseListener(adapter);
  277. titleLabel.addMouseListener(adapter);
  278. }
  279. itemPanel.add(dotLabel);
  280. plcStatusDots.put(key, dotLabel);
  281. plcStatusValues.put(key, false);
  282. parent.add(itemPanel);
  283. }
  284. private ImageIcon greenDotIcon() {
  285. return new ImageIcon(getClass().getResource("/bg/green_dot.png"));
  286. }
  287. private ImageIcon greyDotIcon() {
  288. return new ImageIcon(getClass().getResource("/bg/grey_dot.png"));
  289. }
  290. private void toggleWritablePlcStatus(final String key) {
  291. if (stationConfig == null) {
  292. JOptionPane.showMessageDialog(this, "未加载PLC工位配置,无法切换状态", "提示", JOptionPane.WARNING_MESSAGE);
  293. return;
  294. }
  295. final boolean newValue = !Boolean.TRUE.equals(plcStatusValues.get(key));
  296. String statusName = "allowStart".equals(key) ? "允许启动" : "允许下料";
  297. String actionName = newValue ? "开启" : "关闭";
  298. int confirm = JOptionPane.showConfirmDialog(
  299. this,
  300. "确定要" + actionName + "【" + statusName + "】吗?",
  301. "确认更改",
  302. JOptionPane.YES_NO_OPTION,
  303. JOptionPane.QUESTION_MESSAGE);
  304. if (confirm != JOptionPane.YES_OPTION) {
  305. return;
  306. }
  307. setPlcStatusDot(key, newValue);
  308. SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
  309. @Override
  310. protected Boolean doInBackground() {
  311. if ("allowStart".equals(key)) {
  312. return PLCUtils.writeAllowStart(stationConfig, newValue);
  313. }
  314. if ("allowDown".equals(key)) {
  315. return PLCUtils.writeAllowDown(stationConfig, newValue);
  316. }
  317. return false;
  318. }
  319. @Override
  320. protected void done() {
  321. try {
  322. if (!get()) {
  323. setPlcStatusDot(key, !newValue);
  324. }
  325. } catch (Exception ex) {
  326. setPlcStatusDot(key, !newValue);
  327. JOptionPane.showMessageDialog(WorkStationPanel.this, "PLC状态切换失败:" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  328. }
  329. }
  330. };
  331. worker.execute();
  332. }
  333. private void setPlcStatusDot(String key, boolean value) {
  334. plcStatusValues.put(key, value);
  335. JLabel dot = plcStatusDots.get(key);
  336. if (dot != null) {
  337. dot.setIcon(value ? greenDotIcon() : greyDotIcon());
  338. }
  339. }
  340. private void checkQuality(String sn) {
  341. JSONObject retObj = DataUtil.checkQuality(sn, currentUser, gw, lineSn, serverIp);
  342. if (retObj != null && "true".equalsIgnoreCase(retObj.getString("result"))) {
  343. statusLabel.setForeground(Color.GREEN);
  344. statusLabel.setText("该工件可以加工");
  345. checkQualityResult = true;
  346. workStatus = 1;
  347. finishOkButton.setEnabled(true);
  348. finishNgButton.setEnabled(true);
  349. if ("1".equals(retObj.getString("fx"))) {
  350. fxLabel.setVisible(true);
  351. } else {
  352. fxLabel.setVisible(false);
  353. }
  354. } else {
  355. statusLabel.setForeground(Color.RED);
  356. String msg = (retObj != null && retObj.containsKey("message")) ? retObj.getString("message") : "检查失败";
  357. statusLabel.setText(msg);
  358. checkQualityResult = false;
  359. workStatus = 0;
  360. fxLabel.setVisible(false);
  361. }
  362. }
  363. private void submitResult(String result) {
  364. if (workStatus == 1 && checkQualityResult) {
  365. String sn = productSnField.getText().trim();
  366. if (sn.isEmpty()) {
  367. statusLabel.setForeground(Color.RED);
  368. statusLabel.setText("工件码为空,请重试");
  369. return;
  370. }
  371. JSONObject retObj = DataUtil.sendQuality(sn, result, currentUser, gw, lineSn, serverIp);
  372. if (retObj != null && "true".equalsIgnoreCase(retObj.getString("result"))) {
  373. resetState();
  374. statusLabel.setForeground(Color.GREEN);
  375. statusLabel.setText("结果提交成功,请扫下一件");
  376. finishNgButton.setEnabled(false);
  377. } else {
  378. statusLabel.setForeground(Color.RED);
  379. String msg = (retObj != null && retObj.containsKey("message")) ? retObj.getString("message") : "提交失败";
  380. statusLabel.setText(msg);
  381. }
  382. }
  383. }
  384. private void resetState() {
  385. workStatus = 0;
  386. plcStatus = 0;
  387. checkQualityResult = false;
  388. productSnField.setText("");
  389. finishOkButton.setEnabled(false);
  390. fxLabel.setVisible(false);
  391. lastWeldingParamContent = "";
  392. stopWeldingParamSampler();
  393. }
  394. public void resetScanA() {
  395. JSONObject retObj = DataUtil.delCurSn(gw, serverIp, lineSn);
  396. if (retObj.get("result")!=null && retObj.get("result").toString().equalsIgnoreCase("true")) {
  397. this.workStatus = 0;
  398. this.checkQualityResult = false;
  399. finishOkButton.setEnabled(false);
  400. // finishNgButton.setEnabled(false);
  401. productSnField.setText("");
  402. fxLabel.setVisible(false);
  403. lastWeldingParamContent = "";
  404. stopWeldingParamSampler();
  405. PLCUtils.writeStartfalseMethod(stationConfig);
  406. scanButton.setEnabled(true);
  407. statusLabel.setText("请扫工件码");
  408. // MesClient.setMenuStatus("开班点检,请先进行OKNG样件测试",-1);
  409. updateMaterailData();
  410. // shiftUserCheck();
  411. } else {
  412. statusLabel.setText("刷新失败");
  413. }
  414. }
  415. public static void updateMaterailData(){
  416. try{
  417. JSONObject retObj = DataUtil.getBindMaterail();
  418. if(retObj.get("result")!=null&&retObj.get("result").toString().equalsIgnoreCase("true")) {
  419. List<BindMaterialResp> arrs = retObj.getList("data",BindMaterialResp.class);
  420. int i = 0;
  421. for (BindMaterialResp bindMaterialResp:arrs){
  422. rowData[i][0] = bindMaterialResp.getMaterialTitle();
  423. rowData[i][1] = bindMaterialResp.getBatchSn();
  424. rowData[i][2] = bindMaterialResp.getLastTimes();
  425. rowData[i][3] = "";
  426. rowData[i][4] = bindMaterialResp.getCraft();
  427. rowData[i][5] = bindMaterialResp.getMaterialId();
  428. rowData[i][6] = bindMaterialResp.getType();
  429. i++;
  430. }
  431. // MesClient.table.repaint();
  432. }
  433. }catch (Exception e){
  434. log.info(e.getMessage());
  435. }
  436. }
  437. private void startHeartBeatTimer() {
  438. if (heartBeatTimer != null) {
  439. heartBeatTimer.cancel();
  440. }
  441. heartBeatTimer = new Timer();
  442. heartBeatTimer.schedule(new TimerTask() {
  443. @Override
  444. public void run() {
  445. if (iconREDFlag) {
  446. heartBeatLabel.setIcon(new ImageIcon(getClass().getResource("/bg/grey_dot.png")));
  447. iconREDFlag = false;
  448. } else {
  449. heartBeatLabel.setIcon(new ImageIcon(getClass().getResource("/bg/green_dot.png")));
  450. iconREDFlag = true;
  451. }
  452. }
  453. }, 100, 1000);
  454. }
  455. private void startPlcStatusTimer() {
  456. if (plcStatusTimer != null) {
  457. plcStatusTimer.cancel();
  458. }
  459. plcStatusTimer = new Timer();
  460. long initialDelay = 500L + Math.abs(gw == null ? 0 : gw.hashCode() % 2000);
  461. plcStatusTimer.schedule(new TimerTask() {
  462. @Override
  463. public void run() {
  464. refreshPlcStatus();
  465. }
  466. }, initialDelay, PLC_STATUS_REFRESH_INTERVAL_MS);
  467. }
  468. private void refreshPlcStatus() {
  469. if (stationConfig == null) {
  470. return;
  471. }
  472. long now = System.currentTimeMillis();
  473. if (now < nextPlcStatusReadTime) {
  474. return;
  475. }
  476. try {
  477. final PLCUtils.StationStatus status = PLCUtils.readStationStatus(stationConfig);
  478. reportFaultStatusIfChanged(status.isFault());
  479. plcStatusReadFailCount = 0;
  480. nextPlcStatusReadTime = 0L;
  481. SwingUtilities.invokeLater(new Runnable() {
  482. @Override
  483. public void run() {
  484. setPlcStatusDot("allowStart", status.isAllowStart());
  485. setPlcStatusDot("allowDown", status.isAllowDown());
  486. setPlcStatusDot("start", status.isStart());
  487. setPlcStatusDot("finish", status.isFinish());
  488. setPlcStatusDot("fault", status.isFault());
  489. }
  490. });
  491. } catch (Exception e) {
  492. plcStatusReadFailCount++;
  493. nextPlcStatusReadTime = now + PLC_STATUS_RETRY_BACKOFF_MS;
  494. if (now - lastPlcStatusWarnTime >= PLC_STATUS_WARN_INTERVAL_MS) {
  495. lastPlcStatusWarnTime = now;
  496. log.warn("读取PLC状态失败,工位={},连续失败{}次,{}ms后重试", gw, plcStatusReadFailCount, PLC_STATUS_RETRY_BACKOFF_MS, e);
  497. }
  498. }
  499. }
  500. private void reportFaultStatusIfChanged(boolean fault) {
  501. if (lastFaultSignal != null && lastFaultSignal.booleanValue() == fault) {
  502. return;
  503. }
  504. Boolean oldFaultSignal = lastFaultSignal;
  505. lastFaultSignal = Boolean.valueOf(fault);
  506. if (oldFaultSignal == null && !fault) {
  507. return;
  508. }
  509. String state = fault ? DeviceStateReporter.STATE_FAULT : DeviceStateReporter.STATE_RUNNING;
  510. String content = fault ? "故障" : "故障回复";
  511. DeviceStateReporter.reportAsync(serverIp, gw, lineSn, state, content);
  512. log.info("PLC故障状态变化上报,工位={},fault={},state={},content={}", gw, fault, state, content);
  513. }
  514. private void startGetCurSn(){
  515. if (getSnBeatTimer != null) {
  516. getSnBeatTimer.cancel();
  517. }
  518. getSnBeatTimer = new Timer();
  519. getSnBeatTimer.schedule(new TimerTask() {
  520. @Override
  521. public void run() {
  522. runWorkFlowSafely();
  523. }
  524. }, 100, 1000);
  525. }
  526. private void runWorkFlowSafely() {
  527. long now = System.currentTimeMillis();
  528. if (now < nextPlcWorkflowTime) {
  529. return;
  530. }
  531. try {
  532. runWorkFlow();
  533. plcWorkflowFailCount = 0;
  534. nextPlcWorkflowTime = 0L;
  535. } catch (Exception e) {
  536. handleWorkflowException(e);
  537. }
  538. }
  539. private void runWorkFlow() {
  540. if (workStatus == 1) {
  541. if (plcStatus == 0){
  542. // 等待扫码
  543. String sn = productSnField.getText().trim();
  544. if (!sn.isEmpty()) {
  545. plcStatus = 1;
  546. }
  547. } else if (plcStatus == 1) {
  548. // 质量检查合格后,发送允许启动信号。
  549. Boolean ret = PLCUtils.writeStartMethod(stationConfig);
  550. if (ret) {
  551. statusLabel.setForeground(Color.GREEN);
  552. statusLabel.setText("已允许启动,等待开始加工");
  553. plcStatus = 2;
  554. }
  555. } else if (plcStatus == 2) {
  556. // 等待开始加工信号为 true,收到后将允许启动置为 false。
  557. Boolean ret = PLCUtils.readStartMethod(stationConfig);
  558. System.out.println("开始加工信号"+stationConfig.getGw()+ret);
  559. if (ret){
  560. boolean ret2 = PLCUtils.writeStopMethod(stationConfig);
  561. if (ret2) {
  562. startWeldingParamSampler();
  563. statusLabel.setForeground(Color.GREEN);
  564. statusLabel.setText("加工中,等待加工结束");
  565. plcStatus = 3;
  566. }
  567. }
  568. } else if (plcStatus ==3) {
  569. // 等待加工结束信号为 true,提交结果后发送允许下料信号。
  570. Boolean ret = PLCUtils.readStopMethod(stationConfig);
  571. if (ret){
  572. // 发送结果
  573. String sn = productSnField.getText().trim();
  574. if (lastWeldingParamContent == null || lastWeldingParamContent.trim().isEmpty()) {
  575. lastWeldingParamContent = stopWeldingParamSamplerAndGetContent();
  576. log.info("PLC中读取"+lastWeldingParamContent);
  577. }
  578. JSONObject retObj = DataUtil.sendQuality( sn,"OK", currentUser, gw, lineSn, serverIp);
  579. if (retObj != null && "true".equalsIgnoreCase(retObj.getString("result"))) {
  580. if (lastWeldingParamContent != null && !lastWeldingParamContent.trim().isEmpty()) {
  581. JSONObject saveParamRet = DataUtil.saveWeldingParams(sn, gw, lineSn, serverIp, lastWeldingParamContent);
  582. if (saveParamRet == null || !"true".equalsIgnoreCase(saveParamRet.getString("result"))) {
  583. log.warn("焊接参数上传失败,工位={}, 工件码={}", gw, sn);
  584. }
  585. }
  586. Boolean downRet = PLCUtils.writeDownMethod(stationConfig);
  587. if (downRet) {
  588. statusLabel.setForeground(Color.GREEN);
  589. statusLabel.setText("已允许下料,等待加工结束信号复位");
  590. finishOkButton.setEnabled(false);
  591. finishNgButton.setEnabled(false);
  592. plcStatus = 4;
  593. }
  594. } else {
  595. statusLabel.setForeground(Color.RED);
  596. String msg = (retObj != null && retObj.containsKey("message")) ? retObj.getString("message") : "提交失败";
  597. statusLabel.setText(msg);
  598. }
  599. }
  600. }else if (plcStatus == 4){
  601. // 等待加工结束信号为 false,收到后将允许下料置为 false。
  602. Boolean ret = PLCUtils.readStopMethod(stationConfig);
  603. if (!ret){
  604. PLCUtils.writeDownStopMethod(stationConfig);
  605. resetState();
  606. }
  607. }
  608. return;
  609. } else if (workStatus == 0) {
  610. JSONObject result = DataUtil.getCurSn(gw, serverIp, lineSn);
  611. // 正常处理结果
  612. if (result.containsKey("data")) {
  613. String data = result.getString("data");
  614. if (data != null && !data.isEmpty()) {
  615. productSnField.setText(data);
  616. checkQuality(data);
  617. } else {
  618. JOptionPane.showMessageDialog(WorkStationPanel.this, "获取工件码为空", "提示", JOptionPane.INFORMATION_MESSAGE);
  619. }
  620. }
  621. }
  622. }
  623. private void handleWorkflowException(Exception e) {
  624. plcWorkflowFailCount++;
  625. long now = System.currentTimeMillis();
  626. long retryDelay = Math.min(30000L, 3000L * plcWorkflowFailCount);
  627. nextPlcWorkflowTime = now + retryDelay;
  628. if (now - lastPlcWorkflowWarnTime >= PLC_WORKFLOW_WARN_INTERVAL_MS) {
  629. lastPlcWorkflowWarnTime = now;
  630. log.warn("PLC自动流程执行失败,工位={},流程状态={},连续失败{}次,下次继续等待", gw, plcStatus, plcWorkflowFailCount, e);
  631. }
  632. }
  633. private void startWeldingParamSampler() {
  634. if (stationConfig == null || weldingParamSampler != null) {
  635. return;
  636. }
  637. lastWeldingParamContent = "";
  638. weldingParamSampler = PLCUtils.startWeldingParamSampler(stationConfig);
  639. log.info("start welding param sampler, gw={}", gw);
  640. }
  641. private String stopWeldingParamSamplerAndGetContent() {
  642. PLCUtils.WeldingParamSampler sampler = weldingParamSampler;
  643. weldingParamSampler = null;
  644. String content;
  645. if (sampler == null) {
  646. content = PLCUtils.getWeldingParamContent(stationConfig);
  647. } else {
  648. content = sampler.stopAndGetContent();
  649. }
  650. hjparams = new ArrayList<>();
  651. if (content != null && !content.trim().isEmpty()) {
  652. hjparams.add(content);
  653. }
  654. log.info("stop welding param sampler, gw={}, contentLength={}", gw, content == null ? 0 : content.length());
  655. return content;
  656. }
  657. private void stopWeldingParamSampler() {
  658. PLCUtils.WeldingParamSampler sampler = weldingParamSampler;
  659. weldingParamSampler = null;
  660. if (sampler != null) {
  661. sampler.stopAndGetContent();
  662. }
  663. }
  664. public void setCurrentUser(String user) {
  665. this.currentUser = user;
  666. }
  667. private void showCheckRecordDialog() {
  668. JDialog dialog = new JDialog((Frame) SwingUtilities.getWindowAncestor(this),
  669. gw + " - 点检记录", true);
  670. dialog.setSize(1000, 600);
  671. dialog.setLocationRelativeTo(this);
  672. String url = "http://" + serverIp + ":8980/js/a/mes/mesProcessCheckRecord/ulist?ucode=" + currentUser + "&oprno=" + gw + "&lineSn=" + lineSn;
  673. MesWebView checkPanel = new MesWebView(url);
  674. checkPanel.setSize(990, 550);
  675. dialog.add(checkPanel);
  676. dialog.setVisible(true);
  677. }
  678. private void showWorkRecordDialog() {
  679. JDialog dialog = new JDialog((Frame) SwingUtilities.getWindowAncestor(this),
  680. gw + " - 工作记录", true);
  681. dialog.setSize(1000, 600);
  682. dialog.setLocationRelativeTo(this);
  683. String url = "http://" + serverIp + ":8980/js/a/mes/mesProductRecord/work?oprno=" + gw + "&lineSn=" + lineSn;
  684. MesWebView workRecordPanel = new MesWebView(url);
  685. workRecordPanel.setSize(990, 550);
  686. dialog.add(workRecordPanel);
  687. dialog.setVisible(true);
  688. }
  689. }