Compare commits

...

31 Commits

Author SHA1 Message Date
sige b9fbddbc49 nnn 1 year ago
sige 68caac0b76 1 year ago
sige 04e2d89451 Refactor Operator.vue to clear timer on unmount 1 year ago
sige 8135027804 ik 1 year ago
sige d8cedc7262 nj 1 year ago
sige f236e093d1 d 1 year ago
sige 450b96bd5d 配方名称重复检查 1 year ago
sige 2187ed9a3f 消毒时更改配置没有蓝色选中框,且不能覆盖参数只能删除参数 1 year ago
sige 845458b178 s 1 year ago
sige f0abd6228b 加液排空管内液体时需要能够暂停 1 year ago
sige f108e5ce14 更新发布脚本 1 year ago
sige 5e77c0b810 测试页面增加压力显示 1 year ago
sige b8a1fedeaa 消毒状态显示更新 1 year ago
sige cb83164317 弹框确认和取消按钮位置不统一 1 year ago
sige 31c8cb56e6 弹框确认和取消按钮位置不统一 1 year ago
sige 4216b6c110 设置-设备参数设置增加恢复出厂设置配置 1 year ago
sige cf955fb97b 审计内容页面增加导出按钮 1 year ago
sige 5049a1d916 当加液设置为0时,仍然可以正常执行加液操作 1 year ago
sige e38e9adc95 #107 水浸错误检查由事件通知,收到错误后弹框,确认后调用指定接口关闭弹框 1 year ago
sige 5f4d851338 #115 消毒开始时,调用消毒开始失败需要弹框显示错误信息,并且不跳转到消毒处理页面 1 year ago
sige f704d6f159 登录时密码输入框高度不足,Placeholder显示不完整, 顶部缺失 1 year ago
sige 0ff677939b 输入框激活时全选所有内容 1 year ago
sige 4a69444189 update readme 1 year ago
sige ff4a4283f8 ~ 1 year ago
sige 4d64a80a61 还是宽度 1 year ago
sige 0374f6775b 历史记录详情宽度更新 1 year ago
sige 167ad428f3 增加相对饱和度显示 1 year ago
sige 021780bc91 feat: Add support for Chinese language in README.md 1 year ago
sige 66f542ad58 Refactor .env file to remove commented out lines and update VITE_BASE_WS2_URL 1 year ago
sige fd2fc90bd3 排序问题,排序混乱、数据导出,导出时全部都会导出,无法选择单次数据导出 1 year ago
sige 323b51093c 加液界面,加液过程中切换页面后切换回来设置跳转,如,设置 1 year ago
  1. 7
      .env
  2. 2
      .env.production
  3. 7
      README.md
  4. 32
      publish.ps1
  5. 40
      src/App.vue
  6. 17
      src/assets/img/icon/exclamation-cricle-red-fill.svg
  7. 114
      src/components/AddPreSetting.vue
  8. 31
      src/components/Audit.vue
  9. 129
      src/components/LiquidHandle.vue
  10. 2
      src/components/LoginForm.vue
  11. 90
      src/components/MyInput.vue
  12. 133
      src/components/MyModal.vue
  13. 38
      src/components/Operator.vue
  14. 168
      src/components/Progress.vue
  15. 118
      src/components/Setting/components/Device.vue
  16. 115
      src/components/Setting/components/History.vue
  17. 132
      src/components/Setting/components/RunInfectionSetting.vue
  18. 8
      src/components/Setting/index.vue
  19. 42
      src/components/Test.vue
  20. 93
      src/components/UpdatePreSetting.vue
  21. 110
      src/components/dialogs/ClearRecordByKeysModal.vue
  22. 39
      src/components/dialogs/DelPreModal.vue
  23. 59
      src/components/dialogs/DisinfectModal.vue
  24. 58
      src/components/dialogs/LiquidModal.vue
  25. 40
      src/components/dialogs/UserModal.vue
  26. 6
      src/components/info/EnvironmentInfo.vue
  27. 12
      src/main.js
  28. 13
      src/mock/command.js
  29. 18
      src/store/modules/device.js
  30. 14
      src/store/modules/echarts.js
  31. 3
      src/store/modules/operator.js
  32. 2
      src/store/modules/setting.js
  33. 5
      src/store/modules/test.js
  34. 94
      src/store/modules/websocket.js
  35. 60
      src/utils/MyModal.js

7
.env

@ -1,5 +1,2 @@
# VITE_BASE_WS1_URL=ws://192.168.8.10:19001/
# VITE_BASE_WS2_URL=ws://192.168.8.10:19002/
VITE_BASE_WS1_URL=ws://127.0.0.1:19001/
VITE_BASE_WS2_URL=ws://127.0.0.1:19002/
VITE_BASE_WS1_URL=ws://192.168.8.10:19001/
VITE_BASE_WS2_URL=ws://192.168.8.10:19002/

2
.env.production

@ -0,0 +1,2 @@
VITE_BASE_WS1_URL=ws://127.0.0.1:19001/
VITE_BASE_WS2_URL=ws://127.0.0.1:19002/

7
README.md

