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.
290 lines
7.7 KiB
290 lines
7.7 KiB
<script lang="ts" setup>
|
|
import { sendCmd } from 'apis/system'
|
|
import homeFinish from 'assets/images/home/home-finish.svg'
|
|
import homeStart from 'assets/images/home/home-start.svg'
|
|
import { ElLoading } from 'element-plus'
|
|
import { startTimer, stopTimer } from 'libs/countdownTimer'
|
|
import { deviceStateMap } from 'libs/utils'
|
|
import { computed, ref, watchEffect } from 'vue'
|
|
|
|
import { getDeviceStatus } from '@/libs/deviceComm'
|
|
import { FtMessage } from '@/libs/message'
|
|
import { FtMessageBox } from '@/libs/messageBox'
|
|
import { useFormulaStore } from '@/stores/formulaStore'
|
|
import { useHomeStore } from '@/stores/homeStore'
|
|
|
|
/**
|
|
* 消毒操作控制组件
|
|
* @description 负责处理消毒流程控制(开始/结束)、状态监听及倒计时逻辑
|
|
*/
|
|
|
|
// 状态管理
|
|
const homeStore = useHomeStore()
|
|
const formulaStore = useFormulaStore()
|
|
|
|
// 组件状态
|
|
const curStateRemainTimeS = ref<string>('') // 当前状态剩余时间(字符串格式)
|
|
const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
|
|
const btnStyle = {
|
|
width: '25vw',
|
|
height: '7vh',
|
|
textSize: '24px',
|
|
borderRadius: '12px',
|
|
textColor: '#FFFFFF',
|
|
}
|
|
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) => {
|
|
homeStore.updateHomeRemainTime(times)
|
|
curStateRemainTimeS.value = times
|
|
})
|
|
}
|
|
})
|
|
|
|
/**
|
|
* @function 开始消毒操作
|
|
* @desc 校验设备状态并发起消毒请求
|
|
*/
|
|
const onStartDisinfect = () => {
|
|
// 校验日志等级
|
|
if (!formulaStore.loglevel) {
|
|
FtMessage.warning('请选择消毒等级')
|
|
return
|
|
}
|
|
|
|
FtMessageBox.warning('请确认是否开始消毒').then(() => {
|
|
doStartDisinfect()
|
|
})
|
|
}
|
|
|
|
const doStartDisinfect = async () => {
|
|
// 校验设备状态
|
|
const statusName = getDeviceStatus()
|
|
if (statusName) {
|
|
FtMessageBox.error(statusName)
|
|
return
|
|
}
|
|
|
|
const loading = ElLoading.service({
|
|
lock: true,
|
|
text: '准备开始消毒',
|
|
background: 'rgba(255, 255, 255, 0.8)',
|
|
})
|
|
try {
|
|
// 使用选中配方或默认配置启动消毒
|
|
if (formulaStore.selectedFormulaInfo && formulaStore.selectedFormulaInfo.formula_id) {
|
|
await formulaStore.startDisinfectFormula(formulaStore.selectedFormulaInfo)
|
|
const poll = setInterval(() => {
|
|
if (!operationState.value) {
|
|
loading.close()
|
|
clearInterval(poll)
|
|
}
|
|
}, 100)
|
|
}
|
|
else {
|
|
const startParams = {
|
|
className: 'DisinfectionCtrlServiceExt',
|
|
fnName: 'start',
|
|
params: { loglevel: formulaStore.loglevel },
|
|
}
|
|
await sendCmd(startParams).catch((res) => {
|
|
FtMessageBox.error(`错误码: ${res.ackcode}, 信息: ${res.message}`)
|
|
})
|
|
const poll = setInterval(() => {
|
|
if (!operationState.value) {
|
|
loading.close()
|
|
clearInterval(poll)
|
|
}
|
|
}, 100)
|
|
}
|
|
}
|
|
catch (e) {
|
|
console.log(e)
|
|
loading.close()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @function 结束消毒操作
|
|
* @desc 停止倒计时并发起结束消毒请求
|
|
*/
|
|
const onFinishDisinfect = () => {
|
|
FtMessageBox.warning('请确认是否结束消毒').then(() => {
|
|
homeStore.setRate(undefined)
|
|
homeStore.setLog(undefined)
|
|
doStopDisinfect()
|
|
})
|
|
}
|
|
|
|
const doStopDisinfect = async () => {
|
|
stopTimer() // 停止倒计时
|
|
const loading = ElLoading.service({
|
|
lock: true,
|
|
text: '正在停止消毒',
|
|
background: 'rgba(255, 255, 255, 0.8)',
|
|
})
|
|
try {
|
|
const stopParams = {
|
|
className: 'DisinfectionCtrlServiceExt',
|
|
fnName: 'stop',
|
|
params: { loglevel: formulaStore.loglevel },
|
|
}
|
|
await sendCmd(stopParams)
|
|
const poll = setInterval(() => {
|
|
if (operationState.value) {
|
|
loading.close()
|
|
clearInterval(poll)
|
|
}
|
|
}, 100)
|
|
}
|
|
catch (e) {
|
|
console.log(e)
|
|
loading.close()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @computed 计算属性 - 操作状态判断
|
|
* @returns {boolean} - 是否处于空闲或已完成状态
|
|
* @desc 控制开始/结束按钮的显示逻辑
|
|
*/
|
|
const operationState = computed(() => {
|
|
return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
|
|
})
|
|
|
|
const startInjection = async () => {
|
|
const stopParams = {
|
|
className: 'DisinfectionCtrlServiceExt',
|
|
fnName: 'handleStartPumpInjection',
|
|
params: {},
|
|
}
|
|
await sendCmd(stopParams)
|
|
FtMessage.success('操作成功')
|
|
}
|
|
|
|
const stopInjection = async () => {
|
|
const stopParams = {
|
|
className: 'DisinfectionCtrlServiceExt',
|
|
fnName: 'handleStopPumpInjection',
|
|
params: {},
|
|
}
|
|
await sendCmd(stopParams)
|
|
FtMessage.success('操作成功')
|
|
}
|
|
|
|
const formatSeconds = (seconds: number) => {
|
|
const hours = Math.floor(seconds / 3600)
|
|
const minutes = Math.floor((seconds % 3600) / 60)
|
|
const remainingSeconds = seconds % 60
|
|
|
|
// 补零函数
|
|
const padZero = (num: number) => num.toString().padStart(2, '0')
|
|
|
|
return `${padZero(hours)}:${padZero(minutes)}:${padZero(remainingSeconds)}`
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="home-disinfect">
|
|
<bt-button
|
|
v-if="operationState"
|
|
button-text="开始消毒"
|
|
bg-color="#31CB7A"
|
|
:text-color="btnStyle.textColor"
|
|
:width="btnStyle.width"
|
|
:height="btnStyle.height"
|
|
:text-size="btnStyle.textSize"
|
|
:border-radius="btnStyle.borderRadius"
|
|
min-height="4rem"
|
|
@click="onStartDisinfect"
|
|
>
|
|
<template #icon>
|
|
<img :src="homeStart" alt="">
|
|
</template>
|
|
</bt-button>
|
|
<bt-button
|
|
v-else
|
|
button-text="结束消毒"
|
|
bg-color="#FF6767"
|
|
:text-color="btnStyle.textColor"
|
|
:width="btnStyle.width"
|
|
:height="btnStyle.height"
|
|
:text-size="btnStyle.textSize"
|
|
:border-radius="btnStyle.borderRadius"
|
|
min-height="4rem"
|
|
@click="onFinishDisinfect"
|
|
>
|
|
<template #icon>
|
|
<img :src="homeFinish" alt="">
|
|
</template>
|
|
</bt-button>
|
|
</div>
|
|
<div
|
|
v-if="!operationState"
|
|
style="width: 100%; display: flex; align-items: center; justify-content: center; margin-top: 10px"
|
|
>
|
|
<!-- <div style="margin-right: 10px"> -->
|
|
<!-- <span v-if="homeStore.disinfectionState.handlePumpStopFlag">已开启</span> -->
|
|
<!-- <span v-else>已关闭</span> -->
|
|
<!-- </div> -->
|
|
<el-button type="primary" @click="startInjection">
|
|
开启喷液
|
|
</el-button>
|
|
<el-button type="danger" @click="stopInjection">
|
|
关闭喷液
|
|
</el-button>
|
|
</div>
|
|
|
|
<!-- 开始消毒时显示剩余时间或状态 -->
|
|
<div v-if="!operationState" class="home-remain-time">
|
|
<div class="home-remaini-label">
|
|
<span v-if="disinfectionState.state === 'disinfection'"> 预计剩余时间: </span>
|
|
<span v-else> 消毒状态: </span>
|
|
</div>
|
|
<div v-if="disinfectionState.state === 'disinfection'" class="home-remaini-value">
|
|
{{ formatSeconds(homeStore.disinfectionState.curStateRemainTimeS) }}
|
|
</div>
|
|
<div v-else>
|
|
{{ deviceStateMap[disinfectionState.state] }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.home-disinfect {
|
|
display: flex;
|
|
justify-content: center;
|
|
margin-top: 20px;
|
|
}
|
|
.home-start {
|
|
background: #31cb7a;
|
|
}
|
|
.home-end {
|
|
background: #ff6767;
|
|
}
|
|
.home-remain-time {
|
|
background: #fff;
|
|
margin: 10px;
|
|
height: 40px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 20px;
|
|
gap: 10px;
|
|
.home-remaini-value {
|
|
color: #2892f3;
|
|
}
|
|
}
|
|
</style>
|