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.
391 lines
11 KiB
391 lines
11 KiB
<script lang="ts" setup>
|
|
import { sendCmd, syncSendCmd } from 'apis/system'
|
|
import homeFinish from 'assets/images/home/home-finish.svg'
|
|
import RunFormulaConfig from 'components/formula/RunFormulaConfig.vue'
|
|
import LineChart from 'components/home/LineChart.vue'
|
|
import { ElLoading } from 'element-plus'
|
|
import { stopTimer } from 'libs/countdownTimer'
|
|
import { FtMessage } from 'libs/message'
|
|
import { FtMessageBox } from 'libs/messageBox'
|
|
import { compareJSON, deviceStateMap } from 'libs/utils'
|
|
import { computed, onMounted, onUnmounted, provide, ref, watchEffect } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
import { useFormulaStore } from '@/stores/formulaStore'
|
|
import { useHomeStore } from '@/stores/homeStore'
|
|
|
|
const configRef = ref()
|
|
provide<(methods: Home.GrandsonMethods) => void>('registerGrandsonMethods', (methods) => {
|
|
configRef.value = methods
|
|
})
|
|
const router = useRouter()
|
|
const formulaStore = useFormulaStore()
|
|
const homeStore = useHomeStore()
|
|
const formulaInfo = ref()
|
|
const disinfectionState = ref(homeStore.disinfectionState)
|
|
const curStateRemainTime = ref(homeStore.curStateRemainTime)
|
|
const disinfectFormulaVisible = ref(false)
|
|
const isDeviceIdle = ref(homeStore.isDeviceIdle)
|
|
|
|
const rate = ref()
|
|
const log = ref()
|
|
|
|
watchEffect(async () => {
|
|
formulaInfo.value = formulaStore.currentSelectedFormulaInfo
|
|
disinfectionState.value = homeStore.disinfectionState
|
|
curStateRemainTime.value = homeStore.curStateRemainTime
|
|
isDeviceIdle.value = homeStore.isDeviceIdle
|
|
|
|
if (['idle', 'finished'].includes(homeStore.disinfectionState.state)) {
|
|
formulaInfo.value = formulaStore.selectedFormulaInfo
|
|
rate.value = formulaStore.selectedFormulaInfo?.injection_pump_speed
|
|
log.value = formulaStore.selectedFormulaInfo?.loglevel
|
|
}
|
|
else {
|
|
const realForm = (await formulaStore.getRealtimeConfig()).rely
|
|
rate.value = homeStore.realRate || realForm?.injection_pump_speed
|
|
log.value = homeStore.realLog || realForm?.loglevel
|
|
}
|
|
})
|
|
|
|
const onDisinfectConfig = () => {
|
|
disinfectFormulaVisible.value = true
|
|
}
|
|
|
|
// 结束消毒
|
|
const onFinishDisinfect = async () => {
|
|
await FtMessageBox.warning('请确认是否结束消毒')
|
|
homeStore.setRate(undefined)
|
|
homeStore.setLog(undefined)
|
|
stopTimer()
|
|
const loading = ElLoading.service({
|
|
lock: true,
|
|
text: '正在结束消毒',
|
|
background: 'rgba(255, 255, 255, 0.8)',
|
|
})
|
|
try {
|
|
const stopParams = {
|
|
className: 'DisinfectionCtrlServiceExt',
|
|
fnName: 'stop',
|
|
params: { loglevel: formulaStore.loglevel },
|
|
}
|
|
await sendCmd(stopParams)
|
|
const poll = setInterval(() => {
|
|
if (operationState.value) {
|
|
loading.close()
|
|
clearInterval(poll)
|
|
}
|
|
}, 100)
|
|
}
|
|
catch (e) {
|
|
console.log(e)
|
|
loading.close()
|
|
}
|
|
}
|
|
const chartRef = ref()
|
|
const onSave = async () => {
|
|
const formData = await chartRef.value?.saveFormData()
|
|
if (!formData) {
|
|
return
|
|
}
|
|
// 消毒中更新实时配置
|
|
const res = await formulaStore.getRealtimeConfig()
|
|
const diff = compareJSON(res.rely, formData)
|
|
const diffKeys = Object.keys(diff)
|
|
if (diffKeys.length) {
|
|
await Promise.all(
|
|
diffKeys.map(async (key) => {
|
|
await formulaStore.setRealtimeConfig(key, diff[key].newVal)
|
|
}),
|
|
)
|
|
FtMessage.success('设定成功')
|
|
homeStore.setRate(formData.injection_pump_speed)
|
|
homeStore.setLog(formData.loglevel)
|
|
}
|
|
}
|
|
|
|
const goHome = () => {
|
|
router.push('/home')
|
|
}
|
|
const onClose = () => {
|
|
disinfectFormulaVisible.value = false
|
|
}
|
|
|
|
const chartList = ref<any[]>([])
|
|
const operationState = computed(() => {
|
|
return disinfectionState.value.state === 'idle' || disinfectionState.value.state === 'finished'
|
|
})
|
|
|
|
let poll: any = null
|
|
|
|
const chartRefs = ref([])
|
|
|
|
const getData = async (type?: string) => {
|
|
const data = await syncSendCmd({
|
|
className: 'H2O2SensorMgr',
|
|
fnName: 'getH2O2SensorList',
|
|
})
|
|
|
|
const list = data.rely
|
|
console.log(list)
|
|
!type && (chartList.value = list.filter(item => item.isOnline).map(item => ({ ...item, data: [] })))
|
|
for (let i = 0; i < list.length; i++) {
|
|
const item: any = list[i]
|
|
const res = await syncSendCmd({
|
|
className: 'H2O2SensorMgr',
|
|
fnName: 'getDisinfectionH2O2DataRecordList',
|
|
params: {
|
|
type: item.type,
|
|
id: item.id,
|
|
interval: 30,
|
|
},
|
|
})
|
|
item.data = res.rely
|
|
}
|
|
console.log(list)
|
|
chartList.value = list.filter(item => item.isOnline)
|
|
console.log(chartList.value)
|
|
}
|
|
|
|
const chartLoading = ref(false)
|
|
onMounted(async () => {
|
|
chartLoading.value = true
|
|
await getData()
|
|
chartLoading.value = false
|
|
poll = setInterval(() => {
|
|
if (operationState.value) {
|
|
clearInterval(poll)
|
|
return
|
|
}
|
|
getData('interval')
|
|
}, 1000 * 30)
|
|
})
|
|
|
|
onUnmounted(() => {
|
|
clearInterval(poll)
|
|
})
|
|
|
|
const formatSeconds = (seconds: number) => {
|
|
if (seconds === -1) {
|
|
seconds = 0
|
|
}
|
|
const hours = Math.floor(seconds / 3600)
|
|
const minutes = Math.floor((seconds % 3600) / 60)
|
|
const remainingSeconds = seconds % 60
|
|
|
|
// 补零函数
|
|
const padZero = (num: number) => num.toString().padStart(2, '0')
|
|
|
|
return `${padZero(hours)}:${padZero(minutes)}:${padZero(remainingSeconds)}`
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<main class="main-content">
|
|
<el-descriptions :column="4">
|
|
<!-- <el-descriptions-item label="设定注射速率"> -->
|
|
<!-- <el-tag> -->
|
|
<!-- <span style="color: #31cb7a; font-size: 18px; margin: 0 5px">{{ rate }}</span>g/min -->
|
|
<!-- </el-tag> -->
|
|
<!-- </el-descriptions-item> -->
|
|
<el-descriptions-item label="实时注射速率">
|
|
<el-tag>
|
|
<span style="color: #31cb7a; font-size: 18px; margin: 0 5px">{{
|
|
homeStore.disinfectionState.injectedVelocity
|
|
}}</span>g/min
|
|
</el-tag>
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="目标消毒等级">
|
|
<el-tag>
|
|
<span style="color: #31cb7a; font-size: 18px; margin: 0 5px">{{ log }}</span>Log
|
|
</el-tag>
|
|
</el-descriptions-item>
|
|
|
|
<el-descriptions-item label="实时消毒等级">
|
|
<el-tag>
|
|
<span style="color: #31cb7a; font-size: 18px; margin: 0 5px">{{
|
|
parseInt(homeStore.disinfectionState.nlog?.toString())
|
|
}}</span>Log
|
|
</el-tag>
|
|
</el-descriptions-item>
|
|
</el-descriptions>
|
|
<div
|
|
v-loading="chartLoading"
|
|
element-loading-background="rgba(255, 255, 255, 0.1)"
|
|
class="line-chart-content"
|
|
:style="{ 'grid-template-columns': `repeat(${chartList.length},1fr)` }"
|
|
>
|
|
<LineChart
|
|
v-for="(item, index) in chartList"
|
|
ref="chartRefs"
|
|
:key="index"
|
|
class="chart-box"
|
|
:style="{ width: `calc(100% / ${chartList.length} - 10px)` }"
|
|
:env-data="item"
|
|
/>
|
|
</div>
|
|
<div class="line-chart-bottom">
|
|
<div class="home-chart-time">
|
|
<div v-if="!homeStore.isDeviceIdle" class="home-remain-time">
|
|
<div class="home-chart-label">
|
|
<span v-if="disinfectionState.state === 'disinfection'"> 预计剩余时间: </span>
|
|
<span v-else> 消毒状态: </span>
|
|
</div>
|
|
<div v-if="disinfectionState.state === 'disinfection'" class="home-chart-value">
|
|
{{ formatSeconds(homeStore.disinfectionState.curStateRemainTimeS) }}
|
|
</div>
|
|
<div v-else class="home-chart-value">
|
|
{{ deviceStateMap[disinfectionState.state] }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="home-chart-btn">
|
|
<el-button v-if="!isDeviceIdle" type="danger" @click="onFinishDisinfect">
|
|
<template #icon>
|
|
<img :src="homeFinish" alt="" style="height: 20px">
|
|
</template>
|
|
结束消毒
|
|
</el-button>
|
|
<el-button v-if="!isDeviceIdle" type="primary" @click="onDisinfectConfig">
|
|
运行参数
|
|
</el-button>
|
|
<el-button @click="goHome">
|
|
返回
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
|
|
<ft-dialog v-model="disinfectFormulaVisible" title="运行参数" width="80vw">
|
|
<div class="formula-config">
|
|
<RunFormulaConfig ref="chartRef" />
|
|
</div>
|
|
<template #footer>
|
|
<div class="config-btn">
|
|
<el-button @click="onClose">
|
|
关闭
|
|
</el-button>
|
|
<el-button type="primary" @click="onSave">
|
|
确认
|
|
</el-button>
|
|
</div>
|
|
</template>
|
|
</ft-dialog>
|
|
</main>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.main-content {
|
|
overflow: hidden;
|
|
background: rgba(147, 203, 255, 0.1);
|
|
height: 100%;
|
|
border-radius: 10px;
|
|
box-shadow: 0 1px 5px 0 rgba(9, 39, 62, 0.15);
|
|
padding: 10px;
|
|
.formula-config {
|
|
display: grid;
|
|
padding: 10px;
|
|
width: 100%;
|
|
}
|
|
.line-chart-formula {
|
|
width: 40vw;
|
|
//background: #E0F0FF;
|
|
height: 3.5rem;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
//border: 1px solid #E0F0FF;
|
|
border-radius: 10px;
|
|
margin-left: 2rem;
|
|
}
|
|
.line-chart-set {
|
|
display: flex;
|
|
justify-content: end;
|
|
align-items: center;
|
|
width: 65vw;
|
|
padding-right: 20px;
|
|
}
|
|
.line-chart-title {
|
|
height: 15%;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.line-chart-content {
|
|
display: flex;
|
|
flex-direction: row; // 子元素水平排列(默认值)
|
|
align-items: flex-start; // 子元素顶部对齐
|
|
overflow-x: auto; // 横向滚动支持
|
|
width: 100%;
|
|
height: calc(100% - 80px);
|
|
gap: 10px;
|
|
.chart-box {
|
|
flex: 0 0 auto;
|
|
width: 100%;
|
|
height: 100%;
|
|
min-width: 200px;
|
|
}
|
|
}
|
|
.line-chart-bottom {
|
|
height: 40px;
|
|
display: flex;
|
|
padding-right: 20px;
|
|
align-items: center;
|
|
.home-chart-btn {
|
|
display: flex;
|
|
justify-content: end;
|
|
width: 65%;
|
|
}
|
|
.home-chart-time {
|
|
width: 35%;
|
|
.home-remain-time {
|
|
background: #fff;
|
|
margin: 10px;
|
|
height: 40px;
|
|
border-radius: 12px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 20px;
|
|
gap: 10px;
|
|
.home-remaini-value {
|
|
color: #2892f3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
:deep(.el-descriptions) {
|
|
width: 100%;
|
|
height: 40px;
|
|
.el-descriptions__body {
|
|
background: rgba(0, 0, 0, 0);
|
|
.el-descriptions__table {
|
|
tr {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
:deep(.el-descriptions__cell) {
|
|
display: flex;
|
|
align-items: center;
|
|
//background: #fff;
|
|
//margin-bottom: 5px;
|
|
//padding: 5px !important;
|
|
//.el-descriptions__label {
|
|
// display: inline-block;
|
|
// width: 120px;
|
|
// margin: 0;
|
|
// font-size: 15px;
|
|
// font-weight: 600;
|
|
// color: #606266;
|
|
//}
|
|
//.el-descriptions__content {
|
|
// flex: 1;
|
|
// text-align: right;
|
|
// display: flex;
|
|
// justify-content: flex-end;
|
|
//}
|
|
}
|
|
</style>
|