@ -1,3 +1,5 @@
# 大空间消毒机
# 技术选型
- 本项目采用的 vue3 + vite + js 脚手架搭建
@ -54,7 +56,7 @@ https://tdesign.tencent.com/
│ └─modules // 分modules
├─views // 视图
├─App.vue // 项目根组件
├─main.js // 项目入口
├─main.js // 项目入口yarn
└─style.scss // 全局样式
```
@ -63,4 +65,7 @@ https://tdesign.tencent.com/
```bash
yarn
yarn dev
# 工控机浏览器打开右键菜单
touch /var/zapp_flag/chrome_in_test_mode
```

32
publish.ps1

@ -0,0 +1,32 @@
Param(
[String]$Exec="Deploy"
)
if ( $Exec -eq "DevDisable" ) {
ssh root:zwsd@192.168.8.10 "rm /var/zapp_flag/chrome_in_test_mode";
ssh root:zwsd@192.168.8.10 "reboot"
} elseif ( $Exec -eq "DevEnable" ) {
ssh root:zwsd@192.168.8.10 "touch /var/zapp_flag/chrome_in_test_mode";
ssh root:zwsd@192.168.8.10 "reboot"
} elseif ( $Exec -eq "Deploy" ) {
# build project
yarn build
# rename dist to current time, like 20221215121300
$now = Get-Date -Format "yyyyMMddHHmmss"
Rename-Item -Path ./dist -NewName $now
# compress dist to app.zip
Compress-Archive -Path ./$now -DestinationPath ./app.zip -Force
# upload app.zip to server
scp app.zip root@192.168.8.10:/frontend/
# unzip app.zip
ssh root:zwsd@192.168.8.10 "cd /frontend && unzip app.zip"
# remove old link
ssh root:zwsd@192.168.8.10 "cd /frontend && rm -f dist"
# create link
ssh root:zwsd@192.168.8.10 "cd /frontend && ln -s /frontend/$now /frontend/dist"
# remove app.zip
ssh root:zwsd@192.168.8.10 "cd /frontend && rm -f app.zip"
Remove-Item -Path ./app.zip
# remove folder
Remove-Item -Path ./$now -Recurse
}

40
src/App.vue

@ -1,7 +1,41 @@
<script setup></script>
<template>
<router-view></router-view>
<my-modal type="info" icon="warning"
v-model:visible="deviceAlert.visible"
:content="deviceAlert.content"
@ok="actionDeviceAlertOk"
></my-modal>
</template>
<script setup>
import { useWebSocketStore } from '@/store'
import { onMounted, ref } from 'vue';
/** @var {webSocketStore} */
const webSocketStore = useWebSocketStore();
/** @var {Object} */
const deviceAlert = ref({
visible: false,
content: '',
key : null,
});
// on mounted
onMounted(mounted);
// on mounted
function mounted() {
webSocketStore.registerEventHandler('AlertEvent', handleAlertEvent);
}
// handle alert event
async function handleAlertEvent(data) {
deviceAlert.value.visible = true;
deviceAlert.value.content = data.displayInfo;
deviceAlert.value.key = data.alertContext;
await webSocketStore.call('AlertEventFrontEndConfirm', {alertContext:data.alertContext});
}
// action device alert ok
async function actionDeviceAlertOk() {
await webSocketStore.call('AlertEventUsrConfirm', {alertContext:deviceAlert.value.key});
}
<style scoped></style>
</script>

17
src/assets/img/icon/exclamation-cricle-red-fill.svg

@ -0,0 +1,17 @@
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="69"
height="69"
viewBox="0 0 69 69"
>
<g>
<path
d="M34.5,0C15.456,0,0,15.456,0,34.5C0,53.544,15.456,69,34.5,69C53.544,69,69,53.544,69,34.5C69,15.456,53.544,0,34.5,0ZM34.5,55.2C32.5335,55.2,30.981,53.613,30.981,51.681C30.981,49.7145,32.568,48.162,34.5,48.162C36.4665,48.162,38.019,49.749,38.019,51.681C38.019,53.613,36.4665,55.2,34.5,55.2ZM38.3295,15.8355L37.605,40.9515C37.5705,42.2625,36.225,43.2975,34.638,43.2975L34.086,43.2975C32.499,43.2975,31.1535,42.2625,31.119,40.9515L30.36,15.8355C30.291,13.8345,31.9125,12.144,33.9825,12.144L34.707,12.144C36.777,12.144,38.3985,13.8345,38.3295,15.8355Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
</svg>

114
src/components/AddPreSetting.vue

@ -3,99 +3,71 @@
<div class="row_wrap">
<p class="title">注射蠕动泵速率(g/min)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="sprayLiquidConfigVal"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="sprayLiquidConfigVal"
:formatter="formatter7"
readonly
@click.stop="hideClickKey(2)"
/>
@done="setSprayLiquidVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="stoped_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_gs"
:formatter="formatter1"
readonly
@click.stop="hideClickKey(3)"
/>
@done="setStopedGsVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="continued_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_gs"
:formatter="formatter2"
readonly
@click.stop="hideClickKey(4)"
/>
@done="setcontinuedGsVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止相对湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="stoped_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_humi"
:formatter="formatter9"
readonly
@click.stop="hideClickKey(9)"
/>
@done="setstoped_humiVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续相对湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="continued_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_humi"
:formatter="formatter10"
readonly
@click.stop="hideClickKey(10)"
/>
@done="setcontinued_humiVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
class="field_font"
type="number"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_satur"
:formatter="formatter3"
v-model="stoped_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(5)"
/>
@done="setstopedSaturVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
type="number"
class="field_font"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_satur"
:formatter="formatter4"
v-model="continued_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(6)"
/>
@done="setContinuedSaturVal"
></my-input>
</p>
</div>
<div class="row_wrap" @click="showLogPicker">
@ -237,7 +209,7 @@
import { ref, onMounted } from 'vue'
import SimpleKeyboard from 'cpns/SimpleKeyboard'
import { showSuccessToast, showFailToast } from 'vant'
import { useSettingStore, useWebSocketStore, useOperatorStore } from '@/store'
import { useSettingStore, useWebSocketStore, useOperatorStore, useFormulaStore } from '@/store'
import { storeToRefs } from 'pinia'
import {
setSettingValJSON,
@ -249,6 +221,7 @@ import LogPicker from 'cpns/dialogs/LogPicker'
const settingStore = useSettingStore()
const webSocketStore = useWebSocketStore()
const operatorStore = useOperatorStore()
const formulaStore = useFormulaStore()
const max_humidity = ref('0')
const continued_satur = ref('0')
@ -281,6 +254,15 @@ const save = () => {
showFailToast('配方名称不能为空')
return
}
let list = formulaStore?.formulaList;
for (let i = 0; i < list.length; i++) {
if (list[i].formula_id == formula_id.value) {
showFailToast('配方名称已存在')
return
}
}
const data = {
formula_id: formula_id.value,
loglevel: logVal.value,
@ -718,7 +700,7 @@ const handleShowKeyBoard = () => {
showkeyboard.value = true
}
onMounted(() => {
onMounted(async () => {
document.addEventListener('click', e => {
let box = document.getElementById('keyboard_formula')
let room = document.getElementById('id_formula')
@ -737,6 +719,20 @@ onMounted(() => {
}
})
$('#id_formula').virtualkeyboard()
//
let defaultSettings = await webSocketStore.call('getAllSetting');
defaultSettings = defaultSettings.dbval;
let defaultSettingKV = {};
defaultSettings.forEach(item => defaultSettingKV[item.name] = item.val);
sprayLiquidConfigVal.value = defaultSettingKV['injection_pump_speed'] || 0;
stoped_gs.value = defaultSettingKV['stoped_gs'] || 0;
continued_gs.value = defaultSettingKV['continued_gs'] || 0;
stoped_satur.value = defaultSettingKV['stoped_satur'] || 0;
continued_satur.value = defaultSettingKV['continued_satur'] || 0;
stoped_humi.value = defaultSettingKV['stoped_humi'] || 0;
continued_humi.value = defaultSettingKV['continued_humi'] || 0;
})
</script>
@ -813,7 +809,7 @@ onMounted(() => {
align-items: center;
justify-content: center;
}
.field_font {
:deep(.field_font) {
font-size: 26px;
width: 180px;
}

31
src/components/Audit.vue

@ -59,6 +59,8 @@
</svg>
</div>
<div class="page_wrap">
<div class="btn mb" @click="exportAudit">导出审计</div>
<el-pagination
background
layout="prev, pager, next"
@ -81,12 +83,13 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useWebSocketStore, useAuditStore } from '@/store'
import { getUserBehaviorRecordDescJSON } from '@/mock/command'
import { useWebSocketStore, useAuditStore, useSettingStore } from '@/store'
import { getUserBehaviorRecordDescJSON, exportUserBehaviorRecordJSON } from '@/mock/command'
import moment from 'moment'
const webSocketStore = useWebSocketStore()
const auditStore = useAuditStore()
const settingStore = useSettingStore()
onMounted(() => {
//
@ -99,6 +102,12 @@ const handleCurrentPageChange = page => {
webSocketStore.sendCommandMsg(getUserBehaviorRecordDescJSON(page - 1, 6))
auditStore.updateAuditLoading(true)
}
const exportAudit = () => {
settingStore.updateExportText('导出审计中')
settingStore.updateExportLoading(true)
webSocketStore.sendCommandMsg(exportUserBehaviorRecordJSON)
}
</script>
<style lang="scss" scoped>
@ -187,7 +196,7 @@ const handleCurrentPageChange = page => {
padding-right: 32px;
display: flex;
align-items: center;
justify-content: flex-end;
justify-content: space-between;
}
}
.wrapper {
@ -215,4 +224,20 @@ const handleCurrentPageChange = page => {
white-space: nowrap;
}
}
.btn {
background: #06518b;
display: flex;
align-items: center;
justify-content: center;
width: 147px;
height: 30px;
border-radius: 30px;
font-family: Source Han Sans CN;
font-size: 20px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.1em;
color: #ffffff;
margin-left: 32px;
}
</style>

129
src/components/LiquidHandle.vue

@ -2,33 +2,11 @@
<div class="liquid_contaienr">
<div class="left_container">
<p class="status">
<svg
v-if="operatorStore.replenishingFluidsWorkState == 1 && tabType == 1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="155"
height="38"
viewBox="0 0 155 38"
>
<g>
<g>
<path
d="M50.888,17.076L50.888,29.348L47.352,29.348L47.352,31.246L70.7,31.246L70.7,29.348L60.69,29.348L60.69,21.158L68.828,21.158L68.828,19.26L60.69,19.26L60.69,12.318L69.842,12.318L69.842,10.394L48.34,10.394L48.34,12.318L58.635999999999996,12.318L58.635999999999996,29.348L52.89,29.348L52.89,17.076L50.888,17.076ZM83.726,8.48584C83.362,9.81509,82.894,11.1968,82.348,12.526L75.19800000000001,12.526L75.19800000000001,14.398L81.49000000000001,14.398C79.826,17.726,77.538,20.82,74.548,22.9C74.86,23.342,75.354,24.174,75.562,24.694C76.654,23.914,77.668,23.03,78.578,22.068L78.578,32.312L80.52799999999999,32.312L80.52799999999999,19.754C81.75,18.09,82.816,16.27,83.7,14.398L97.97399999999999,14.398L97.97399999999999,12.526L84.506,12.526C84.97399999999999,11.3532,85.39,10.1543,85.75399999999999,8.98106L83.726,8.48584ZM89.108,15.75L89.108,20.768L83.25800000000001,20.768L83.25800000000001,22.588L89.108,22.588L89.108,29.972L82.218,29.972L82.218,31.792L97.94800000000001,31.792L97.94800000000001,29.972L91.05799999999999,29.972L91.05799999999999,22.588L96.96000000000001,22.588L96.96000000000001,20.768L91.05799999999999,20.768L91.05799999999999,15.75L89.108,15.75ZM115.992,11.72L115.992,32.0337L117.864,32.0337L117.864,30.102L122.908,30.102L122.908,31.8249L124.858,31.8249L124.858,11.72L115.992,11.72ZM117.864,28.23L117.864,13.618L122.908,13.618L122.908,28.23L117.864,28.23ZM106.19,8.82425L106.164,13.436L102.49799999999999,13.436L102.49799999999999,15.334L106.112,15.334C105.93,21.886,105.124,27.658,101.848,31.09C102.342,31.402,103.044,32,103.356,32.4461C106.866,28.62,107.77600000000001,22.38,108.00999999999999,15.334L111.962,15.334C111.754,25.344,111.52,28.906,110.974,29.66C110.74,29.998,110.48,30.102,110.09,30.076C109.622,30.076,108.50399999999999,30.076,107.282,29.972C107.62,30.518,107.80199999999999,31.35,107.854,31.922C109.024,32,110.22,32.0264,110.948,31.922C111.702,31.818,112.196,31.584,112.664,30.908C113.47,29.79,113.652,25.994,113.86,14.424C113.86,14.138,113.86,13.436,113.86,13.436L108.062,13.436L108.114,8.82425L106.19,8.82425ZM145.372,19.9636C146.28199999999998,20.8224,147.322,22.0452,147.764,22.8781L148.82999999999998,21.9412C148.388,21.1348,147.348,19.9636,146.412,19.1828L145.372,19.9636ZM131.046,10.3912C132.346,11.434,133.958,12.9684,134.686,13.9832L136.038,12.734C135.232,11.746,133.64600000000002,10.2607,132.32,9.26909L131.046,10.3912ZM129.772,17.3913C131.124,18.3277,132.788,19.7325,133.594,20.6693L134.84199999999998,19.3685C134.01,18.4317,132.346,17.1308,130.994,16.2204L129.772,17.3913ZM130.31799999999998,30.6074L132.00799999999998,31.6742C133.074,29.3326,134.296,26.1845,135.20600000000002,23.5569L133.672,22.4905C132.684,25.3261,131.30599999999998,28.6302,130.31799999999998,30.6074ZM143.26600000000002,8.93028C143.656,9.66072,144.046,10.5476,144.358,11.356L136.376,11.356L136.376,13.228L153.562,13.228L153.562,11.356L146.412,11.356C146.1,10.4432,145.554,9.2955,145.034,8.40825L143.26600000000002,8.93028ZM145.112,18.35L150.624,18.35C149.922,21.2128,148.726,23.6329,147.21800000000002,25.6105C145.94400000000002,23.9449,144.93,22.0192,144.228,19.9636C144.54000000000002,19.4172,144.826,18.8968,145.112,18.35ZM145.112,13.618C144.228,16.634,142.382,20.302,140.06799999999998,22.6181C140.43200000000002,22.8781,141.03,23.4765,141.34199999999998,23.8409C141.966,23.1905,142.59,22.4357,143.162,21.6292C143.942,23.5809,144.93,25.3761,146.1,26.9637C144.436,28.7593,142.486,30.0862,140.406,30.971C140.796,31.3094,141.29000000000002,31.9858,141.55,32.4282C143.656,31.4654,145.57999999999998,30.1382,147.244,28.3689C148.752,30.0602,150.494,31.4134,152.47,32.3762C152.78199999999998,31.9078,153.35399999999998,31.1794,153.76999999999998,30.841C151.74200000000002,29.9822,149.94799999999998,28.6809,148.414,27.0417C150.416,24.4917,151.924,21.2388,152.73000000000002,17.102L151.534,16.66L151.22199999999998,16.764L145.86599999999999,16.764C146.28199999999998,15.854,146.62,14.944,146.93200000000002,14.06L145.112,13.618ZM139.834,13.566C138.924,16.4,137.05200000000002,19.8856,134.946,22.1237C135.336,22.4097,135.95999999999998,22.9821,136.24599999999998,23.3465C136.89600000000002,22.6441,137.546,21.8112,138.144,20.9264L138.144,32.4022L139.886,32.4022L139.886,18.038C140.588,16.712,141.186,15.36,141.68,14.086L139.834,13.566Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
<g>
<path
d="M15.017,4Q18.1087,4,20.8437,5.17347Q23.5787,6.34694,25.6172,8.38776Q27.6557,10.42857,28.8279,13.16667Q30,15.9048,30,19Q30,22.1293,28.8279,24.8503Q27.6557,27.5714,25.6172,29.6122Q23.5787,31.6531,20.8437,32.826499999999996Q18.1087,34,15.017,34Q11.8913,34,9.15628,32.826499999999996Q6.42129,31.6531,4.38279,29.6122Q2.34428,27.5714,1.17214,24.8503Q-3.79701e-7,22.1293,0,19Q0,15.9048,1.17214,13.16667Q2.34428,10.42857,4.38279,8.38775Q6.42129,6.34694,9.15628,5.17347Q11.8913,3.999999113026,15.017,4ZM23.5787,21.0748Q24.4621,21.0748,25.0736,20.4456Q25.6852,19.8163,25.6852,18.932000000000002Q25.6852,18.0476,25.0736,17.4354Q24.4621,16.8231,23.5787,16.8231L17.1914,16.8231L17.1914,10.42857Q17.1914,9.54422,16.5629,8.91497Q15.9343,8.28571,15.051,8.28571Q14.1676,8.28571,13.5561,8.91497Q12.9445,9.54422,12.9445,10.42857L12.9445,16.8231L6.55719,16.8231Q5.67384,16.8231,5.06229,17.4354Q4.45074,18.0476,4.45074,18.932000000000002Q4.45074,19.8163,5.06229,20.4456Q5.67384,21.0748,6.55719,21.0748L12.9445,21.0748L12.9445,27.4354Q12.9445,28.3197,13.5561,28.949Q14.1676,29.5782,15.051,29.5782Q15.9343,29.5782,16.5629,28.949Q17.1914,28.3197,17.1914,27.4354L17.1914,21.0748L23.5787,21.0748Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
</g>
</svg>
<template v-if="tabType == 1">
<span v-if="operatorStore.replenishingFluidsWorkState == 1" style="color: rgb(250, 28, 28);font-size: 1.5rem;vertical-align: super;">正在加液</span>
<span v-if="operatorStore.replenishingFluidsWorkState == 2" style="color: rgb(250, 28, 28);font-size: 1.5rem;vertical-align: super;">正在排空管道</span>
</template>
<svg
v-if="operatorStore.drainingWorkState == 1 && tabType == 2"
xmlns="http://www.w3.org/2000/svg"
@ -76,46 +54,38 @@
</div>
<div class="right_container">
<div class="add_liquid_wrap" v-if="tabType == 1">
<van-field
type="number"
v-model="addLiquidVal"
readonly
<my-input type="number" class="add_liquid_input"
v-model:value="addLiquidVal"
:formatter="formatter"
@click.stop="handleClickInput"
class="add_liquid_input"
/>
></my-input>
</div>
<div class="push_liquid_wrap" v-if="tabType == 2">
<p class="num">
{{ disinfectantCapacity <= 0 ? 0 : disinfectantCapacity }}
</p>
</div>
<img
class="btn mb"
v-if="!operatorStore.replenishingFluidsWorkState && tabType == 1"
:src="StartLiquid"
alt=""
@click="startAdd"
/>
<img
class="btn mb"
v-if="operatorStore.replenishingFluidsWorkState && tabType == 1"
:src="StopLiquidPause"
alt=""
/>
<img
class="btn"
v-if="operatorStore.replenishingFluidsWorkState && tabType == 1"
:src="StopLiquid"
alt=""
@click="stopAdd"
/>
<img
class="btn"
v-if="!operatorStore.replenishingFluidsWorkState && tabType == 1"
:src="StartLiquidPause"
alt=""
/>
<!-- 加液 -->
<template v-if="tabType == 1">
<!-- 开始加液 -->
<img v-if="!operatorStore.replenishingFluidsWorkState" class="btn mb" :src="StartLiquid" @click="startAdd" />
<img v-if="operatorStore.replenishingFluidsWorkState" class="btn mb" :src="StopLiquidPause" />
<img v-if="operatorStore.replenishingFluidsWorkState" class="btn" :src="StopLiquid" @click="actionAddStop" />
<img v-if="!operatorStore.replenishingFluidsWorkState" class="btn" :src="StartLiquidPause" />
</template>
<img
class="btn mb"
v-if="!operatorStore.drainingWorkState && tabType == 2"
@ -142,6 +112,14 @@
@click="stopPop"
alt=""
/>
</div>
<LiquidModal
v-if="tabType == 2 && tipModalVisible"
@ -169,7 +147,7 @@ import StopPushPause from '@/assets/img/liquid/7.png'
import LiquidModal from './dialogs/LiquidModal.vue'
import { useDeviceStore, useWebSocketStore, useOperatorStore } from '@/store'
import { ref } from 'vue'
import { onMounted, onUnmounted, ref } from 'vue'
import { storeToRefs } from 'pinia'
import {
startReplenishingFluidsJSON,
@ -192,6 +170,22 @@ const webSocketStore = useWebSocketStore()
const isPopLiquidStatus = ref(false)
onMounted(() => {
addLiquidVal.value = operatorStore.liquidAddtionVolume + '';
});
onUnmounted(() => {
operatorStore.liquidAddtionVolume = parseInt(addLiquidVal.value);
});
//
async function actionAddStop() {
await webSocketStore.call('stopReplenishingFluids');
}
const formatter = value => {
if (parseInt(value) > 5000) {
return '5000'
@ -206,6 +200,11 @@ const formatter = value => {
}
const startAdd = () => {
let value = parseInt(addLiquidVal.value);
if ( 0 === value || value > 5000 ) {
console.warn(`加液量不合法 : ${value}`);
return;
}
if (!(operatorStore.replenishingFluidsWorkState == 1)) {
webSocketStore.sendCommandMsg(
startReplenishingFluidsJSON(parseInt(addLiquidVal.value)),
@ -213,11 +212,7 @@ const startAdd = () => {
}
}
const stopAdd = () => {
if (operatorStore.replenishingFluidsWorkState == 1) {
webSocketStore.sendCommandMsg(stopReplenishingFluidsJSON)
}
}
const stopPop = () => {
if (operatorStore.drainingWorkState == 1) {
@ -343,7 +338,7 @@ const handleClickInput = () => {
background-size: 100% 100%;
margin-bottom: 41px;
background: url(../assets/img/liquid/form.png);
.add_liquid_input {
:deep(.add_liquid_input) {
position: absolute;
left: -9px;
bottom: 8px;

2
src/components/LoginForm.vue

@ -159,7 +159,7 @@ const handleLogin = () => {
border: none;
outline: none;
width: 253px;
height: 17px;
height: 20px;
position: absolute;
left: 120px;
top: 209px;

90
src/components/MyInput.vue

@ -0,0 +1,90 @@
<template>
<van-field
ref="input"
v-model="value"
readonly
:formatter="props.formatter"
:class="props.class"
:type="props.type"
@click.stop="actionInputClick"
></van-field>
<template v-if="keyboardVisible">
<van-number-keyboard v-if="'number' === props.type"
v-model="value"
:show="true"
:title="value"
:theme="props.theme"
:close-button-text="props.closeText"
@input="actionKeyBoardInput"
@blur="actionKeyBoardBlur"
@close="actionKeyBoardClose"
></van-number-keyboard>
</template>
</template>
<script setup>
import { nextTick, ref, watch } from 'vue';
/** @var {Function} */
const emits = defineEmits(['update:value','done']);
/** @var {Object} */
const props = defineProps({
//
formatter : { type: Function, default: value => value},
//
class : { type: String, default: ''},
//
type : { type: String, default: 'text'},
//
value : { type: String, default: ''},
//
theme : { type: String, default: ''},
//
closeText : { type: String, default: ''},
});
/** @var {String} */
const value = ref(props.value);
/** @var {Boolean} */
const keyboardVisible = ref(false);
/** @var {Boolean} */
const isFirstClick = ref(true);
/** @var {Component} */
const input = ref(null);
/** @var {String} */
let originValue = null;
//
watch(() => props.value, (val) => value.value = val);
//
async function actionInputClick() {
originValue = props.value;
isFirstClick.value = true;
keyboardVisible.value = true;
await nextTick();
input.value.$el.querySelector('input').select();
input.value.$el.querySelector('input').focus();
}
//
async function actionKeyBoardInput(val) {
if (isFirstClick.value) {
isFirstClick.value = false
await nextTick();
value.value = val + '';
}
}
//
function actionKeyBoardBlur() {
actionKeyBoardClose();
}
//
function actionKeyBoardClose() {
keyboardVisible.value = false;
window.getSelection().removeAllRanges();
emits('update:value', value.value);
if (`${originValue}` !== value.value) {
emits('done');
}
}
</script>

133
src/components/MyModal.vue

@ -0,0 +1,133 @@
<template>
<div v-if="visible" class="clear_record_modal_container">
<div class="modal_content">
<div v-if="'warning' === props.icon">
<img src="@/assets/img/icon/exclamation-cricle-red-fill.svg " />
</div>
<template v-if="'' === props.content">
<slot></slot>
</template>
<p v-else class="tips">
<span>{{ props.content }}</span>
</p>
<div v-if="'confirm' === props.type" class="btns">
<div class="cancel" @click="actionCancel">取消</div>
<div class="ok" @click="actionOk">确定</div>
</div>
<div v-else-if="'info' === props.type" class="btns" style="justify-content: center;">
<div class="ok" @click="actionOk">确定</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
/** @var {Function} */
const emits = defineEmits(['update:visible', 'ok', 'cancel']);
/** @var {Object} */
const props = defineProps({
visible: {type:Boolean, default:false}, //
content : {type:String, default:''}, //
type : {type:String, default:'confirm'}, //
icon : {type:String, default:''} //
});
/** @var {Boolean} */
const visible = ref(props.visible);
// watch visible
watch(() => props.visible, val => visible.value = val);
// expose public functions
defineExpose({show});
// show dialog
function show() {
emits('update:visible', true);
visible.value = true;
}
// action ok
function actionOk() {
emits('ok');
emits('update:visible', false);
visible.value = false;
}
// action cancel
function actionCancel() {
emits('cancel');
emits('update:visible', false);
visible.value = false;
}
</script>
<style lang="scss" scoped>
.clear_record_modal_container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
.modal_content {
width: 476px;
height: 350px;
border-radius: 16px;
background: #ffffff;
padding: 52px 37px 55px 37px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
.tips {
margin-top: 33px;
margin-bottom: 50px;
font-family: Source Han Sans CN;
font-size: 21px;
font-weight: normal;
letter-spacing: 0.04em;
color: #000000;
.red {
color: #fa1c1c;
}
}
.btns {
display: flex;
align-items: center;
justify-content: space-between;
width: 362px;
.cancel {
width: 173px;
height: 68px;
border-radius: 34px;
background: #06518b;
font-family: Source Han Sans CN;
font-size: 23px;
font-weight: 350;
letter-spacing: 0em;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.ok {
width: 173px;
height: 68px;
border-radius: 34px;
background: #1f6397;
font-family: Source Han Sans CN;
font-size: 23px;
font-weight: 350;
letter-spacing: 0em;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
</style>

38
src/components/Operator.vue

@ -487,6 +487,7 @@ import { useOperatorStore, useWebSocketStore, useSettingStore } from '@/store'
import { startDisinfectionJSON, getStateJSON } from '@/mock/command'
import { showSuccessToast, showFailToast } from 'vant'
import { time_To_hhmmss } from '@/utils'
import MyModal from '../utils/MyModal'
const operatorStore = useOperatorStore()
const webSocketStore = useWebSocketStore()
@ -570,20 +571,29 @@ const startDisinfect = () => {
realStart()
}
const realStart = () => {
localStorage.setItem('logVal', logVal.value)
if (
operatorStore.disinfectStatus == 0 ||
operatorStore.disinfectStatus == 5
) {
localStorage.removeItem('bin')
localStorage.removeItem('envir1')
localStorage.removeItem('envir2')
webSocketStore.sendCommandMsg(
startDisinfectionJSON(parseInt(logVal.value), parseInt(roomSize.value)),
)
props.changeShowOperator(false)
}
//
async function realStart() {
operatorStore.updateShowStartReady(true)
localStorage.setItem('logVal', logVal.value)
if ( operatorStore.disinfectStatus == 0 || operatorStore.disinfectStatus == 5 ) {
localStorage.removeItem('bin')
localStorage.removeItem('envir1')
localStorage.removeItem('envir2')
try {
await webSocketStore.call('startDisinfection', {
loglevel : parseInt(logVal.value),
roomVolume : parseInt(roomSize.value),
});
} catch ( e ) {
operatorStore.updateShowStartReady(false)
await MyModal.error(`无法开始消毒 : ${e.message || e}`);
return ;
}
operatorStore.updateShowStartReady(false)
props.changeShowOperator(false)
}
}
const showLogPicker = () => {

168
src/components/Progress.vue

@ -1,94 +1,31 @@
<template>
<div class="progress_container">
<div class="header_wrap">
<div class="left_time">
<p class="time">
{{
operatorStore.estimatedRemainingTimeS == 0
? '已结束'
: operatorStore.disinfectStatus == 1
? `${time_To_hhmmss(operatorStore.estimatedRemainingTimeS)}`
: operatorStore.estimatedRemainingTimeS < 0
? '评估中'
: `${time_To_hhmmss(operatorStore.estimatedRemainingTimeS)}`
}}
</p>
<div style="width:400px;">
<div class="left_time" v-if="-1 != operatorStore.estimatedRemainingTimeS">
<p class="time">
{{
operatorStore.estimatedRemainingTimeS == 0
? '已结束'
: operatorStore.disinfectStatus == 1
? `${time_To_hhmmss(operatorStore.estimatedRemainingTimeS)}`
: operatorStore.estimatedRemainingTimeS < 0
? '评估中'
: `${time_To_hhmmss(operatorStore.estimatedRemainingTimeS)}`
}}
</p>
</div>
</div>
<svg
v-if="[2, 3].includes(operatorStore.disinfectStatus)"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="181"
height="52"
viewBox="0 0 181 52"
>
<g>
<g>
<g>
<path
d="M82.64,13.3438C81.84,15.7875,80.28,18.9925,79.12,21.0362L83.28,22.5987C84.52000000000001,20.6756,86,17.8306,87.28,15.0263L82.64,13.3438ZM62.72,15.4269C64.28,17.7506,65.84,20.8756,66.36,22.8794L70.72,20.8356C70.08,18.7925,68.4,15.8275,66.8,13.6244L62.72,15.4269ZM52,16.1481C54.480000000000004,17.4706,57.56,19.5537,59,21.0762L61.96,17.35C60.4,15.8675,57.24,13.9444,54.8,12.7825L52,16.1481ZM50.12,26.76C52.68,28.08,55.88,30.2,57.32,31.72L60.24,27.96C58.6,26.48,55.36,24.56,52.84,23.36L50.12,26.76ZM51.24,46.76L55.480000000000004,49.84C57.6,45.8,59.84,41.12,61.68,36.84L58.16,33.92C55.96,38.64,53.2,43.68,51.24,46.76ZM68.68,35.08L80.88,35.08L80.88,38.08L68.68,38.08L68.68,35.08ZM68.68,31.04L68.68,28.08L80.88,28.08L80.88,31.04L68.68,31.04ZM72.48,12.4225L72.48,23.64L64,23.64L64,49.9606L68.68,49.9606L68.68,42.12L80.88,42.12L80.88,44.76C80.88,45.28,80.68,45.48,80.03999999999999,45.52C79.44,45.52,77.32,45.52,75.48,45.4C76.12,46.64,76.76,48.64,76.92,49.92C79.96000000000001,49.92,82.08,49.88,83.6,49.12C85.12,48.4,85.56,47.12,85.56,44.84L85.56,23.64L77.32,23.64L77.32,12.4225L72.48,12.4225ZM121.2,33.76L121.08,35.92L114.16,35.92L115.16,35.36C115,34.88,114.64,34.32,114.16,33.76L121.2,33.76ZM100.72,30.32C100.6,32.08,100.44,34,100.24000000000001,35.92L94.28,35.92L94.28,39.44L99.88,39.44C99.6,41.56,99.36,43.52,99.08,45.12L119.96,45.12C119.8,45.6,119.64,45.88,119.48,46.08C119.12,46.52,118.76,46.6,118.08,46.6C117.36,46.64,115.8,46.6,114.08,46.44C114.6,47.36,115.08,48.84,115.12,49.8C117.2,49.8812,119.2,49.9219,120.44,49.72C121.72,49.6,122.8,49.28,123.68,48.2C124.12,47.64,124.52,46.68,124.84,45.12L129.44,45.12L129.44,41.68L125.36,41.68L125.56,39.44L131.72,39.44L131.72,35.92L125.84,35.92L126.04,32.16C126.08,31.6,126.12,30.32,126.12,30.32L100.72,30.32ZM110.08,34.24C110.56,34.72,111,35.32,111.4,35.92L104.96000000000001,35.92L105.16,33.76L111,33.76L110.08,34.24ZM120.84,39.44L120.6,41.68L113.68,41.68L114.96,41C114.76,40.52,114.4,39.96,113.96,39.44L120.84,39.44ZM109.75999999999999,39.88C110.28,40.4,110.8,41.04,111.16,41.68L104.32,41.68L104.6,39.44L110.6,39.44L109.75999999999999,39.88ZM110.52000000000001,12.4262L110.52000000000001,15.36L97.2,15.36L97.2,18.72L110.52000000000001,18.72L110.52000000000001,20.36L99.88,20.36L99.88,23.68L110.52000000000001,23.68L110.52000000000001,25.4L95.36,25.4L95.36,28.88L130.64,28.88L130.64,25.4L115.44,25.4L115.44,23.68L126.64,23.68L126.64,20.36L115.44,20.36L115.44,18.72L129.36,18.72L129.36,15.36L115.44,15.36L115.44,12.4262L110.52000000000001,12.4262ZM154.36,12.4231L154.36,19.4L140.51999999999998,19.4L140.51999999999998,39.6838L145.32,39.6838L145.32,37.48L154.36,37.48L154.36,50.0187L159.44,50.0187L159.44,37.48L168.51999999999998,37.48L168.51999999999998,39.4831L173.56,39.4831L173.56,19.4L159.44,19.4L159.44,12.4231L154.36,12.4231ZM145.32,32.76L145.32,24.12L154.36,24.12L154.36,32.76L145.32,32.76ZM168.51999999999998,32.76L159.44,32.76L159.44,24.12L168.51999999999998,24.12L168.51999999999998,32.76Z"
fill="#17F179"
fill-opacity="1"
/>
</g>
<g transform="matrix(0,1,-1,0,52,-22)">
<path
d="M61.3114,50.5847L56.491,45.7322C62.778400000000005,44.923500000000004,67.8084,39.8689,67.8084,33.8033C67.8084,27.9399,63.1976,22.88525,57.1198,21.87432L52.7186,17.62841L54.6048,17.62841C64.24549999999999,17.62841,72,24.9071,72,33.8033C72,39.8689,68.2276,45.3279,62.988,47.9563L62.988,52L61.3114,50.5847ZM56.7006,49.776C56.0719,49.776,55.2335,49.9781,54.3952,49.9781C44.75449,49.9781,37,42.6995,37,33.8033C37,27.7377,40.77246,22.27869,46.01198,19.650280000000002L46.01198,15L48.7365,17.62842L52.9281,21.67213C46.43114,22.27869,41.4012,27.5355,41.4012,33.8033C41.4012,39.8689,46.22156,44.923500000000004,52.509,45.7322L56.7006,49.776Z"
fill="#17F179"
fill-opacity="1"
/>
</g>
</g>
</g>
</svg>
<svg
v-if="operatorStore.disinfectStatus == 1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="132"
height="52"
viewBox="0 0 132 52"
>
<g>
<g>
<g>
<g>
<path
d="M26.04,27.36L26.04,34.68C26.04,38.44,24.84,43.48,16,46.44C17.12,47.28,18.4,48.84,19,49.8C28.92,46.04,30.52,39.96,30.52,34.72L30.52,27.36L26.04,27.36ZM28.96,43.8C31.2,45.76,34.32,48.48,35.76,50.2037L39.08,46.96C37.48,45.32,34.24,42.72,32.04,40.92L28.96,43.8ZM2.68,23.2C4.56,24.4,7,25.92,9.04,27.32L1.04,27.32L1.04,31.56L7,31.56L7,44.8C7,45.24,6.84,45.36,6.28,45.4C5.72,45.4,3.84,45.4,2.16,45.36C2.76,46.64,3.4,48.6,3.6,49.96C6.28,49.96,8.28,49.84,9.76,49.12C11.28,48.4,11.64,47.12,11.64,44.88L11.64,31.56L14.04,31.56C13.6,33.44,13.08,35.28,12.64,36.6L16.2,37.36C17.12,34.96,18.2,31.2,19.08,27.84L16.12,27.2L15.48,27.32L13.64,27.32L14.68,25.92C13.92,25.36,12.88,24.72,11.76,24C14,21.76,16.36,18.68,18.04,15.92L15.16,13.9187L14.32,14.16L2,14.16L2,18.32L11.32,18.32C10.4,19.64,9.36,20.96,8.36,21.96L5.2,20.12L2.68,23.2ZM19.52,21.08L19.52,40.4L23.96,40.4L23.96,25.36L32.6,25.36L32.6,40.24L37.28,40.24L37.28,21.08L30.16,21.08L31.12,18.2L38.84,18.2L38.84,14L18.24,14L18.24,18.2L26,18.2L25.52,21.08L19.52,21.08ZM57.08,42.0844C57.52,44.5687,57.84,47.8544,57.84,49.8175L62.56,49.1369C62.52,47.1731,62.04,44.0075,61.52,41.5637L57.08,42.0844ZM65.24,42.0044C66.12,44.4888,67.04,47.6944,67.28,49.6575L72.08,48.7356C71.76,46.7325,70.72,43.6069,69.72,41.2431L65.24,42.0044ZM73.4,41.9244C75.2,44.5287,77.32,48.055,78.16,50.2188L82.72,48.175C81.72,45.9712,79.48,42.565,77.64,40.1612L73.4,41.9244ZM50.24,40.4412C48.96,43.2463,46.92,46.4519,45.32,48.335L49.92,50.2188C51.56,47.9744,53.56,44.5687,54.84,41.6437L50.24,40.4412ZM65.64,12.3838L65.56,18L60.88,18L60.88,22.04L65.4,22.04C65.28,23.88,65.08,25.56,64.8,27.08L62.44,25.76L60.4,28.72L59.96,24.6L56,25.52L56,22.2L60.16,22.2L60.16,17.8L56,17.8L56,12.5444L51.6,12.5444L51.6,17.8L46.28,17.8L46.28,22.2L51.6,22.2L51.6,26.52L45.36,27.84L46.32,32.48L51.6,31.16L51.6,34.88C51.6,35.36,51.44,35.52,50.88,35.52C50.36,35.52,48.68,35.52,47.08,35.44C47.64,36.68,48.24,38.52,48.36,39.76C51.04,39.76,52.92,39.64,54.28,38.96C55.64,38.24,56,37.08,56,34.92L56,30.04L60.24,28.96L60.16,29.08L63.52,31.12C62.44,33.4,60.84,35.28,58.36,36.76C59.4,37.56,60.76,39.24,61.32,40.3212C64.16,38.56,66.08,36.36,67.36,33.64C68.88,34.68,70.24,35.64,71.16,36.48L73.56,32.64C72.4,31.72,70.68,30.6,68.8,29.44C69.36,27.24,69.68,24.76,69.84,22.04L73.56,22.04C73.36,32.84,73.4,39.6,78.52,39.6C81.52,39.6,82.76,38.16,83.2,33.24C82.12,32.92,80.52,32.2,79.64,31.44C79.52,34.28,79.28,35.48,78.72,35.48C77.48,35.48,77.64,29.12,78.08,18L70.04,18L70.16,12.3838L65.64,12.3838ZM105.36,12.4231L105.36,19.4L91.52,19.4L91.52,39.6838L96.32,39.6838L96.32,37.48L105.36,37.48L105.36,50.0187L110.44,50.0187L110.44,37.48L119.52,37.48L119.52,39.4831L124.56,39.4831L124.56,19.4L110.44,19.4L110.44,12.4231L105.36,12.4231ZM96.32,32.76L96.32,24.12L105.36,24.12L105.36,32.76L96.32,32.76ZM119.52,32.76L110.44,32.76L110.44,24.12L119.52,24.12L119.52,32.76Z"
fill="#F74104"
fill-opacity="1"
/>
</g>
</g>
</g>
</g>
</svg>
<svg
v-if="operatorStore.disinfectStatus == 4"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="132"
height="52"
viewBox="0 0 132 52"
>
<g>
<g>
<g>
<path
d="M30.16,19.56C29.16,20.88,27.96,22.04,26.56,23.12C25.16,22.08,24,20.96,23.08,19.68L23.16,19.56L30.16,19.56ZM22.84,12.5056C21.2,15.5187,18.32,19,14.16,21.56C15.12,22.28,16.56,23.88,17.2,24.88C18.28,24.12,19.32,23.32,20.24,22.48C21.04,23.52,21.92,24.48,22.92,25.36C20.16,26.76,17,27.84,13.72,28.48C14.56,29.4,15.6,31.2,16.04,32.32C19.88,31.36,23.48,30,26.64,28.12C29.48,29.84,32.76,31.08,36.48,31.84C37.12,30.64,38.32,28.84,39.32,27.92C36.04,27.44,33.04,26.56,30.48,25.4C33.04,23.16,35.16,20.4,36.56,17.08L33.6,15.6394L32.84,15.84L26.08,15.84C26.6,15.0369,27.08,14.2331,27.56,13.43L22.84,12.5056ZM16.76,32.4L16.76,36.52L25.12,36.52L25.12,40.44L20.76,40.44L21.44,37.88L17.12,37.36C16.6,39.72,15.76,42.6,15.04,44.56L16.96,44.56L25.12,44.6006L25.12,50.0169L29.72,50.0169L29.72,44.6L37.96,44.6L37.96,40.44L29.72,40.44L29.72,36.52L37,36.52L37,32.4L29.72,32.4L29.72,30.12L25.12,30.12L25.12,32.4L16.76,32.4ZM2.6,14.04L2.6,49.8962L6.8,49.8962L6.8,18.32L10.12,18.32C9.36,20.96,8.4,24.2,7.48,26.6C10.12,29.44,10.8,32.04,10.8,33.96C10.84,35.16,10.6,36,10.04,36.36C9.72,36.6,9.28,36.72,8.8,36.72C8.28,36.72,7.64,36.72,6.84,36.64C7.52,37.8,7.88,39.6,7.92,40.76C8.92,40.8006,9.92,40.8006,10.72,40.68C11.68,40.52,12.44,40.28,13.12,39.8C14.44,38.84,15.04,37.04,15.04,34.48C15.04,32.08,14.48,29.28,11.68,26.08C12.96,23.04,14.44,19.04,15.6,15.64L12.44,13.8387L11.76,14.04L2.6,14.04ZM54.04,26.28L54.04,29.72L51.88,29.72L51.88,26.28L54.04,26.28ZM57.2,26.28L59.48,26.28L59.48,29.72L57.2,29.72L57.2,26.28ZM51.36,22.76C51.88,21.8,52.32,20.84,52.76,19.8L56.72,19.8C56.4,20.84,56,21.88,55.6,22.76L51.36,22.76ZM50.72,12.425C49.6,17.2,47.52,21.88,44.76,24.84C45.6,25.36,47.08,26.6,47.92,27.4L47.92,33.36C47.92,37.84,47.68,43.8,44.96,47.9625C45.92,48.405,47.68,49.4906,48.4,50.1744C50.12,47.6006,51,44.16,51.44,40.72L54.04,40.72L54.04,47.52L57.2,47.52L57.2,46.12C57.64,47.2,58,48.6,58.08,49.52C59.88,49.52,61.12,49.44,62.16,48.72C63.16,48.04,63.4,46.84,63.4,45.12L63.4,36.8C64.36,37.24,66,38.08,66.76,38.6C67.36,37.72,67.88,36.68,68.4,35.48L72.16,35.48L72.16,39.12L64.56,39.12L64.56,43.24L72.16,43.24L72.16,50.0175L76.72,50.0175L76.72,43.24L82.68,43.24L82.68,39.12L76.72,39.12L76.72,35.48L81.84,35.48L81.84,31.44L76.72,31.44L76.72,28.28L72.16,28.28L72.16,31.44L69.76,31.44C69.96,30.6,70.16,29.76,70.32,28.92L66.8,28.2C70.8,25.96,72.28,22.6,72.96,18.44L77.4,18.44C77.24,21.76,77.04,23.12,76.68,23.56C76.4,23.92,76.08,23.96,75.6,23.96C75.08,23.96,74,23.92,72.72,23.8C73.32,24.84,73.72,26.48,73.8,27.68C75.44,27.72,76.96,27.72,77.88,27.56C78.88,27.44,79.64,27.08,80.32,26.28C81.2,25.2,81.52,22.44,81.72,16.04C81.76,15.52,81.8,14.48,81.8,14.48L64.16,14.48L64.16,18.44L68.64,18.44C68.08,21.4,66.88,23.8,63.4,25.36L63.4,22.76L59.76,22.76C60.6,21.12,61.44,19.32,62,17.76L59.16,15.9994L58.52,16.16L54.12,16.16C54.44,15.2369,54.72,14.2725,54.96,13.3488L50.72,12.425ZM54.04,33.16L54.04,37.2L51.76,37.2C51.84,35.88,51.88,34.56,51.88,33.4L51.88,33.16L54.04,33.16ZM57.2,33.16L59.48,33.16L59.48,37.2L57.2,37.2L57.2,33.16ZM57.2,40.72L59.48,40.72L59.48,45.04C59.48,45.44,59.4,45.56,59.04,45.56L57.2,45.52L57.2,40.72ZM63.4,36.6L63.4,25.8C64.28,26.6006,65.16,27.8819,65.6,28.8025L66.4,28.4025C65.84,31.44,64.8,34.48,63.4,36.6ZM105.36,12.4231L105.36,19.4L91.52,19.4L91.52,39.6838L96.32,39.6838L96.32,37.48L105.36,37.48L105.36,50.0187L110.44,50.0187L110.44,37.48L119.52,37.48L119.52,39.4831L124.56,39.4831L124.56,19.4L110.44,19.4L110.44,12.4231L105.36,12.4231ZM96.32,32.76L96.32,24.12L105.36,24.12L105.36,32.76L96.32,32.76ZM119.52,32.76L110.44,32.76L110.44,24.12L119.52,24.12L119.52,32.76Z"
fill="#2485FF"
fill-opacity="1"
/>
</g>
</g>
</g>
</svg>
<div>
<span v-if="operatorStore.disinfectStatus == 1" style="color: #F74104;font-size: 2.3rem;font-weight: 600;">预热中</span>
<span v-if="operatorStore.disinfectStatus == 2" style="color: #17F179;font-size: 2.3rem;font-weight: 600;">消毒中</span>
<span v-if="operatorStore.disinfectStatus == 4" style="color: #2485FF;font-size: 2.3rem;font-weight: 600;">降解中</span>
<span v-if="operatorStore.disinfectStatus == 6" style="color: #2485FF;font-size: 2.3rem;font-weight: 600;">除湿中</span>
<span v-if="operatorStore.disinfectStatus == 7" style="color: #2485FF;font-size: 2.3rem;font-weight: 600;">除湿中</span>
<span v-if="operatorStore.disinfectStatus == 8" style="color: #2485FF;font-size: 2.3rem;font-weight: 600;">排空管路</span>
</div>
<div
class="left_log_wrap"
v-if="[1, 2, 3, 4].includes(operatorStore.disinfectStatus)"
@ -106,13 +43,10 @@
}}log
</p>
</div>
<div
<div v-if="!([0,5].includes(operatorStore.disinfectStatus))"
class="btn"
v-if="[1, 2, 3, 4].includes(operatorStore.disinfectStatus)"
@click="stopDisinfect"
>
结束消毒
</div>
>结束消毒</div>
<div
class="btn"
v-if="
@ -662,25 +596,25 @@ onMounted(() => {
name: '温度',
type: 'line',
stack: '1',
data: [],
data: echartsStore.envir1Temp,
},
{
name: '湿度',
type: 'line',
stack: '2',
data: [],
data: echartsStore.envir1Humidity,
},
{
name: 'H2O2浓度',
type: 'line',
stack: '3',
data: [],
data: echartsStore.envir1HP,
},
{
name: 'H2O2饱和度',
type: 'line',
stack: '4',
data: [],
data: echartsStore.envir1Saturation,
},
],
})
@ -710,25 +644,25 @@ onMounted(() => {
name: '温度',
type: 'line',
stack: '1',
data: [],
data: echartsStore.envir2Temp,
},
{
name: '湿度',
type: 'line',
stack: '2',
data: [],
data: echartsStore.envir2Humidity,
},
{
name: 'H2O2浓度',
type: 'line',
stack: '3',
data: [],
data: echartsStore.envir2HP,
},
{
name: 'H2O2饱和度',
type: 'line',
stack: '4',
data: [],
data: echartsStore.envir2Saturation,
},
],
})
@ -765,6 +699,40 @@ const continueDisinfect = () => {
// webSocketStore.sendCommandMsg(continueDisinfectionJSON)
// }
}
</script>
<style lang="scss" scoped>

118
src/components/Setting/components/Device.vue

@ -10,129 +10,100 @@
<div class="row_wrap">
<p class="title">注射蠕动泵速率(g/min)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="sprayLiquidConfigVal"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="sprayLiquidConfigVal"
:formatter="formatter7"
readonly
@click.stop="hideClickKey(2)"
@done="setSprayLiquidVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="stoped_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_gs"
:formatter="formatter1"
readonly
@click.stop="hideClickKey(3)"
@done="setStopedGsVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="continued_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_gs"
:formatter="formatter2"
readonly
@click.stop="hideClickKey(4)"
@done="setcontinuedGsVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止相对湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="stoped_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_humi"
:formatter="formatter9"
readonly
@click.stop="hideClickKey(9)"
@done="setstoped_humiVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续相对湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="continued_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_humi"
:formatter="formatter10"
readonly
@click.stop="hideClickKey(10)"
@done="setcontinued_humiVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
class="field_font"
type="number"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_satur"
:formatter="formatter3"
v-model="stoped_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(5)"
@done="setstopedSaturVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
class="field_font"
type="number"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_satur"
:formatter="formatter4"
v-model="continued_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(6)"
@done="setContinuedSaturVal"
/>
</p>
</div>
<div class="row_wrap" v-if="[0, 5].includes(operatorStore.disinfectStatus)">
<p class="title">允许消毒最大湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="max_humidity"
:formatter="formatter5"
type="number"
v-model="max_humidity"
:clickable="true"
readonly
@click.stop="hideClickKey(7)"
@done="setMaxHumidityVal"
/>
</p>
</div>
<div class="row_wrap" v-if="[0, 5].includes(operatorStore.disinfectStatus)">
<p class="title">预热时间(s)</p>
<p class="num">
<van-field
class="field_font"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="pre_heat_time_s"
:formatter="formatter8"
type="number"
v-model="pre_heat_time_s"
:clickable="true"
readonly
@click.stop="hideClickKey(8)"
@done="setHeat_timeVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">恢复默认设置</p>
<p class="num">
<div class="btn" style="font-size: 1rem;margin-right: 50px;" @click="actionDefaultSetting">恢复</div>
</p>
</div>
<van-number-keyboard
v-model="addLiquidConfigVal"
:title="addLiquidConfigVal"
@ -245,10 +216,15 @@ import Down from '@/assets/img/arrow/down.png'
import Top from '@/assets/img/arrow/top.png'
import {
setSettingValJSON,
getAllSettingJSON,
changeDisinfectionParameterJSON,
updateSettingInRunInfectionJSON,
} from '@/mock/command'
import MyModal from '../../../utils/MyModal'
const topContainer = () => {
const ele = document.getElementById('set_device_container')
ele.scrollTop = ele.scrollTop - 100 < 100 ? 0 : ele.scrollTop - 100
@ -757,6 +733,20 @@ const setSprayLiquidVal = () => {
}
showSuccessToast('设置成功')
}
//
async function actionDefaultSetting() {
let isConfirmed = await MyModal.confirm('是否恢复到默认设置?');
if (!isConfirmed) {
return;
}
if ( !props.runInfection ) {
await webSocketStore.call('factoryResetSettings');
webSocketStore.sendCommandMsg(getAllSettingJSON);
}
showSuccessToast('设置成功')
}
</script>
<style lang="scss" scoped>
@ -812,7 +802,7 @@ const setSprayLiquidVal = () => {
color: #000000;
display: flex;
align-items: center;
.field_font {
:deep(.field_font) {
font-size: 26px;
width: 180px;
}

115
src/components/Setting/components/History.vue

@ -2,7 +2,14 @@
<div class="histrory_container">
<div class="header_wrap">
<p class="title_text">消毒名称</p>
<p class="operator_text">操作</p>
<p class="operator_text">
<van-dropdown-menu>
<van-dropdown-item title="操作"
:options="[{text:'导出',value:'export'},{text:'删除',value:'delete'}]"
@change="actionOperationExecute"
></van-dropdown-item>
</van-dropdown-menu>
</p>
</div>
<div class="content_wrap" id="set_device_container">
<img
@ -54,16 +61,14 @@
</g>
</svg>
</div>
<div
class="data_line"
v-for="item in historyStore.historyDataList"
:key="item"
>
<p class="title">{{ item }}</p>
<div class="btns">
<div class="btn" @click="showDetailModal(item)">详情</div>
<van-checkbox-group v-model="checkedItems">
<div class="data_line" v-for="item in historyDataList" :key="item">
<p class="title"><van-checkbox :name="item"/> &nbsp; {{ item }}</p>
<div class="btns">
<div class="btn" @click="showDetailModal(item)">详情</div>
</div>
</div>
</div>
</van-checkbox-group>
</div>
<div class="detail_modal" v-if="showDetailVisible">
<img :src="Top" @click.prevent="topContainer2" class="top_arrow" alt="" />
@ -86,9 +91,9 @@
class="right_arrow"
alt=""
/>
<div class="table_wrap" id="tabledetail_device_container">
<div
class="table_column"
<div class="table_column"
v-for="(item, index) in historyStore.tableData"
:key="index"
>
@ -101,25 +106,67 @@
</div>
</div>
</div>
<div class="bottom_line">
<div class="return_btn" @click="showDetailVisible = false">返回</div>
</div>
</div>
<my-modal type="confirm" icon="warning"
content="确定要所选消毒记录吗!"
v-model:visible="clearRecordByKeysModalVisible"
@ok="actionClearRecordByKeysExecute"
></my-modal>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ref, computed } from 'vue'
import Down from '@/assets/img/arrow/down.png'
import Top from '@/assets/img/arrow/top.png'
import Right from '@/assets/img/arrow/right.png'
import Left from '@/assets/img/arrow/left.png'
import { useHistoryStore, useWebSocketStore } from '@/store'
import { getDetailInfoById } from '@/mock/command'
import { useHistoryStore, useWebSocketStore, useSettingStore } from '@/store'
import { getDetailInfoById, exportDisinfectionRecordByKeyListJSON, getAllLocalHistoryData } from '@/mock/command'
import MyModal from 'cpns/MyModal.vue';
/** @var {Object} */
const webSocketStore = useWebSocketStore();
//
const checkedItems = ref([])
/** @var {Boolean} */
const clearRecordByKeysModalVisible = ref(false);
// clear record by keys
async function actionClearRecordByKeysExecute() {
await webSocketStore.call('cleanDisinfectionRecord',{keys:checkedItems.value});
webSocketStore.sendCommandMsg(getAllLocalHistoryData);
}
const showDetailVisible = ref(false)
const historyStore = useHistoryStore()
const webSocketStore = useWebSocketStore()
const settingStore = useSettingStore()
//
const clearRecordByKeys = ref(null)
//
const historyDataList = computed(() => {
return historyStore.historyDataList.sort((a, b) => b.localeCompare(a));
});
//
function actionOperationExecute( action ) {
if ( checkedItems.value.length === 0 ) {
return;
}
if ( 'export' === action ) {
settingStore.updateExportText('导出消毒记录中')
settingStore.updateExportLoading(true)
webSocketStore.sendCommandMsg(exportDisinfectionRecordByKeyListJSON(checkedItems.value));
} else if ( 'delete' === action ) {
// clearRecordByKeys.value.showDialog();
clearRecordByKeysModalVisible.value = true;
}
}
const topContainer = () => {
const ele = document.getElementById('set_device_container')
@ -160,7 +207,29 @@ const showDetailModal = item => {
})
}
</script>
<style scoped>
:deep(.operator_text) .van-dropdown-menu__title {
font-family: Source Han Sans CN;
font-size: 18px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.07em;
color: #999999;
}
:deep(.operator_text) .van-dropdown-item {
position: absolute;
top: 80px !important;
}
:deep(.operator_text) .van-cell__title {
font-family: Source Han Sans CN;
font-size: 18px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.07em;
color: #999999;
}
:deep(.operator_text) .van-dropdown-menu__bar {background: transparent !important;box-shadow: none !important;}
</style>
<style lang="scss" scoped>
.histrory_container {
display: flex;
@ -241,6 +310,7 @@ const showDetailModal = item => {
line-height: normal;
letter-spacing: 0.07em;
color: #191919;
display : inline-flex;
}
.btns {
display: flex;
@ -290,7 +360,7 @@ const showDetailModal = item => {
width: 40px;
height: 40px;
position: fixed;
right: 50px;
right: 160px;
bottom: 111px;
z-index: 4;
}
@ -306,21 +376,21 @@ const showDetailModal = item => {
width: 40px;
height: 40px;
position: fixed;
right: 126px;
right: 220px;
bottom: 111px;
z-index: 4;
}
.table_wrap {
// flex: 1;
width: 2680px;
width: 100%;
height: 580px;
display: flex;
justify-content: space-evenly;
align-items: center;
overflow: scroll;
.table_column {
// height: 500px;
// position: relative;
padding : 0 10px;
min-height: 500px;
.title {
height: 80px;
@ -343,6 +413,7 @@ const showDetailModal = item => {
.first_box {
position: relative;
.content {
white-space: nowrap;
height: 60px;
display: flex;
align-items: center;
@ -368,7 +439,7 @@ const showDetailModal = item => {
display: flex;
align-items: center;
justify-content: flex-end;
padding: 20px 174px;
padding: 20px;
.return_btn {
width: 91px;
height: 40px;

132
src/components/Setting/components/RunInfectionSetting.vue

@ -10,162 +10,74 @@
<div class="row_wrap">
<p class="title">注射蠕动泵速率(g/min)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="sprayLiquidConfigVal"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="sprayLiquidConfigVal"
:formatter="formatter7"
readonly
@click.stop="hideClickKey(2)"
@done="setSprayLiquidVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="stoped_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_gs"
:formatter="formatter1"
readonly
@click.stop="hideClickKey(3)"
@done="setStopedGsVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="continued_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_gs"
:formatter="formatter2"
readonly
@click.stop="hideClickKey(4)"
@done="setStopedGsVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止相对湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="stoped_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_humi"
:formatter="formatter9"
readonly
@click.stop="hideClickKey(9)"
@done="setstoped_humiVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续相对湿度(%RH)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="continued_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_humi"
:formatter="formatter10"
readonly
@click.stop="hideClickKey(10)"
@done="setcontinued_humiVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
type="number"
class="field_font"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_satur"
:formatter="formatter3"
v-model="stoped_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(5)"
@done="setstopedSaturVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
class="field_font"
type="number"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_satur"
:formatter="formatter4"
v-model="continued_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(6)"
@done="setContinuedSaturVal"
/>
</p>
</div>
<van-number-keyboard
v-model="sprayLiquidConfigVal"
@input="val => handleInput(val, 2)"
:title="sprayLiquidConfigVal"
:show="sprayLiquidConfigValShow"
theme="custom"
@close="setSprayLiquidVal"
close-button-text="配置"
@blur="sprayLiquidConfigValShow = false"
/>
<van-number-keyboard
v-model="stoped_gs"
@input="val => handleInput(val, 3)"
:title="stoped_gs"
:show="stoped_gsShow"
theme="custom"
@close="setStopedGsVal"
close-button-text="配置"
@blur="stoped_gsShow = false"
/>
<van-number-keyboard
v-model="continued_gs"
@input="val => handleInput(val, 4)"
:title="continued_gs"
@close="setcontinuedGsVal"
:show="continued_gsShow"
theme="custom"
close-button-text="配置"
@blur="continued_gsShow = false"
/>
<van-number-keyboard
v-model="stoped_satur"
@input="val => handleInput(val, 5)"
:title="stoped_satur"
@close="setstopedSaturVal"
:show="stoped_saturShow"
theme="custom"
close-button-text="配置"
@blur="stoped_saturShow = false"
/>
<van-number-keyboard
v-model="continued_satur"
@input="val => handleInput(val, 6)"
:title="continued_satur"
@close="setContinuedSaturVal"
:show="continued_saturShow"
theme="custom"
close-button-text="配置"
@blur="continued_saturShow = false"
/>
<van-number-keyboard
@input="val => handleInput(val, 9)"
theme="custom"
close-button-text="配置"
@close="setstoped_humiVal"
v-model="stoped_humi"
:title="stoped_humi"
:show="stoped_humiShow"
@blur="stoped_humiShow = false"
/>
<van-number-keyboard
theme="custom"
@input="val => handleInput(val, 10)"
close-button-text="配置"
@ -645,7 +557,7 @@ const setSprayLiquidVal = () => {
color: #000000;
display: flex;
align-items: center;
.field_font {
:deep(.field_font) {
font-size: 26px;
width: 180px;
}

8
src/components/Setting/index.vue

@ -21,16 +21,16 @@
<p :class="activeTab == 4 ? 'title active' : 'title'">日期/时间设置</p>
<div :class="activeTab == 4 ? 'btn style-btn' : 'dis_btn'">配置</div>
</div>
<div class="tab_wrap" @click="changeActiveTab(5)">
<!-- <div class="tab_wrap" @click="changeActiveTab(5)">
<p class="active_line" v-show="activeTab == 5"></p>
<p :class="activeTab == 5 ? 'title active' : 'title'">审计管理</p>
<div :class="activeTab == 5 ? 'btn style-btn' : 'dis_btn'">操作</div>
</div>
<div class="tab_wrap" @click="changeActiveTab(6)">
</div> -->
<!-- <div class="tab_wrap" @click="changeActiveTab(6)">
<p class="active_line" v-show="activeTab == 6"></p>
<p :class="activeTab == 6 ? 'title active' : 'title'">消毒记录管理</p>
<div :class="activeTab == 6 ? 'btn style-btn' : 'dis_btn'">操作</div>
</div>
</div> -->
<div class="tab_wrap" @click="changeActiveTab(7)">
<p class="active_line" v-show="activeTab == 7"></p>
<p :class="activeTab == 7 ? 'title active' : 'title'">历史记录</p>

42
src/components/Test.vue

@ -62,14 +62,10 @@
<div class="common_set switch_wrap">
<p class="title">注射蠕动泵</p>
<div class="num">
<van-field
type="number"
<my-input type="number" class="add_liquid_input" theme="custom" close-text="配置"
v-model:value="addLiquidVal2"
:formatter="formatter7"
v-model="addLiquidVal2"
:clickable="true"
readonly
@click.stop="hideAllKeyboards(3)"
class="add_liquid_input"
@done="setHeat_timeVal"
/>
<p>g/min</p>
</div>
@ -190,14 +186,14 @@
</div>
</div>
<div class="common_set update_wrap">
<p class="title">水浸1</p>
<p class="title" style="width:150px;">设备底部水浸</p>
<p class="num">{{ testStore.waterImmersionSensor1 ? '有水' : '没水' }}</p>
<div class="btn_wrap style-btn" @click="handleUpdate" style="opacity: 0">
更新读取水浸状态
</div>
</div>
<div class="common_set update_wrap">
<p class="title">水浸2</p>
<p class="title">蒸发仓水浸</p>
<p class="num">{{ testStore.waterImmersionSensor2 ? '有水' : '没水' }}</p>
<div class="btn_wrap style-btn" @click="handleUpdate" style="opacity: 0">
更新读取水浸状态
@ -235,6 +231,17 @@
<p class="info">湿度 {{ deviceStore.envirHumidity2 }} </p>
<p class="info">过氧化氢浓度 {{ deviceStore.envirHP2 }} PPM</p>
</div>
<div class="common_set update_wrap pressure">
<p class="title">
气路压力计 <span>{{ testStore.allPressure[1] }}</span>
</p>
<p class="title">
加液压力计 <span>{{ testStore.allPressure[2] }}</span>
</p>
<p class="title">
喷液压力计 <span>{{ testStore.allPressure[3] }}</span>
</p>
</div>
<van-number-keyboard
v-model="addLiquidVal"
@input="val => handleInput(val, 1)"
@ -555,7 +562,7 @@ const changeDraughtStatus = flag => {
display: flex;
align-items: center;
margin-right: 4px;
.add_liquid_input {
:deep(.add_liquid_input) {
width: 40px;
margin-right: 2px;
text-align: right;
@ -568,6 +575,21 @@ const changeDraughtStatus = flag => {
}
}
}
.pressure {
display: flex;
align-items: center;
justify-content: space-evenly !important;
.title {
display: flex;
line-height: 30px;
justify-content: center !important;
flex-direction: column;
align-items: center;
span {
font-size: 26px;
}
}
}
.switch_wrap {
padding: 0 17px 0 17px;
justify-content: space-between;

93
src/components/UpdatePreSetting.vue

@ -3,99 +3,71 @@
<div class="row_wrap">
<p class="title">消毒停止过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
class="field_font"
type="number"
v-model="stoped_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_gs"
:formatter="formatter1"
readonly
@click.stop="hideClickKey(3)"
@done="setStopedGsVal"
/>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢浓度(ppm)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="continued_gs"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_gs"
:formatter="formatter2"
readonly
@click.stop="hideClickKey(4)"
/>
@done="setcontinuedGsVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止相对湿度(%RH)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="stoped_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_humi"
:formatter="formatter9"
readonly
@click.stop="hideClickKey(9)"
/>
@done="setstoped_humiVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续相对湿度(%RH)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="continued_humi"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_humi"
:formatter="formatter10"
readonly
@click.stop="hideClickKey(10)"
/>
@done="setcontinued_humiVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒停止过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
type="number"
class="field_font"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="stoped_satur"
:formatter="formatter3"
v-model="stoped_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(5)"
/>
@done="setstopedSaturVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">消毒继续过氧化氢相对饱和度(%RS)</p>
<p class="num">
<van-field
type="number"
class="field_font"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="continued_satur"
:formatter="formatter4"
v-model="continued_satur"
:clickable="true"
readonly
@click.stop="hideClickKey(6)"
/>
@done="setContinuedSaturVal"
></my-input>
</p>
</div>
<div class="row_wrap">
<p class="title">注射蠕动泵速率(g/min)</p>
<p class="num">
<van-field
type="number"
class="field_font"
v-model="sprayLiquidConfigVal"
:clickable="true"
<my-input type="number" class="field_font" theme="custom" close-text="配置"
v-model:value="sprayLiquidConfigVal"
:formatter="formatter7"
readonly
@click.stop="hideClickKey(2)"
/>
@done="setSprayLiquidVal"
></my-input>
</p>
</div>
<div class="row_wrap" @click="showLogPicker">
@ -307,6 +279,15 @@ const save = () => {
showFailToast('配方名称不能为空')
return
}
let list = formulaStore?.formulaList;
for (let i = 0; i < list.length; i++) {
if (list[i].formula_id == formula_id.value && list[i].id != props.formulaInfo.id) {
showFailToast('配方名称已存在')
return
}
}
const data = {
id: props.formulaInfo.id,
formula_id: formula_id.value,
@ -874,7 +855,7 @@ onMounted(() => {
align-items: center;
justify-content: center;
}
.field_font {
:deep(.field_font) {
font-size: 26px;
width: 180px;
}

110
src/components/dialogs/ClearRecordByKeysModal.vue

@ -0,0 +1,110 @@
<template>
<my-modal type="confirm" icon="warning"
content="确定要删除所选消毒记录吗!"
v-model:visible="enable"
@ok="handleStart"
@cancel="handleCancel"
></my-modal>
</template>
<script setup>
import { useWebSocketStore } from '@/store'
import { cleanDisinfectionRecordByKeysJSON } from '@/mock/command'
import { ref } from 'vue'
// props
const props = defineProps({
keys : {type: Array,default: () => []}
})
// WebSocket store
const webSocketStore = useWebSocketStore()
//
const enable = ref(false);
//
defineExpose({showDialog});
function showDialog() {
enable.value = true;
}
const handleCancel = () => {
enable.value = false;
}
const handleStart = () => {
webSocketStore.sendCommandMsg(cleanDisinfectionRecordByKeysJSON(props.keys))
enable.value = false;
}
</script>
<style lang="scss" scoped>
.clear_record_modal_container {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
.modal_content {
width: 476px;
height: 350px;
border-radius: 16px;
background: #ffffff;
padding: 52px 37px 55px 37px;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
.tips {
margin-top: 33px;
margin-bottom: 50px;
font-family: Source Han Sans CN;
font-size: 21px;
font-weight: normal;
letter-spacing: 0.04em;
color: #000000;
.red {
color: #fa1c1c;
}
}
.btns {
display: flex;
align-items: center;
justify-content: space-between;
width: 362px;
.cancel {
width: 173px;
height: 68px;
border-radius: 34px;
background: #06518b;
font-family: Source Han Sans CN;
font-size: 23px;
font-weight: 350;
letter-spacing: 0em;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
.ok {
width: 173px;
height: 68px;
border-radius: 34px;
background: #1f6397;
font-family: Source Han Sans CN;
font-size: 23px;
font-weight: 350;
letter-spacing: 0em;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
</style>

39
src/components/dialogs/DelPreModal.vue

@ -1,37 +1,16 @@
<template>
<div class="del_pre_modal_container">
<div class="modal_content">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="69"
height="69"
viewBox="0 0 69 69"
>
<g>
<path
d="M34.5,0C15.456,0,0,15.456,0,34.5C0,53.544,15.456,69,34.5,69C53.544,69,69,53.544,69,34.5C69,15.456,53.544,0,34.5,0ZM34.5,55.2C32.5335,55.2,30.981,53.613,30.981,51.681C30.981,49.7145,32.568,48.162,34.5,48.162C36.4665,48.162,38.019,49.749,38.019,51.681C38.019,53.613,36.4665,55.2,34.5,55.2ZM38.3295,15.8355L37.605,40.9515C37.5705,42.2625,36.225,43.2975,34.638,43.2975L34.086,43.2975C32.499,43.2975,31.1535,42.2625,31.119,40.9515L30.36,15.8355C30.291,13.8345,31.9125,12.144,33.9825,12.144L34.707,12.144C36.777,12.144,38.3985,13.8345,38.3295,15.8355Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
</svg>
<p class="tips">
<span class="red">确定要删除当前预设吗</span>
</p>
<div class="btns">
<div class="ok style-btn" @click="delThisPre">确定</div>
<div class="cancel style-btn" @click="handleCancel">取消</div>
</div>
</div>
</div>
<my-modal type="confirm" icon="warning"
content="确定要删除当前预设吗?"
v-model:visible="visible"
@ok="delThisPre"
@cancel="handleCancel"
></my-modal>
</template>
<script setup>
import { useFormulaStore, useWebSocketStore } from '@/store'
import { delFormulaJSON, getAllFormulaJSON } from '@/mock/command'
import { ref } from 'vue'
const formulaStore = useFormulaStore()
const webSocketStore = useWebSocketStore()
@ -41,6 +20,10 @@ const props = defineProps({
},
})
const visible = ref(true);
const handleCancel = () => {
props.hideDelModal()
}

59
src/components/dialogs/DisinfectModal.vue

@ -1,43 +1,28 @@
<template>
<div class="disinfect_modal_container">
<div class="modal_content">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="69"
height="69"
viewBox="0 0 69 69"
>
<g>
<path
d="M34.5,0C15.456,0,0,15.456,0,34.5C0,53.544,15.456,69,34.5,69C53.544,69,69,53.544,69,34.5C69,15.456,53.544,0,34.5,0ZM34.5,55.2C32.5335,55.2,30.981,53.613,30.981,51.681C30.981,49.7145,32.568,48.162,34.5,48.162C36.4665,48.162,38.019,49.749,38.019,51.681C38.019,53.613,36.4665,55.2,34.5,55.2ZM38.3295,15.8355L37.605,40.9515C37.5705,42.2625,36.225,43.2975,34.638,43.2975L34.086,43.2975C32.499,43.2975,31.1535,42.2625,31.119,40.9515L30.36,15.8355C30.291,13.8345,31.9125,12.144,33.9825,12.144L34.707,12.144C36.777,12.144,38.3985,13.8345,38.3295,15.8355Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
</svg>
<p class="tips">
<span class="red">消毒正在进行中是否终止消毒</span>
</p>
<div class="btns">
<div class="ok style-btn" @click="handleStart">确定</div>
<div class="cancel style-btn" @click="handleCancel">取消</div>
</div>
</div>
</div>
<my-modal type="confirm" icon="warning"
v-model:visible="visible"
@ok="handleStart"
@cancel="handleCancel"
>
<p class="tips"><span class="red">消毒正在进行中是否终止消毒</span></p>
</my-modal>
</template>
<script setup>
import { stopDisinfectionJSON } from '@/mock/command'
import { useOperatorStore, useWebSocketStore } from '@/store'
import { ref } from 'vue'
const props = defineProps({
hideDisinfectModal: {
type: Function,
},
})
const visible = ref(true)
const operatorStore = useOperatorStore()
const webSocketStore = useWebSocketStore()
@ -59,6 +44,24 @@ const handleStart = () => {
</script>
<style lang="scss" scoped>
.tips {
margin-top: 33px;
margin-bottom: 50px;
font-family: Source Han Sans CN;
font-size: 21px;
font-weight: normal;
letter-spacing: 0.04em;
color: #000000;
.red {
color: #fa1c1c;
}
}
.disinfect_modal_container {
position: fixed;
top: 0;

58
src/components/dialogs/LiquidModal.vue

@ -1,40 +1,18 @@
<template>
<div class="liquid_modal_container">
<div class="modal_content">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="69"
height="69"
viewBox="0 0 69 69"
>
<g>
<path
d="M34.5,0C15.456,0,0,15.456,0,34.5C0,53.544,15.456,69,34.5,69C53.544,69,69,53.544,69,34.5C69,15.456,53.544,0,34.5,0ZM34.5,55.2C32.5335,55.2,30.981,53.613,30.981,51.681C30.981,49.7145,32.568,48.162,34.5,48.162C36.4665,48.162,38.019,49.749,38.019,51.681C38.019,53.613,36.4665,55.2,34.5,55.2ZM38.3295,15.8355L37.605,40.9515C37.5705,42.2625,36.225,43.2975,34.638,43.2975L34.086,43.2975C32.499,43.2975,31.1535,42.2625,31.119,40.9515L30.36,15.8355C30.291,13.8345,31.9125,12.144,33.9825,12.144L34.707,12.144C36.777,12.144,38.3985,13.8345,38.3295,15.8355Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
</svg>
<p class="warn_info mg">
<span class="red">检查</span>是否接入排出容器
</p>
<p class="warn_info">
并确认<span class="red">容器是否大于</span>排出液体容积
</p>
<div class="btns">
<div class="ok style-btn" @click="tapLiquid">确定</div>
<div class="cancel style-btn" @click="cancelTap">取消</div>
</div>
</div>
</div>
<my-modal type="confirm" icon="warning"
v-model:visible="visible"
@ok="tapLiquid"
@cancel="cancelTap"
>
<p class="warn_info mg"><span class="red">检查</span>是否接入排出容器</p>
<p class="warn_info" style="margin-bottom: 50px;">并确认<span class="red">容器是否大于</span>排出液体容积</p>
</my-modal>
</template>
<script setup>
import { useWebSocketStore } from '@/store'
import { startDrainingJSON } from '@/mock/command'
import { ref } from 'vue'
const webSocketStore = useWebSocketStore()
@ -44,6 +22,9 @@ const props = defineProps({
},
})
const visible = ref(true)
const tapLiquid = () => {
webSocketStore.sendCommandMsg(startDrainingJSON)
props?.hideTabLiquid()
@ -55,6 +36,21 @@ const cancelTap = () => {
</script>
<style lang="scss" scoped>
.warn_info {
font-family: Source Han Sans CN;
font-size: 22px;
font-weight: normal;
letter-spacing: 0.04em;
color: #000000;
.red {
color: #fa1c1c;
}
}
.mg {
margin-top: 34px;
margin-bottom: 16px;
}
.liquid_modal_container {
position: fixed;
top: 0;

40
src/components/dialogs/UserModal.vue

@ -1,35 +1,13 @@
<template>
<div class="user_modal_container">
<div class="modal_content">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="69"
height="69"
viewBox="0 0 69 69"
>
<g>
<path
d="M34.5,0C15.456,0,0,15.456,0,34.5C0,53.544,15.456,69,34.5,69C53.544,69,69,53.544,69,34.5C69,15.456,53.544,0,34.5,0ZM34.5,55.2C32.5335,55.2,30.981,53.613,30.981,51.681C30.981,49.7145,32.568,48.162,34.5,48.162C36.4665,48.162,38.019,49.749,38.019,51.681C38.019,53.613,36.4665,55.2,34.5,55.2ZM38.3295,15.8355L37.605,40.9515C37.5705,42.2625,36.225,43.2975,34.638,43.2975L34.086,43.2975C32.499,43.2975,31.1535,42.2625,31.119,40.9515L30.36,15.8355C30.291,13.8345,31.9125,12.144,33.9825,12.144L34.707,12.144C36.777,12.144,38.3985,13.8345,38.3295,15.8355Z"
fill="#FA1C1C"
fill-opacity="1"
/>
</g>
</svg>
<p class="tips">
请确认是否将 <span class="red">{{ userWarnInfo }}</span>
</p>
<div class="btns">
<div class="ok style-btn" @click="ok">确定</div>
<div class="cancel style-btn" @click="handleCancel">取消</div>
</div>
</div>
</div>
<my-modal type="confirm" icon="warning"
:content="`请确认是否将 ${userWarnInfo}`"
v-model:visible="visible"
@ok="ok"
@cancel="handleCancel"
></my-modal>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
userWarnInfo: {
type: String,
@ -42,6 +20,10 @@ const props = defineProps({
},
})
/** @var {Boolean} */
const visible = ref(true);
const ok = () => {
props.handleOk()
props.hideUserModal()

6
src/components/info/EnvironmentInfo.vue

@ -66,9 +66,11 @@ const {
envirTemperature1,
envirHumidity1,
envirHP1,
envSaturation1,
envirTemperature2,
envirHumidity2,
envirHP2,
envSaturation2
} = storeToRefs(deviceStore)
const props = defineProps({
cardType: {
@ -130,10 +132,10 @@ const getSaturation = () => {
return binSaturation
}
if (props.cardType == 2) {
return 0
return envSaturation1
}
if (props.cardType == 3) {
return 0
return envSaturation2
}
}
</script>

12
src/main.js

@ -11,6 +11,10 @@ import {
NumberKeyboard,
Toast,
Overlay,
Checkbox,
CheckboxGroup,
DropdownMenu,
DropdownItem
} from 'vant'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
@ -18,6 +22,8 @@ import '@vant/touch-emulator'
import 'vant/lib/index.css'
import '@/assets/css/reset.css'
import './style.scss'
import MyInput from 'cpns/MyInput.vue'
import MyModal from 'cpns/MyModal.vue'
createApp(App)
.use(router)
@ -28,7 +34,13 @@ createApp(App)
.use(TimePicker)
.use(Field)
.use(Overlay)
.use(Checkbox)
.use(CheckboxGroup)
.use(DropdownMenu)
.use(DropdownItem)
.use(ElementPlus)
.use(Toast)
.use(store)
.component('my-input', MyInput)
.component('my-modal', MyModal)
.mount('#app')

13
src/mock/command.js

@ -223,11 +223,24 @@ export const exportDisinfectionRecordJSON = {
messageId: 'exportDisinfectionRecord',
}
export const exportDisinfectionRecordByKeyListJSON = ( keys ) => ({
command: 'exportDisinfectionRecord',
messageId: 'exportDisinfectionRecord',
keys,
});
export const cleanDisinfectionRecordJSON = {
command: 'cleanDisinfectionRecord',
messageId: 'cleanDisinfectionRecord',
}
export const cleanDisinfectionRecordByKeysJSON = ( keys ) => ({
command: 'cleanDisinfectionRecord',
messageId: 'cleanDisinfectionRecord',
keys,
});
export const cleanUserBehaviorRecordJSON = {
command: 'cleanUserBehaviorRecord',
messageId: 'cleanUserBehaviorRecord',

18
src/store/modules/device.js

@ -19,12 +19,16 @@ export const useDeviceStore = defineStore({
envirHumidity1: 0,
// 环境一 过氧化氢浓度
envirHP1: 0,
// 环境一 相对饱和度
envSaturation1 : 0,
// 环境二 温度
envirTemperature2: 0,
// 环境二 湿度
envirHumidity2: 0,
// 环境二 过氧化氢浓度
envirHP2: 0,
// 环境二 相对饱和度
envSaturation2 : 0,
// 仓内过氧化氢相对饱和度
binSaturation: 0,
// 剩余log
@ -101,6 +105,13 @@ export const useDeviceStore = defineStore({
}
this.envirHP1 = envirHP1
},
updateEnvSaturation1(envSaturation1) {
if (envSaturation1 < 0) {
this.envSaturation1 = 0
return
}
this.envSaturation1 = envSaturation1
},
updateEnvirTemperature2(envirTemperature2) {
if (envirTemperature2 < 0) {
this.envirTemperature2 = 0
@ -122,5 +133,12 @@ export const useDeviceStore = defineStore({
}
this.envirHP2 = envirHP2
},
updateEnvSaturation2(envSaturation2) {
if (envSaturation2 < 0) {
this.envSaturation2 = 0
return
}
this.envSaturation2 = envSaturation2
},
},
})

14
src/store/modules/echarts.js

@ -78,6 +78,13 @@ export const useEchartsStore = defineStore({
})
return arr
},
envir1Saturation(state) {
let arr = []
Object.values(state.envir1Charts).map(item => {
arr.push(item[3])
})
return arr
},
envir2Temp(state) {
let arr = []
Object.values(state.envir2Charts).map(item => {
@ -99,5 +106,12 @@ export const useEchartsStore = defineStore({
})
return arr
},
envir2Saturation(state) {
let arr = []
Object.values(state.envir2Charts).map(item => {
arr.push(item[3])
})
return arr
},
},
})

3
src/store/modules/operator.js

@ -23,6 +23,9 @@ export const useOperatorStore = defineStore({
showStartReady: false,
// 结束消毒loading
showStopReady: false,
// 加液量
liquidAddtionVolume: 0,
}
},
// actions

2
src/store/modules/setting.js

@ -113,6 +113,7 @@ export const useSettingStore = defineStore({
this.stoped_satur = stoped_saturObj.val
this.continued_gs = continued_gsObj.val
this.stoped_gs = stoped_gsObj.val
this.allSettingList = allSettingList
// 对当前数组进行处理 赋予给泵参数
const addLiquid = allSettingList.filter(
item => item.name == 'drainage_pump_speed',
@ -123,7 +124,6 @@ export const useSettingStore = defineStore({
this.addLiquidConfigVal = addLiquid.val
this.sprayLiquidConfigVal = sprayLiquid.val
this.allSettingList = allSettingList
},
updateInitLoading() {
this.initLoading = false

5
src/store/modules/test.js

@ -21,10 +21,15 @@ export const useTestStore = defineStore({
heatingStripObj: {},
waterImmersionSensor1: false,
waterImmersionSensor2: false,
allPressure: [0, 0, 0, 0],
}
},
// actions
actions: {
updateAllPressure(allPressure) {
this.allPressure = allPressure
},
updateWaterImmersionSensor1(waterImmersionSensor1) {
this.waterImmersionSensor1 = waterImmersionSensor1
},

94
src/store/modules/websocket.js

@ -23,10 +23,31 @@ export const useWebSocketStore = defineStore({
socketCommandInstance: null,
// 事件上报websocket 实例
socketEventInstance: null,
// Event Handlers
eventHandlers : {},
// Call ID Counter
callIdCounter : 0,
// Call Resolve Handler Map
callPromiseHandlers : {},
// Call Param Merge Commands
callparamMergeCmds : [
'cleanDisinfectionRecord', 'startDisinfection', 'changeDisinfectionParameter','setSettingVal'
],
}
},
// actions
actions: {
// register event handler
registerEventHandler( event, handler ) {
this.eventHandlers[event] = this.eventHandlers[event] || [];
this.eventHandlers[event].push(handler);
},
initCommandSocket() {
const url = import.meta.env.VITE_BASE_WS1_URL
const init = new Socket(url)
@ -41,8 +62,27 @@ export const useWebSocketStore = defineStore({
const runningStore = useRunningStore()
const historyStore = useHistoryStore()
init.connect()
let $this = this;
init.ws.onmessage = function (ev) {
const { messageId, timeStamp } = JSON.parse(ev.data)
// 优先处理call-response
if ( undefined !== $this.callPromiseHandlers[messageId] ) {
let response = JSON.parse(ev.data);
const handler = $this.callPromiseHandlers[messageId];
delete $this.callPromiseHandlers[messageId];
console.log(`[Call Response : ${messageId}] ${handler.message.command} => ${JSON.stringify(response)}`);
if ( 0 === response.ackcode ) {
handler.resolve(response);
} else {
handler.reject(response.ackDisplayInfo);
}
return;
}
console.log(JSON.parse(ev.data))
switch (messageId) {
case 'getState':
@ -73,6 +113,8 @@ export const useWebSocketStore = defineStore({
humid_2,
humid_3,
saturation_1,
saturation_2,
saturation_3,
temp_1,
temp_2,
temp_3,
@ -87,6 +129,7 @@ export const useWebSocketStore = defineStore({
chargingPumpRPM,
sprinklerPumpRPM,
sprinklerPumpGPM,
pressure,
} = sensor_data
const { nowlog, targetlog } = disinfectionState || {}
deviceStore.updateTargetLog(targetlog)
@ -107,6 +150,7 @@ export const useWebSocketStore = defineStore({
operatorStore.updateReplenishingFluidsWorkState(
replenishingFluidsWorkState,
)
testStore.updateWaterImmersionSensor1(
waterImmersionSensor1 == 0 ? false : true,
)
@ -119,6 +163,7 @@ export const useWebSocketStore = defineStore({
testStore.updateHeatingStripObj(heatingStrip)
testStore.updateSprinklerPump(sprinklerPump)
testStore.updateChargingPump(chargingPump)
testStore.updateAllPressure(pressure)
settingStore.updateDeviceIp('192.168.8.10')
deviceStore.updateDisinfectantCapacity(disinfectant_volume)
deviceStore.updateBinTemperature(temp_1)
@ -128,9 +173,11 @@ export const useWebSocketStore = defineStore({
deviceStore.updateEnvirTemperature1(temp_2)
deviceStore.updateEnvirHumidity1(humid_2)
deviceStore.updateEnvirHP1(h2o2_2)
deviceStore.updateEnvSaturation1(saturation_2)
deviceStore.updateEnvirTemperature2(temp_3)
deviceStore.updateEnvirHumidity2(humid_3)
deviceStore.updateEnvirHP2(h2o2_3)
deviceStore.updateEnvSaturation2(saturation_3)
userStore.updatePermission(permissionLevel)
settingStore.updateInitLoading()
@ -145,8 +192,8 @@ export const useWebSocketStore = defineStore({
saveEchartsDataToLocal(
moment().utcOffset(8).format('HH:mm'),
[temp_1, humid_1, h2o2_1, saturation_1],
[temp_2, humid_2, h2o2_2, saturation_1],
[temp_3, humid_3, h2o2_3, saturation_1],
[temp_2, humid_2, h2o2_2, saturation_2],
[temp_3, humid_3, h2o2_3, saturation_3],
)
echartsStore.updateBinCharts(
JSON.parse(localStorage.getItem('bin')),
@ -271,6 +318,31 @@ export const useWebSocketStore = defineStore({
sendCommandMsg(message) {
this.socketCommandInstance?.msg(message)
},
// call and wait for response
call( command, params=null ) {
this.callIdCounter += 1;
if ( this.callIdCounter > 1000000 ) {
this.callIdCounter = 0;
}
const callId = `call-${this.callIdCounter}`;
return new Promise(( resolve, reject ) => {
let message = {};
message.command = command;
message.messageId = callId;
if ( null !== params ) {
if ( this.callparamMergeCmds.includes(command) ) {
message = { ...message, ...params };
} else {
message.params = params;
}
}
this.callPromiseHandlers[callId] = { resolve, reject, message };
console.log(`[Call Request : ${callId}] ${command}(${JSON.stringify(params)})`);
this.sendCommandMsg(message);
});
},
initEventSocket() {
const url = import.meta.env.VITE_BASE_WS2_URL
const init = new Socket(url)
@ -280,9 +352,21 @@ export const useWebSocketStore = defineStore({
const settingStore = useSettingStore()
const operatorStore = useOperatorStore()
const echartsStore = useEchartsStore()
let $this = this;
init.ws.onmessage = function (ev) {
// console.log(JSON.parse(ev.data))
const { command, timeStamp } = JSON.parse(ev.data)
if ( undefined !== $this.eventHandlers[command] ) {
let data = JSON.parse(ev.data);
data = data.data;
for ( const handler of $this.eventHandlers[command] ) {
handler(data);
}
return ;
}
switch (command) {
case 'RealtimeSensorDataReport':
const { sensor_data } = JSON.parse(ev.data)
@ -297,6 +381,8 @@ export const useWebSocketStore = defineStore({
temp_2,
temp_3,
saturation_1,
saturation_2,
saturation_3,
airCompressor,
disinfectant_volume,
heatingStrip,
@ -336,8 +422,8 @@ export const useWebSocketStore = defineStore({
saveEchartsDataToLocal(
moment().utcOffset(8).format('HH:mm'),
[temp_1, humid_1, h2o2_1, saturation_1],
[temp_2, humid_2, h2o2_2, saturation_1],
[temp_3, humid_3, h2o2_3, saturation_1],
[temp_2, humid_2, h2o2_2, saturation_2],
[temp_3, humid_3, h2o2_3, saturation_3],
)
echartsStore.updateBinCharts(
JSON.parse(localStorage.getItem('bin')),

60
src/utils/MyModal.js

@ -0,0 +1,60 @@
import { createApp, h } from 'vue';
import MyModalComponent from 'cpns/MyModal.vue';
export default class MyModal {
// show error message
static error( message ) {
return new Promise( resolve => {
const modalContainer = document.createElement('div');
document.body.appendChild(modalContainer);
const modalApp = createApp({
render() {
return h(MyModalComponent, {
ref : 'modal',
icon : 'warning',
type : 'info',
content : message,
onOk : () => {
modalApp.unmount();
document.body.removeChild(modalContainer);
resolve();
}
});
},
});
const vm = modalApp.mount(modalContainer);
vm.$refs.modal.show();
});
}
// show confirm message
static confirm( message ) {
return new Promise( resolve => {
const modalContainer = document.createElement('div');
document.body.appendChild(modalContainer);
const modalApp = createApp({
render() {
return h(MyModalComponent, {
ref : 'modal',
icon : 'warning',
type : 'confirm',
content : message,
onOk : () => {
modalApp.unmount();
document.body.removeChild(modalContainer);
resolve(true);
},
onCancel : () => {
modalApp.unmount();
document.body.removeChild(modalContainer);
resolve(false);
}
});
},
});
const vm = modalApp.mount(modalContainer);
vm.$refs.modal.show();
});
}
}
Loading…
Cancel
Save