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

288 lines
7.6 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)
  92. const poll = setInterval(() => {
  93. if (!operationState.value) {
  94. loading.close()
  95. clearInterval(poll)
  96. }
  97. }, 100)
  98. }
  99. }
  100. catch (e) {
  101. console.log(e)
  102. loading.close()
  103. }
  104. }
  105. /**
  106. * @function 结束消毒操作
  107. * @desc 停止倒计时并发起结束消毒请求
  108. */
  109. const onFinishDisinfect = () => {
  110. FtMessageBox.warning('请确认是否结束消毒').then(() => {
  111. homeStore.setRate(undefined)
  112. homeStore.setLog(undefined)
  113. doStopDisinfect()
  114. })
  115. }
  116. const doStopDisinfect = async () => {
  117. stopTimer() // 停止倒计时
  118. const loading = ElLoading.service({
  119. lock: true,
  120. text: '正在停止消毒',
  121. background: 'rgba(255, 255, 255, 0.8)',
  122. })
  123. try {
  124. const stopParams = {
  125. className: 'DisinfectionCtrlServiceExt',
  126. fnName: 'stop',
  127. params: { loglevel: formulaStore.loglevel },
  128. }
  129. await sendCmd(stopParams)
  130. const poll = setInterval(() => {
  131. if (operationState.value) {
  132. loading.close()
  133. clearInterval(poll)
  134. }
  135. }, 100)
  136. }
  137. catch (e) {
  138. console.log(e)
  139. loading.close()
  140. }
  141. }
  142. /**
  143. * @computed 计算属性 - 操作状态判断
  144. * @returns {boolean} - 是否处于空闲或已完成状态
  145. * @desc 控制开始/结束按钮的显示逻辑
  146. */
  147. const operationState = computed(() => {
  148. return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
  149. })
  150. const startInjection = async () => {
  151. const stopParams = {
  152. className: 'DisinfectionCtrlServiceExt',
  153. fnName: 'handleStartPumpInjection',
  154. params: {},
  155. }
  156. await sendCmd(stopParams)
  157. FtMessage.success('操作成功')
  158. }
  159. const stopInjection = async () => {
  160. const stopParams = {
  161. className: 'DisinfectionCtrlServiceExt',
  162. fnName: 'handleStopPumpInjection',
  163. params: {},
  164. }
  165. await sendCmd(stopParams)
  166. FtMessage.success('操作成功')
  167. }
  168. const formatSeconds = (seconds: number) => {
  169. const hours = Math.floor(seconds / 3600)
  170. const minutes = Math.floor((seconds % 3600) / 60)
  171. const remainingSeconds = seconds % 60
  172. // 补零函数
  173. const padZero = (num: number) => num.toString().padStart(2, '0')
  174. return `${padZero(hours)}:${padZero(minutes)}:${padZero(remainingSeconds)}`
  175. }
  176. </script>
  177. <template>
  178. <div class="home-disinfect">
  179. <bt-button
  180. v-if="operationState"
  181. button-text="开始消毒"
  182. bg-color="#31CB7A"
  183. :text-color="btnStyle.textColor"
  184. :width="btnStyle.width"
  185. :height="btnStyle.height"
  186. :text-size="btnStyle.textSize"
  187. :border-radius="btnStyle.borderRadius"
  188. min-height="4rem"
  189. @click="onStartDisinfect"
  190. >
  191. <template #icon>
  192. <img :src="homeStart" alt="">
  193. </template>
  194. </bt-button>
  195. <bt-button
  196. v-else
  197. button-text="结束消毒"
  198. bg-color="#FF6767"
  199. :text-color="btnStyle.textColor"
  200. :width="btnStyle.width"
  201. :height="btnStyle.height"
  202. :text-size="btnStyle.textSize"
  203. :border-radius="btnStyle.borderRadius"
  204. min-height="4rem"
  205. @click="onFinishDisinfect"
  206. >
  207. <template #icon>
  208. <img :src="homeFinish" alt="">
  209. </template>
  210. </bt-button>
  211. </div>
  212. <div
  213. v-if="!operationState"
  214. style="width: 100%; display: flex; align-items: center; justify-content: center; margin-top: 10px"
  215. >
  216. <!-- <div style="margin-right: 10px"> -->
  217. <!-- <span v-if="homeStore.disinfectionState.handlePumpStopFlag">已开启</span> -->
  218. <!-- <span v-else>已关闭</span> -->
  219. <!-- </div> -->
  220. <el-button type="primary" @click="startInjection">
  221. 开启喷液
  222. </el-button>
  223. <el-button type="danger" @click="stopInjection">
  224. 关闭喷液
  225. </el-button>
  226. </div>
  227. <!-- 开始消毒时显示剩余时间或状态 -->
  228. <div v-if="!operationState" class="home-remain-time">
  229. <div class="home-remaini-label">
  230. <span v-if="disinfectionState.state === 'disinfection'"> 预计剩余时间: </span>
  231. <span v-else> 消毒状态 </span>
  232. </div>
  233. <div v-if="disinfectionState.state === 'disinfection'" class="home-remaini-value">
  234. {{ formatSeconds(homeStore.disinfectionState.curStateRemainTimeS) }}
  235. </div>
  236. <div v-else>
  237. {{ deviceStateMap[disinfectionState.state] }}
  238. </div>
  239. </div>
  240. </template>
  241. <style lang="scss" scoped>
  242. .home-disinfect {
  243. display: flex;
  244. justify-content: center;
  245. margin-top: 20px;
  246. }
  247. .home-start {
  248. background: #31cb7a;
  249. }
  250. .home-end {
  251. background: #ff6767;
  252. }
  253. .home-remain-time {
  254. background: #fff;
  255. margin: 10px;
  256. height: 40px;
  257. border-radius: 12px;
  258. display: flex;
  259. align-items: center;
  260. justify-content: center;
  261. font-size: 20px;
  262. gap: 10px;
  263. .home-remaini-value {
  264. color: #2892f3;
  265. }
  266. }
  267. </style>