|
|
<script lang="ts" setup> import { sendCmd, syncSendCmd } from 'apis/system' // import homeChart from 'assets/images/home/home-chart.svg'
import BtButton from 'components/common/BTButton/index.vue' import CascadingSelectModal from 'components/common/CascadingSelectModal/index.vue' import Config from 'components/home/config.vue' import { getDeviceStatus } from 'libs/deviceComm' import { FtMessageBox } from 'libs/messageBox' import { compareJSON } from 'libs/utils' import { cloneDeep } from 'lodash' import { computed, onMounted, provide, ref, watchEffect } from 'vue' import { useRouter } from 'vue-router'
import { FtMessage } from '@/libs/message' import { useDeviceStore } from '@/stores/deviceStore' import { useFormulaStore } from '@/stores/formulaStore' import { useHomeStore } from '@/stores/homeStore'
/** * 主页操作控制组件 * @description 负责处理压力控制、消毒设置、图表导航等功能,协调组件间通信 */
// 依赖注入
const configRef = ref() provide<(methods: Home.GrandsonMethods) => void>('registerGrandsonMethods', (methods) => { configRef.value = methods })
// 状态管理
const router = useRouter() const formulaStore = useFormulaStore() const deviceStore = useDeviceStore() const homeStore = useHomeStore()
// 组件状态
const isModalOpen = ref(false) // 级联选择模态框是否打开
const optionsLeft = ref<System.Option[]>([]) // 压力类型选项(左列)
const optionsRight = ref<System.Option[]>([]) // 压力强度选项(右列)
const selectedValue = ref() // 选中的压力配置值
const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
const disinfectFormulaVisible = ref(false) // 消毒设置对话框是否显示
const selectedByFormulas = ref(cloneDeep(formulaStore.selectedFormulaInfo)) // 当前选中的配方信息
const pressureConfig = ref(homeStore.pressureConfig) const defaultIntensityValue = ref()
/** * @hook 响应式依赖监听 * @description 监听消毒状态和配方变化,同步更新组件状态 */ watchEffect(() => { disinfectionState.value = homeStore.disinfectionState selectedByFormulas.value = formulaStore.selectedFormulaInfo pressureConfig.value = homeStore.pressureConfig })
/** * @hook 生命周期钩子 - 组件挂载完成时执行 * @description 初始化压力配置 */ onMounted(async () => { const deviceInfo: Device.DeviceInfo = deviceStore.deviceInfo if (deviceInfo.deviceType !== useDeviceStore().deviceTypeMap.LargeSpaceDM_B) { await getPressureConfig() // 获取压力配置
} })
/** * @function getPressureConfig * @desc 获取当前压力配置信息 */ const getPressureConfig = async () => { const pressureParams = { className: 'PipelinePressureControl', fnName: 'getConfig', } const res = await syncSendCmd(pressureParams) if (res.ackcode === 0) { homeStore.updatePressureConfig(res.rely) } }
/** * @computed 计算属性 - 设备状态判断 * @returns {boolean} - 设备是否处于空闲或已完成状态 * @desc 控制按钮可用状态 */ const deviceState = computed(() => { return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished' }) const disinfectFormulaTitle = ref<string>('消毒设置') /** * @function 打开消毒设置对话框 * @desc 根据当前选中配方或默认配方初始化设置 */ const onDisinfectConfig = (title: string) => { formulaStore.updateSelectedFormulaDataByList(selectedByFormulas.value || cloneDeep(formulaStore.defaultFormulaInfo)) disinfectFormulaVisible.value = true disinfectFormulaTitle.value = title }
/** * @function 导航到图表页面 * @desc 路由跳转至消毒图表页面 */ const onShowChart = () => { router.push('/home/chart') }
/** * @function 保存消毒参数 * @desc 处理表单数据保存逻辑,区分消毒中与非消毒状态 */ const onSave = async () => { const formData = configRef.value?.getFormData() if (!formData) { return } formulaStore.updateSelectedFormulaDataByList(cloneDeep(formData)) // 更新选中配方
if (!homeStore.isDeviceIdle) { // 消毒中时更新实时配置
const res = await sendCmd({ className: 'DisinfectionCtrlServiceExt', fnName: 'getRealtimeConfig', params: {}, }) 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 { // 非消毒时保存配方
if (formData.formula_id) { formulaStore.updateSelectedFormulaDataByList(formData) } } onClose() // 关闭对话框
} console.log(onSave)
/** * @function 设置实时消毒参数 * @param {string} key - 参数键名 * @param {string} val - 参数值 * @desc 向设备发送实时参数修改指令 */ const setRealtimeConfig = async (key: string, val: string) => { await syncSendCmd({ className: 'DisinfectionCtrlServiceExt', fnName: 'setRealtimeConfig', params: { key, val }, }) }
/** * @function 打开压力控制模态框 * @desc 初始化压力类型和强度选项 */ const onSetPressure = () => { // 校验设备状态
const statusName = getDeviceStatus() if (statusName) { FtMessageBox.error(statusName) return } 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 }) }) }
optionsLeft.value = leftOptions optionsRight.value = rightOptions
// 获取已经设置的压力值
syncSendCmd({ className: 'PipelinePressureControl', fnName: 'getState', }).then((res) => { if (res.ackcode === 0) { defaultIntensityValue.value = res.rely.intensity homeStore.updateDefaultIntensityValue(res.rely.intensity) homeStore.updateDefaultIntensityTypeValue(res.rely.type) 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 }
const settingWidth = computed(() => { if (__DEVICE_TYPE__ === deviceStore.deviceTypeMap.LargeSpaceDM_B) { return '12rem' } return '7.5rem' }) </script>
<template> <div class="home-start-opt"> <div class="home-opt-flex"> <div v-if="__DEVICE_TYPE__ === deviceStore.deviceTypeMap.PipeDM"> <BtButton button-text="压力控制" text-size="1.3rem" border-radius="5px" width="7.5rem" text-color="#1989fa" height="3rem" @click="onSetPressure" /> </div> <div class="home-opt-ml"> <BtButton button-text="查看图表" text-size="1.3rem" border-radius="5px" :width="settingWidth" height="3rem" text-color="#1989fa" :disabled="deviceState" @click="onShowChart" /> </div> <div class="home-opt-ml"> <BtButton v-if="deviceState" button-text="消毒设置" text-size="1.3rem" border-radius="5px" :width="settingWidth" text-color="#1989fa" height="3rem" @click="onDisinfectConfig('消毒设置')" /> <BtButton v-else button-text="运行参数" text-size="1.3rem" border-radius="5px" :width="settingWidth" text-color="#1989fa" height="3rem" @click="onDisinfectConfig('运行参数')" /> </div> </div> </div> <ft-dialog v-model="disinfectFormulaVisible" :title="disinfectFormulaTitle" width="80vw"> <div style="height: 80vh; overflow: auto"> <Config ref="configRef" /> </div> <template #footer> <div class="config-btn"> <BtButton button-text="关闭" border-radius="5px" width="7rem" text-size="1.5rem" text-color="#1989fa" height="3rem" @click="onClose" /> <!-- <BtButton --> <!-- bg-color="#1989fa" --> <!-- button-text="确认" --> <!-- border-radius="5px" --> <!-- width="7rem" --> <!-- text-size="1.5rem" --> <!-- text-color="#ffffff" --> <!-- height="3rem" --> <!-- @click="onSave" --> <!-- /> --> </div> </template> </ft-dialog> <CascadingSelectModal v-if="isModalOpen" :options-left="optionsLeft" :options="optionsRight" :selected-value="selectedValue" :default-value="defaultIntensityValue" placeholder="请选择" @confirm="handleConfirm" @cancel="handleCancel" /> </template>
<style lang="scss" scoped> .home-start-opt { margin: 0.5rem; gap: 5px; width: 100%; .home-opt-flex { display: grid; grid-template-columns: 1fr 1fr 1fr; .home-opt-ml { margin-left: 5px; } } }
.config { border: 1px solid red; } .config-btn { //margin-top: -3rem
} </style>
|