|
|
<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 { 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 () => { 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' })
/** * @function 打开消毒设置对话框 * @desc 根据当前选中配方或默认配方初始化设置 */ const onDisinfectConfig = () => { 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() 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() // 关闭对话框
}
/** * @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 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 (deviceStore.isLowCost) { return '13rem' } return '7.5rem' }) </script>
<template> <div class="home-start-opt"> <div class="home-opt-flex"> <div v-if="!deviceStore.isLowCost"> <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="1rem" border-radius="5px" :width="settingWidth" text-color="#1989fa" height="3rem" @click="onDisinfectConfig" /> </div> </div> </div> <ft-dialog v-model="disinfectFormulaVisible" width="80vw" style="height: 95vh"> <div> <Config ref="configRef" /> </div> <template #footer> <div class="config-btn"> <BtButton bg-color="#1989fa" button-text="确认" border-radius="5px" width="7rem" text-size="1.5rem" text-color="#ffffff" height="3rem" @click="onSave" /> <BtButton button-text="取消" border-radius="5px" width="7rem" text-size="1.5rem" text-color="#1989fa" height="3rem" @click="onClose" /> </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{ position: absolute; bottom: 0; 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-btn{ margin-top: -3rem } </style>
|