| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- package com.mes.ui;
- import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
- import com.mes.util.JdbcUtils;
- import javax.swing.*;
- import javax.swing.table.DefaultTableModel;
- import java.awt.*;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Map;
- /**
- * 设备管理:IP、预设数量、按颗数区间的铆接参数配置
- */
- public class DeviceManagePanel extends JPanel {
- private static final String[] PARAM_COLUMNS = {"起始颗", "结束颗", "F-min", "F-max", "S-min", "S-max"};
- private static final int CONTENT_WIDTH = 940;
- private JTextField txtASet;
- private JTextField txtBSet;
- private JTextField txtIpA;
- private JTextField txtIpB;
- private DefaultTableModel tableModelA;
- private DefaultTableModel tableModelB;
- private JTable tableA;
- private JTable tableB;
- public DeviceManagePanel() {
- setLayout(null);
- setPreferredSize(new Dimension(980, 720));
- buildUi();
- loadConfigToUi();
- }
- private void buildUi() {
- Font labelFont = new Font("微软雅黑", Font.PLAIN, 18);
- Font fieldFont = new Font("微软雅黑", Font.PLAIN, 18);
- Font hintFont = new Font("微软雅黑", Font.PLAIN, 14);
- addLabel("A枪预设数量:", 20, 16, 130, 34, labelFont);
- txtASet = addField(String.valueOf(MesClient.aSetNum), 150, 16, 120, 34, fieldFont);
- addLabel("B枪预设数量:", 320, 16, 130, 34, labelFont);
- txtBSet = addField(String.valueOf(MesClient.bSetNum), 450, 16, 120, 34, fieldFont);
- addLabel("A枪IP:", 20, 58, 80, 34, labelFont);
- txtIpA = addField(MesClient.curIpA, 100, 58, 170, 34, fieldFont);
- addLabel("B枪IP:", 320, 58, 80, 34, labelFont);
- txtIpB = addField(MesClient.curIpB, 400, 58, 170, 34, fieldFont);
- addLabel("说明:S-min/S-max 为PLC原始值,界面行程显示值 = S / 1000", 20, 98, CONTENT_WIDTH, 24, hintFont);
- addLabel("A枪参数区间", 20, 128, 200, 28, labelFont);
- tableModelA = createParamTableModel();
- tableA = createParamTable(tableModelA, 20, 156, CONTENT_WIDTH, 150);
- JButton btnAddA = new JButton("A枪添加行");
- btnAddA.setFont(labelFont);
- btnAddA.setBounds(20, 316, 120, 32);
- btnAddA.addActionListener(e -> tableModelA.addRow(new Object[]{"", "", "0", "0", "0", "0"}));
- add(btnAddA);
- JButton btnDelA = new JButton("A枪删除行");
- btnDelA.setFont(labelFont);
- btnDelA.setBounds(150, 316, 120, 32);
- btnDelA.addActionListener(e -> removeSelectedRow(tableA, tableModelA));
- add(btnDelA);
- addLabel("B枪参数区间", 20, 360, 200, 28, labelFont);
- tableModelB = createParamTableModel();
- tableB = createParamTable(tableModelB, 20, 388, CONTENT_WIDTH, 150);
- JButton btnAddB = new JButton("B枪添加行");
- btnAddB.setFont(labelFont);
- btnAddB.setBounds(20, 548, 120, 32);
- btnAddB.addActionListener(e -> tableModelB.addRow(new Object[]{"", "", "0", "0", "0", "0"}));
- add(btnAddB);
- JButton btnDelB = new JButton("B枪删除行");
- btnDelB.setFont(labelFont);
- btnDelB.setBounds(150, 548, 120, 32);
- btnDelB.addActionListener(e -> removeSelectedRow(tableB, tableModelB));
- add(btnDelB);
- JButton btnSave = new JButton("保存全部设置");
- btnSave.setFont(new Font("微软雅黑", Font.PLAIN, 20));
- btnSave.setBounds(380, 596, 180, 45);
- btnSave.addActionListener(e -> saveAllConfig());
- add(btnSave);
- addLabel("每行表示「从起始颗到结束颗」使用同一套参数;开工时下发第1颗参数,每完成一颗后自动切换下一颗区间。",
- 20, 652, CONTENT_WIDTH, 40, hintFont);
- }
- private void addLabel(String text, int x, int y, int w, int h, Font font) {
- JLabel label = new JLabel("<html>" + text + "</html>");
- label.setFont(font);
- label.setBounds(x, y, w, h);
- add(label);
- }
- private JTextField addField(String text, int x, int y, int w, int h, Font font) {
- JTextField field = new JTextField(text);
- field.setFont(font);
- field.setBounds(x, y, w, h);
- add(field);
- return field;
- }
- private DefaultTableModel createParamTableModel() {
- return new DefaultTableModel(PARAM_COLUMNS, 0) {
- @Override
- public boolean isCellEditable(int row, int column) {
- return true;
- }
- };
- }
- private JTable createParamTable(DefaultTableModel model, int x, int y, int w, int h) {
- JTable table = new JTable(model);
- table.setRowHeight(28);
- table.setFont(new Font("微软雅黑", Font.PLAIN, 14));
- table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
- JScrollPane scrollPane = new JScrollPane(table);
- scrollPane.setBounds(x, y, w, h);
- add(scrollPane);
- return table;
- }
- private void removeSelectedRow(JTable table, DefaultTableModel model) {
- int row = table.getSelectedRow();
- if (row >= 0) {
- model.removeRow(row);
- }
- }
- private void loadConfigToUi() {
- txtASet.setText(String.valueOf(MesClient.aSetNum));
- txtBSet.setText(String.valueOf(MesClient.bSetNum));
- txtIpA.setText(MesClient.curIpA);
- txtIpB.setText(MesClient.curIpB);
- fillTableModel(tableModelA, JdbcUtils.getRivetParams("A"));
- fillTableModel(tableModelB, JdbcUtils.getRivetParams("B"));
- }
- // 重新从数据库加载到界面(进入设备管理页时调用)
- public void reloadFromDb() {
- Map<String, Object> config = JdbcUtils.getConfig();
- if (config.size() > 0) {
- MesClient.aSetNum = (Short) config.get("a_set_num");
- MesClient.bSetNum = (Short) config.get("b_set_num");
- MesClient.curIpA = (String) config.get("plc_ip_a");
- MesClient.curIpB = (String) config.get("plc_ip_b");
- }
- MesClient.loadRivetParamConfig();
- loadConfigToUi();
- }
- private void fillTableModel(DefaultTableModel model, List<RivetParamRange> ranges) {
- model.setRowCount(0);
- for (RivetParamRange range : ranges) {
- model.addRow(new Object[]{
- String.valueOf(range.getStartRivet()),
- String.valueOf(range.getEndRivet()),
- String.valueOf(range.getFMin()),
- String.valueOf(range.getFMax()),
- String.valueOf(range.getSMin()),
- String.valueOf(range.getSMax())
- });
- }
- }
- private List<RivetParamRange> parseTableModel(DefaultTableModel model, String gunType) throws IllegalArgumentException {
- List<RivetParamRange> ranges = new ArrayList<>();
- for (int i = 0; i < model.getRowCount(); i++) {
- String startText = String.valueOf(model.getValueAt(i, 0)).trim();
- String endText = String.valueOf(model.getValueAt(i, 1)).trim();
- if (startText.isEmpty() && endText.isEmpty()) {
- continue;
- }
- if (startText.isEmpty() || endText.isEmpty()) {
- throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行起始颗/结束颗不能为空");
- }
- int start = Integer.parseInt(startText);
- int end = Integer.parseInt(endText);
- if (start < 1 || end < start) {
- throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行颗数范围无效");
- }
- int fMin = parseIntCell(model, i, 2);
- int fMax = parseIntCell(model, i, 3);
- int sMin = parseIntCell(model, i, 4);
- int sMax = parseIntCell(model, i, 5);
- if (fMin > fMax) {
- throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行 F-min 不能大于 F-max");
- }
- if (sMin > sMax) {
- throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行 S-min 不能大于 S-max");
- }
- // PLC Int16 写入上限,避免溢出后下发错误值
- if (fMin < Short.MIN_VALUE || fMax > Short.MAX_VALUE
- || sMin < Short.MIN_VALUE || sMax > Short.MAX_VALUE) {
- throw new IllegalArgumentException(gunType + "枪第" + (i + 1) + "行参数超出范围(-32768~32767)");
- }
- RivetParamRange range = new RivetParamRange();
- range.setGunType(gunType);
- range.setStartRivet(start);
- range.setEndRivet(end);
- range.setFMin(fMin);
- range.setFMax(fMax);
- range.setSMin(sMin);
- range.setSMax(sMax);
- ranges.add(range);
- }
- if (ranges.isEmpty()) {
- throw new IllegalArgumentException(gunType + "枪至少配置一行参数区间");
- }
- // 检查区间是否重叠,重叠会导致下发时命中错误行
- for (int i = 0; i < ranges.size(); i++) {
- RivetParamRange a = ranges.get(i);
- for (int j = i + 1; j < ranges.size(); j++) {
- RivetParamRange b = ranges.get(j);
- if (a.getStartRivet() <= b.getEndRivet() && b.getStartRivet() <= a.getEndRivet()) {
- throw new IllegalArgumentException(gunType + "枪参数区间存在重叠:"
- + a.getStartRivet() + "-" + a.getEndRivet()
- + " 与 " + b.getStartRivet() + "-" + b.getEndRivet());
- }
- }
- }
- return ranges;
- }
- private int parseIntCell(DefaultTableModel model, int row, int col) {
- String text = String.valueOf(model.getValueAt(row, col)).trim();
- if (text.isEmpty()) {
- return 0;
- }
- return Integer.parseInt(text);
- }
- // 提交表格编辑并将参数下发到PLC
- private boolean pushRivetParamsToDevice(ModbusTcp plc, List<RivetParamRange> ranges, String gunType) {
- if (plc == null) {
- System.out.println(gunType + "枪PLC未连接,跳过参数下发");
- return false;
- }
- try {
- ModbusUtil.syncRivetParamsToPlc(plc, ranges);
- return true;
- } catch (Exception ex) {
- ex.printStackTrace();
- return false;
- }
- }
- private void saveAllConfig() {
- // 保存前先结束表格编辑,确保最新输入写入模型
- if (tableA != null && tableA.isEditing()) {
- tableA.getCellEditor().stopCellEditing();
- }
- if (tableB != null && tableB.isEditing()) {
- tableB.getCellEditor().stopCellEditing();
- }
- try {
- short newASet = Short.parseShort(txtASet.getText().trim());
- short newBSet = Short.parseShort(txtBSet.getText().trim());
- String newIpA = txtIpA.getText().trim();
- String newIpB = txtIpB.getText().trim();
- if (newIpA.isEmpty() || newIpB.isEmpty()) {
- JOptionPane.showMessageDialog(MesClient.mesClientFrame, "IP地址不能为空", "错误", JOptionPane.ERROR_MESSAGE);
- return;
- }
- List<RivetParamRange> rangesA = parseTableModel(tableModelA, "A");
- List<RivetParamRange> rangesB = parseTableModel(tableModelB, "B");
- boolean configOk = JdbcUtils.updateConfig(newASet, newBSet, newIpA, newIpB);
- boolean saveAOk = JdbcUtils.saveRivetParams("A", rangesA);
- boolean saveBOk = JdbcUtils.saveRivetParams("B", rangesB);
- if (!configOk || !saveAOk || !saveBOk) {
- JOptionPane.showMessageDialog(MesClient.mesClientFrame,
- "配置保存失败,请查看控制台日志后重试(常见原因:数据库被占用)",
- "错误", JOptionPane.ERROR_MESSAGE);
- // 回读数据库,避免界面显示未真正落库的值
- reloadFromDb();
- return;
- }
- MesClient.aSetNum = newASet;
- MesClient.bSetNum = newBSet;
- MesClient.rivetParamRangesA = rangesA;
- MesClient.rivetParamRangesB = rangesB;
- if (MesClient.param1 != null) {
- MesClient.param1.setText(String.valueOf(MesClient.aSetNum));
- }
- if (MesClient.param3 != null) {
- MesClient.param3.setText(String.valueOf(MesClient.bSetNum));
- }
- boolean ipAChanged = !newIpA.equals(MesClient.curIpA);
- boolean ipBChanged = !newIpB.equals(MesClient.curIpB);
- if (ipAChanged) {
- if (MesClient.plcA != null) {
- MesClient.plcA.close();
- }
- MesClient.curIpA = newIpA;
- MesClient.plcA = new ModbusTcp(1, MesClient.curIpA);
- }
- if (ipBChanged) {
- if (MesClient.plcB != null) {
- MesClient.plcB.close();
- }
- MesClient.curIpB = newIpB;
- MesClient.plcB = new ModbusTcp(1, MesClient.curIpB);
- }
- // 保存后立即将拉力/行程参数下发到设备
- boolean syncA = pushRivetParamsToDevice(MesClient.plcA, rangesA, "A");
- boolean syncB = pushRivetParamsToDevice(MesClient.plcB, rangesB, "B");
- if (syncA && syncB) {
- JOptionPane.showMessageDialog(MesClient.mesClientFrame, "配置已保存,并已下发到设备", "提示", JOptionPane.INFORMATION_MESSAGE);
- } else {
- JOptionPane.showMessageDialog(MesClient.mesClientFrame,
- "配置已保存到本地,但部分设备参数下发失败,请检查设备连接;下次开工时会按新配置重新下发",
- "提示", JOptionPane.WARNING_MESSAGE);
- }
- } catch (NumberFormatException ex) {
- JOptionPane.showMessageDialog(MesClient.mesClientFrame, "请输入有效的数字", "错误", JOptionPane.ERROR_MESSAGE);
- } catch (IllegalArgumentException ex) {
- JOptionPane.showMessageDialog(MesClient.mesClientFrame, ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
- }
- }
- }
|