You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
9.3 KiB
341 lines
9.3 KiB
<script lang="ts" setup>
|
|
import { FtMessage } from '@/libs/message'
|
|
import { useFormulaStore } from '@/stores/formulaStore'
|
|
import { useHomeStore } from '@/stores/homeStore'
|
|
import { sendCmd, syncSendCmd } from 'apis/system'
|
|
// import homeChart from 'assets/images/home/home-chart.svg'
|
|
import homeRunSvg from 'assets/images/home/home-run.svg'
|
|
import homeSettingSvg from 'assets/images/home/home-setting.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'
|
|
|
|
/**
|
|
* 主页操作控制组件
|
|
* @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<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)
|
|
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
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="home-start-opt">
|
|
<div class="home-opt-flex">
|
|
<div>
|
|
<BtButton
|
|
button-text="压力控制"
|
|
text-size="1.3rem"
|
|
border-radius="5px"
|
|
width="7.5rem"
|
|
text-color="#1989fa"
|
|
height="3rem"
|
|
@click="onSetPressure"
|
|
>
|
|
<template #icon>
|
|
<el-icon><Sort /></el-icon>
|
|
</template>
|
|
</BtButton>
|
|
</div>
|
|
<div class="home-opt-ml">
|
|
<BtButton
|
|
button-text="查看图表"
|
|
text-size="1.3rem"
|
|
border-radius="5px"
|
|
width="7.5rem"
|
|
height="3rem"
|
|
text-color="#1989fa"
|
|
:disabled="deviceState"
|
|
@click="onShowChart"
|
|
>
|
|
<template #icon>
|
|
<el-icon><Picture /></el-icon>
|
|
</template>
|
|
</BtButton>
|
|
</div>
|
|
<div class="home-opt-ml">
|
|
<BtButton
|
|
v-if="deviceState"
|
|
button-text="消毒设置"
|
|
text-size="1.3rem"
|
|
border-radius="5px"
|
|
width="7.5rem"
|
|
text-color="#1989fa"
|
|
height="3rem"
|
|
@click="onDisinfectConfig"
|
|
>
|
|
<template #icon>
|
|
<img :src="homeSettingSvg" width="12" style="margin-right: 5px" alt="">
|
|
</template>
|
|
</BtButton>
|
|
<BtButton
|
|
v-else
|
|
button-text="运行参数"
|
|
text-size="1rem"
|
|
border-radius="5px"
|
|
width="7rem"
|
|
text-color="#1989fa"
|
|
height="3rem"
|
|
@click="onDisinfectConfig"
|
|
>
|
|
<template #icon>
|
|
<img :src="homeRunSvg" width="15" alt="">
|
|
</template>
|
|
</BtButton>
|
|
</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
|
|
bgColor="#1989fa"
|
|
button-text="确认"
|
|
text-size="1rem"
|
|
border-radius="5px"
|
|
width="7rem"
|
|
textSize="1.5rem"
|
|
text-color="#ffffff"
|
|
height="3rem"
|
|
@click="onSave"
|
|
/>
|
|
<BtButton
|
|
button-text="取消"
|
|
text-size="1rem"
|
|
border-radius="5px"
|
|
width="7rem"
|
|
textSize="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;
|
|
.home-opt-flex{
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr;
|
|
.home-opt-ml{
|
|
margin-left: 5px;
|
|
}
|
|
}
|
|
}
|
|
.config-btn{
|
|
margin-top: -3rem
|
|
}
|
|
</style>
|