const settingsService = require('../../store/settings-store.js') const themeService = require('../../store/theme-store.js') const transport = require('../../transport/ble-core.js') const manualRtuService = require('../../features/manual-rtu/service.js') const { createPageToast } = require('../../utils/page-toast.js') const communicationService = require('../../features/communication/service.js') const { LOG_MODE_OPTIONS, STORAGE_ACCESS_AREA_OPTIONS, STORAGE_ACCESS_COMMAND_OPTIONS, decorateLogs, getLogModeToggleText, getManualStatePayload, getNextLogMode, getNextSerialMode, getProtocolModeState, normalizeStorageAccessState, normalizeSerialState } = require('../../features/communication/view-model.js') const INITIAL_SERIAL_STATE = normalizeSerialState({ serialInputText: '', serialMode: 'hex' }) Page({ data: { ...themeService.getState(), ...settingsService.getState(), ...getProtocolModeState(settingsService.getState()), ...transport.getState(), ...manualRtuService.getState(), logs: decorateLogs(transport.getState().logs, 'hex'), logMode: 'hex', logModeToggleText: getLogModeToggleText('hex'), logModeOptions: LOG_MODE_OPTIONS, storageAccessAreaOptions: STORAGE_ACCESS_AREA_OPTIONS, storageAccessCommandOptions: STORAGE_ACCESS_COMMAND_OPTIONS, ...normalizeStorageAccessState({ storageAccessAreaIndex: 3, storageAccessAddress: '0000', storageAccessCommandIndex: 0, storageAccessDataText: '', storageAccessLength: '0004' }), serialTitleText: '串口发送', ...INITIAL_SERIAL_STATE, toastText: '', toastType: '' }, onLoad() { this.pageToast = createPageToast(this, this.data) this.lastSyncedSlaveAddress = '' transport.init() settingsService.init() themeService.init() const settingsState = settingsService.getState() manualRtuService.setProtocolInput({ slaveAddress: settingsState.modbusSlaveAddress }) this.lastSyncedSlaveAddress = settingsState.modbusSlaveAddress this.unsubscribeTheme = themeService.subscribe((themeState) => { this.setData(themeState) }) this.unsubscribeSettings = settingsService.subscribe((settingsState) => { this.setData({ ...settingsState, ...getProtocolModeState(settingsState) }) if (settingsState.modbusSlaveAddress !== this.lastSyncedSlaveAddress) { this.lastSyncedSlaveAddress = settingsState.modbusSlaveAddress manualRtuService.setProtocolInput({ slaveAddress: settingsState.modbusSlaveAddress }) } }) this.unsubscribeTransport = transport.subscribe((transportState) => { this.setData({ ...transportState, logs: decorateLogs(transportState.logs, this.data.logMode) }) }) this.unsubscribeManualRtu = manualRtuService.subscribe((manualState) => { this.setData(getManualStatePayload(manualState)) }) }, onShow() { if (this.pageToast) { this.pageToast.setActive(true) } }, onHide() { if (this.pageToast) { this.pageToast.setActive(false) } }, onUnload() { if (this.pageToast) { this.pageToast.destroy() this.pageToast = null } if (this.unsubscribeTheme) { this.unsubscribeTheme() this.unsubscribeTheme = null } if (this.unsubscribeSettings) { this.unsubscribeSettings() this.unsubscribeSettings = null } if (this.unsubscribeTransport) { this.unsubscribeTransport() this.unsubscribeTransport = null } if (this.unsubscribeManualRtu) { this.unsubscribeManualRtu() this.unsubscribeManualRtu = null } }, noop() {}, switchSerialMode() { this.setData(normalizeSerialState(this.data, { serialMode: getNextSerialMode(this.data.serialMode) })) }, switchLogMode(event) { const requestedMode = event && event.currentTarget && event.currentTarget.dataset ? event.currentTarget.dataset.mode : '' const mode = requestedMode || getNextLogMode(this.data.logMode) this.setData({ logMode: mode, logModeToggleText: getLogModeToggleText(mode), logs: decorateLogs(transport.getState().logs, mode) }) }, clearCommunicationLogs() { transport.clearLogs() }, onSerialInput(event) { this.setData(normalizeSerialState(this.data, { serialInputText: event.detail.value })) }, clearSerialInput() { this.setData(normalizeSerialState(this.data, { serialInputText: '' })) }, async sendSerialFrame() { try { const result = await communicationService.sendSerialFrame(this.data) if (!result.ok) { this.setData({ serialErrorText: result.errorText || '发送失败' }) return } if (this.pageToast) this.pageToast.show('已发送') this.setData({ ...(result.serialState || {}), serialErrorText: '', serialPreviewHex: result.previewHex || '', serialPreviewLengthText: `${(result.bytes || []).length} bytes` }) } catch (error) { this.setData({ serialErrorText: error.message || '发送失败' }) } }, onProtocolCommandChange(event) { manualRtuService.setCommandIndex(Number(event.detail.value)) }, onProtocolInput(event) { const field = event.currentTarget.dataset.field if (!field) return manualRtuService.setProtocolInput({ [field]: event.detail.value }) }, onProtocolCoilChange(event) { manualRtuService.setProtocolInput({ coilEnabled: !!event.detail.value }) }, openProtocolMultipleDialog() { manualRtuService.openProtocolMultipleDialog() }, closeProtocolMultipleDialog() { manualRtuService.closeProtocolMultipleDialog() }, toggleProtocolMultipleExpanded() { manualRtuService.toggleProtocolMultipleExpanded() }, onProtocolMultipleQuantityChange(event) { manualRtuService.setProtocolMultipleQuantity(event.detail.value) }, onProtocolMultipleValueInput(event) { const index = Number(event.currentTarget.dataset.index) manualRtuService.setProtocolMultipleValue(index, event.detail.value) }, onProtocolMultipleTypeChange(event) { const index = Number(event.currentTarget.dataset.index) manualRtuService.setProtocolMultipleType(index, Number(event.detail.value)) }, onProtocolMultipleTextLengthInput(event) { const index = Number(event.currentTarget.dataset.index) manualRtuService.setProtocolMultipleTextLength(index, event.detail.value) }, async sendProtocolFrame(event) { const source = event && event.currentTarget && event.currentTarget.dataset ? event.currentTarget.dataset.source : '' if (this.data.protocolMultipleDialog && this.data.protocolMultipleDialog.visible && source !== 'dialog') { if (this.pageToast) this.pageToast.show('请在多值窗口内发送', 'error') return } if (!this.data.connectedDevice) { if (this.pageToast) this.pageToast.show('请先连接蓝牙设备', 'error') return } const response = await manualRtuService.sendGeneratedFrame() if (response && this.pageToast) { this.pageToast.show(response === true ? '已发送' : '已收到回复') } else if (this.pageToast) { const manualState = manualRtuService.getState() this.pageToast.show(manualState.protocolStatusText || '发送失败或超时未回复', 'error') } }, switchStorageAccessCommandMode(event) { const storageAccessCommandIndex = Number(event.currentTarget.dataset.index) const nextState = normalizeStorageAccessState(this.data, { storageAccessCommandIndex }) this.setData(nextState) }, onStorageAccessInput(event) { const field = event.currentTarget.dataset.field if (!field) return const changed = { [field]: event.detail.value } const nextState = normalizeStorageAccessState(this.data, changed) this.setData(nextState) }, onStorageAccessAreaChange(event) { const storageAccessAreaIndex = Number(event.detail.value) const nextState = normalizeStorageAccessState(this.data, { storageAccessAreaIndex }) this.setData(nextState) }, async sendStorageAccessProtocolFrame() { try { const command = STORAGE_ACCESS_COMMAND_OPTIONS[Number(this.data.storageAccessCommandIndex) || 0] || STORAGE_ACCESS_COMMAND_OPTIONS[0] const result = await communicationService.executeStorageAccessProtocol(this.data) if (!result.ok) { this.setData({ storageAccessErrorText: result.errorText || '操作失败' }) return } if (command.key === 'sync') { this.setData({ storageAccessErrorText: '', storageAccessSyncInfoText: result.syncInfoText || this.data.storageAccessSyncInfoText }) if (this.pageToast) { const codeInfoAddressText = result.codeInfoAddressText || '0000' const codeInfoByteLengthText = result.codeInfoByteLengthText || '0000' this.pageToast.show(`同步完成 codeInfo 0x${codeInfoAddressText} / 0x${codeInfoByteLengthText}`) } return } if (command.key === 'read') { this.setData({ storageAccessErrorText: '', storageAccessPreviewHexText: result.previewHex || '' }) if (this.pageToast) this.pageToast.show(`读取完成 ${(result.bytes || []).length} bytes`) return } this.setData({ storageAccessErrorText: '' }) if (this.pageToast) this.pageToast.show('写入完成') } catch (error) { this.setData({ storageAccessErrorText: error.message || '操作失败' }) } } })