| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- package com.mes.ui;
- import com.alibaba.fastjson2.JSONObject;
- import com.mes.component.MesWebView;
- import com.mes.device.DeviceStateReporter;
- import com.mes.util.ConfigUtils;
- import com.mes.util.JdbcUtils;
- import com.mes.util.StationConfig;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import javax.swing.*;
- import java.awt.*;
- import java.awt.event.WindowAdapter;
- import java.awt.event.WindowEvent;
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Properties;
- import java.util.Timer;
- import java.util.TimerTask;
- import static com.mes.ui.WorkStationPanel.*;
- public class MultiStationClient extends JFrame {
- private static final Logger log = LoggerFactory.getLogger(MultiStationClient.class);
- private static final int DEFAULT_DEVICE_HEARTBEAT_MINUTES = 5;
- private static int deviceHeartbeatMinutes = DEFAULT_DEVICE_HEARTBEAT_MINUTES;
- private List<WorkStationPanel> stationPanels = new ArrayList<>();
- // 当前工作站配置中的所有工位,用于开机、心跳、停机逐个上报。
- private List<StationConfig> stationConfigs = new ArrayList<>();
- private Timer deviceReportTimer;
- // 避免窗口关闭和退出菜单连续触发时重复上报停机。
- private boolean deviceStopReported = true;
- private JButton userMenu;
- private JLabel statusLabel;
- private JLabel heartBeatLabel;
- public static JFrame welcomeWin;
- public static MultiStationClient mainFrame;
- public static JScrollPane searchScrollPaneWork; // 已弃用,改为使用WebView
- public static JScrollPane searchScrollPaneCheck;
- public static JPanel indexPaneWork; // 已弃用,改为使用WebView
- public static JPanel indexPaneCheck;
- public static MesWebView workRecordPanel = null;
- public static MesWebView checkPanel = null;
- public static void main(String[] args) {
- /* if (LockUtil.getInstance().isAppActive()) {
- JOptionPane.showMessageDialog(null, "已有一个程序在运行,程序退出");
- return;
- }*/
- EventQueue.invokeLater(() -> {
- try {
- MesClient.readProperty();
- Properties props = ConfigUtils.loadProperties();
- // 设备运行心跳间隔可通过 mes.device.heartbeat.minutes 配置,未配置默认 5 分钟。
- deviceHeartbeatMinutes = parseDeviceHeartbeatMinutes(props);
- log.info("client config={}, stations={}, proxyEnabled={}, proxyBaseUrl={}",
- ConfigUtils.getConfigPath(),
- props.getProperty("mes.stations", ""),
- props.getProperty("plc.proxy.enabled", "false"),
- props.getProperty("plc.proxy.base_url", ""));
- System.out.println("client config=" + ConfigUtils.getConfigPath()
- + ", stations=" + props.getProperty("mes.stations", "")
- + ", proxy=" + props.getProperty("plc.proxy.base_url", ""));
- JdbcUtils.getConn();
- welcomeWin = new LoginFarme();
- welcomeWin.setVisible(true);
- MultiStationClient frame = new MultiStationClient();
- frame.setVisible(false);
- } catch (Exception e) {
- e.printStackTrace();
- JOptionPane.showMessageDialog(null, "启动失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
- }
- });
- }
-
- public MultiStationClient() {
- mainFrame = this;
- initUI();
- }
-
- private void initUI() {
- setTitle("MES系统客户端 - 多工位模式");
- setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- int choice = JOptionPane.showConfirmDialog(null, "确定要关闭窗口吗?", "关闭确认",
- JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (choice == JOptionPane.YES_OPTION) {
- // 关闭窗口视为设备停机,先同步上报所有工位再退出。
- reportDeviceStopped();
- dispose();
- System.exit(0);
- }
- }
- });
-
- setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("/bg/logo.png")));
-
- JMenuBar menuBar = new JMenuBar();
- setJMenuBar(menuBar);
-
- JMenu fileMenu = new JMenu("用户");
- fileMenu.setIcon(new ImageIcon(getClass().getResource("/bg/user.png")));
- fileMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- menuBar.add(fileMenu);
-
- JMenuItem exitMenuItem = new JMenuItem("退出");
- exitMenuItem.setIcon(new ImageIcon(getClass().getResource("/bg/logoff.png")));
- exitMenuItem.setFont(new Font("微软雅黑", Font.PLAIN, 18));
- exitMenuItem.addActionListener(e -> {
- int choice = JOptionPane.showConfirmDialog(null, "确定要退出吗?", "退出确认",
- JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
- if (choice == JOptionPane.YES_OPTION) {
- // 菜单退出同样视为设备停机。
- reportDeviceStopped();
- System.exit(0);
- }
- });
- fileMenu.add(exitMenuItem);
-
- JMenu settingMenu = new JMenu("设置");
- settingMenu.setIcon(new ImageIcon(getClass().getResource("/bg/menu_setting.png")));
- settingMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- menuBar.add(settingMenu);
- JToolBar toolBar = new JToolBar();
- toolBar.setFloatable(false);
-
- JLabel statusLabelTitle = new JLabel("状态:");
- statusLabelTitle.setFont(new Font("微软雅黑", Font.PLAIN, 24));
- toolBar.add(statusLabelTitle);
-
- statusLabel = new JLabel("已连接MES服务器");
- statusLabel.setForeground(Color.GREEN);
- statusLabel.setFont(new Font("微软雅黑", Font.PLAIN, 24));
- statusLabel.setBackground(Color.BLACK);
- toolBar.add(statusLabel);
-
- toolBar.add(Box.createHorizontalStrut(20));
-
- JLabel heartBeatTitle = new JLabel("心跳:");
- heartBeatTitle.setFont(new Font("微软雅黑", Font.PLAIN, 24));
- toolBar.add(heartBeatTitle);
-
- heartBeatLabel = new JLabel(new ImageIcon(getClass().getResource("/bg/green_dot.png")));
- toolBar.add(heartBeatLabel);
-
- toolBar.add(Box.createHorizontalStrut(20));
-
- JLabel userTitle = new JLabel("登录用户:");
- userTitle.setFont(new Font("微软雅黑", Font.PLAIN, 24));
- toolBar.add(userTitle);
-
- userMenu = new JButton("未知用户");
- userMenu.setForeground(Color.GREEN);
- userMenu.setFont(new Font("微软雅黑", Font.PLAIN, 24));
- userMenu.setBackground(Color.BLACK);
- toolBar.add(userMenu);
-
- add(toolBar, BorderLayout.NORTH);
- JTabbedPane tabbedPane = new JTabbedPane();
- tabbedPane.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- try {
- List<StationConfig> stations = StationConfig.loadAllStations();
- // 保存配置中的全部工位,状态上报时按列表逐个提交。
- stationConfigs = new ArrayList<>(stations);
- if (stations.isEmpty()) {
- JOptionPane.showMessageDialog(this, "未配置任何工位", "错误", JOptionPane.ERROR_MESSAGE);
- return;
- }
-
- JPanel mainPanel = new JPanel(new GridLayout(2, 3, 1, 1));
- mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
- mainPanel.setBackground(Color.WHITE);
- for (StationConfig config : stations) {
- WorkStationPanel panel = new WorkStationPanel(config);
- stationPanels.add(panel);
- mainPanel.add(panel);
- addResetMenuItem(settingMenu, panel, config);
- }
-
- tabbedPane.addTab("工作面板",new ImageIcon(MesClient.class.getResource("/bg/a_side.png")), new JScrollPane(mainPanel));
- indexPaneCheck = new JPanel();
- searchScrollPaneCheck = new JScrollPane(indexPaneCheck);
- indexPaneCheck.setLayout(null);
- // tabbedPane.addTab("开班点检", new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")),searchScrollPaneCheck);
- indexPaneWork = new JPanel();
- searchScrollPaneWork = new JScrollPane(indexPaneWork);
- // tabbedPane.addTab("生产记录",new ImageIcon(MesClient.class.getResource("/bg/menu_data_preprocess.png")),searchScrollPaneWork);
-
- add(tabbedPane, BorderLayout.CENTER);
-
- } catch (IOException e) {
- JOptionPane.showMessageDialog(this, "加载工位配置失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
- }
-
- pack();
- setExtendedState(JFrame.MAXIMIZED_BOTH);
- }
- public void setUser(String user) {
- userMenu.setText(user);
- if (stationPanels != null) {
- for (WorkStationPanel panel : stationPanels) {
- panel.setCurrentUser(user);
- }
- }
- }
- public synchronized void reportDeviceRunning() {
- deviceStopReported = false;
- // 登录成功后上报开机/运行,当前工作站内每个工位都提交一次。
- DeviceStateReporter.reportStationsAsync(stationConfigs, DeviceStateReporter.STATE_RUNNING, "工位登录,开始运行");
- startDeviceReportTimer();
- log.info("device running report submitted for {} stations", stationConfigs.size());
- }
- public synchronized void reportDeviceStopped() {
- stopDeviceReportTimer();
- if (deviceStopReported) {
- return;
- }
- // 退出程序前同步上报停机,降低异步线程未执行完就退出的风险。
- int successCount = DeviceStateReporter.reportStationsSync(stationConfigs, DeviceStateReporter.STATE_STOP, "工位退出,停止运行");
- deviceStopReported = true;
- log.info("device stop report submitted for {} stations, success={}", stationConfigs.size(), successCount);
- }
- private void startDeviceReportTimer() {
- stopDeviceReportTimer();
- long intervalMs = deviceHeartbeatMinutes * 60L * 1000L;
- deviceReportTimer = new Timer("device-report-timer", true);
- deviceReportTimer.schedule(new TimerTask() {
- @Override
- public void run() {
- // 定时补报运行状态,保持 MES 侧设备在线状态。
- DeviceStateReporter.reportStationsAsync(stationConfigs, DeviceStateReporter.STATE_RUNNING, "运行心跳");
- }
- }, intervalMs, intervalMs);
- log.info("device heartbeat timer started, intervalMinutes={}", deviceHeartbeatMinutes);
- }
- private void stopDeviceReportTimer() {
- if (deviceReportTimer != null) {
- deviceReportTimer.cancel();
- deviceReportTimer = null;
- }
- }
- private static int parseDeviceHeartbeatMinutes(Properties props) {
- try {
- int minutes = Integer.parseInt(props.getProperty("mes.device.heartbeat.minutes", String.valueOf(DEFAULT_DEVICE_HEARTBEAT_MINUTES)).trim());
- return minutes > 0 ? minutes : DEFAULT_DEVICE_HEARTBEAT_MINUTES;
- } catch (Exception e) {
- return DEFAULT_DEVICE_HEARTBEAT_MINUTES;
- }
- }
- private void addResetMenuItem(JMenu settingMenu, WorkStationPanel panel, StationConfig config) {
- JMenuItem resetMenu = new JMenuItem("刷新" + config.getGw() + "工件");
- resetMenu.setIcon(new ImageIcon(MesClient.class.getResource("/bg/reset_logo.png")));
- resetMenu.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- resetMenu.addActionListener(e -> panel.resetScanA());
- settingMenu.add(resetMenu);
- }
- }
|