const controlService = require('./control-service.js') const genericModbusService = require('../generic-modbus/service.js') const paramsPageState = require('../../domain/motor-control/params-state.js') const settingsService = require('../../store/settings-store.js') const syncService = require('./sync-service.js') const { getStatusPageState } = require('../../domain/motor-control/status-state.js') const themeService = require('../../store/theme-store.js') const GROUP_LABELS = { dq: 'DQ轴电流环参数', estimator: '估算器参数', oil: '上油参数', preposition: '预定位配置', protection: '保护', speedLoop: '速度环路', tailwind: '顺逆风配置', vsp: 'VSP曲线' } const COMBINED_GROUPS = { speed: ['speedLoop', 'vsp', 'oil'], startup: ['tailwind', 'preposition'] } const COMBINED_GROUP_LABELS = { speed: '速度管理', startup: '启动位置管理' } const PARAM_VIEWS = [ 'driver', 'protection', 'estimator', 'dq', 'startup', 'speed', 'genericModbus', 'genericModbusGroup', 'status' ] function getGroupLabel(groupKey) { return GROUP_LABELS[groupKey] || '参数' } function getCombinedGroupKeys(viewKey) { return COMBINED_GROUPS[viewKey] || [] } function getCombinedGroupLabel(viewKey) { return COMBINED_GROUP_LABELS[viewKey] || '参数' } function hasDirtyItem(items = []) { return items.some((item) => !!item && !!item.isDirty) } function hasWritableGroupChanges(data, groupKey) { if (groupKey === 'tailwind') { return hasDirtyItem(data.tailwindSwitchRegisters) || hasDirtyItem(data.tailwindAtoBandwidthDisplayRegisters) } if (groupKey === 'preposition') { return hasDirtyItem(data.prepositionSwitchRegisters) || hasDirtyItem(data.prepositionParameterDisplayRegisters) } if (groupKey === 'speedLoop') { return hasDirtyItem(data.speedLoopInputDisplayRegisters) || hasDirtyItem(data.speedLoopExtraDisplayRegisters) } if (groupKey === 'vsp') { return hasDirtyItem(data.vspCurveRegisters) || !!(data.speedSlopeRegister && data.speedSlopeRegister.isDirty) } if (groupKey === 'oil') return hasDirtyItem(data.oilParameterInputRegisters) return false } function getControlViewState(controlState = controlService.getState()) { return { ...controlState, ...getStatusPageState(controlState.userStatusCount), canReadStatus: !!controlState.connectedDevice } } function getProtocolFlags(settingsState = settingsService.getState()) { return { isGenericProtocol: settingsState.modbusProtocolFilter === 'generic', isMotorControlProtocol: settingsState.modbusProtocolFilter !== 'generic' } } function getPageState( paramsState = syncService.getParamsSnapshot(), controlState = controlService.getState() ) { const settingsState = settingsService.getState() return { ...paramsPageState.refreshState(paramsState), ...getControlViewState(controlState), ...genericModbusService.getState(), ...themeService.getState(), ...settingsState, ...getProtocolFlags(settingsState) } } function resolveActiveParamView(currentView, settingsState) { if (settingsState.modbusProtocolFilter === 'generic') { return currentView === 'genericModbus' || currentView === 'genericModbusGroup' ? currentView : 'genericModbus' } return PARAM_VIEWS.includes(currentView) && currentView !== 'genericModbus' && currentView !== 'genericModbusGroup' ? currentView : '' } function getSettingsPageState(currentData, settingsState) { const activeParamView = resolveActiveParamView(currentData.activeParamView, settingsState) return { ...settingsState, activeParamView, ...getProtocolFlags(settingsState) } } function getVisiblePageState(currentData) { const snapshot = syncService.getParamsSnapshot() const nextParamsState = snapshot.syncVersion && snapshot.syncVersion !== currentData.syncVersion ? paramsPageState.refreshState(snapshot) : paramsPageState.refreshState(currentData) const pageState = { ...nextParamsState, ...getControlViewState(), ...genericModbusService.getState(), ...themeService.getState(), ...settingsService.getState() } return { ...pageState, activeParamView: resolveActiveParamView(currentData.activeParamView, pageState), ...getProtocolFlags(pageState) } } function getGenericOption(options, index) { return options[Number(index)] || options[0] || {} } function createGenericModbusDialogState(overrides = {}) { const registerType = getGenericOption(genericModbusService.REGISTER_TYPE_OPTIONS, 0) const dataType = getGenericOption(genericModbusService.DATA_TYPE_OPTIONS, 0) return { cancelText: '取消', confirmText: '确认', dataTypeIndex: 0, dataTypeText: dataType.label || '', groupId: '', groupName: '', mode: '', name: '', quantity: '1', registerIndex: -1, registerTypeIndex: 0, registerTypeText: registerType.label || '', remark: '', startAddress: '0000', title: '', textByteLength: '32', showTextLength: false, unit: '', visible: false, maxValue: '', minValue: '', addressText: '', displayValue: '', rawValueText: '', showDataType: false, showRange: false, showUnit: false, readOnly: false, parsedStructRegisters: [], structDefinition: '', structParsedSummary: '', ...overrides } } function createGenericGroupDialogState(group) { const isEdit = !!group const registerTypeIndex = isEdit ? (group.registerTypeIndex || 0) : 0 const registerType = getGenericOption(genericModbusService.REGISTER_TYPE_OPTIONS, registerTypeIndex) return createGenericModbusDialogState({ confirmText: isEdit ? '保存' : '确认', groupId: isEdit ? group.id : '', groupName: isEdit ? group.name : '寄存器组', layout: isEdit ? (group.layout || 'register') : 'register', mode: isEdit ? 'editGroup' : 'createGroup', quantity: isEdit ? String(group.quantity || 1) : '1', registerTypeIndex, registerTypeText: registerType.label || '', startAddress: isEdit && group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000', title: isEdit ? '编辑寄存器组' : '添加寄存器组', visible: true }) } function createGenericRegisterDialogState(mode, group, register, registerIndex) { const isView = mode === 'viewRegister' const dataTypeIndex = register.dataTypeIndex || 0 const dataType = getGenericOption(genericModbusService.DATA_TYPE_OPTIONS, dataTypeIndex) return createGenericModbusDialogState({ cancelText: isView ? '关闭' : '取消', confirmText: isView ? '' : '保存', dataTypeIndex, dataTypeText: register.dataTypeText || dataType.label || '', groupId: group.id, groupName: group.name, mode, name: register.name, registerIndex, registerTypeIndex: group.registerTypeIndex || 0, remark: register.remark || '', startAddress: group.startAddressText ? group.startAddressText.replace(/^0x/i, '') : '0000', title: isView ? '寄存器信息' : '寄存器配置', textByteLength: String(register.textByteLength || '32'), showTextLength: !!register.showTextLength, unit: register.unit || '', visible: true, maxValue: register.maxValue || '', minValue: register.minValue || '', addressText: register.addressRangeText || register.addressText || '', displayValue: register.displayValue || '', rawValueText: register.rawValueText || '--', showDataType: !!register.showDataType, showRange: !!register.showRange, showUnit: !!register.showUnit, readOnly: isView }) } function getGenericDialogDataTypeState(dialog, dataTypeOptions, dataTypeIndex) { const dataType = getGenericOption(dataTypeOptions, dataTypeIndex) const isTextType = dataType.kind === 'text' const showUnit = dataType.kind === 'number' && dataType.key !== 'hex' return { dataTypeIndex, dataTypeText: dataType.label || '', maxValue: isTextType ? '' : dialog.maxValue, minValue: isTextType ? '' : dialog.minValue, showRange: !isTextType, showTextLength: isTextType, showUnit, textByteLength: isTextType ? (dialog.textByteLength || '32') : dialog.textByteLength, unit: showUnit ? dialog.unit : '' } } function createGenericGroupConfig(dialog) { const registers = Array.isArray(dialog.parsedStructRegisters) ? dialog.parsedStructRegisters : [] return { groupName: dialog.groupName, layout: registers.length ? 'struct' : (dialog.layout || 'register'), quantity: registers.length ? String(registers.length) : dialog.quantity, registerTypeIndex: dialog.registerTypeIndex, startAddress: dialog.startAddress, ...(registers.length ? { registers: registers.map((register) => ({ dataType: register.dataType, isStructField: true, name: register.name, textByteLength: register.textByteLength })) } : {}) } } function createGenericRegisterChangedData(dialog, dataTypeOptions) { const dataType = getGenericOption(dataTypeOptions, dialog.dataTypeIndex) const isTextType = dataType.kind === 'text' const showUnit = dataType.kind === 'number' && dataType.key !== 'hex' return { name: dialog.name, dataType: dataType.key, maxValue: isTextType ? '' : dialog.maxValue, minValue: isTextType ? '' : dialog.minValue, remark: dialog.remark, textByteLength: isTextType ? dialog.textByteLength : '', unit: showUnit ? dialog.unit : '' } } function findGenericGroup(groups, groupId) { return (groups || []).find((item) => item.id === groupId) || null } function findGenericRegister(groups, groupId, registerIndex) { const group = findGenericGroup(groups, groupId) const register = group && group.registers ? group.registers[registerIndex] : null return { group, register } } function getActiveGenericGroup(groups, groupId) { return findGenericGroup(groups, groupId) || null } module.exports = { createGenericGroupConfig, createGenericGroupDialogState, createGenericModbusDialogState, createGenericRegisterChangedData, createGenericRegisterDialogState, findGenericGroup, findGenericRegister, getActiveGenericGroup, getCombinedGroupKeys, getCombinedGroupLabel, getControlViewState, getGenericDialogDataTypeState, getGenericOption, getGroupLabel, getPageState, getSettingsPageState, getVisiblePageState, hasWritableGroupChanges, resolveActiveParamView }