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

251 lines
6.5 KiB

3 weeks ago
1 month ago
1 month ago
1 month ago
3 weeks ago
3 weeks ago
  1. <script lang="ts" setup>
  2. import { sendCmd, subscribeEvent } 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 { startTimer, stopTimer } from 'libs/countdownTimer'
  6. import { deviceStateMap } from 'libs/utils'
  7. import { computed, onMounted, ref, watchEffect } from 'vue'
  8. import { getDeviceStatus } from '@/libs/deviceComm'
  9. import { FtMessage } from '@/libs/message'
  10. import { FtMessageBox } from '@/libs/messageBox'
  11. import { useFormulaStore } from '@/stores/formulaStore'
  12. import { useHomeStore } from '@/stores/homeStore'
  13. import { useSystemStore } from '@/stores/systemStore'
  14. /**
  15. * 消毒操作控制组件
  16. * @description 负责处理消毒流程控制开始/结束状态监听及倒计时逻辑
  17. */
  18. // 状态管理
  19. const homeStore = useHomeStore()
  20. const formulaStore = useFormulaStore()
  21. const systemStore = useSystemStore()
  22. // 组件状态
  23. const curStateRemainTimeS = ref<string>('') // 当前状态剩余时间(字符串格式)
  24. const disinfectionState = ref(homeStore.disinfectionState) // 消毒状态
  25. const btnStyle = {
  26. width: '25vw',
  27. height: '7vh',
  28. textSize: '24px',
  29. borderRadius: '12px',
  30. textColor: '#FFFFFF',
  31. }
  32. let isDisinfection = false // 是否处于消毒中状态
  33. /**
  34. * @hook 响应式依赖监听
  35. * @description 监听消毒状态变化处理倒计时逻辑
  36. */
  37. watchEffect(() => {
  38. disinfectionState.value = homeStore.disinfectionState
  39. const time = disinfectionState.value.curStateRemainTimeS
  40. // 进入消毒状态且未启动倒计时时开始计时
  41. if (disinfectionState.value.state === 'disinfection' && !isDisinfection && time > 0) {
  42. isDisinfection = true
  43. startTimer(time * 1000, (times: string) => {
  44. homeStore.updateHomeRemainTime(times)
  45. curStateRemainTimeS.value = times
  46. })
  47. }
  48. })
  49. /**
  50. * @hook 生命周期钩子 - 组件挂载完成时执行
  51. * @description 订阅消毒状态更新事件
  52. */
  53. onMounted(async () => {
  54. await systemStore.subscribeDisinfectEvent() // 订阅状态更新
  55. subscribeEvent('stateUpdate', handleDisinfectState)
  56. })
  57. /**
  58. * @function 处理消毒状态更新事件
  59. * @param {Socket.WebSocketResponse<Home.DisinfectState>} report - 状态更新报告
  60. * @desc 接收并更新消毒状态数据
  61. */
  62. const handleDisinfectState = (report: Socket.WebSocketResponse<Home.DisinfectState>) => {
  63. if (report.fromClass === 'DisinfectionCtrlServiceExt') {
  64. homeStore.updateHomeDisinfectionState(report.rely)
  65. }
  66. }
  67. /**
  68. * @function 开始消毒操作
  69. * @desc 校验设备状态并发起消毒请求
  70. */
  71. const onStartDisinfect = () => {
  72. // 校验日志等级
  73. if (!formulaStore.loglevel) {
  74. FtMessage.warning('请选择消毒等级')
  75. return
  76. }
  77. FtMessageBox.warning('请确认是否开始消毒').then(() => {
  78. doStartDisinfect()
  79. })
  80. }
  81. const doStartDisinfect = async () => {
  82. // 校验设备状态
  83. const statusName = getDeviceStatus()
  84. if (statusName) {
  85. FtMessageBox.error(statusName)
  86. return
  87. }
  88. systemStore.updateLoading(true)
  89. try {
  90. // 使用选中配方或默认配置启动消毒
  91. if (formulaStore.selectedFormulaInfo && formulaStore.selectedFormulaInfo.formula_id) {
  92. await formulaStore.startDisinfectFormula(formulaStore.selectedFormulaInfo)
  93. }
  94. else {
  95. const startParams = {
  96. className: 'DisinfectionCtrlServiceExt',
  97. fnName: 'start',
  98. params: { loglevel: formulaStore.loglevel },
  99. }
  100. await sendCmd(startParams)
  101. }
  102. }
  103. finally {
  104. systemStore.updateLoading(false)
  105. }
  106. }
  107. /**
  108. * @function 结束消毒操作
  109. * @desc 停止倒计时并发起结束消毒请求
  110. */
  111. const onFinishDisinfect = () => {
  112. FtMessageBox.warning('请确认是否结束消毒').then(() => {
  113. doStopDisinfect()
  114. })
  115. }
  116. const doStopDisinfect = async () => {
  117. stopTimer() // 停止倒计时
  118. systemStore.updateLoading(true)
  119. try {
  120. const stopParams = {
  121. className: 'DisinfectionCtrlServiceExt',
  122. fnName: 'stop',
  123. params: { loglevel: formulaStore.loglevel },
  124. }
  125. await sendCmd(stopParams)
  126. }
  127. finally {
  128. systemStore.updateLoading(false)
  129. }
  130. }
  131. /**
  132. * @computed 计算属性 - 操作状态判断
  133. * @returns {boolean} - 是否处于空闲或已完成状态
  134. * @desc 控制开始/结束按钮的显示逻辑
  135. */
  136. const operationState = computed(() => {
  137. return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
  138. })
  139. </script>
  140. <template>
  141. <div class="home-disinfect">
  142. <bt-button
  143. v-if="operationState"
  144. button-text="开始消毒"
  145. bg-color="#31CB7A"
  146. :text-color="btnStyle.textColor"
  147. :width="btnStyle.width"
  148. :height="btnStyle.height"
  149. :text-size="btnStyle.textSize"
  150. :border-radius="btnStyle.borderRadius"
  151. min-height="4rem"
  152. @click="onStartDisinfect"
  153. >
  154. <template #icon>
  155. <img :src="homeStart" alt="">
  156. </template>
  157. </bt-button>
  158. <bt-button
  159. v-else
  160. button-text="结束消毒"
  161. bg-color="#FF6767"
  162. :text-color="btnStyle.textColor"
  163. :width="btnStyle.width"
  164. :height="btnStyle.height"
  165. :text-size="btnStyle.textSize"
  166. :border-radius="btnStyle.borderRadius"
  167. min-height="4rem"
  168. @click="onFinishDisinfect"
  169. >
  170. <template #icon>
  171. <img :src="homeFinish" alt="">
  172. </template>
  173. </bt-button>
  174. </div>
  175. <!-- 开始消毒时显示剩余时间或状态 -->
  176. <div v-if="!operationState" class="home-remain-time">
  177. <div class="home-remaini-label">
  178. <span v-if="disinfectionState.state === 'disinfection'">
  179. 预计剩余时间:
  180. </span>
  181. <span v-else>
  182. 消毒状态
  183. </span>
  184. </div>
  185. <div v-if="disinfectionState.state === 'disinfection'" class="home-remaini-value">
  186. {{ curStateRemainTimeS }}
  187. </div>
  188. <div v-else>
  189. {{ deviceStateMap[disinfectionState.state] }}
  190. </div>
  191. </div>
  192. </template>
  193. <style lang="scss" scoped>
  194. .home-disinfect{
  195. display: flex;
  196. justify-content: center;
  197. margin-top: 5vh;
  198. }
  199. .home-disinfect-btn{
  200. width: 27vw;
  201. height: 8vh;
  202. border-radius: 12px;
  203. color: #FFFFFF;
  204. display: flex;
  205. align-items: center;
  206. justify-content: center;
  207. font-size: 24px;
  208. gap: 10px;
  209. }
  210. .home-start{
  211. background: #31CB7A;
  212. }
  213. .home-end{
  214. background: #FF6767;
  215. }
  216. .home-remain-time{
  217. background: #F6FAFE;
  218. margin-top: 6rem;
  219. width: 27vw;
  220. height: 8vh;
  221. border-radius: 12px;
  222. display: flex;
  223. align-items: center;
  224. justify-content: center;
  225. font-size: 24px;
  226. gap: 10px;
  227. margin-left: 1rem;
  228. .home-remaini-value{
  229. color: #2892F3;
  230. }
  231. }
  232. </style>