|
|
@ -80,21 +80,22 @@ |
|
|
|
</div> |
|
|
|
<div class="emergency-controller"> |
|
|
|
<div class="controller"> |
|
|
|
<div |
|
|
|
class="emergency-ball" |
|
|
|
:class="{ active: isActive }" |
|
|
|
@click="showEmergencyInfo(emergencyStore.emergencyInfo)" |
|
|
|
> |
|
|
|
1 |
|
|
|
</div> |
|
|
|
<span class="emergency-desc"> |
|
|
|
{{ |
|
|
|
emergencyStore.emergencyInfo |
|
|
|
? emergencyStateDesc[emergencyStore.emergencyInfo.state] || |
|
|
|
'未知' |
|
|
|
: '--' |
|
|
|
}} |
|
|
|
</span> |
|
|
|
</div> |
|
|
|
<button |
|
|
|
class="controller-button" |
|
|
|
@click="addEmergency" |
|
|
|
:style="`background-color:${emergencyStatus ? '#c84141' : '#b4b4b4'}`" |
|
|
|
:disabled="!emergencyStatus" |
|
|
|
:style="`background-color:${canSetEmergency ? '#c84141' : '#b4b4b4'}`" |
|
|
|
:disabled="!canSetEmergency" |
|
|
|
> |
|
|
|
添加急诊 |
|
|
|
急诊 |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
@ -106,7 +107,7 @@ |
|
|
|
</div> |
|
|
|
<button |
|
|
|
class="id-button" |
|
|
|
@click="openTableModal" |
|
|
|
@click="openIdCardTableModal" |
|
|
|
:disabled="!consumableStore.isIdCardInserted" |
|
|
|
> |
|
|
|
<span class="button-text"> |
|
|
@ -136,20 +137,6 @@ |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<InitWarn v-if="showEmergencyModal" :visible="showEmergencyModal" title="检查耗材" message="请将耗材加载完整后再添加" |
|
|
|
icon="/src/assets/update-pin-icon.svg" confirmText="确认" @confirm="showEmergencyModal = false" /> |
|
|
|
|
|
|
|
<InitWarn |
|
|
|
v-if="showModal" |
|
|
|
:visible="showModal" |
|
|
|
title="提示" |
|
|
|
message="请及时清理废料箱" |
|
|
|
icon="/src/assets/Warn.svg" |
|
|
|
confirmText="确定" |
|
|
|
@close="showModal = false" |
|
|
|
@confirm="handleConfirm" |
|
|
|
/> |
|
|
|
<!--缓冲液大--> |
|
|
|
<div class="buffer-area"> |
|
|
|
<div class="buffer-title"> |
|
|
@ -170,40 +157,57 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<IdCardInfo v-model="visible" v-if="visible"></IdCardInfo> |
|
|
|
|
|
|
|
<InitWarn |
|
|
|
v-if="showEmergencyModal" |
|
|
|
:visible="showEmergencyModal" |
|
|
|
title="检查耗材" |
|
|
|
message="请将耗材加载完整后再添加" |
|
|
|
icon="/src/assets/update-pin-icon.svg" |
|
|
|
confirmText="确认" |
|
|
|
@confirm="showEmergencyModal = false" |
|
|
|
/> |
|
|
|
|
|
|
|
<InitWarn |
|
|
|
v-if="showWasteAlertModal" |
|
|
|
:visible="showWasteAlertModal" |
|
|
|
title="提示" |
|
|
|
message="请及时清理废料箱" |
|
|
|
icon="/src/assets/Warn.svg" |
|
|
|
confirmText="确定" |
|
|
|
@close="showWasteAlertModal = false" |
|
|
|
@confirm="handleConfirm" |
|
|
|
/> |
|
|
|
<IdCardInfo |
|
|
|
v-model="idCardListDialogVisible" |
|
|
|
v-if="idCardListDialogVisible" |
|
|
|
></IdCardInfo> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
|
import BallGrid from './BallGrid.vue' |
|
|
|
import BallGrid2 from './BallGrid2.vue' |
|
|
|
import IdCardInfo from './IdCardInfo.vue' |
|
|
|
import { ref, watch, reactive, onMounted } from 'vue' |
|
|
|
import { ref, watch, computed } from 'vue' |
|
|
|
import { useRouter } from 'vue-router' |
|
|
|
import { useEmergencyStore, useConsumablesStore, useDeviceStore } from '../../../../store' |
|
|
|
import { |
|
|
|
useEmergencyStore, |
|
|
|
useConsumablesStore, |
|
|
|
useDeviceStore, |
|
|
|
} from '../../../../store' |
|
|
|
import { LiquidState } from '../../../../types/Index/index' |
|
|
|
import wasteFullIcon from '@/assets/Index/waste-full.svg' |
|
|
|
import wasteIcon from '@/assets/Index/waste.svg' |
|
|
|
import type { |
|
|
|
EmergencyPosStateMessage, |
|
|
|
LargeBottleGroup, |
|
|
|
import { |
|
|
|
emergencyStateDesc, |
|
|
|
type EmergencyPosStateMessage, |
|
|
|
type LargeBottleGroup, |
|
|
|
} from '@/websocket/socket' |
|
|
|
import { createWebSocket } from '@/websocket/socket' |
|
|
|
import { isTubeExist } from '@/services/Index/index' |
|
|
|
import { InitWarn } from './Warn' |
|
|
|
import { getServerInfo } from '@/utils/getServerInfo' |
|
|
|
import { EMERGENCY_STATE } from "@/constant" |
|
|
|
|
|
|
|
const { wsUrl } = getServerInfo('/api/v1/app/ws/state') |
|
|
|
const socket = createWebSocket(wsUrl) |
|
|
|
|
|
|
|
const emergencyStore = useEmergencyStore() |
|
|
|
const consumableStore = useConsumablesStore() |
|
|
|
const deviceStore = useDeviceStore(); |
|
|
|
const deviceStore = useDeviceStore() |
|
|
|
|
|
|
|
const visible = ref(false) |
|
|
|
const openTableModal = () => { |
|
|
|
visible.value = true |
|
|
|
} |
|
|
|
// 从父组件接收状态和事件 |
|
|
|
const props = defineProps({ |
|
|
|
moveLiquids: { |
|
|
@ -225,6 +229,29 @@ const emit = defineEmits([ |
|
|
|
'updateTipNum', |
|
|
|
]) |
|
|
|
|
|
|
|
const idCardListDialogVisible = ref(false) |
|
|
|
const openIdCardTableModal = () => { |
|
|
|
idCardListDialogVisible.value = true |
|
|
|
} |
|
|
|
|
|
|
|
const canSetEmergency = computed(() => { |
|
|
|
if (!emergencyStore.emergencyInfo) { |
|
|
|
return false |
|
|
|
} |
|
|
|
return ( |
|
|
|
deviceStore.deviceState.workState === 'IDLE' || |
|
|
|
(deviceStore.deviceState.workState === 'WORKING' && |
|
|
|
(emergencyStore.emergencyInfo.state === 'EMPTY' || |
|
|
|
emergencyStore.emergencyInfo.state === 'PROCESS_COMPLETE' || |
|
|
|
emergencyStore.emergencyInfo.state === 'ERROR')) || |
|
|
|
(deviceStore.deviceState.workState === 'PAUSE' && |
|
|
|
(emergencyStore.emergencyInfo.state === 'EMPTY' || |
|
|
|
emergencyStore.emergencyInfo.state === 'TO_BE_PROCESSED' || |
|
|
|
emergencyStore.emergencyInfo.state === 'PROCESS_COMPLETE' || |
|
|
|
emergencyStore.emergencyInfo.state === 'ERROR')) |
|
|
|
) |
|
|
|
}) |
|
|
|
|
|
|
|
let longPressTimer: ReturnType<typeof setTimeout> | null = null |
|
|
|
const handleTouchStart = () => { |
|
|
|
longPressTimer = setTimeout(() => { |
|
|
@ -240,11 +267,9 @@ const handleTouchEnd = () => { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//设备当前运行状态 |
|
|
|
// const workState = ref(deviceStore.deviceState.workState) |
|
|
|
let showModal = ref(false) |
|
|
|
let showWasteAlertModal = ref(false) |
|
|
|
const handleConfirm = () => { |
|
|
|
showModal.value = false |
|
|
|
showWasteAlertModal.value = false |
|
|
|
} |
|
|
|
//通过传感器事件监听废料区状态 |
|
|
|
const wasteStatus = ref(props.wasteStatus) |
|
|
@ -252,148 +277,31 @@ watch( |
|
|
|
() => props.wasteStatus, |
|
|
|
(newVal) => { |
|
|
|
wasteStatus.value = newVal |
|
|
|
if (newVal) showModal.value = true |
|
|
|
if (newVal) showWasteAlertModal.value = true |
|
|
|
}, |
|
|
|
{ immediate: true, deep: true }, |
|
|
|
) |
|
|
|
//使用websocket保证数据的实时性 |
|
|
|
const startWebSocket = () => { |
|
|
|
socket.connect() |
|
|
|
} |
|
|
|
const emergencyStateList = [ |
|
|
|
'EMPTY', |
|
|
|
'TO_BE_PROCESSED', |
|
|
|
'PROCESS_COMPLETE', |
|
|
|
'ERROR', |
|
|
|
] //只有当前急诊位状态为EMPTY,PROCESS_COMPLETE,ERROR才能添加添加新的耗材 |
|
|
|
onMounted(() => { |
|
|
|
//获取急诊位状态 |
|
|
|
getEmergencyStatus() |
|
|
|
startWebSocket() |
|
|
|
socket.subscribe<EmergencyPosStateMessage>( |
|
|
|
'EmergencyPosState', |
|
|
|
handleEmergencyPosState, |
|
|
|
) |
|
|
|
}) |
|
|
|
|
|
|
|
let emergencyStatus = ref(false) |
|
|
|
if (deviceStore.deviceState.workState === 'WORKING') { |
|
|
|
emergencyStatus.value = false; |
|
|
|
} |
|
|
|
//处理急诊状态消息 |
|
|
|
const handleEmergencyPosState = (data: EmergencyPosStateMessage['data']) => { |
|
|
|
// data.tube.state = 'PROCESSING' |
|
|
|
if (deviceStore.deviceState.workState === 'WORKING') { |
|
|
|
emergencyStatus.value = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
let { state } = data.tube |
|
|
|
//当急诊试管状态是 EMPTY、TO_BE_PROCESSED、PROCESS_COMPLETE、ERROR可以编辑 |
|
|
|
emergencyStore.setInfo(data.tube) |
|
|
|
if(emergencyStateList.includes(state)){ |
|
|
|
emergencyStatus.value = true; |
|
|
|
}else{ |
|
|
|
emergencyStatus.value = false; |
|
|
|
} |
|
|
|
emergencyStore.setInfo(data.tube) |
|
|
|
//当试管状态是完成时"PROCESS_COMPLETE",取消订阅上报事件 |
|
|
|
if (state === 'PROCESS_COMPLETE') { |
|
|
|
socket.unsubscribe<EmergencyPosStateMessage>( |
|
|
|
'EmergencyPosState', |
|
|
|
unSubEmergencyPosState, |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//取消急诊事件消息处理 |
|
|
|
const unSubEmergencyPosState = () => {} |
|
|
|
|
|
|
|
//获取急诊位状态 |
|
|
|
const getEmergencyStatus = () => { |
|
|
|
isTubeExist().then((res) => { |
|
|
|
console.log('这是急诊位状态=1=', res) |
|
|
|
if (res && res.data) { |
|
|
|
const data = res.data |
|
|
|
const { tube } = data |
|
|
|
|
|
|
|
if (tube && tube.state && emergencyStateList.includes(tube.state)) { |
|
|
|
emergencyStatus.value = true |
|
|
|
} |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 激活的移液盘 索引 |
|
|
|
const activeTab = ref(0) |
|
|
|
// 废料区状态判断 |
|
|
|
const isActive = ref(false) |
|
|
|
|
|
|
|
watch( |
|
|
|
() => props.emergencyInfo, |
|
|
|
(newVal) => { |
|
|
|
// 只有当急诊数据存在且不为空或者不是异常状态时,不激活小球 |
|
|
|
if (newVal && (newVal.state == EMERGENCY_STATE.EMPTY || newVal.state == EMERGENCY_STATE.ERROR)) { |
|
|
|
isActive.value = false // 没有急诊数据时,不激活小球 |
|
|
|
} else {//其它状态激活小球 |
|
|
|
isActive.value = true |
|
|
|
} |
|
|
|
}, |
|
|
|
{ immediate: true }, // 确保初始化时会触发一次 |
|
|
|
) |
|
|
|
|
|
|
|
const emergencyInfo = reactive(emergencyStore.emergencyInfo || {}) |
|
|
|
const router = useRouter() |
|
|
|
// 跳转到添加急诊页面 |
|
|
|
let showEmergencyModal = ref(false) |
|
|
|
const addEmergency = () => { |
|
|
|
//未返回 反应板夹 数组时,直接提示 |
|
|
|
if(!consumableStore.consumableData.reactionPlateGroup){ |
|
|
|
showEmergencyModal.value = true; |
|
|
|
return |
|
|
|
} |
|
|
|
//有反应板夹数据,但无项目时 也要给出提示信息 |
|
|
|
const clonereactionList = [...consumableStore.consumableData.reactionPlateGroup] |
|
|
|
const hasRactionPlatGroup = clonereactionList.every(item => !item.projId) |
|
|
|
if(hasRactionPlatGroup){ |
|
|
|
showEmergencyModal.value = true; |
|
|
|
return |
|
|
|
} |
|
|
|
//已经有急诊位时 |
|
|
|
if (emergencyStore.emergencyInfo?.pos) { |
|
|
|
//如果有急诊数据,就携带数据跳转,便于回显 |
|
|
|
router.push({ |
|
|
|
path: '/index/emergency', |
|
|
|
query: { data: encodeURIComponent(JSON.stringify(props.emergencyInfo)) }, |
|
|
|
}) |
|
|
|
} else { |
|
|
|
if (canSetEmergency) { |
|
|
|
//未返回 反应板夹 数组时,直接提示 |
|
|
|
if ( |
|
|
|
consumableStore.consumableData.reactionPlateGroup.every( |
|
|
|
(p) => !p.isInstall, |
|
|
|
) |
|
|
|
) { |
|
|
|
showEmergencyModal.value = true |
|
|
|
return |
|
|
|
} |
|
|
|
router.push('/index/emergency') |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//回显急诊信息 |
|
|
|
const showEmergencyInfo = (item?: EmergencyPosStateMessage['data']['tube']) => { |
|
|
|
console.log('回显急诊信息', item) |
|
|
|
router.push({ |
|
|
|
path: '/index/emergency', |
|
|
|
}) |
|
|
|
} |
|
|
|
// 跟踪激活的小球状态 |
|
|
|
const activeEmergencyBalls = ref<{ [key: number]: boolean }>({}) |
|
|
|
|
|
|
|
// 更新急诊区域小球状态 |
|
|
|
const updateEmergencyBalls = () => { |
|
|
|
activeEmergencyBalls.value[1] = Object.keys(emergencyInfo).length > 0 |
|
|
|
} |
|
|
|
|
|
|
|
// 深度监听 emergencyInfo 的变化,及时更新状态 |
|
|
|
watch( |
|
|
|
() => emergencyInfo, |
|
|
|
() => { |
|
|
|
updateEmergencyBalls() |
|
|
|
}, |
|
|
|
{ immediate: true, deep: true }, |
|
|
|
) |
|
|
|
// 发出更新事件,通知父组件新的 remainingCount 值 |
|
|
|
const handleUpdateTipNum = ( |
|
|
|
remainingCount: number, |
|
|
@ -463,7 +371,6 @@ const changePlate = (index: number) => { |
|
|
|
} |
|
|
|
|
|
|
|
.move-liquid-controller { |
|
|
|
|
|
|
|
display: flex; |
|
|
|
justify-content: space-between; |
|
|
|
flex-wrap: nowrap; |
|
|
@ -502,8 +409,8 @@ const changePlate = (index: number) => { |
|
|
|
color: #e9f1ff; |
|
|
|
/* 选中时文字颜色 */ |
|
|
|
.controller-number { |
|
|
|
background-color: #3D7AF1; |
|
|
|
border-color: #3D7AF1; |
|
|
|
background-color: #3d7af1; |
|
|
|
border-color: #3d7af1; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -577,21 +484,15 @@ const changePlate = (index: number) => { |
|
|
|
background-color: #fff; |
|
|
|
align-items: center; |
|
|
|
|
|
|
|
.emergency-ball { |
|
|
|
width: 40px; |
|
|
|
height: 40px; |
|
|
|
border-radius: 50%; |
|
|
|
background-color: #d9d9d9; |
|
|
|
align-items: center; |
|
|
|
.emergency-desc { |
|
|
|
width: 100%; |
|
|
|
border-radius: 6px; |
|
|
|
background-color: #ddd; |
|
|
|
line-height: 40px; |
|
|
|
font-weight: 700; |
|
|
|
font-size: 30px; |
|
|
|
color: #a1a1a1; |
|
|
|
|
|
|
|
&.active { |
|
|
|
background-color: red; |
|
|
|
color: white; |
|
|
|
} |
|
|
|
font-weight: 600; |
|
|
|
font-size: 24px; |
|
|
|
color: #999; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|