package com.mes.core; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yaml.snakeyaml.Yaml; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 工位配置类 - 从YAML配置文件加载工位配置 * 解决工位号硬编码问题,支持单工位/双工位动态切换 */ public class StationConfig { private static final Logger log = LoggerFactory.getLogger(StationConfig.class); // 单例实例 private static StationConfig instance; // ========== 工位配置 ========== private String mode; // single | dual private String stationName; // 工位/工序名称(如"液冷板安装+激光点固") private List stations; // 工位列表 private String lineSn; // 线体号 // ========== 服务器配置 ========== private String serverIp; private int tcpPort; private int httpPort; // HTTP服务端口 private int heartBeatCycle; // ========== 流程配置 ========== private List workflowSteps; private String submitMode; // manual | auto (手动点击OK/NG | 自动提交) private Map yamlFeatures = new HashMap<>(); // yaml 中定义的功能默认开关 // ========== 设备配置 ========== private boolean deviceEnabled; private String deviceType; // modbus_tcp | modbus_rtu | s7 | none private List deviceConnections; private boolean timeoutEnabled; private int connectTimeout = 3000; // Modbus连接超时(ms) private int heartbeatAddress; private int readySignalAddress; // 设备地址配置 private DeviceAddresses deviceAddresses; // 完成条件配置 private CompleteCondition completeCondition; // 心跳配置 private HeartbeatConfig heartbeatConfig; // 继电器配置 private RelayConfig relayConfig; // 过程参数采集配置 private ProdParamsConfig prodParamsConfig; // ========== UI配置 ========== private boolean showDeviceInfo; private boolean showDeviceInfo2; // 是否显示第二行设备信息 private boolean showMaterialInput; private String materialLabel; private List deviceInfoRows; // 设备信息行配置 // 原始配置Map,用于获取未解析的配置 private Map rawConfig; private StationConfig() { stations = new ArrayList<>(); workflowSteps = new ArrayList<>(); deviceConnections = new ArrayList<>(); deviceInfoRows = new ArrayList<>(); } /** * 获取单例实例 */ public static synchronized StationConfig getInstance() { if (instance == null) { instance = new StationConfig(); instance.loadFromResource("resources/config/station.yaml"); } return instance; } /** * 重新加载配置(用于热更新) */ public static synchronized void reload() { instance = new StationConfig(); instance.loadFromResource("resources/config/station.yaml"); } /** * 从指定路径加载配置 */ public static synchronized StationConfig loadFrom(String resourcePath) { instance = new StationConfig(); instance.loadFromResource(resourcePath); return instance; } /** * 从资源文件加载配置 */ private void loadFromResource(String resourcePath) { try (InputStream is = getClass().getClassLoader().getResourceAsStream(resourcePath)) { if (is == null) { log.error("配置文件不存在: {}", resourcePath); throw new RuntimeException("配置文件不存在: " + resourcePath); } Yaml yaml = new Yaml(); Map config = yaml.load(new InputStreamReader(is, StandardCharsets.UTF_8)); parseConfig(config); log.info("配置加载成功: mode={}, stations={}", mode, stations.size()); } catch (Exception e) { log.error("加载配置文件失败: {}", e.getMessage(), e); throw new RuntimeException("加载配置文件失败", e); } } /** * 展开 steps 列表:遇到 feature 块时按功能开关(含 override)过滤 * feature 块形如: * - feature: cold_plate * steps: [...] */ @SuppressWarnings("unchecked") private void expandSteps(List> stepsArr, List out) { for (Map node : stepsArr) { Object featureKey = node.get("feature"); if (featureKey != null) { String fname = featureKey.toString(); if (!isFeatureEnabled(fname)) { log.debug("跳过禁用的feature: {}", fname); continue; } List> inner = (List>) node.get("steps"); if (inner != null) { expandSteps(inner, out); } continue; } // 普通步骤 if (node.get("id") == null) continue; StepConfig stepConfig = new StepConfig(); stepConfig.setId((String) node.get("id")); stepConfig.setName((String) node.get("name")); stepConfig.setCraft((String) node.get("craft")); Map stepConfigMap = (Map) node.get("config"); if (stepConfigMap != null) { stepConfig.setConfig(stepConfigMap); } out.add(stepConfig); } } /** * 查询功能是否启用 * 优先级:运行时 override (ProjectConfigManager) > yaml 默认 > false */ public boolean isFeatureEnabled(String feature) { Boolean override = ProjectConfigManager.getInstance().getFeatureOverride(feature); if (override != null) return override; Boolean def = yamlFeatures.get(feature); return def != null && def; } /** * 获取所有 yaml 定义的功能开关(用于 UI 显示可用功能列表) */ public Map getYamlFeatures() { return new HashMap<>(yamlFeatures); } /** * 根据当前功能开关推导物料码标签: * 启用 cold_plate → "冷板码" * 启用 bottom_plate → "底护板码" * 都未启用 → yaml 配置的 materialLabel */ public String getEffectiveMaterialLabel() { if (isFeatureEnabled("cold_plate")) return "冷板码"; if (isFeatureEnabled("bottom_plate")) return "底护板码"; return materialLabel; } /** * 解析YAML配置 */ @SuppressWarnings("unchecked") private void parseConfig(Map config) { rawConfig = config; // 解析工位配置 Map stationObj = (Map) config.get("station"); if (stationObj != null) { mode = (String) stationObj.get("mode"); stationName = (String) stationObj.get("name"); lineSn = (String) stationObj.get("line_sn"); List> stationsArr = (List>) stationObj.get("stations"); if (stationsArr != null) { for (int i = 0; i < stationsArr.size(); i++) { Map s = stationsArr.get(i); stations.add(new StationInfo( i, (String) s.get("code") )); } } } // 解析服务器配置 Map serverObj = (Map) config.get("server"); if (serverObj != null) { serverIp = (String) serverObj.get("ip"); tcpPort = getIntValue(serverObj, "tcp_port", 3000); httpPort = getIntValue(serverObj, "http_port", 8980); heartBeatCycle = getIntValue(serverObj, "heart_beat_cycle", 60); } // 解析流程配置 Map workflowObj = (Map) config.get("workflow"); if (workflowObj != null) { // 提交模式:manual(手动点击OK/NG) | auto(设备信号自动提交) submitMode = (String) workflowObj.get("submit_mode"); if (submitMode == null || submitMode.isEmpty()) { submitMode = "manual"; // 默认手动模式 } // 解析功能开关(yaml 默认值) yamlFeatures.clear(); Map featuresObj = (Map) workflowObj.get("features"); if (featuresObj != null) { for (Map.Entry e : featuresObj.entrySet()) { if (e.getValue() instanceof Boolean) { yamlFeatures.put(e.getKey(), (Boolean) e.getValue()); } } } List> stepsArr = (List>) workflowObj.get("steps"); if (stepsArr != null) { expandSteps(stepsArr, workflowSteps); } } // 解析设备配置 Map deviceObj = (Map) config.get("device"); if (deviceObj != null) { deviceEnabled = getBooleanValue(deviceObj, "enabled", false); deviceType = (String) deviceObj.get("type"); timeoutEnabled = getBooleanValue(deviceObj, "timeout_enabled", false); connectTimeout = getIntValue(deviceObj, "connect_timeout", 3000); heartbeatAddress = getIntValue(deviceObj, "heartbeat_address", 4160); readySignalAddress = getIntValue(deviceObj, "ready_signal_address", 8); List> connArr = (List>) deviceObj.get("connections"); if (connArr != null) { for (int i = 0; i < connArr.size(); i++) { Map conn = connArr.get(i); deviceConnections.add(new DeviceConnection( getIntValue(conn, "station_index", i), (String) conn.get("ip"), getIntValue(conn, "port", 502) )); } } // 解析设备地址配置 Map addressesObj = (Map) deviceObj.get("addresses"); if (addressesObj != null) { deviceAddresses = new DeviceAddresses(); deviceAddresses.setEnableSignal((String) addressesObj.get("enable_signal")); deviceAddresses.setStartSignal((String) addressesObj.get("start_signal")); deviceAddresses.setCompleteSignal((String) addressesObj.get("complete_signal")); deviceAddresses.setDeviceStatus((String) addressesObj.get("device_status")); deviceAddresses.setFinishedCount(getIntValue(addressesObj, "finished_count", 0)); deviceAddresses.setPresetCount(getIntValue(addressesObj, "preset_count", 0)); deviceAddresses.setQualifiedCount(getIntValue(addressesObj, "qualified_count", 0)); deviceAddresses.setStartCommand(getIntValue(addressesObj, "start_command", 0)); } // 解析完成条件配置 Map conditionObj = (Map) deviceObj.get("complete_condition"); if (conditionObj != null) { completeCondition = new CompleteCondition(); completeCondition.setType((String) conditionObj.get("type")); completeCondition.setRunningValue(getIntValue(conditionObj, "running_value", 1)); completeCondition.setStoppedValue(getIntValue(conditionObj, "stopped_value", 0)); completeCondition.setMinRunningTime(getIntValue(conditionObj, "min_running_time", 0)); } else { // 默认使用信号判断 completeCondition = new CompleteCondition(); completeCondition.setType("signal"); } // 解析心跳配置 Map heartbeatObj = (Map) deviceObj.get("heartbeat"); if (heartbeatObj != null) { heartbeatConfig = new HeartbeatConfig(); heartbeatConfig.setEnabled(getBooleanValue(heartbeatObj, "enabled", true)); heartbeatConfig.setAddress(getIntValue(heartbeatObj, "address", 4160)); heartbeatConfig.setInterval(getIntValue(heartbeatObj, "interval", 500)); heartbeatConfig.setTimeoutAddress(getIntValue(heartbeatObj, "timeout_address", 4170)); heartbeatConfig.setTimeoutValue(getIntValue(heartbeatObj, "timeout_value", 10)); } // 解析继电器配置 Map relayObj = (Map) deviceObj.get("relay"); if (relayObj != null) { relayConfig = new RelayConfig(); relayConfig.setEnabled(getBooleanValue(relayObj, "enabled", true)); relayConfig.setType((String) relayObj.get("type")); relayConfig.setPort((String) relayObj.get("port")); relayConfig.setBaudrate(getIntValue(relayObj, "baudrate", 38400)); relayConfig.setOpenCommand((String) relayObj.get("open_command")); relayConfig.setCloseCommand((String) relayObj.get("close_command")); } // 解析过程参数采集配置 Map prodParamsObj = (Map) deviceObj.get("prod_params"); if (prodParamsObj != null) { prodParamsConfig = new ProdParamsConfig(); prodParamsConfig.setEnabled(getBooleanValue(prodParamsObj, "enabled", false)); prodParamsConfig.setFoutAddress(getIntValue(prodParamsObj, "fout_address", 4112)); prodParamsConfig.setSoutAddress(getIntValue(prodParamsObj, "sout_address", 4120)); prodParamsConfig.setFminAddress(getIntValue(prodParamsObj, "fmin_address", 4116)); prodParamsConfig.setSminAddress(getIntValue(prodParamsObj, "smin_address", 4126)); prodParamsConfig.setFmaxAddress(getIntValue(prodParamsObj, "fmax_address", 4114)); prodParamsConfig.setSmaxAddress(getIntValue(prodParamsObj, "smax_address", 4124)); prodParamsConfig.setQtyAddress(getIntValue(prodParamsObj, "qty_address", 4)); prodParamsConfig.setUploadInterval(getIntValue(prodParamsObj, "upload_interval", 60)); } } // 解析UI配置 Map uiObj = (Map) config.get("ui"); if (uiObj != null) { showMaterialInput = getBooleanValue(uiObj, "show_material_input", false); materialLabel = (String) uiObj.get("material_label"); // 解析设备信息行配置 List> rowsArr = (List>) uiObj.get("device_info_rows"); if (rowsArr != null && !rowsArr.isEmpty()) { for (int i = 0; i < Math.min(rowsArr.size(), 2); i++) { Map row = rowsArr.get(i); DeviceInfoRow infoRow = new DeviceInfoRow(); infoRow.setLabel((String) row.get("label")); infoRow.setConnectionIndex(getIntValue(row, "connection_index", 0)); infoRow.setPresetAddress(getIntValue(row, "preset_address", 0)); infoRow.setFinishedAddress(getIntValue(row, "finished_address", 0)); deviceInfoRows.add(infoRow); } showDeviceInfo = true; showDeviceInfo2 = deviceInfoRows.size() > 1; } else { // 兼容旧配置 showDeviceInfo = getBooleanValue(uiObj, "show_device_info", false); showDeviceInfo2 = false; } } // features 覆盖:prod_params 功能开关生效到 prodParamsConfig if (prodParamsConfig != null && yamlFeatures.containsKey("prod_params")) { boolean effective = isFeatureEnabled("prod_params"); if (prodParamsConfig.isEnabled() != effective) { log.info("prod_params 启用状态被 features 覆盖: {} -> {}", prodParamsConfig.isEnabled(), effective); prodParamsConfig.setEnabled(effective); } } // 应用 UI 覆盖:设备信息行启用/label ProjectConfigManager pc = ProjectConfigManager.getInstance(); applyDeviceRowOverride(0, pc.getDeviceRow1EnabledOverride(), pc.getDeviceRow1LabelOverride()); applyDeviceRowOverride(1, pc.getDeviceRow2EnabledOverride(), pc.getDeviceRow2LabelOverride()); // showDeviceInfo / showDeviceInfo2 按 enabled 合并重算 showDeviceInfo = !deviceInfoRows.isEmpty() && deviceInfoRows.get(0).isEnabled(); showDeviceInfo2 = deviceInfoRows.size() > 1 && deviceInfoRows.get(1).isEnabled(); // 物料码输入框显隐覆盖 Boolean smiOverride = pc.getShowMaterialInputOverride(); if (smiOverride != null) { showMaterialInput = smiOverride; } } private void applyDeviceRowOverride(int idx, Boolean enabled, String label) { if (idx < 0 || idx >= deviceInfoRows.size()) return; DeviceInfoRow row = deviceInfoRows.get(idx); if (enabled != null) row.setEnabled(enabled); if (label != null) row.setLabel(label); } /** * 从Map中获取整数值,支持默认值 */ private int getIntValue(Map map, String key, int defaultValue) { Object value = map.get(key); if (value instanceof Number) { return ((Number) value).intValue(); } return defaultValue; } /** * 从Map中获取布尔值,支持默认值 */ private boolean getBooleanValue(Map map, String key, boolean defaultValue) { Object value = map.get(key); if (value instanceof Boolean) { return (Boolean) value; } return defaultValue; } // ========== 便捷方法 ========== /** * 是否为单工位模式 */ public boolean isSingleMode() { return "single".equalsIgnoreCase(mode); } /** * 是否为双工位模式 */ public boolean isDualMode() { return "dual".equalsIgnoreCase(mode); } /** * 获取工位数量 */ public int getStationCount() { return stations.size(); } /** * 根据索引获取工位信息 */ public StationInfo getStation(int index) { if (index >= 0 && index < stations.size()) { return stations.get(index); } return null; } /** * 根据工位号获取工位信息 */ public StationInfo getStationByCode(String code) { for (StationInfo station : stations) { if (station.getCode().equalsIgnoreCase(code)) { return station; } } return null; } /** * 获取工位号(兼容旧代码) */ public String getStationCode(int index) { StationInfo station = getStation(index); return station != null ? station.getCode() : null; } /** * 检查是否有指定功能 */ public boolean hasFeature(String featureName) { for (StepConfig step : workflowSteps) { if (step.getId().contains(featureName)) { return true; } } return false; } /** * 检查是否有物料绑定步骤 */ public boolean hasMaterialBinding() { return hasFeature("scan_material") || hasFeature("bind_material"); } /** * 检查是否有物料校验步骤 */ public boolean hasMaterialValidation() { return hasFeature("validate_material"); } /** * 是否为手动提交模式 */ public boolean isManualSubmitMode() { return "manual".equalsIgnoreCase(submitMode); } /** * 是否为自动提交模式 */ public boolean isAutoSubmitMode() { return "auto".equalsIgnoreCase(submitMode); } /** * 获取提交模式 */ public String getSubmitMode() { return submitMode; } /** * 获取设备连接配置 */ public DeviceConnection getDeviceConnection(int stationIndex) { for (DeviceConnection conn : deviceConnections) { if (conn.getStationIndex() == stationIndex) { return conn; } } return null; } // ========== Getters ========== public String getMode() { return mode; } public List getStations() { return stations; } public String getLineSn() { return lineSn; } /** 运行时覆盖线体号 */ public void setLineSn(String lineSn) { this.lineSn = lineSn; } public String getServerIp() { return serverIp; } /** 运行时覆盖服务器IP */ public void setServerIp(String serverIp) { this.serverIp = serverIp; } public int getTcpPort() { return tcpPort; } public int getHttpPort() { return httpPort; } public int getHeartBeatCycle() { return heartBeatCycle; } public List getWorkflowSteps() { return workflowSteps; } public boolean isDeviceEnabled() { // 优先使用运行时覆盖 Boolean override = ProjectConfigManager.getInstance().getDeviceEnabledOverride(); if (override != null) return override; return deviceEnabled; } public String getDeviceType() { return deviceType; } public List getDeviceConnections() { return deviceConnections; } public boolean isTimeoutEnabled() { return timeoutEnabled; } public int getConnectTimeout() { return connectTimeout; } public int getHeartbeatAddress() { return heartbeatAddress; } public int getReadySignalAddress() { return readySignalAddress; } public String getStationName() { return stationName; } public boolean isShowDeviceInfo() { return showDeviceInfo; } public boolean isShowDeviceInfo2() { return showDeviceInfo2; } public List getDeviceInfoRows() { return deviceInfoRows; } public DeviceInfoRow getDeviceInfoRow(int index) { if (index >= 0 && index < deviceInfoRows.size()) { return deviceInfoRows.get(index); } return null; } public boolean isShowMaterialInput() { return showMaterialInput; } /** * 是否显示物料码输入框 * 直接返回 yaml 的 showMaterialInput(不再被 feature 强制覆盖) */ public boolean isEffectiveShowMaterialInput() { return showMaterialInput; } public String getMaterialLabel() { return materialLabel; } public Map getRawConfig() { return rawConfig; } public DeviceAddresses getDeviceAddresses() { return deviceAddresses; } public CompleteCondition getCompleteCondition() { return completeCondition; } public HeartbeatConfig getHeartbeatConfig() { return heartbeatConfig; } public RelayConfig getRelayConfig() { return relayConfig; } /** * 检查是否配置了心跳 */ public boolean hasHeartbeat() { return heartbeatConfig != null && heartbeatConfig.isEnabled(); } /** * 检查是否配置了继电器 */ public boolean hasRelay() { return relayConfig != null && relayConfig.isEnabled(); } public ProdParamsConfig getProdParamsConfig() { return prodParamsConfig; } /** * 检查是否启用过程参数采集 */ public boolean hasProdParams() { return prodParamsConfig != null && prodParamsConfig.isEnabled(); } // ========== 内部类 ========== /** * 工位信息 */ public static class StationInfo { private int index; private String code; public StationInfo(int index, String code) { this.index = index; this.code = code; } public int getIndex() { return index; } public String getCode() { return code; } /** 运行时覆盖工位号 */ public void setCode(String code) { this.code = code; } @Override public String toString() { return "StationInfo{code='" + code + "'}"; } } /** * 步骤配置 */ public static class StepConfig { private String id; private String name; private String craft; private Map config; public StepConfig() { this.config = new HashMap<>(); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCraft() { return craft; } public void setCraft(String craft) { this.craft = craft; } public Map getConfig() { return config; } public void setConfig(Map config) { this.config = config != null ? config : new HashMap<>(); } public String getConfigString(String key) { Object value = config.get(key); return value != null ? value.toString() : null; } public boolean getConfigBoolean(String key, boolean defaultValue) { Object value = config.get(key); if (value instanceof Boolean) { return (Boolean) value; } return defaultValue; } @Override public String toString() { return "StepConfig{id='" + id + "', name='" + name + "'}"; } } /** * 设备连接配置 */ public static class DeviceConnection { private int stationIndex; private String ip; private int port; public DeviceConnection(int stationIndex, String ip, int port) { this.stationIndex = stationIndex; this.ip = ip; this.port = port; } public int getStationIndex() { return stationIndex; } public String getIp() { return ip; } /** 运行时修改IP(用于软件内切换设备IP) */ public void setIp(String ip) { this.ip = ip; } public int getPort() { return port; } @Override public String toString() { return "DeviceConnection{stationIndex=" + stationIndex + ", ip='" + ip + "', port=" + port + "}"; } } /** * 设备地址配置 */ public static class DeviceAddresses { private String enableSignal; // 允许信号地址(S7格式如 DB9.18.1) private String startSignal; // 启动信号地址 private String completeSignal; // 完成信号地址 private String deviceStatus; // 设备状态地址(Modbus格式如 15001) private int finishedCount; // 完成数量地址 private int presetCount; // 预设数量地址 private int qualifiedCount; // 合格数量地址 private int startCommand; // 启动命令地址 public String getEnableSignal() { return enableSignal; } public void setEnableSignal(String enableSignal) { this.enableSignal = enableSignal; } public String getStartSignal() { return startSignal; } public void setStartSignal(String startSignal) { this.startSignal = startSignal; } public String getCompleteSignal() { return completeSignal; } public void setCompleteSignal(String completeSignal) { this.completeSignal = completeSignal; } public String getDeviceStatus() { return deviceStatus; } public void setDeviceStatus(String deviceStatus) { this.deviceStatus = deviceStatus; } public int getFinishedCount() { return finishedCount; } public void setFinishedCount(int finishedCount) { this.finishedCount = finishedCount; } public int getPresetCount() { return presetCount; } public void setPresetCount(int presetCount) { this.presetCount = presetCount; } public int getQualifiedCount() { return qualifiedCount; } public void setQualifiedCount(int qualifiedCount) { this.qualifiedCount = qualifiedCount; } public int getStartCommand() { return startCommand; } public void setStartCommand(int startCommand) { this.startCommand = startCommand; } } /** * 完成条件配置 */ public static class CompleteCondition { private String type = "signal"; // signal | count | signal_with_time private int runningValue = 1; // 运行中的值 private int stoppedValue = 0; // 停止的值 private int minRunningTime = 0; // 最小运行时间(ms) public String getType() { return type; } public void setType(String type) { this.type = type != null ? type : "signal"; } public int getRunningValue() { return runningValue; } public void setRunningValue(int runningValue) { this.runningValue = runningValue; } public int getStoppedValue() { return stoppedValue; } public void setStoppedValue(int stoppedValue) { this.stoppedValue = stoppedValue; } public int getMinRunningTime() { return minRunningTime; } public void setMinRunningTime(int minRunningTime) { this.minRunningTime = minRunningTime; } } /** * 心跳配置 */ public static class HeartbeatConfig { private boolean enabled = true; private int address = 4160; private int interval = 500; // 心跳间隔(ms) private int timeoutAddress = 4170; // 心跳超时寄存器地址(PLC 读这个值判断超时阈值) private int timeoutValue = 10; // 心跳超时阈值(单位100ms,10=1秒) public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public int getAddress() { return address; } public void setAddress(int address) { this.address = address; } public int getInterval() { return interval; } public void setInterval(int interval) { this.interval = interval; } public int getTimeoutAddress() { return timeoutAddress; } public void setTimeoutAddress(int timeoutAddress) { this.timeoutAddress = timeoutAddress; } public int getTimeoutValue() { return timeoutValue; } public void setTimeoutValue(int timeoutValue) { this.timeoutValue = timeoutValue; } } /** * 继电器配置 */ public static class RelayConfig { private boolean enabled = true; private String type; // modbus_rtu private String port; // COM2 private int baudrate = 38400; private String openCommand; // 开继电器命令(十六进制) private String closeCommand; // 关继电器命令(十六进制) public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getPort() { return port; } public void setPort(String port) { this.port = port; } public int getBaudrate() { return baudrate; } public void setBaudrate(int baudrate) { this.baudrate = baudrate; } public String getOpenCommand() { return openCommand; } public void setOpenCommand(String openCommand) { this.openCommand = openCommand; } public String getCloseCommand() { return closeCommand; } public void setCloseCommand(String closeCommand) { this.closeCommand = closeCommand; } } /** * 设备信息行配置 */ public static class DeviceInfoRow { private String label; // 可选前置标签(如"M6"),为空或null则不显示 private int connectionIndex; // 对应 connections 中的索引,指定从哪个设备读数据 private int presetAddress; // 预设数量寄存器地址 private int finishedAddress; // 完成数量寄存器地址 private boolean enabled = true; // 是否启用(UI 覆盖用) public String getLabel() { return label; } public void setLabel(String label) { this.label = label; } public int getConnectionIndex() { return connectionIndex; } public void setConnectionIndex(int connectionIndex) { this.connectionIndex = connectionIndex; } public int getPresetAddress() { return presetAddress; } public void setPresetAddress(int presetAddress) { this.presetAddress = presetAddress; } public int getFinishedAddress() { return finishedAddress; } public void setFinishedAddress(int finishedAddress) { this.finishedAddress = finishedAddress; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public boolean hasLabel() { return label != null && !label.trim().isEmpty(); } } /** * 过程参数采集配置 */ public static class ProdParamsConfig { private boolean enabled; private int foutAddress = 4112; // 力输出值 F-out private int soutAddress = 4120; // 行程输出值 S-out private int fminAddress = 4116; // 力最小值 F-min private int sminAddress = 4126; // 行程最小值 S-min private int fmaxAddress = 4114; // 力最大值 F-max private int smaxAddress = 4124; // 行程最大值 S-max private int qtyAddress = 4; // 数量寄存器地址 private int uploadInterval = 60; // 上传间隔(秒) public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public int getFoutAddress() { return foutAddress; } public void setFoutAddress(int foutAddress) { this.foutAddress = foutAddress; } public int getSoutAddress() { return soutAddress; } public void setSoutAddress(int soutAddress) { this.soutAddress = soutAddress; } public int getFminAddress() { return fminAddress; } public void setFminAddress(int fminAddress) { this.fminAddress = fminAddress; } public int getSminAddress() { return sminAddress; } public void setSminAddress(int sminAddress) { this.sminAddress = sminAddress; } public int getFmaxAddress() { return fmaxAddress; } public void setFmaxAddress(int fmaxAddress) { this.fmaxAddress = fmaxAddress; } public int getSmaxAddress() { return smaxAddress; } public void setSmaxAddress(int smaxAddress) { this.smaxAddress = smaxAddress; } public int getQtyAddress() { return qtyAddress; } public void setQtyAddress(int qtyAddress) { this.qtyAddress = qtyAddress; } public int getUploadInterval() { return uploadInterval; } public void setUploadInterval(int uploadInterval) { this.uploadInterval = uploadInterval; } } }