From ef611cf3a51f8e590e77813ced4f6cd9cbfabd50 Mon Sep 17 00:00:00 2001 From: LiLongLong <13717757313@163.com> Date: Fri, 6 Jun 2025 09:46:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=BD=91=E7=BB=9C=E6=96=AD?= =?UTF-8?q?=E5=BC=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/system.ts | 30 ++-- src/app.vue | 112 +++++++++----- src/assets/images/background-login.svg | 2 +- src/components/formula/FormulaConfig.vue | 245 ++++++++++++++++++++++++++---- src/components/formula/FormulaTable.vue | 8 +- src/components/home/Environment.vue | 28 +++- src/components/home/HomeOperation.vue | 106 +++++++++---- src/components/home/HomeSetting.vue | 192 ++++++++++++++--------- src/components/home/config.vue | 58 +++++-- src/components/liquid/LiquidLevel.vue | 1 + src/components/setting/SystemDate.vue | 4 +- src/components/system/NetReconnection.vue | 100 ++++++++++++ src/layouts/default.vue | 70 +++++---- src/libs/constant.ts | 4 +- src/libs/countdownTimer.ts | 10 +- src/libs/socket.ts | 12 +- src/libs/utils.ts | 23 ++- src/stores/deviceStore.ts | 24 +++ src/stores/formulaStore.ts | 70 ++++++++- src/stores/homeStore.ts | 100 +++++------- src/stores/initHomeData.ts | 4 +- src/stores/liquidStore.ts | 31 +++- src/stores/sealStore.ts | 14 ++ src/stores/settingStore.ts | 34 +++++ src/stores/systemStore.ts | 64 ++++++++ src/types/system.d.ts | 6 + src/views/audit/index.vue | 64 ++++++-- src/views/liquid/index.vue | 19 +-- src/views/login/index.vue | 95 ++++++++++-- src/views/seal/index.vue | 8 +- 30 files changed, 1189 insertions(+), 349 deletions(-) create mode 100644 src/components/system/NetReconnection.vue diff --git a/src/apis/system.ts b/src/apis/system.ts index f3a6130..ec371ce 100644 --- a/src/apis/system.ts +++ b/src/apis/system.ts @@ -1,13 +1,19 @@ +import { useSystemStore } from '@/stores/systemStore' import { createWebSocket } from 'libs/socket' +import { nanoid } from 'nanoid' const wsClient = createWebSocket() -export async function sendCmd(resParams: { className: string, fnName: string, params: Record }) { + +export async function sendCmd(resParams: System.SendCmdParams) { + const { className, fnName, params = {} } = resParams + const systemStore = useSystemStore() + systemStore.updateConnected(wsClient.isConnected.value) const res = await wsClient.waitAndSend({ messageType: 'Command', - fnName: resParams.fnName, - className: resParams.className, - messageId: `msg_${Date.now()}`, - params: resParams.params, + fnName, + className, + messageId: `msg_${nanoid()}`, + params, }) if (res.ackcode === 0) { return res.rely @@ -16,16 +22,20 @@ export async function sendCmd(resParams: { className: string, fnName: string, pa throw new Error(res.message) } } -export async function syncSendCmd(resParams: { className: string, fnName: string, params: Record }) { +export async function syncSendCmd(resParams: System.SendCmdParams) { + const { className, fnName, params = {} } = resParams + const systemStore = useSystemStore() + systemStore.updateConnected(wsClient.isConnected.value) return await wsClient.sendRequest({ messageType: 'Command', - fnName: resParams.fnName, - className: resParams.className, - messageId: `msg_${Date.now()}`, - params: resParams.params, + fnName, + className, + messageId: `msg_${nanoid()}`, + params, }) } +// 业务状态订阅 export async function subscribeEvent(fromFn: string | '*', callback: (response: Socket.WebSocketResponse) => void) { wsClient.socket.addEventListener('message', (event) => { const data = JSON.parse(event.data) diff --git a/src/app.vue b/src/app.vue index 5b1a5c5..dbc2004 100644 --- a/src/app.vue +++ b/src/app.vue @@ -6,19 +6,38 @@ import { useLiquidStore } from 'stores/liquidStore' import { onBeforeMount, ref } from 'vue' import { useFormulaStore } from './stores/formulaStore' +/** + * 应用初始化组件 + * @description 负责系统初始化流程控制,包括设备信息获取、数据同步及进度展示 + */ + +// 状态管理 const deviceStore = useDeviceStore() const homeStore = useHomeStore() const formulaStore = useFormulaStore() const liquidStore = useLiquidStore() + +// 组件状态 +const progress = ref(0) // 初始化进度百分比 +const version = __APP_VERSION__ // 应用版本号 +let timer: any = null // 进度条定时器 + +/** + * @hook 生命周期钩子 - 组件挂载前执行 + * @description 启动初始化流程和数据轮询 + */ onBeforeMount(async () => { - // 过渡页面加载进度 - startProgress() - // 环境(探头)数据需要轮询获取,没有上报的事件 - setInterval(async () => { - await readH2o2Data() - }, 2000) + startProgress() // 启动进度条 + // 环境数据轮询(每2秒获取一次) + // setInterval(async () => { + // await readH2o2Data() + // }, 3000) }) +/** + * @function 初始化设备信息 + * @desc 从服务端获取设备信息并更新到状态存储 + */ const initDeviceInfo = async () => { const deviceParams = { className: 'DeviceInfoMgrService', @@ -30,82 +49,91 @@ const initDeviceInfo = async () => { return res } +/** + * @function 获取默认配方数据 + * @desc 从服务端获取所有配置信息并更新配方配置 + */ const getFormualDefaultData = async () => { - const defaultParams = { - className: 'SettingMgrService', - fnName: 'getAllSetting', - params: {}, - } - const res = await sendCmd(defaultParams) - formulaStore.updateFormulaConfigData(res) + formulaStore.getFormualDefaultData() } -const progress = ref(0) -let timer: any = null -const version = __APP_VERSION__ - +/** + * @function 启动初始化进度条 + * @desc 模拟初始化进度,同步加载各项数据 + */ const startProgress = () => { timer = setInterval(async () => { - const randomStep = Math.floor(Math.random() * 9 + 1) + // 生成随机进度增长(1-9%) + const randomStep = Math.floor((Math.random() * 9) + 1) progress.value = Math.min(progress.value + randomStep, 100) + + // 初始化数据流程 await initData() - // 获取设备信息 await initLiquidConfig() await initDeviceInfo() - // 获取默认配方数据 await getFormualDefaultData() + + // 进度完成后清除定时器 if (progress.value >= 100) { clearInterval(timer) } }, 100) } -const readH2o2Data = async () => { - const envParams = { - fnName: 'readH2O2SensorData', - className: 'FrontEndRealtimeDisplayContentMgr', - params: {}, - } - const resData = await sendCmd(envParams) - if (resData.val.length) { - homeStore.updateHomeData(resData.val) - } -} +/** + * @function 读取过氧化氢传感器数据 + * @desc 轮询获取环境传感器数据并更新到主页状态 + */ +// const readH2o2Data = async () => { +// const envParams = { +// fnName: 'readH2O2SensorData', +// className: 'FrontEndRealtimeDisplayContentMgr', +// params: {}, +// } +// const resData = await sendCmd(envParams) +// if (resData.val.length) { +// homeStore.updateHomeData(resData.val) +// } +// } + +/** + * @function 初始化核心数据 + * @desc 同步获取消毒状态、液体余量和设备状态数据 + */ const initData = async () => { - // 获取消毒时状态 + // 获取消毒状态 const disinfectionParams = { className: 'DisinfectionCtrlServiceExt', fnName: 'getState', - params: {}, } const disinfectionData = await sendCmd(disinfectionParams) homeStore.updateHomeDisinfectionState(disinfectionData) - // 消毒液当前使用余量 + // 获取液体余量 const liquidParams = { fnName: 'getState', className: 'AddLiquidService', - params: {}, } const liquidData = await sendCmd(liquidParams) liquidStore.updateLiquidState(liquidData) + // 获取设备状态 const deviceParams = { className: 'AppCore', - fnName: 'getState', - params: {}, + fnName: 'startStateReport', } - // 当前设备状态 - const deviceData = await sendCmd(deviceParams) - homeStore.setDeviceState(deviceData) + await sendCmd(deviceParams) + // deviceStore.setDeviceState(deviceData) } -// 消毒液最大量 +/** + * @function 初始化液体配置 + * @desc 获取液体最大容量和更新周期配置 + */ const initLiquidConfig = async () => { const params = { className: 'AddLiquidService', fnName: 'getServiceConfig', - params: {}, } const liquidConfig = await sendCmd(params) liquidStore.initLiquidConfig(liquidConfig) diff --git a/src/assets/images/background-login.svg b/src/assets/images/background-login.svg index 6e73b39..5e1e2cb 100644 --- a/src/assets/images/background-login.svg +++ b/src/assets/images/background-login.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/formula/FormulaConfig.vue b/src/components/formula/FormulaConfig.vue index 839d446..12b3398 100644 --- a/src/components/formula/FormulaConfig.vue +++ b/src/components/formula/FormulaConfig.vue @@ -1,30 +1,81 @@ diff --git a/src/components/home/HomeOperation.vue b/src/components/home/HomeOperation.vue index eac28d0..1f00781 100644 --- a/src/components/home/HomeOperation.vue +++ b/src/components/home/HomeOperation.vue @@ -12,11 +12,19 @@ import { startTimer, stopTimer } from 'libs/countdownTimer' import { deviceStateMap } from 'libs/utils' import { computed, onMounted, ref, watchEffect } from 'vue' +/** + * 消毒操作控制组件 + * @description 负责处理消毒流程控制(开始/结束)、状态监听及倒计时逻辑 + */ + +// 状态管理 const homeStore = useHomeStore() const formulaStore = useFormulaStore() const systemStore = useSystemStore() -const curStateRemainTimeS = ref('') -const disinfectionState = ref(homeStore.disinfectionState) + +// 组件状态 +const curStateRemainTimeS = ref('') // 当前状态剩余时间(字符串格式) +const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态 const btnStyle = { width: '27vw', height: '7vh', @@ -24,11 +32,17 @@ const btnStyle = { borderRadius: '12px', textColor: '#FFFFFF', } -let isDisinfection = false +let isDisinfection = false // 是否处于消毒中状态 +/** + * @hook 响应式依赖监听 + * @description 监听消毒状态变化,处理倒计时逻辑 + */ watchEffect(() => { disinfectionState.value = homeStore.disinfectionState const time = disinfectionState.value.curStateRemainTimeS + + // 进入消毒状态且未启动倒计时时开始计时 if (disinfectionState.value.state === 'disinfection' && !isDisinfection && time > 0) { isDisinfection = true startTimer(time * 1000, (times: string) => { @@ -38,58 +52,89 @@ watchEffect(() => { } }) -onMounted(() => { +/** + * @hook 生命周期钩子 - 组件挂载完成时执行 + * @description 订阅消毒状态更新事件 + */ +onMounted(async () => { + await systemStore.subscribeDisinfectEvent() // 订阅状态更新 subscribeEvent('stateUpdate', handleDisinfectState) }) +/** + * @function 处理消毒状态更新事件 + * @param {Socket.WebSocketResponse} report - 状态更新报告 + * @desc 接收并更新消毒状态数据 + */ const handleDisinfectState = (report: Socket.WebSocketResponse) => { if (report.fromClass === 'DisinfectionCtrlServiceExt') { homeStore.updateHomeDisinfectionState(report.rely) } } -// 开始消毒 + +/** + * @function 开始消毒操作 + * @desc 校验设备状态并发起消毒请求 + */ const onStartDisinfect = async () => { + // 校验日志等级 if (!formulaStore.loglevel) { - FtMessage.warning('选择消毒等级') + FtMessage.warning('请选择消毒等级') return } + + // 校验设备状态 const statusName = getDeviceStatus() if (statusName) { FtMessageBox.error(statusName) return } - if (formulaStore.selectedFormulaInfo && formulaStore.selectedFormulaInfo.formula_id) { - formulaStore.saveDisinfectFormula(formulaStore.selectedFormulaInfo) - } - else { - const startParams = { - className: 'DisinfectionCtrlServiceExt', - fnName: 'start', - params: { - loglevel: formulaStore.loglevel, - }, + systemStore.updateLoading(true) + try { + // 使用选中配方或默认配置启动消毒 + if (formulaStore.selectedFormulaInfo && formulaStore.selectedFormulaInfo.formula_id) { + await formulaStore.saveDisinfectFormula(formulaStore.selectedFormulaInfo) } - systemStore.updateLoading(true) - await sendCmd(startParams) + else { + const startParams = { + className: 'DisinfectionCtrlServiceExt', + fnName: 'start', + params: { loglevel: formulaStore.loglevel }, + } + await sendCmd(startParams) + } + } + finally { + systemStore.updateLoading(false) } - homeStore.subscribeDisinfectEvent() } -// 结束消毒 +/** + * @function 结束消毒操作 + * @desc 停止倒计时并发起结束消毒请求 + */ const onFinishDisinfect = async () => { - stopTimer() - const stopParams = { - className: 'DisinfectionCtrlServiceExt', - fnName: 'stop', - params: { - loglevel: formulaStore.loglevel, - }, - } + stopTimer() // 停止倒计时 systemStore.updateLoading(true) - await sendCmd(stopParams) + try { + const stopParams = { + className: 'DisinfectionCtrlServiceExt', + fnName: 'stop', + params: { loglevel: formulaStore.loglevel }, + } + await sendCmd(stopParams) + } + finally { + systemStore.updateLoading(false) + } } +/** + * @computed 计算属性 - 操作状态判断 + * @returns {boolean} - 是否处于空闲或已完成状态 + * @desc 控制开始/结束按钮的显示逻辑 + */ const operationState = computed(() => { return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished' }) @@ -128,7 +173,7 @@ const operationState = computed(() => { - +
@@ -138,7 +183,6 @@ const operationState = computed(() => { 消毒状态:
-
{{ curStateRemainTimeS }}
diff --git a/src/components/home/HomeSetting.vue b/src/components/home/HomeSetting.vue index c5d5d94..42feb58 100644 --- a/src/components/home/HomeSetting.vue +++ b/src/components/home/HomeSetting.vue @@ -13,133 +13,187 @@ import { cloneDeep } from 'lodash' import { computed, onMounted, provide, ref, watchEffect } from 'vue' import { useRouter } from 'vue-router' +/** + * 主页操作控制组件 + * @description 负责处理压力控制、消毒设置、图表导航等功能,协调组件间通信 + */ + +// 依赖注入 const configRef = ref() provide<(methods: Home.GrandsonMethods) => void>('registerGrandsonMethods', (methods) => { configRef.value = methods }) + +// 状态管理 const router = useRouter() const formulaStore = useFormulaStore() const homeStore = useHomeStore() -const isModalOpen = ref(false) -const optionsLeft = ref([]) -const optionsRight = ref([]) -const selectedValue = ref() -const disinfectionState = ref(homeStore.disinfectionState) -// 消毒设置 -const disinfectFormulaVisible = ref(false) -const selectedByFormulas = ref(cloneDeep(formulaStore.selectedFormulaInfo)) +// 组件状态 +const isModalOpen = ref(false) // 级联选择模态框是否打开 +const optionsLeft = ref([]) // 压力类型选项(左列) +const optionsRight = ref([]) // 压力强度选项(右列) +const selectedValue = ref() // 选中的压力配置值 +const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态 +const disinfectFormulaVisible = ref(false) // 消毒设置对话框是否显示 +const selectedByFormulas = ref(cloneDeep(formulaStore.selectedFormulaInfo)) // 当前选中的配方信息 +const pressureConfig = ref(homeStore.pressureConfig) + +/** + * @hook 响应式依赖监听 + * @description 监听消毒状态和配方变化,同步更新组件状态 + */ watchEffect(() => { disinfectionState.value = homeStore.disinfectionState selectedByFormulas.value = formulaStore.selectedFormulaInfo + pressureConfig.value = homeStore.pressureConfig }) -onMounted(() => { - // 初始化正负压力值 - homeStore.getPressureConfig() +/** + * @hook 生命周期钩子 - 组件挂载完成时执行 + * @description 初始化压力配置 + */ +onMounted(async () => { + await getPressureConfig() // 获取压力配置 }) +/** + * @function getPressureConfig + * @desc 获取当前压力配置信息 + */ +const getPressureConfig = async () => { + const pressureParams = { + className: 'PipelinePressureControl', + fnName: 'getConfig', + } + const res = await sendCmd(pressureParams) + console.log('res---', res) + homeStore.updatePressureConfig(res) +} + +/** + * @computed 计算属性 - 设备状态判断 + * @returns {boolean} - 设备是否处于空闲或已完成状态 + * @desc 控制按钮可用状态 + */ const deviceState = computed(() => { return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished' }) +/** + * @function 打开消毒设置对话框 + * @desc 根据当前选中配方或默认配方初始化设置 + */ const onDisinfectConfig = () => { - if (selectedByFormulas.value) { - formulaStore.updateSelectedFormulaDataByList(cloneDeep(selectedByFormulas.value)) - } - else { - formulaStore.updateSelectedFormulaDataByList(cloneDeep(formulaStore.defaultFormulaInfo)) - } + formulaStore.updateSelectedFormulaDataByList(selectedByFormulas.value || cloneDeep(formulaStore.defaultFormulaInfo)) disinfectFormulaVisible.value = true } +/** + * @function 导航到图表页面 + * @desc 路由跳转至消毒图表页面 + */ const onShowChart = () => { router.push('/home/chart') } -// 保存消毒参数 +/** + * @function 保存消毒参数 + * @desc 处理表单数据保存逻辑,区分消毒中与非消毒状态 + */ const onSave = async () => { const formData = configRef.value?.getFormData() - console.log('formData---', JSON.stringify(formData)) - formulaStore.updateSelectedFormulaDataByList(cloneDeep(formData)) - // 消毒中 设置消毒参数 - if (!homeStore.isDeviceIdle) { - // 获取正在执行的消毒参数 - const params = { + if (!formData) { + return + } + formulaStore.updateSelectedFormulaDataByList(cloneDeep(formData)) // 更新选中配方 + + if (!homeStore.isDeviceIdle) { // 消毒中时更新实时配置 + const res = await sendCmd({ className: 'DisinfectionCtrlServiceExt', fnName: 'getRealtimeConfig', params: {}, - } - const res = await sendCmd(params) - const result = compareJSON(res, formData) - const resultKey = Object.keys(result) - if (resultKey && resultKey.length) { - resultKey.forEach(async (item) => { - await setRealtimeConfig(item, result[item].newVal) - }) + }) + const diff = compareJSON(res, formData) + const diffKeys = Object.keys(diff) + if (diffKeys.length) { + await Promise.all(diffKeys.map(async (key) => { + await setRealtimeConfig(key, diff[key].newVal) + })) FtMessage.success('配方修改成功') } } - else { - // 未消毒 设置消毒配方 + else { // 非消毒时保存配方 if (formData.formula_id) { await formulaStore.saveDisinfectFormula(formData) } } - onClose() + onClose() // 关闭对话框 } +/** + * @function 设置实时消毒参数 + * @param {string} key - 参数键名 + * @param {string} val - 参数值 + * @desc 向设备发送实时参数修改指令 + */ const setRealtimeConfig = async (key: string, val: string) => { - const params = { + await sendCmd({ className: 'DisinfectionCtrlServiceExt', fnName: 'setRealtimeConfig', - params: { - key, - val, - }, - } - await sendCmd(params) + params: { key, val }, + }) } -// 设置压力 +/** + * @function 打开压力控制模态框 + * @desc 初始化压力类型和强度选项 + */ const onSetPressure = () => { - // 接口中获取压力值 - const pressureConfig = homeStore.pressureConfig - const { typeDisplayNames, types } = pressureConfig - const intensitys: Record = pressureConfig.intensitys - const left: System.Option[] = [] - let negativePressure: string[] = [] - if (typeDisplayNames && typeDisplayNames.length) { - typeDisplayNames.forEach((el: string, index: number) => { - left.push({ - label: el, - value: types[index], - }) - if (types[index] === 'positivePressure') { - negativePressure = intensitys.positivePressure - } - }) - } - optionsLeft.value = left - const right: System.Option[] = [] - if (negativePressure.length) { - negativePressure.forEach((el) => { - right.push({ - label: el, - value: el, - }) + const pressureVal = pressureConfig.value + const { typeDisplayNames, types, intensitys } = pressureVal || {} + + // 构建压力类型选项(左列) + const leftOptions: System.Option[] = typeDisplayNames?.map((name: string, index: number) => ({ + label: name, + value: types[index], + })) || [] + + // 构建压力强度选项(右列) + const rightOptions: System.Option[] = [] + if (types?.includes('positivePressure')) { + intensitys?.positivePressure?.forEach((intensity: string) => { + rightOptions.push({ label: `${intensity}%`, value: intensity }) }) } - optionsRight.value = right + + optionsLeft.value = leftOptions + optionsRight.value = rightOptions isModalOpen.value = true } + +/** + * @function 确认压力选择 + * @param {string|number[]} value - 选中的压力配置值([类型, 强度]) + * @desc 关闭模态框并更新压力配置 + */ const handleConfirm = (value: string | number[]) => { isModalOpen.value = false homeStore.updatePressure(value) } + +/** + * @function 取消压力选择 + * @desc 关闭模态框 + */ const handleCancel = () => { isModalOpen.value = false } + +/** + * @function 关闭消毒设置对话框 + * @desc 重置对话框状态 + */ const onClose = () => { disinfectFormulaVisible.value = false } diff --git a/src/components/home/config.vue b/src/components/home/config.vue index fa5f83a..a528cfb 100644 --- a/src/components/home/config.vue +++ b/src/components/home/config.vue @@ -6,27 +6,48 @@ import SelectModal from 'components/common/SelectModal/index.vue' import FormulaConfig from 'components/formula/FormulaConfig.vue' import { computed, onMounted, ref, watchEffect } from 'vue' +/** + * 配方选择页面组件 + * @description 负责处理配方选择逻辑、设备状态判断及界面交互 + */ + +// 状态管理 const formulaStore = useFormulaStore() const homeStore = useHomeStore() -const recipes = ref([]) -const isModalOpen = ref(false) -const selectedValue = ref() -const isDeviceIdle = ref(homeStore.isDeviceIdle) + +// 组件状态 +const recipes = ref([]) // 配方列表 +const isModalOpen = ref(false) // 选择模态框是否打开 +const selectedValue = ref() // 选中的配方ID +const isDeviceIdle = ref(homeStore.isDeviceIdle) // 设备是否空闲状态 + +/** + * @hook 生命周期钩子 - 挂载完成时执行 + * @description 初始化时检查配方列表,若为空则重新获取 + */ onMounted(() => { - // store中没有配方表单时,重新获取 if (!formulaStore.formulaList || !formulaStore.formulaList.length) { formulaStore.initFormulaList() } }) + +/** + * @hook 响应式依赖监听 + * @description 监听store数据变化,同步更新组件状态 + */ watchEffect(() => { recipes.value = [...formulaStore.formulaList] isDeviceIdle.value = homeStore.isDeviceIdle }) +/** + * @computed 计算属性 - 生成选择框选项 + * @returns {System.Option[]} 包含label和value的选项数组 + */ const options = computed(() => { const list = formulaStore.formulaList const optionList: System.Option[] = [] - list.forEach((item) => { + list.forEach((item: Formula.FormulaItem) => { optionList.push({ label: item.name.toString(), value: item.formula_id, @@ -34,6 +55,12 @@ const options = computed(() => { }) return optionList }) + +/** + * @function 确认选择处理函数 + * @param {any} value - 选中的配方ID + * @description 关闭模态框,更新选中配方并转换数值类型 + */ const handleConfirm = (value: any) => { isModalOpen.value = false let selectedFormula = {} @@ -42,18 +69,31 @@ const handleConfirm = (value: any) => { selectedFormula = item } }) - const selectedFormulaToInt = convertValuesToInt(selectedFormula, 'name') - // 更新选择的配方 + const selectedFormulaToInt = convertValuesToInt(selectedFormula) formulaStore.updateSelectedFormulaDataByList(selectedFormulaToInt as Formula.FormulaItem) } + +/** + * @function 取消选择处理函数 + * @description 关闭模态框 + */ const handleCancel = () => { isModalOpen.value = false } + +/** + * @function 打开选择配方模态框 + * @description 触发模态框显示 + */ const onChooseFormula = () => { isModalOpen.value = true } + +/** + * @function 应用默认配方 + * @description 重置配方数据为默认配置 + */ const onDefaultFormula = () => { - // 获取默认值数据 formulaStore.initFormulaData() } diff --git a/src/components/liquid/LiquidLevel.vue b/src/components/liquid/LiquidLevel.vue index 16a6d91..59229d4 100644 --- a/src/components/liquid/LiquidLevel.vue +++ b/src/components/liquid/LiquidLevel.vue @@ -61,6 +61,7 @@ const liquidHeight = computed(() => { width: 100%; background: linear-gradient(to top, #0099ff, #e6f7ff); /* 颜色渐变,可按需调整 */ border-radius: 10px; + min-height: 1.5rem; } .liquid-level-middle{ background: linear-gradient(352deg, #0093f5, #effafe); diff --git a/src/components/setting/SystemDate.vue b/src/components/setting/SystemDate.vue index 913dc7b..2736ecd 100644 --- a/src/components/setting/SystemDate.vue +++ b/src/components/setting/SystemDate.vue @@ -1,9 +1,11 @@ + + + + diff --git a/src/layouts/default.vue b/src/layouts/default.vue index ad73a5a..6ef3432 100644 --- a/src/layouts/default.vue +++ b/src/layouts/default.vue @@ -6,7 +6,8 @@ import { useLiquidStore } from '@/stores/liquidStore' import { useSealStore } from '@/stores/sealStore' import { useSystemStore } from '@/stores/systemStore' import HomeAlarmSvg from 'assets/images/home/home-alarm.svg' -import ErrorBox from 'libs/modalUtil' +import NetReconnection from 'components/system/NetReconnection.vue' +// import ErrorBox from 'libs/modalUtil' import { formatDateTime, openFullscreen } from 'libs/utils' import { authRoutes } from 'router/routes' import { useDeviceStore } from 'stores/deviceStore' @@ -30,11 +31,19 @@ const wordStateName = ref('空闲') const disinfectState = ref(homeStore.disinfectionState.state) const liquidAddState = ref(liquidStore.liquidAddWorkState) const liquidDrainState = ref(liquidStore.liquidDrainWorkState) +const deviceStete = ref(deviceStore.deviceStete) const sealInfo = ref(sealStore.sealInfo) +const websocketConnected = ref(systemStore.websocketConnected) let touchStartTime = 0 let touchCount = 0 + onMounted(() => { // 连续3次点击任意地方,全屏显示 + onFullScreen() + deviceStore.startSubscribDevice() +}) + +const onFullScreen = () => { document.body.addEventListener('touchstart', (event) => { const now = Date.now() const timeDiff = now - touchStartTime @@ -50,29 +59,22 @@ onMounted(() => { } touchStartTime = now }) -}) - -const showWorkState = () => { - // 消毒状态 - disinfectState.value = homeStore.disinfectionState.state - // 加液/排液状态 - liquidAddState.value = liquidStore.liquidStateData - liquidDrainState.value = liquidStore.liquidDrainWorkState - - // 密封测试状态 - sealInfo.value = sealStore.sealInfo +} - if (disinfectState.value !== 'idle' && disinfectState.value !== 'finished') { - wordStateName.value = homeStore.disinfectionState.statedisplayName - } - else if (liquidAddState.value.workState !== 'idle') { - wordStateName.value = liquidAddState.value.workStateDisplay - } - else if (liquidDrainState.value.workState !== 'idle') { - wordStateName.value = liquidDrainState.value.workStateDisplay - } - else if (sealInfo.value.workState !== 'idle') { - wordStateName.value = sealInfo.value.workStateDisplay +const showDeviceStateName = () => { + if (deviceStete.value.state.toLocaleLowerCase() !== 'idle') { + if (disinfectState.value !== 'idle' && disinfectState.value !== 'finished') { + wordStateName.value = homeStore.disinfectionState.statedisplayName + } + else if (liquidAddState.value.workState !== 'idle') { + wordStateName.value = liquidAddState.value.workStateDisplay + } + else if (liquidDrainState.value.workState !== 'idle') { + wordStateName.value = liquidDrainState.value.workStateDisplay + } + else if (sealInfo.value.workState !== 'idle') { + wordStateName.value = sealInfo.value.workStateDisplay + } } else { wordStateName.value = '空闲' @@ -81,15 +83,24 @@ const showWorkState = () => { watchEffect(() => { deviceInfo.value = deviceStore.deviceInfo - showWorkState() + websocketConnected.value = systemStore.websocketConnected + // 消毒状态 + disinfectState.value = homeStore.disinfectionState.state + // 加液/排液状态 + liquidAddState.value = liquidStore.liquidStateData + liquidDrainState.value = liquidStore.liquidDrainWorkState + deviceStete.value = deviceStore.deviceStete + // 密封测试状态 + sealInfo.value = sealStore.sealInfo + showDeviceStateName() }) onUnmounted(() => { clearInterval(timeInterval) }) -const showErrorModal = () => { - ErrorBox.alert('这是一条警告信息') -} +// const showErrorModal = () => { +// ErrorBox.alert('这是一条警告信息') +// } const onLogout = () => { // 判断是否有正在执行的操作 const hasEx = getDeviceStatus() @@ -156,14 +167,15 @@ const onLogout = () => {
IP : {{ deviceInfo.ip }}
-
+
报警 -
{{ wordStateName }}
+
{{ wordStateName || '空闲' }}
{{ currentTime }}
+ diff --git a/src/libs/constant.ts b/src/libs/constant.ts index b5b41d1..4fa070b 100644 --- a/src/libs/constant.ts +++ b/src/libs/constant.ts @@ -22,8 +22,8 @@ export const formulaNameMap: Record = { export const PARSSURE_DATA = { intensitys: { constantPressure: null, - negativePressure: ['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'], - positivePressure: ['0%', '10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%'], + negativePressure: ['0', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100'], + positivePressure: ['0', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100'], }, typeDisplayNames: ['恒压', '正压', '负压'], types: ['constantPressure', 'positivePressure', 'negativePressure'], diff --git a/src/libs/countdownTimer.ts b/src/libs/countdownTimer.ts index 538e819..1d311f6 100644 --- a/src/libs/countdownTimer.ts +++ b/src/libs/countdownTimer.ts @@ -28,8 +28,14 @@ class CountdownTimer { private initDiaplay(): void { const seconds = Math.floor(this.endTime / 1000) const curStateRemainTimeS = this.formatTime(seconds) - this.callback && this.callback(curStateRemainTimeS) - this.endTime -= 1000 + if (this.endTime === 0 || this.endTime < 1000) { + this.callback && this.callback('0') + this.stopTimer() + } + else { + this.callback && this.callback(curStateRemainTimeS) + this.endTime -= 1000 + } } private updateDisplay(): void { diff --git a/src/libs/socket.ts b/src/libs/socket.ts index 7fe96e3..227ff31 100644 --- a/src/libs/socket.ts +++ b/src/libs/socket.ts @@ -13,6 +13,9 @@ export class WebSocketClient { private responseHandlers = new Map void>() private eventListeners = new Map void)[]>() + private connectCount = 0 + private maxConnectCount = 10 + private intervalVal: any = 0 constructor(url: string) { this.url = url @@ -161,6 +164,11 @@ export class WebSocketClient { // 重连逻辑 private reconnect() { + if (this.connectCount > this.maxConnectCount) { + clearInterval(this.intervalVal) + console.log('-----达到最大重连次数,停止重连------') + return + } this.isConnecting = true if (this.socket.readyState !== WebSocket.CLOSED && this.socket.readyState !== WebSocket.CLOSING) { this.socket.close() @@ -174,8 +182,10 @@ export class WebSocketClient { return } this.isConnecting = true - setTimeout(() => { + this.intervalVal = setInterval(() => { this.isConnecting = false + this.connectCount++ + console.log('重连------------', this.connectCount) this.reconnect() }, 3000) // 3秒后重连 } diff --git a/src/libs/utils.ts b/src/libs/utils.ts index 5e9fd95..bd31cf7 100644 --- a/src/libs/utils.ts +++ b/src/libs/utils.ts @@ -30,7 +30,7 @@ export const deviceStateMap = >{ finished: '消毒完成', dehumidificationBeforeDisinfection: '消毒前除湿', dehumidificationAfterDisinfection: '消毒后除湿', - emptyLiquidFromTheLine: '排空管路', + emptyLineLiquid: '排空管路', } export const sealStateMap = >{ @@ -96,10 +96,15 @@ export const convertValuesToString = (jsonObj: Record, exName: stri return result } -export const convertValuesToInt = (jsonObj: Record, exName: string) => { +function isNumber(str: string | number) { + // 先转换为数字,再用 isNaN 判断是否为 NaN + return !Number.isNaN(Number(str)) && Number.isFinite(Number(str)) +} + +export const convertValuesToInt = (jsonObj: Record) => { const result: Record = {} for (const [key, value] of Object.entries(jsonObj)) { - if (key !== exName) { + if (isNumber(value)) { result[key] = Number(value) } else { @@ -108,3 +113,15 @@ export const convertValuesToInt = (jsonObj: Record, exName: string) } return result } + +export const DEVICE_STATES = { + IDLE: 'idle', // 空闲 + INIT: 'init', // 初始化 + PREHEAT: 'preheat', // 预热 + DISINFECTION: 'disinfection', // 消毒 + DEGRADATION: 'degradation', // 降解 + FINISHED: 'finished', // 结束 + DEHUMIDIFICATION_BEFORE: 'dehumidification_before_disinfection', // 消毒前除湿 + DEHUMIDIFICATION_AFTER: 'dehumidification_after_disinfection', // 消毒后除湿 + EMPTY_LINE: 'empty_liquid_from_the_line', // 清空管路 +} diff --git a/src/stores/deviceStore.ts b/src/stores/deviceStore.ts index a1c787d..0ef5adb 100644 --- a/src/stores/deviceStore.ts +++ b/src/stores/deviceStore.ts @@ -1,3 +1,5 @@ +import { subscribeEvent } from '@/apis/system' +import { DEVICE_STATES } from '@/libs/utils' import { defineStore } from 'pinia' import { ref } from 'vue' @@ -12,12 +14,34 @@ const initDeviceInfo = { export const useDeviceStore = defineStore('device', () => { const deviceInfo = ref(initDeviceInfo) + const deviceStete = ref({ state: DEVICE_STATES.IDLE }) // 设备状态 + const updateDeviceInfo = (info: Device.DeviceInfo) => { deviceInfo.value = info } + /** + * @function setDeviceState + * @param {Device.State} deviceInfo - 设备状态信息 + * @desc 更新设备整体状态 + */ + const setDeviceState = (deviceInfo: Device.State) => { + deviceStete.value = deviceInfo + } + + const startSubscribDevice = () => { + subscribeEvent('stateUpdate', (report: Socket.WebSocketResponse) => { + if (report.fromClass === 'AppCore') { + deviceStete.value = report.rely + } + }) + } + return { deviceInfo, + deviceStete, updateDeviceInfo, + setDeviceState, + startSubscribDevice, } }) diff --git a/src/stores/formulaStore.ts b/src/stores/formulaStore.ts index 38b1a95..e2a84cc 100644 --- a/src/stores/formulaStore.ts +++ b/src/stores/formulaStore.ts @@ -2,7 +2,7 @@ import { FtMessage } from '@/libs/message' import { sendCmd, syncSendCmd } from 'apis/system' import { cloneDeep } from 'lodash' import { defineStore } from 'pinia' -import { computed, ref } from 'vue' +import { computed, ref, watch } from 'vue' // 常量定义 const LOG_ITEMS = Array.from({ length: 12 }, (_, i) => ({ @@ -45,10 +45,17 @@ export const useFormulaStore = defineStore('formula', () => { const formulaList = ref([]) const loglevel = ref('1') + watch(defaultFormulaInfo, (newVal) => { + currentSelectedFormulaInfo.value = cloneDeep(newVal) + }, { deep: true }) // 计算属性 const isDefaultFormula = computed(() => currentSelectedFormulaInfo.value.name === defaultFormulaInfo.value.name) - // 私有 + /** + * @function mapConfigToFormula + * @param {Formula.FormulaConfig[]} config - 配方配置列表 + * @desc 将配方配置映射为配方项对象 + */ const mapConfigToFormula = (config: Formula.FormulaConfig[]) => { const formulaMap: Record = {} config.forEach((item) => { @@ -61,13 +68,32 @@ export const useFormulaStore = defineStore('formula', () => { return formulaMap as Formula.FormulaItem } - // 公共方法 + /** + * @function updateFormulaConfigData + * @param {Formula.FormulaConfig[]} data - 配方配置数据 + * @desc 更新配方配置数据并生成默认配方 + */ const updateFormulaConfigData = (data: Formula.FormulaConfig[]) => { const visibleConfig = data.filter(item => item.is_visible_in_formula_page) formulaConfigList.value = visibleConfig defaultFormulaInfo.value = mapConfigToFormula(visibleConfig) } + const getFormualDefaultData = async () => { + const defaultParams = { + className: 'SettingMgrService', + fnName: 'getAllSetting', + params: {}, + } + const res = await sendCmd(defaultParams) + updateFormulaConfigData(res) + } + + /** + * @function updateLogLevels + * @param {Formula.FormulaConfig} logLevelItem - 日志级别配置项 + * @desc 更新日志级别选项 + */ const updateLogLevels = (logLevelItem: Formula.FormulaConfig) => { const list: System.Option[] = [] const { enum_display_names, enums } = logLevelItem @@ -82,22 +108,46 @@ export const useFormulaStore = defineStore('formula', () => { logLevelOptions.value = list } + /** + * @function updateLogLevel + * @param {string} level - 日志级别值 + * @desc 更新当前选中的日志级别 + */ const updateLogLevel = (level: string) => { loglevel.value = level } + /** + * @function updatePressurList + * @param {string[]} pressurData - 压力选项数据 + * @desc 更新压力选项列表 + */ const updatePressurList = (pressurData: string[]) => { pressurOptionList.value = cloneDeep(pressurData) } + /** + * @function updateSelectedFormulaData + * @param {Formula.FormulaItem} formulaItem - 配方项 + * @desc 更新当前选中的配方数据 + */ const updateSelectedFormulaData = (formulaItem: Formula.FormulaItem) => { currentSelectedFormulaInfo.value = cloneDeep(formulaItem) } + /** + * @function updateSelectedFormulaDataByList + * @param {Formula.FormulaItem} formulaItem - 配方项 + * @desc 通过配方列表更新选中的配方数据 + */ const updateSelectedFormulaDataByList = (formulaItem: Formula.FormulaItem) => { selectedFormulaInfo.value = cloneDeep(formulaItem) } + /** + * @function initFormulaList + * @desc 初始化配方列表,从服务器获取所有配方 + */ const initFormulaList = async () => { try { const params = { @@ -115,15 +165,28 @@ export const useFormulaStore = defineStore('formula', () => { } } + /** + * @function initFormulaData + * @desc 初始化配方数据,重置为默认配方 + */ const initFormulaData = () => { selectedFormulaInfo.value = null resetToDefaultFormula() } + /** + * @function resetToDefaultFormula + * @desc 重置为默认配方 + */ const resetToDefaultFormula = () => { currentSelectedFormulaInfo.value = cloneDeep(defaultFormulaInfo.value) } + /** + * @function saveDisinfectFormula + * @param {Formula.FormulaItem} formData - 配方数据 + * @desc 保存消毒配方并启动消毒程序 + */ const saveDisinfectFormula = async (formData: Formula.FormulaItem) => { try { const params = { @@ -165,5 +228,6 @@ export const useFormulaStore = defineStore('formula', () => { saveDisinfectFormula, updateLogLevel, resetToDefaultFormula, + getFormualDefaultData, } }) diff --git a/src/stores/homeStore.ts b/src/stores/homeStore.ts index 461d39c..901e96e 100644 --- a/src/stores/homeStore.ts +++ b/src/stores/homeStore.ts @@ -1,18 +1,10 @@ +import { DEVICE_STATES } from '@/libs/utils' import { sendCmd } from 'apis/system' import { PARSSURE_DATA } from 'libs/constant' import { defineStore } from 'pinia' import { computed, ref } from 'vue' -// 空闲 idle -// 初始化 init -// 预热 preheat -// 消毒 disinfection -// 降解 degradation -// 结束 finished -// 消毒前除湿 dehumidification_before_disinfection -// 消毒后除湿 dehumidification_after_disinfection -// 清空管路 empty_liquid_from_the_line - +// 传感器数据初始值 const h2O2Data: Home.DisplayrelyMgrParams[] = [{ type: 'inside', title: '仓内', @@ -23,29 +15,33 @@ const h2O2Data: Home.DisplayrelyMgrParams[] = [{ chartId: 'inside', }] -// 消毒中状态初始值 +// 消毒状态初始值 const initDisinfectState = { curStateRemainTimeS: 0, h2o2SensorData: h2O2Data, injectedVelocity: 0, nlog: 0, - state: 'idle', + state: DEVICE_STATES.IDLE, statedisplayName: '空闲', tlog: 0, } +/** + * 主页数据管理模块 + * @module useHomeStore + */ export const useHomeStore = defineStore('home', () => { + // 状态定义 const h2O2SensorData = ref(h2O2Data) const pressureConfig = ref(PARSSURE_DATA) const curStateRemainTime = ref() - const disinfectionState = ref(initDisinfectState)// 当前设备正在消毒时的状态 - const deviceStete = ref({ state: 'idle' }) // 设备状态 + const disinfectionState = ref(initDisinfectState) // 当前设备消毒状态 let renderTimer: any /** * @function updateHomeData - * @params data 当前设备所有环境数据。 仓内、探头 - * @desc 获取当前的压力值 + * @param {Home.DisplayrelyMgr[]} data - 当前设备所有环境数据(仓内、探头) + * @desc 更新环境传感器数据(温度、湿度、过氧化氢浓度等) */ const updateHomeData = (data: Home.DisplayrelyMgr[]) => { if (data && data.length) { @@ -58,24 +54,14 @@ export const useHomeStore = defineStore('home', () => { } } - /** - * @function getPressureConfig - * @desc 获取当前的压力值 - */ - const getPressureConfig = async () => { - const pressureParams = { - className: 'PipelinePressureControl', - fnName: 'getConfig', - params: {}, - } - const res = await sendCmd(pressureParams) - pressureConfig.value = res + const updatePressureConfig = (data: Home.ParssureData) => { + pressureConfig.value = data || PARSSURE_DATA } /** * @function updatePressure - * @param pressureData : 数组 压力类型及选择的压力值 - * @desc 更新压力类型及选择的压力值 + * @param {Array} pressureData - 压力配置数据 [压力类型, 压力值] + * @desc 更新压力类型及对应压力值配置 */ const updatePressure = async (pressureData: string | number[]) => { if (pressureData && pressureData.length) { @@ -83,19 +69,17 @@ export const useHomeStore = defineStore('home', () => { const pressureTypeParams = { className: 'PipelinePressureControl', fnName: 'setType', - params: { - type, - }, + params: { type }, } await sendCmd(pressureTypeParams) - if (type === 'positivePressure' || type === 'positivePressure') { // type 是正压或负压时保存设置的压力值 + + // 正压或负压时保存设置的压力值 + if (type === 'positivePressure' || type === 'negativePressure') { const intensity = pressureData[1] const intensityParams = { className: 'PipelinePressureControl', fnName: 'setIntensity', - params: { - intensity, - }, + params: { intensity }, } await sendCmd(intensityParams) } @@ -103,22 +87,16 @@ export const useHomeStore = defineStore('home', () => { } /** - * @function setDeviceState - * @param deviceInfo 当前设备状态 - */ - const setDeviceState = (deviceInfo: Device.State) => { - deviceStete.value = deviceInfo - } - - /** * @function updateHomeDisinfectionState - * @param disinfectState 当前设备消毒状态 + * @param {Home.DisinfectState} disinfectState - 当前消毒状态信息 + * @desc 更新消毒状态信息,每3秒更新一次传感器数据 */ const updateHomeDisinfectionState = (disinfectState: Home.DisinfectState) => { disinfectionState.value = disinfectState if (!renderTimer) { renderTimer = setTimeout(() => { - h2O2SensorData.value = [...disinfectionState.value.h2o2SensorData] // 创建副本 + h2O2SensorData.value = [...disinfectionState.value.h2o2SensorData]// 创建副本 + // updateHomeData(disinfectionState.value.h2o2SensorData) renderTimer = null }, 3000) as unknown as NodeJS.Timeout // 类型断言兼容不同环境 } @@ -126,40 +104,34 @@ export const useHomeStore = defineStore('home', () => { /** * @function updateHomeRemainTime - * @param timer 当前设备消毒状态下的剩余时间 + * @param {string} timer - 当前状态剩余时间 + * @desc 更新当前消毒状态剩余时间 */ const updateHomeRemainTime = (timer: string) => { curStateRemainTime.value = timer } + /** + * @computed isDeviceIdle + * @returns {boolean} - 设备是否处于空闲或已完成状态 + * @desc 判断设备是否处于空闲或已完成状态 + */ const isDeviceIdle = computed(() => { - return disinfectionState.value.state.toLocaleLowerCase() === 'idle' || disinfectionState.value.state === 'finished' + return disinfectionState.value.state.toLocaleLowerCase() === DEVICE_STATES.IDLE || disinfectionState.value.state === DEVICE_STATES.FINISHED }) - const subscribeDisinfectEvent = () => { - // 发起订阅 - const subParams = { - className: 'DisinfectionCtrlServiceExt', - fnName: 'startStateReport', - params: {}, - } - sendCmd(subParams) - } return { - // 属性 + // 状态属性 h2O2SensorData, - deviceStete, disinfectionState, pressureConfig, curStateRemainTime, isDeviceIdle, - // 方法 + // 操作方法 updateHomeData, updatePressure, - setDeviceState, updateHomeDisinfectionState, - getPressureConfig, + updatePressureConfig, updateHomeRemainTime, - subscribeDisinfectEvent, } }) diff --git a/src/stores/initHomeData.ts b/src/stores/initHomeData.ts index a2bee33..3104a4d 100644 --- a/src/stores/initHomeData.ts +++ b/src/stores/initHomeData.ts @@ -1,8 +1,10 @@ import { sendCmd } from '@/apis/system' import { useHomeStore } from 'stores/homeStore' import { useLiquidStore } from 'stores/liquidStore' +import { useDeviceStore } from './deviceStore' const homeStore = useHomeStore() +const deviceStore = useDeviceStore() const liquidStore = useLiquidStore() export const initData = async () => { @@ -60,5 +62,5 @@ const initBaseData = async () => { } // 当前设备状态 const deviceData = await sendCmd(deviceParams) - homeStore.setDeviceState(deviceData) + deviceStore.setDeviceState(deviceData) } diff --git a/src/stores/liquidStore.ts b/src/stores/liquidStore.ts index bf3fbde..355f74c 100644 --- a/src/stores/liquidStore.ts +++ b/src/stores/liquidStore.ts @@ -6,40 +6,67 @@ const liquidItem: Liquid.LiquidData = { workState: 'idle', workStateDisplay: '空闲', } + +/** + * 液体管理模块状态仓库 + * @module useLiquidStore + */ export const useLiquidStore = defineStore('Liquid', () => { + // 状态定义 const liquidAddWorkState = ref(liquidItem) const liquidDrainWorkState = ref(liquidItem) const liquidStateData = ref(liquidItem) const liquidTotal = ref(2500) const liquidPeriod = ref(300) + /** + * @function updateAddLiquidWorkState + * @param {Liquid.LiquidData} item - 加液工作状态数据 + * @desc 更新加液工作状态并同步到总状态 + */ const updateAddLiquidWorkState = (item: Liquid.LiquidData) => { liquidAddWorkState.value = item liquidStateData.value = item } + /** + * @function updateDrainLiquidWorkState + * @param {Liquid.LiquidData} item - 排液工作状态数据 + * @desc 更新排液工作状态并同步到总状态 + */ const updateDrainLiquidWorkState = (item: Liquid.LiquidData) => { liquidDrainWorkState.value = item liquidStateData.value = item } + /** + * @function updateLiquidState + * @param {Liquid.LiquidData} liquidInfo - 液体状态信息 + * @desc 直接更新液体总体状态 + */ const updateLiquidState = (liquidInfo: Liquid.LiquidData) => { liquidStateData.value = liquidInfo } + /** + * @function initLiquidConfig + * @param {Liquid.LiquidConfig} liquidConfig - 液体配置信息 + * @desc 初始化液体配置参数(总容量和更新周期) + */ const initLiquidConfig = async (liquidConfig: Liquid.LiquidConfig) => { liquidTotal.value = liquidConfig.maxLiquid liquidPeriod.value = liquidConfig.updatePeriod } return { - // 属性 + // 状态属性 liquidAddWorkState, liquidDrainWorkState, liquidTotal, liquidPeriod, liquidStateData, - // 方法 + + // 操作方法 updateAddLiquidWorkState, updateDrainLiquidWorkState, initLiquidConfig, diff --git a/src/stores/sealStore.ts b/src/stores/sealStore.ts index 6fd8a8e..1f6c082 100644 --- a/src/stores/sealStore.ts +++ b/src/stores/sealStore.ts @@ -1,20 +1,34 @@ import { defineStore } from 'pinia' import { ref } from 'vue' +/** + * 密封状态管理模块 + * @module useSealStore + */ export const useSealStore = defineStore('seal', () => { + // 状态定义 const sealState = ref('idle') const sealInfo = ref({ pressure: '0', workState: 'idle', workStateDisplay: '空闲', }) + + /** + * @function updateSealInfo + * @param {Seal.SealStateItem} dataInfo - 密封状态信息 + * @desc 更新密封状态信息,包括压力值和工作状态 + */ const updateSealInfo = (dataInfo: Seal.SealStateItem) => { sealInfo.value = dataInfo } return { + // 状态属性 sealState, sealInfo, + + // 操作方法 updateSealInfo, } }) diff --git a/src/stores/settingStore.ts b/src/stores/settingStore.ts index ea7c6e9..c3c6166 100644 --- a/src/stores/settingStore.ts +++ b/src/stores/settingStore.ts @@ -1,7 +1,12 @@ import { defineStore } from 'pinia' import { ref } from 'vue' +/** + * 设置管理模块 + * @module useSettingStore + */ export const useSettingStore = defineStore('setting', () => { + // 设置菜单配置 const settingMenus = [{ name: '消毒历史记录', code: 'history', @@ -19,27 +24,54 @@ export const useSettingStore = defineStore('setting', () => { code: 'deviceInfo', }] + // 历史记录数据 const historyList: Record[] = [] + /* ********************** 用户管理 **************************** */ const userList = ref([]) const addUserVisible = ref(false) const modifyPwdVisible = ref(false) const userModalState = ref('add') const currentEditUser = ref() + + /** + * @function updateUserModalState + * @param {string} state - 模态框状态 ('add' | 'edit') + * @desc 更新用户管理模态框的操作状态 + */ const updateUserModalState = (state: string) => { userModalState.value = state } + + /** + * @function updateCurrentEditUser + * @param {User.UserItem} userItem - 当前编辑的用户信息 + * @desc 更新当前正在编辑的用户数据 + */ const updateCurrentEditUser = (userItem: User.UserItem) => { currentEditUser.value = userItem } + + /** + * @function updateVisible + * @param {boolean} visible - 是否显示添加用户模态框 + * @desc 控制添加用户模态框的显示与隐藏 + */ const updateVisible = (visible: boolean) => { addUserVisible.value = visible } + /** + * @function updatePwdVisible + * @param {boolean} visible - 是否显示修改密码模态框 + * @desc 控制修改密码模态框的显示与隐藏 + */ const updatePwdVisible = (visible: boolean) => { modifyPwdVisible.value = visible } + return { + // 状态属性 settingMenus, historyList, addUserVisible, @@ -47,6 +79,8 @@ export const useSettingStore = defineStore('setting', () => { userModalState, currentEditUser, userList, + + // 操作方法 updateVisible, updateUserModalState, updateCurrentEditUser, diff --git a/src/stores/systemStore.ts b/src/stores/systemStore.ts index cbcf318..b1e2058 100644 --- a/src/stores/systemStore.ts +++ b/src/stores/systemStore.ts @@ -1,7 +1,9 @@ +import { sendCmd } from '@/apis/system' import { defineStore } from 'pinia' import { ref } from 'vue' export const useSystemStore = defineStore('system', () => { + const websocketConnected = ref(true) const systemUser = ref({ username: '', }) @@ -32,6 +34,62 @@ export const useSystemStore = defineStore('system', () => { }, 1500) } + const updateConnected = (isConnected: boolean) => { + websocketConnected.value = isConnected + } + + /** + * @function subscribeDisinfectEvent + * @desc 订阅消毒状态变更事件 + */ + const subscribeDisinfectEvent = async () => { + // 发起订阅 + const subParams = { + className: 'DisinfectionCtrlServiceExt', + fnName: 'startStateReport', + } + await sendCmd(subParams) + } + + /** + * @function subscribeAddLiquidEvent + * @desc 加液状态变更事件 + */ + const subscribeAddLiquidEvent = async () => { + // 发起订阅 + const subParams = { + className: 'AddLiquidService', + fnName: 'startStateReport', + } + await sendCmd(subParams) + } + + /** + * @function subscribeDrainLiquidEvent + * @desc 排液状态变更事件 + */ + const subscribeDrainLiquidEvent = async () => { + // 发起订阅 + const subParams = { + className: 'DrainLiquidService', + fnName: 'startStateReport', + } + await sendCmd(subParams) + } + + /** + * @function subscribeSealEvent + * @desc 密封状态变更事件 + */ + const subscribeSealEvent = async () => { + // 执行订阅 + const subParams = { + className: 'AirLeakDetectTest', + fnName: 'startStateReport', + } + await sendCmd(subParams) + } + return { systemUser, loginForm, @@ -41,6 +99,12 @@ export const useSystemStore = defineStore('system', () => { streamVisible, systemList, loading, + websocketConnected, updateLoading, + updateConnected, + subscribeDisinfectEvent, + subscribeAddLiquidEvent, + subscribeDrainLiquidEvent, + subscribeSealEvent, } }) diff --git a/src/types/system.d.ts b/src/types/system.d.ts index 97ce851..57bf95f 100644 --- a/src/types/system.d.ts +++ b/src/types/system.d.ts @@ -11,4 +11,10 @@ declare namespace System { list: T[] total: number } + + interface SendCmdParams { + className: string + fnName: string + params?: Record // 改为可选属性,搭配后面的默认值处理 + } } diff --git a/src/views/audit/index.vue b/src/views/audit/index.vue index c29731c..3a41bec 100644 --- a/src/views/audit/index.vue +++ b/src/views/audit/index.vue @@ -3,16 +3,32 @@ import { FtMessage } from '@/libs/message' import { sendCmd } from 'apis/system' import { onMounted, ref } from 'vue' -const pageNum = ref(1) -const pageSize = ref(10) -const selectedUserList = ref([]) -const totle = ref(0) +/** + * 审计日志管理组件 + * @description 展示审计日志列表,支持分页和单条记录导出功能 + */ +// 分页控制 +const pageNum = ref(1) // 当前页码 +const pageSize = ref(10) // 每页显示数量 +const totle = ref(0) // 总记录数 + +// 表格数据 +const tableData = ref([]) // 审计日志表格数据 +const selectedUserList = ref([]) // 选中的日志记录 + +/** + * @hook 生命周期钩子 - 组件挂载完成时执行 + * @description 初始化加载审计日志列表 + */ onMounted(() => { - // 获取日志列表 getAuditList() }) +/** + * @function 获取审计日志列表 + * @desc 从服务端获取分页后的审计日志数据 + */ const getAuditList = async () => { const params = { className: 'AuditMgrService', @@ -22,15 +38,24 @@ const getAuditList = async () => { pageSize: pageSize.value, }, } - const res = await sendCmd(params) - const items = res.items - tableData.value = items - totle.value = res.total + try { + const res = await sendCmd(params) + tableData.value = res.items || [] + totle.value = res.total || 0 + } + catch (error) { + FtMessage.error('获取日志列表失败') + console.error('获取审计日志失败:', error) + } } -const tableData = ref() + +/** + * @function 导出选中的审计记录 + * @desc 导出单条审计记录,需先选择一条记录 + */ const onExportRecord = () => { if (selectedUserList.value.length !== 1) { - FtMessage.warning('选择一条数据进行导出') + FtMessage.warning('请选择一条数据进行导出') return } const params = { @@ -39,12 +64,29 @@ const onExportRecord = () => { params: {}, } sendCmd(params) + .then(() => { + FtMessage.success('导出成功') + }) + .catch((error) => { + console.error('导出审计记录失败:', error) + }) } +/** + * @function 页码变更处理 + * @param {number} page - 新的页码 + * @desc 更新页码并重新加载数据 + */ const handleCurrentChange = (page: number) => { pageNum.value = page getAuditList() } + +/** + * @function 表格选择变更处理 + * @param {Audit.AuditItem[]} users - 选中的记录列表 + * @desc 更新选中的记录 + */ const handleSelectionChange = (users: Audit.AuditItem[]) => { selectedUserList.value = users } diff --git a/src/views/liquid/index.vue b/src/views/liquid/index.vue index abe1319..f2b3c4c 100644 --- a/src/views/liquid/index.vue +++ b/src/views/liquid/index.vue @@ -40,6 +40,8 @@ const btnStyle = { } onMounted(() => { + systemStore.subscribeAddLiquidEvent() + systemStore.subscribeDrainLiquidEvent() subScribeLiquid() }) @@ -101,13 +103,6 @@ const onStartAddLiquid = async () => { } systemStore.updateLoading(true) syncSendCmd(params) - // 发起订阅 - const subParams = { - className: 'AddLiquidService', - fnName: 'startStateReport', - params: {}, - } - syncSendCmd(subParams) } const onStopAddLiquid = () => { @@ -134,13 +129,6 @@ const onStartDrainLiquid = async () => { } systemStore.updateLoading(true) await sendCmd(params) - // 发起订阅 - const subParams = { - className: 'DrainLiquidService', - fnName: 'startStateReport', - params: {}, - } - syncSendCmd(subParams) } const onStopDrainLiquid = async () => { @@ -218,13 +206,14 @@ const onStopDrainLiquid = async () => {