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.
351 lines
9.8 KiB
351 lines
9.8 KiB
<script setup lang="ts">
|
|
import { pauseCraft, resumeCraft, stopCraft } from 'apis/crafts'
|
|
import { trayTube } from 'apis/home'
|
|
import errorIcon from 'assets/images/error.svg'
|
|
import ingIcon from 'assets/images/ing.svg'
|
|
import successIcon from 'assets/images/success.svg'
|
|
import waitIcon from 'assets/images/wait.svg'
|
|
import CountDown from 'components/common/Countdown.vue'
|
|
import { useHomeStore } from 'stores/homeStore'
|
|
import { useSystemStore } from 'stores/systemStore'
|
|
import { computed, ref } from 'vue'
|
|
|
|
const props = withDefaults(defineProps<{ data: System.HeatArea }>(), {
|
|
data: () => ({
|
|
moduleCode: 'heat_module_01',
|
|
trayUp: 1,
|
|
trayStatus: 0,
|
|
fanOpen: false,
|
|
heating: false,
|
|
heatingType: 'constant',
|
|
capExist: false,
|
|
temperature: 0,
|
|
targetTemperature: 0,
|
|
}),
|
|
})
|
|
|
|
const emits = defineEmits(['selectChange', 'setTemperature'])
|
|
|
|
const homeStore = useHomeStore()
|
|
const systemStore = useSystemStore()
|
|
const mousedownHandle = async (e: Event) => {
|
|
let event
|
|
if ('touches' in e) {
|
|
event = (e.touches as TouchList)[0]
|
|
}
|
|
else {
|
|
event = e
|
|
}
|
|
if (event.target!.classList!.contains('tube-inner')) {
|
|
const num = event.target!.getAttribute('index')
|
|
await trayTube({
|
|
trayUuid: tray.value!.uuid,
|
|
tubes: [
|
|
{
|
|
tubeNum: Number(num),
|
|
exists: !tray.value?.tubes.find(t => t.tubeNum === Number(num))?.exists,
|
|
},
|
|
],
|
|
})
|
|
}
|
|
}
|
|
|
|
const activeTubeBox = ref(false)
|
|
|
|
const tubeSelect = () => {
|
|
emits('selectChange')
|
|
}
|
|
|
|
const hearInfo = computed(() => {
|
|
return homeStore.heatAreaList.find(item => item.value === props.data.moduleCode)
|
|
})
|
|
|
|
const craft = computed(() => {
|
|
return systemStore.systemStatus.tray?.find(item => item.heatModuleId === props.data.moduleCode)?.crafts
|
|
})
|
|
|
|
const craftSteps = computed(() => {
|
|
const steps = systemStore.systemStatus.tray?.find(item => item.heatModuleId === props.data.moduleCode)?.crafts?.craft?.steps
|
|
return steps ? JSON.parse(steps) : undefined
|
|
})
|
|
console.log(craftSteps.value)
|
|
|
|
const tray = computed(() => {
|
|
return systemStore.systemStatus.tray?.find(item => item.heatModuleId === props.data.moduleCode)
|
|
})
|
|
|
|
const pauseCraftHandle = async () => {
|
|
await pauseCraft({
|
|
heatId: props.data.moduleCode,
|
|
})
|
|
}
|
|
|
|
const resumeCraftHandle = async () => {
|
|
await resumeCraft({
|
|
heatId: props.data.moduleCode,
|
|
})
|
|
}
|
|
|
|
const stopCraftHandle = async () => {
|
|
await stopCraft({
|
|
heatId: props.data.moduleCode,
|
|
})
|
|
}
|
|
|
|
defineExpose({
|
|
activeTubeBox,
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="tube" :class="{ 'tube-active': hearInfo?.selected, 'tube-shadow': data.trayUp === 1 }">
|
|
<div class="header">
|
|
<span>{{ hearInfo?.label }}</span>
|
|
<el-tag v-show="!data.trayStatus" type="info">
|
|
空置
|
|
</el-tag>
|
|
<el-tag v-show="data.trayStatus" type="success">
|
|
已放置
|
|
</el-tag>
|
|
</div>
|
|
<div class="tube-item" :class="{ 'tube-item-heat': ['warm_up', 'thermostatic'].includes(data.heatingType), 'tube-item-constant': data.heatingType === 'constant', 'tube-item-fan': data.fanOpen }" @click.prevent="mousedownHandle" @touch.prevent="mousedownHandle">
|
|
<div v-if="data.trayStatus === 0" class="tube-disable" />
|
|
<div
|
|
v-if="craft?.state"
|
|
class="status" :class="{
|
|
'status-success': craft?.state === 'FINISHED',
|
|
'status-wait': craft?.state === 'READY',
|
|
'status-PAUSED': craft?.state === 'PAUSED',
|
|
'status-error': craft?.state === 'ERROR',
|
|
'status-ing': craft?.state === 'RUNNING',
|
|
}"
|
|
>
|
|
<img v-if="craft?.state === 'FINISHED'" :src="successIcon" alt="">
|
|
<img v-if="craft?.state === 'RUNNING'" :src="ingIcon" alt="">
|
|
<img v-if="craft?.state === 'READY'" :src="waitIcon" alt="">
|
|
<img v-if="craft?.state === 'PAUSED'" :src="waitIcon" alt="">
|
|
<img v-if="craft?.state === 'ERROR'" :src="errorIcon" alt="">
|
|
|
|
<span class="status-name">{{ craft?.craft?.name || ' ' }}</span>
|
|
<span v-if="craft?.state === 'RUNNING'" class="status-text">工艺执行中</span>
|
|
<span v-if="craft?.state === 'READY'" class="status-text">工艺等待执行</span>
|
|
<span v-if="craft?.state === 'PAUSED'" class="status-text">工艺已暂停</span>
|
|
<span v-if="craft?.state === 'ERROR'" class="status-text">工艺执行错误</span>
|
|
<span v-if="craft?.state === 'FINISHED'" class="status-text">工艺执行完毕</span>
|
|
|
|
<el-tooltip v-if="craft?.state === 'RUNNING' && craftSteps && craftSteps[craft.currentIndex || 0]?.params?.description" :content="`${craftSteps[craft.currentIndex || 0].params.description}`" placement="top" trigger="click">
|
|
<div class="status-description">
|
|
{{ craftSteps[craft.currentIndex || 0].params.description }}
|
|
</div>
|
|
</el-tooltip>
|
|
<div class="status-operation">
|
|
<ft-button v-if="craft?.state === 'RUNNING'" type="primary" size="small" :click-handle="pauseCraftHandle">
|
|
暂停
|
|
</ft-button>
|
|
<ft-button v-if="craft?.state === 'PAUSED'" type="primary" size="small" :click-handle="resumeCraftHandle">
|
|
继续
|
|
</ft-button>
|
|
<ft-button v-if="['RUNNING', 'PAUSED'].includes(craft?.state)" size="small" :click-handle="stopCraftHandle">
|
|
停止
|
|
</ft-button>
|
|
<span v-if="craft?.state === 'FINISHED'">请取走托盘</span>
|
|
</div>
|
|
</div>
|
|
<span v-for="item in 16" :key="item" class="tube-inner" :class="{ 'tube-inner-active': tray?.tubes.find(tu => tu.tubeNum === item)?.exists }" :index="item" />
|
|
</div>
|
|
<div class="temperature-box">
|
|
<span>
|
|
<span>当前温度: </span>
|
|
<span>{{ data.temperature || '--' }}</span>
|
|
<span>℃</span>
|
|
</span>
|
|
<span v-show="data.heatingType === 'warm_up'" style="color: #FF4500;font-weight: bold ">预热中</span>
|
|
<span v-show="data.heatingType === 'thermostatic'" style="color: #FF4500;;font-weight: bold ">加热中</span>
|
|
<span v-show="data.heatingType === 'constant'" style="color: #eccbb6;font-weight: bold ">恒温中</span>
|
|
<span v-show="data.fanOpen" style="color: #6CD3FF;font-weight: bold ">降温中</span>
|
|
</div>
|
|
<CountDown v-if="data.startHeatTime && data.targetTime" :current="new Date().getTime()" :start-time="data.startHeatTime" :duration="data.targetTime" />
|
|
<div class="footer">
|
|
<div class="tem-box">
|
|
<span :class="{ 'active-footer': hearInfo?.selected }"> {{ data.targetTemperature || '--' }}℃</span>
|
|
</div>
|
|
<ft-button size="small" :type="hearInfo?.selected ? 'primary' : 'default'" @click="tubeSelect">
|
|
选择
|
|
</ft-button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.tube-active {
|
|
border-color: #275EFB !important;
|
|
}
|
|
.tube-shadow {
|
|
box-shadow: 0 0 10px rgba(0,0,0,0.9);
|
|
}
|
|
.tube {
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
height: 95%;
|
|
background: #E9F3FF;
|
|
border-radius: 10px;
|
|
padding: 10px;
|
|
font-size: 14px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
border: 2px solid #E9F3FF;
|
|
transition: all 0.3s;
|
|
position: relative;
|
|
overflow: hidden;
|
|
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
color: #4D6882;
|
|
}
|
|
.tube-item-heat {
|
|
background: #FF4500 !important;
|
|
}
|
|
.tube-item-fan {
|
|
background: #6CD3FF !important;
|
|
}
|
|
.tube-item-constant {
|
|
background: #F0E5DE !important;
|
|
}
|
|
.tube-item {
|
|
padding: 5px;
|
|
background: #384D5D;
|
|
border-radius: 10px;
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
grid-template-rows: repeat(4, 1fr);
|
|
grid-gap: 5px;
|
|
position: relative;
|
|
.tube-disable {
|
|
position: absolute;
|
|
width: 100%;
|
|
height: 100%;
|
|
top: 0;
|
|
left: 0;
|
|
background: rgba(255,255,255,0.9);
|
|
border-radius: 9px;
|
|
}
|
|
.tube-inner {
|
|
display: inline-block;
|
|
width: 25px;
|
|
height: 25px;
|
|
border-radius: 50%;
|
|
background: #fff;
|
|
margin: 2px;
|
|
transition: background 0.5s;
|
|
}
|
|
.tube-inner-active {
|
|
background: #26D574;
|
|
border: 1px solid #fff;
|
|
}
|
|
}
|
|
.temperature-box {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
background: #fff;
|
|
padding: 5px;
|
|
border-radius: 5px;
|
|
font-size: 12px;
|
|
}
|
|
.footer {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
font-weight: bold;
|
|
color: #4D6882;
|
|
.active-footer {
|
|
color: #1562B7;
|
|
}
|
|
.ft-button {
|
|
margin-right: 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
.status {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(255,255,255,0.9);
|
|
z-index: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
border-radius: 10px;
|
|
img {
|
|
width: 22px;
|
|
margin: 5px 0;
|
|
}
|
|
.status-name {
|
|
font-size: 14px;
|
|
}
|
|
.status-text {
|
|
font-size: 16px;
|
|
font-weight: 700;
|
|
}
|
|
.status-operation {
|
|
width: 100%;
|
|
margin-top: auto;
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
justify-content: space-around;
|
|
.ft-button {
|
|
margin-right: 5px;
|
|
}
|
|
}
|
|
}
|
|
.status-success {
|
|
border: 1px solid #14A656;
|
|
}
|
|
.status-wait {
|
|
background: rgba(242,235,231, 0.9);
|
|
border: 1px solid #EE8223;
|
|
color: #EE8223;
|
|
}
|
|
.status-PAUSED {
|
|
background: rgba(242,235,231, 0.9);
|
|
border: 1px solid #EE8223;
|
|
color: #EE8223;
|
|
}
|
|
.status-error {
|
|
background: rgba(232,212,222, 0.9);
|
|
border: 1px solid #DF1515;
|
|
color: #DF1515;
|
|
}
|
|
.status-ing {
|
|
background: rgba(205,223,255, 0.9);
|
|
border: 1px solid #0256FF;
|
|
color: #0256FF;
|
|
}
|
|
|
|
.tem-box {
|
|
display: flex;
|
|
align-items: center;
|
|
.el-icon {
|
|
margin-left: 5px;
|
|
}
|
|
}
|
|
|
|
.status-description {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
max-width: 95%;
|
|
padding: 0 3px;
|
|
display: inline-block;
|
|
background: #fff;
|
|
border-radius: 2px;
|
|
margin: 2px 0;
|
|
}
|
|
</style>
|