消毒机设备
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

3 weeks ago
1 month ago
1 month ago
1 month ago
1 month ago
3 weeks ago
3 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
  1. <script lang="ts" setup>
  2. import { sendCmd } from 'apis/system'
  3. import homeFinish from 'assets/images/home/home-finish.svg'
  4. import homeStart from 'assets/images/home/home-start.svg'
  5. import { ElLoading } from 'element-plus'
  6. import { startTimer, stopTimer } from 'libs/countdownTimer'
  7. import { deviceStateMap } from 'libs/utils'
  8. import { computed, ref, watchEffect } from 'vue'
  9. import { getDeviceStatus } from '@/libs/deviceComm'
  10. import { FtMessage } from '@/libs/message'
  11. import { FtMessageBox } from '@/libs/messageBox'
  12. import { useFormulaStore } from '@/stores/formulaStore'
  13. import { useHomeStore } from '@/stores/homeStore'
  14. /**
  15. * 消毒操作控制组件
  16. * @description 负责处理消毒流程控制开始/结束状态监听及倒计时逻辑
  17. */
  18. // 状态管理
  19. const homeStore = useHomeStore()
  20. const formulaStore = useFormulaStore()
  21. // 组件状态
  22. const curStateRemainTimeS = ref<string>('') // 当前状态剩余时间(字符串格式)
  23. const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
  24. const btnStyle = {
  25. width: '25vw',
  26. height: '7vh',
  27. textSize: '24px',
  28. borderRadius: '12px',
  29. textColor: '#FFFFFF',
  30. }
  31. let isDisinfection = false // 是否处于消毒中状态
  32. /**
  33. * @hook 响应式依赖监听
  34. * @description 监听消毒状态变化处理倒计时逻辑
  35. */
  36. watchEffect(() => {
  37. disinfectionState.value = homeStore.disinfectionState
  38. const time = disinfectionState.value.curStateRemainTimeS
  39. // 进入消毒状态且未启动倒计时时开始计时
  40. if (disinfectionState.value.state === 'disinfection' && !isDisinfection && time > 0) {
  41. isDisinfection = true
  42. startTimer(time * 1000, (times: string) => {
  43. homeStore.updateHomeRemainTime(times)
  44. curStateRemainTimeS.value = times
  45. })
  46. }
  47. })
  48. /**
  49. * @function 开始消毒操作
  50. * @desc 校验设备状态并发起消毒请求
  51. */
  52. const onStartDisinfect = () => {
  53. // 校验日志等级
  54. if (!formulaStore.loglevel) {
  55. FtMessage.warning('请选择消毒等级')
  56. return
  57. }
  58. FtMessageBox.warning('请确认是否开始消毒').then(() => {
  59. doStartDisinfect()
  60. })
  61. }
  62. const doStartDisinfect = async () => {
  63. // 校验设备状态
  64. const statusName = getDeviceStatus()
  65. if (statusName) {
  66. FtMessageBox.error(statusName)
  67. return
  68. }
  69. const loading = ElLoading.service({
  70. lock: true,
  71. text: '准备开始消毒',
  72. background: 'rgba(255, 255, 255, 0.8)',
  73. })
  74. try {
  75. // 使用选中配方或默认配置启动消毒
  76. if (formulaStore.selectedFormulaInfo && formulaStore.selectedFormulaInfo.formula_id) {
  77. await formulaStore.startDisinfectFormula(formulaStore.selectedFormulaInfo)
  78. const poll = setInterval(() => {
  79. if (!operationState.value) {
  80. loading.close()
  81. clearInterval(poll)
  82. }
  83. }, 100)
  84. }
  85. else {
  86. const startParams = {
  87. className: 'DisinfectionCtrlServiceExt',
  88. fnName: 'start',
  89. params: { loglevel: formulaStore.loglevel },
  90. }
  91. await sendCmd(startParams).catch((res) => {
  92. FtMessageBox.error(`错误码: ${res.ackcode}, 信息: ${res.message}`)
  93. })
  94. const poll = setInterval(() => {
  95. if (!operationState.value) {
  96. loading.close()
  97. clearInterval(poll)
  98. }
  99. }, 100)
  100. }
  101. }
  102. catch (e) {
  103. console.log(e)
  104. loading.close()
  105. }
  106. }
  107. /**
  108. * @function 结束消毒操作
  109. * @desc 停止倒计时并发起结束消毒请求
  110. */
  111. const onFinishDisinfect = () => {
  112. FtMessageBox.warning('请确认是否结束消毒').then(() => {
  113. homeStore.setRate(undefined)
  114. homeStore.setLog(undefined)
  115. doStopDisinfect()
  116. })
  117. }
  118. const doStopDisinfect = async () => {
  119. stopTimer() // 停止倒计时
  120. const loading = ElLoading.service({
  121. lock: true,
  122. text: '正在停止消毒',
  123. background: 'rgba(255, 255, 255, 0.8)',
  124. })
  125. try {
  126. const stopParams = {
  127. className: 'DisinfectionCtrlServiceExt',
  128. fnName: 'stop',
  129. params: { loglevel: formulaStore.loglevel },
  130. }
  131. await sendCmd(stopParams)
  132. const poll = setInterval(() => {
  133. if (operationState.value) {
  134. loading.close()
  135. clearInterval(poll)
  136. }
  137. }, 100)
  138. }
  139. catch (e) {
  140. console.log(e)
  141. loading.close()
  142. }
  143. }
  144. /**
  145. * @computed 计算属性 - 操作状态判断
  146. * @returns {boolean} - 是否处于空闲或已完成状态
  147. * @desc 控制开始/结束按钮的显示逻辑
  148. */
  149. const operationState = computed(() => {
  150. return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
  151. })
  152. const startInjection = async () => {
  153. const stopParams = {
  154. className: 'DisinfectionCtrlServiceExt',
  155. fnName: 'handleStartPumpInjection',
  156. params: {},
  157. }
  158. await sendCmd(stopParams)
  159. FtMessage.success('操作成功')
  160. }
  161. const stopInjection = async () => {
  162. const stopParams = {
  163. className: 'DisinfectionCtrlServiceExt',
  164. fnName: 'handleStopPumpInjection',
  165. params: {},
  166. }
  167. await sendCmd(stopParams)
  168. FtMessage.success('操作成功')
  169. }
  170. const formatSeconds = (seconds: number) => {
  171. const hours = Math.floor(seconds / 3600)
  172. const minutes = Math.floor((seconds % 3600) / 60)
  173. const remainingSeconds = seconds % 60
  174. // 补零函数
  175. const padZero = (num: number) => num.toString().padStart(2, '0')
  176. return `${padZero(hours)}:${padZero(minutes)}:${padZero(remainingSeconds)}`
  177. }
  178. </script>
  179. <template>
  180. <div class="home-disinfect">
  181. <bt-button
  182. v-if="operationState"
  183. button-text="开始消毒"
  184. bg-color="#31CB7A"
  185. :text-color="btnStyle.textColor"
  186. :width="btnStyle.width"
  187. :height="btnStyle.height"
  188. :text-size="btnStyle.textSize"
  189. :border-radius="btnStyle.borderRadius"
  190. min-height="4rem"
  191. @click="onStartDisinfect"
  192. >
  193. <template #icon>
  194. <img :src="homeStart" alt="">
  195. </template>
  196. </bt-button>
  197. <bt-button
  198. v-else
  199. button-text="结束消毒"
  200. bg-color="#FF6767"
  201. :text-color="btnStyle.textColor"
  202. :width="btnStyle.width"
  203. :height="btnStyle.height"
  204. :text-size="btnStyle.textSize"
  205. :border-radius="btnStyle.borderRadius"
  206. min-height="4rem"
  207. @click="onFinishDisinfect"
  208. >
  209. <template #icon>
  210. <img :src="homeFinish" alt="">
  211. </template>
  212. </bt-button>
  213. </div>
  214. <div
  215. v-if="!operationState"
  216. style="width: 100%; display: flex; align-items: center; justify-content: center; margin-top: 10px"
  217. >
  218. <!-- <div style="margin-right: 10px"> -->
  219. <!-- <span v-if="homeStore.disinfectionState.handlePumpStopFlag">已开启</span> -->
  220. <!-- <span v-else>已关闭</span> -->
  221. <!-- </div> -->
  222. <el-button type="primary" @click="startInjection">
  223. 开启喷液
  224. </el-button>
  225. <el-button type="danger" @click="stopInjection">
  226. 关闭喷液
  227. </el-button>
  228. </div>
  229. <!-- 开始消毒时显示剩余时间或状态 -->
  230. <div v-if="!operationState" class="home-remain-time">
  231. <div class="home-remaini-label">
  232. <span v-if="disinfectionState.state === 'disinfection'"> 预计剩余时间: </span>
  233. <span v-else> 消毒状态 </span>
  234. </div>
  235. <div v-if="disinfectionState.state === 'disinfection'" class="home-remaini-value">
  236. {{ formatSeconds(homeStore.disinfectionState.curStateRemainTimeS) }}
  237. </div>
  238. <div v-else>
  239. {{ deviceStateMap[disinfectionState.state] }}
  240. </div>
  241. </div>
  242. </template>
  243. <style lang="scss" scoped>
  244. .home-disinfect {
  245. display: flex;
  246. justify-content: center;
  247. margin-top: 20px;
  248. }
  249. .home-start {
  250. background: #31cb7a;
  251. }
  252. .home-end {
  253. background: #ff6767;
  254. }
  255. .home-remain-time {
  256. background: #fff;
  257. margin: 10px;
  258. height: 40px;
  259. border-radius: 12px;
  260. display: flex;
  261. align-items: center;
  262. justify-content: center;
  263. font-size: 20px;
  264. gap: 10px;
  265. .home-remaini-value {
  266. color: #2892f3;
  267. }
  268. }
  269. </style>