|
|
@ -11,7 +11,8 @@ |
|
|
|
<span>{{ |
|
|
|
getBloodTypeLabel(selectedItem.bloodType) || '无类型' |
|
|
|
}}</span> |
|
|
|
<span>{{ getRemainingTime(selectedItem) }}</span> |
|
|
|
<!--使用store中tank中的remain字段--> |
|
|
|
<span>{{ 1234545634 }}</span> |
|
|
|
</template> |
|
|
|
<template v-else> </template> |
|
|
|
</div> |
|
|
@ -109,7 +110,8 @@ |
|
|
|
item.projInfo.projShortName || '无项目' |
|
|
|
}}</span> |
|
|
|
<span class="barcode">{{ item.sampleBarcode || '无条码' }}</span> |
|
|
|
<span class="time">{{ getRemainingTime(item) }}</span> |
|
|
|
<!--todo--> |
|
|
|
<span class="time">{{ 1234 }}</span> |
|
|
|
</template> |
|
|
|
<div |
|
|
|
:style="`margin-top:140px;background-color:${currentIndex == index ? 'red' : 'rgb(149, 149, 149)'}`" |
|
|
@ -125,7 +127,7 @@ |
|
|
|
<div |
|
|
|
class="emergency-button" |
|
|
|
:class="{ disabled: hasEmergencyPosition }" |
|
|
|
@click="!hasEmergencyPosition && (showEmergencyAlert = !showEmergencyAlert)" |
|
|
|
@click="confirmEmergency()" |
|
|
|
> |
|
|
|
<span>急诊</span> |
|
|
|
</div> |
|
|
@ -202,33 +204,6 @@ |
|
|
|
</div> |
|
|
|
</teleport> |
|
|
|
<!-- 急诊弹窗提示 --> |
|
|
|
<teleport to="body"> |
|
|
|
<div v-if="showEmergencyAlert" class="alert-overlay"> |
|
|
|
<div class="alert-container"> |
|
|
|
<div class="alert-icon"> |
|
|
|
<img class="icon" src="@/assets/emergency.svg" /> |
|
|
|
<span>急</span> |
|
|
|
</div> |
|
|
|
<div class="alert-message">确认要添加急诊吗?</div> |
|
|
|
<div class="action-buttons"> |
|
|
|
<el-button type="info" @click="cancelEmergency" class="confirm-button" |
|
|
|
>取消</el-button |
|
|
|
> |
|
|
|
<el-button |
|
|
|
type="primary" |
|
|
|
@click="confirmEmergency" |
|
|
|
class="cancel-button" |
|
|
|
>确认</el-button |
|
|
|
> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</teleport> |
|
|
|
<EmergencyResultDialog |
|
|
|
:result="emergencyResult!" |
|
|
|
:visible="isDialogVisible" |
|
|
|
@update:visible="confirmEmergencyWarn" |
|
|
|
/> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script setup lang="ts"> |
|
|
@ -236,7 +211,6 @@ import { |
|
|
|
ref, |
|
|
|
onMounted, |
|
|
|
onUnmounted, |
|
|
|
watch, |
|
|
|
onActivated, |
|
|
|
computed, |
|
|
|
} from 'vue' |
|
|
@ -246,29 +220,20 @@ import { getBloodTypeLabel } from '../utils' |
|
|
|
import { |
|
|
|
PlateDisplay, |
|
|
|
LittleBufferDisplay, |
|
|
|
EmergencyResultDialog, |
|
|
|
} from '../components' |
|
|
|
import tubeItem from '../components/TestTube/Tube.vue' |
|
|
|
import BallGrid from '../components/Consumables/BallGrid.vue' |
|
|
|
import { getRunningList } from '@/services/Index/running/running' |
|
|
|
|
|
|
|
import type { |
|
|
|
EmergencyPosStateMessage, |
|
|
|
ProjectInfo, |
|
|
|
SubTank, |
|
|
|
} from '@/websocket/socket' |
|
|
|
import { useEmergencyStore } from '@/store/modules/emergency' |
|
|
|
import { useRunningStore } from '@/store/modules/running' |
|
|
|
|
|
|
|
const emergencyStore = useEmergencyStore() |
|
|
|
const consumablesStore = useConsumablesStore() |
|
|
|
const runningStore = useRunningStore() |
|
|
|
const deviceStore = useDeviceStore() |
|
|
|
const settingTubeStore = useSettingTestTubeStore() |
|
|
|
|
|
|
|
const router = useRouter() |
|
|
|
const route = useRoute() |
|
|
|
|
|
|
|
// 示例数据 |
|
|
|
const sampleTube = { |
|
|
|
userid: 'user123', |
|
|
@ -281,77 +246,17 @@ const hasEmergencyPosition = ref(false) |
|
|
|
onMounted(() => { |
|
|
|
// 在页面加载时检查是否有急诊数据传递 |
|
|
|
// 初次获取路由参数 |
|
|
|
fetchIncubationData() |
|
|
|
}) |
|
|
|
|
|
|
|
// 监听急诊数据变化 |
|
|
|
watch( |
|
|
|
() => emergencyStore.emergencyInfo, |
|
|
|
(newData) => { |
|
|
|
if (newData) { |
|
|
|
const emergencyInfo = newData as EmergencyPosStateMessage['data']['tube'] |
|
|
|
if (emergencyInfo.projInfo && Array.isArray(emergencyInfo.projInfo)) { |
|
|
|
emergencyInfo.projInfo.forEach( |
|
|
|
(project: ProjectInfo, index: number) => { |
|
|
|
//@ts-ignore |
|
|
|
const subtank: SubTank = { |
|
|
|
pos: `EMERGENCY-${index + 1}`, |
|
|
|
state: 'INCUBATING', |
|
|
|
bloodType: emergencyInfo.bloodType, |
|
|
|
sampleBarcode: emergencyInfo.sampleBarcode, |
|
|
|
userid: emergencyInfo.userid, |
|
|
|
projInfo: project, |
|
|
|
sampleId: `${emergencyInfo.sampleId}-${index}`, |
|
|
|
projId: project.projId, |
|
|
|
startIncubatedTime: Date.now(), |
|
|
|
incubatedTimeSec: 300, |
|
|
|
errors: [], |
|
|
|
isEmergency: true, |
|
|
|
} |
|
|
|
// 添加到孵育盘数据中 |
|
|
|
// incubationPlates.value.push(SubTank) |
|
|
|
}, |
|
|
|
) |
|
|
|
} |
|
|
|
fetchEmergencyData() |
|
|
|
} |
|
|
|
}, |
|
|
|
) |
|
|
|
|
|
|
|
// 页面激活时触发 |
|
|
|
onActivated(() => { |
|
|
|
fetchEmergencyData() |
|
|
|
}) |
|
|
|
|
|
|
|
//急诊状态 |
|
|
|
const showEmergencyAlert = ref(false) |
|
|
|
|
|
|
|
//确认添加急诊 |
|
|
|
const confirmEmergency = () => { |
|
|
|
showEmergencyAlert.value = false |
|
|
|
router.push('/index/emergency') |
|
|
|
} |
|
|
|
|
|
|
|
//确认结果 |
|
|
|
const confirmEmergencyWarn = (val: any) => { |
|
|
|
console.log('急诊结果:', val) |
|
|
|
isDialogVisible.value = false |
|
|
|
} |
|
|
|
|
|
|
|
//获取路由参数 |
|
|
|
const fetchEmergencyData = () => { |
|
|
|
const emergencyQuery = route.query.emergencyData as string |
|
|
|
if (emergencyQuery) { |
|
|
|
emergencyData.value = JSON.parse(emergencyQuery) |
|
|
|
console.log('急诊数据:', emergencyData.value) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
//取消 |
|
|
|
const cancelEmergency = () => { |
|
|
|
showEmergencyAlert.value = false |
|
|
|
} |
|
|
|
|
|
|
|
// 获取圆心样式:选中时显示蓝色边框 |
|
|
|
let selectedPlateStyle = computed(()=>{ |
|
|
|
let borderColor = selectedItem.value ? 'blue' : '#ffffff' |
|
|
@ -366,11 +271,9 @@ let selectedPlateStyle = computed(()=>{ |
|
|
|
// const selectedSamples = ref<number[]>([]) |
|
|
|
// 外圈矩形元素的数量 |
|
|
|
// 孵育盘列表数据 |
|
|
|
const incubationPlates = ref<SubTank[]>([]) |
|
|
|
const selectedItem = ref<SubTank | null>(null) // 当前选中的样本 |
|
|
|
const selectedItemId = ref<string | null>(null) // |
|
|
|
const TOTAL_SLOTS = 20 // 总矩形数 |
|
|
|
const emergencyData = ref<SubTank | null>(null) |
|
|
|
|
|
|
|
// 修改获取旋转样式的方法 |
|
|
|
const getRotationStyle = (item: SubTank, index: number) => { |
|
|
@ -378,6 +281,7 @@ const getRotationStyle = (item: SubTank, index: number) => { |
|
|
|
const angleStep = 360 / totalItems |
|
|
|
const angle = index * angleStep |
|
|
|
|
|
|
|
//todo |
|
|
|
return { |
|
|
|
transform: ` |
|
|
|
translate(-50%, -50%) /* 将矩形中心点移到圆心 */ |
|
|
@ -389,8 +293,6 @@ const getRotationStyle = (item: SubTank, index: number) => { |
|
|
|
? '#f0f0f0' |
|
|
|
: selectedItemId.value === item.sampleId |
|
|
|
? '#1890ff' |
|
|
|
: getRemainingTime(item) === '已完成' |
|
|
|
? '#ff4d4f' |
|
|
|
: 'transparent', |
|
|
|
borderWidth: '3px', |
|
|
|
borderStyle: 'solid', |
|
|
@ -406,8 +308,8 @@ const getItemStyle = (item: SubTank, index) => { |
|
|
|
backgroundColor: '#f8f8f8', // 占位符背景色 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const remainingTime = getRemainingTime(item) |
|
|
|
//todo |
|
|
|
let remainingTime = '1';//临时 |
|
|
|
return { |
|
|
|
backgroundColor: item.projInfo.color,//item.isEmergency ? '#ffeded' : item.projInfo.color, // 急诊位特殊背景 |
|
|
|
borderColor: currentIndex.value === index ? 'blue' : remainingTime === '已完成' ? 'red' : 'transparent', |
|
|
@ -440,171 +342,22 @@ const getFillStyle = (item: any) => { |
|
|
|
|
|
|
|
//控制废料区的状态 |
|
|
|
//@ts-ignore |
|
|
|
const isFull = ref(consumablesStore.wasteStatus) |
|
|
|
const showWasteAlert = ref(false) |
|
|
|
// 获取废料区样式 |
|
|
|
const getWasteStyle = () => ({ |
|
|
|
backgroundColor: isFull.value ? '#d9534f' : '#5cb85c', // 红色表示满,绿色表示未满 |
|
|
|
backgroundColor: deviceStore.sensorState?.wasteBinFullFlag ? '#d9534f' : '#5cb85c', // 红色表示满,绿色表示未满 |
|
|
|
transition: 'background-color 0.3s ease', // 增加平滑过渡效果 |
|
|
|
}) |
|
|
|
|
|
|
|
const closeAlert = () => { |
|
|
|
showWasteAlert.value = false |
|
|
|
if (wasteAlertTimeout) clearTimeout(wasteAlertTimeout) // 确保清除防抖计时器 |
|
|
|
} |
|
|
|
|
|
|
|
let wasteAlertTimeout: ReturnType<typeof setTimeout> | null = null |
|
|
|
|
|
|
|
// 获取当前孵育盘列表数据,并初始化倒计时 |
|
|
|
const fetchIncubationData = async () => { |
|
|
|
try { |
|
|
|
const response = await getRunningList() |
|
|
|
let data: SubTank[] = [] |
|
|
|
|
|
|
|
if (response && response.success) { |
|
|
|
// console.log('获取孵育盘列表成功:', response.data) |
|
|
|
// 处理服务器返回的数据 |
|
|
|
data = response.data.subtanks.map((plate: SubTank) => ({ |
|
|
|
...plate, |
|
|
|
isSelected: plate.sampleId === selectedItemId.value, |
|
|
|
})) |
|
|
|
} |
|
|
|
|
|
|
|
// 添加急诊数据到末位(如果存在急诊数据) |
|
|
|
const filledData = emergencyData.value |
|
|
|
? [...data, emergencyData.value] |
|
|
|
: data |
|
|
|
|
|
|
|
// 填充占位符,确保总数为 20 个 |
|
|
|
while (filledData.length < TOTAL_SLOTS) { |
|
|
|
filledData.push({ |
|
|
|
pos: `PLACEHOLDER-${filledData.length + 1}`, |
|
|
|
state: 'EMPTY', |
|
|
|
bloodType: "WHOLE_BLOOD", |
|
|
|
sampleBarcode: '', |
|
|
|
userid: '', |
|
|
|
projInfo: { |
|
|
|
projId: 0, |
|
|
|
projName: '', |
|
|
|
projShortName: '', |
|
|
|
color: '', |
|
|
|
}, |
|
|
|
startIncubatedTime: 0, |
|
|
|
incubatedTimeSec: 0, |
|
|
|
remainTimeSec: 0, |
|
|
|
sampleId: `PLACEHOLDER-${filledData.length + 1}`, |
|
|
|
projId: 0, |
|
|
|
errors: [], |
|
|
|
isEmergency: false |
|
|
|
// isPlaceholder: true, // 标记为占位符 |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 更新 `incubationPlates` 数据 |
|
|
|
// incubationPlates.value = filledData |
|
|
|
|
|
|
|
// 更新开始时间戳 |
|
|
|
updateStartTimes() |
|
|
|
} catch (error) { |
|
|
|
console.error('获取孵育盘列表失败:', error) |
|
|
|
// 即使失败,也需要填充占位符 |
|
|
|
const filledData = emergencyData.value ? [emergencyData.value] : [] |
|
|
|
while (filledData.length < TOTAL_SLOTS) { |
|
|
|
filledData.push({ |
|
|
|
pos: `PLACEHOLDER-${filledData.length + 1}`, |
|
|
|
state: 'EMPTY', |
|
|
|
bloodType: 'WHOLE_BLOOD', |
|
|
|
sampleBarcode: '', |
|
|
|
userid: '', |
|
|
|
projInfo: { |
|
|
|
projId: 0, |
|
|
|
projName: '', |
|
|
|
projShortName: '', |
|
|
|
color: '', |
|
|
|
}, |
|
|
|
startIncubatedTime: 0, |
|
|
|
incubatedTimeSec: 0, |
|
|
|
remainTimeSec: 0, |
|
|
|
sampleId: `PLACEHOLDER-${filledData.length + 1}`, |
|
|
|
projId: 0, |
|
|
|
errors: [], |
|
|
|
isEmergency: false, |
|
|
|
// isPlaceholder: true, |
|
|
|
}) |
|
|
|
} |
|
|
|
// incubationPlates.value = filledData |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 更新开始时间戳(表示计时起点) |
|
|
|
const startTimes = ref<Record<string, number>>({}) |
|
|
|
const updateStartTimes = () => { |
|
|
|
const currentTime = Date.now() // 获取当前时间戳 |
|
|
|
incubationPlates.value?.forEach((plate) => { |
|
|
|
if (!startTimes.value[plate.pos]) { |
|
|
|
startTimes.value[plate.pos] = currentTime // 记录初始时戳 |
|
|
|
} |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// 计算剩余时间 |
|
|
|
const getRemainingTime = (plate: SubTank) => { |
|
|
|
if(!plate.projId){ |
|
|
|
return; |
|
|
|
} |
|
|
|
const startTime = startTimes.value[plate.pos] || Date.now() |
|
|
|
const elapsed = (Date.now() - startTime) / 1000 // 已经过的秒数 |
|
|
|
const remaining = Math.max(0, plate.incubatedTimeSec - elapsed) // 剩余时间,最小为0 |
|
|
|
|
|
|
|
if (remaining === 0) return '已完成' |
|
|
|
const minutes = Math.floor(remaining / 60) |
|
|
|
const seconds = Math.floor(remaining % 60) |
|
|
|
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}` |
|
|
|
} |
|
|
|
|
|
|
|
const emergencyResult = ref() // 存储急诊结果 |
|
|
|
const isDialogVisible = ref(false) // 控制弹窗的显示 |
|
|
|
let emergencyCompleted = ref(false) // 标志位,确保急诊结果只显示一次 |
|
|
|
|
|
|
|
// 监听急诊位的反应时间并触���弹窗 |
|
|
|
const watchEmergencyCompletion = () => { |
|
|
|
watch( |
|
|
|
() => incubationPlates.value, |
|
|
|
(newPlates) => { |
|
|
|
const emergencyPlate = newPlates.find( |
|
|
|
(plate) => plate.isEmergency, |
|
|
|
) |
|
|
|
if (emergencyPlate && getRemainingTime(emergencyPlate) === '已完成') { |
|
|
|
if (!emergencyCompleted.value) { |
|
|
|
// 如果急诊结果还没显示过,显示弹窗并更新结果 |
|
|
|
emergencyResult.value = { |
|
|
|
date: new Date().toLocaleString(), |
|
|
|
sampleBarcode: emergencyPlate.sampleBarcode, |
|
|
|
projInfo: emergencyPlate.projInfo, |
|
|
|
bloodType: emergencyPlate.bloodType, |
|
|
|
operator: 'admin', // 示例操作人 |
|
|
|
expiryDate: '2025-12-31', // 示例数据 |
|
|
|
serialNumber: 'SN12345678', // 示例数据 |
|
|
|
reference: '参考值', // 示例数据 |
|
|
|
value: '5.24 mg/L', // 示例数据 |
|
|
|
} |
|
|
|
isDialogVisible.value = true |
|
|
|
emergencyCompleted.value = true // 设置为已显示 |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
{ deep: true }, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
watchEmergencyCompletion() |
|
|
|
}) |
|
|
|
|
|
|
|
// 停止监听的逻辑 |
|
|
|
onUnmounted(() => { |
|
|
|
isDialogVisible.value = false |
|
|
|
emergencyResult.value = null |
|
|
|
}) |
|
|
|
|
|
|
|
</script> |
|
|
|