A8000
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.
 
 
 
 

371 lines
10 KiB

<template>
<div id="configuration-container" v-loading="loading">
<!-- 渲染试管架列表 -->
<div class="tube-rack-list">
<div v-for="(tubeRack, index) in tubeRacks" :key="`${tubeRack.uuid || index}-${componentRefreshKey}`"
class="tube-rack-container">
<TestTubeRack ref="tubeRackComponentInstance" :tubeRack="tubeRack" :plates="plates" :key="refreshKey"
@updateActivate="handleActivateChange" @updateSelectedSamples="handleUpdateSelectedSamples"
@deleteTubeRack="deleteHandle" @changeUser="handleChangeUser"
@clearProjectSelection="clearProjectSelection" />
</div>
</div>
<!-- 添加试管架按钮 -->
<div class="add-tube" @click="addTubeRack">
<div class="icon">
<img src="@/assets/add.svg" alt="Add Icon" />
</div>
<div class="text">添加试管架</div>
</div>
<!-- 试管信息编辑 -->
<ProjectSelector :uuid="UUID" v-model:visible="showProjectSelector" :selectedSampleIds="selectedSampleIdsInParent"
@updateSample="handleSampleUpdate" @confirm="handleConfirmProjectSelector" @cancel="closeProjectSelector"
@clearSelection="clearProjectSelection" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import { useRouter } from 'vue-router'
import TestTubeRack from '../components/TestTube/TestTubeRack.vue'
import {
addTestTube,
getTestTube,
getProjectInfo,
deleteTube,
updateTubeConfig,
} from '../../../services/Index/Test-tube/test-tube'
import type {
DataItem,
TubeSetting,
} from '../../../types/Index/index'
import { ConsumableGroupBase } from '../../../websocket/socket'
import ProjectSelector from '../components/Consumables/ProjectSelector.vue'
import { useConsumablesStore, useTestTubeStore, useSettingTestTubeStore } from '../../../store'
import { ElMessage } from 'element-plus'
const router = useRouter()
const testTubeStore = useTestTubeStore()
const settingTestTubeStore = useSettingTestTubeStore()
const consumables = useConsumablesStore()
const tubeRacks = ref<DataItem[]>([])
const loading = ref(false) // 控制加载状态
const plates = ref<ConsumableGroupBase[]>(consumables.plates)
const refreshKey = ref(0)
const selectedUUID = ref<string>('')
// 初始化获取试管架数据
onMounted(() => {
getTubeData()
getProjectInfoData()
})
//获取设备支持的项目信息
const getProjectInfoData = async () => {
const res = await getProjectInfo()
if (res.success) {
console.log(res.data)
}
}
//获取已经配置的试管信息
const getTubeData = async () => {
loading.value = true
const res = await getTestTube()
if (res.success) {
// 初始化每个试管架的选中状态
tubeRacks.value = res.data.map((rack: DataItem) => ({
...rack,
selectedSampleIds: [], // 初始化选中状态数组
}))
}
loading.value = false
}
const selectedProject = ref<string | null>(null)
// 添加事件监听,用于清空项目选择状态
const clearProjectSelection = () => {
selectedProject.value = null // 清空选中的项目状态
}
//编辑患者信息
const handleChangeUser = async (uuid: string) => {
selectedUUID.value = uuid
const selectedTube = tubeRacks.value.find((t) => t.uuid === selectedUUID.value)
if (!selectedTube) return
testTubeStore.setTubeInfo(selectedTube)
await updateTubeSettingsHandler()
router.push({
path: '/index/change-user',
})
}
//删除试管架
const deleteHandle = async (uuid: string) => {
const res = await deleteTube(uuid)
if (res.success) {
ElMessage({
message: '删除成功',
type: 'success',
})
getTubeData()
} else {
ElMessage({
message: '删除失败',
type: 'error',
})
}
}
// 添加新试管架
const addTubeRack = async () => {
loading.value = true // 开始加载
const newTubeRack: DataItem = {
uuid: `uuid-${Date.now()}`,
active: false,
lock: false,
tubeSettings: Array.from({ length: 10 }, (_, index) => ({
tubeIndex: index,
userid: '',
sampleBarcode: '',
projId: [],
bloodType: 'WHOLE_BLOOD',
})),
selectedSampleIds: [],
}
// 直接将新试管架添加到 tubeRacks 中
tubeRacks.value.push(newTubeRack)
// 向服务端发送添加请求
const response = await addTestTube()
if (response && response.success) {
// 更新 tubeRacks 列表为最新数据,避免闪烁
tubeRacks.value = [...tubeRacks.value]
} else {
console.error('试管架添加失败')
}
loading.value = false // 加载结束
}
// 处理试管架激活状态变化
const handleActivateChange = (update: { uuid: string; active: boolean }) => {
const rack = tubeRacks.value.find((t) => t.uuid === update.uuid)
if (rack) {
rack.active = update.active
}
}
const handleSampleUpdate = async ({
projectIds,
bloodType,
}: {
projectIds: number[]
bloodType: string
}): Promise<void> => {
if (selectedSampleIdsInParent.value.length > 0) {
// 创建 tubeRacks 的深拷贝
const updatedTubeRacks = JSON.parse(JSON.stringify(tubeRacks.value))
// 找到对应的 tubeRack
const targetTubeRack = updatedTubeRacks.find(
(t: DataItem) => t.uuid === UUID.value,
)
if (targetTubeRack) {
targetTubeRack.tubeSettings = targetTubeRack.tubeSettings.map(
(tube: TubeSetting) => {
if (selectedSampleIdsInParent.value.includes(tube.tubeIndex)) {
return {
...tube,
projId: [...projectIds],
bloodType: bloodType,
}
}
return tube
},
)
// 清空数组再重新赋值,确保响应式更新
tubeRacks.value = []
await nextTick()
tubeRacks.value = updatedTubeRacks// 新赋值触发响应式
console.log("🚀 ~ handleSampleUpdate ~ updatedTubeRacks:", updatedTubeRacks)
const selectedTube = updatedTubeRacks.find((t: any) => t.uuid === UUID.value)
console.log("🚀 ~ handleSampleUpdate ~ selectedTube:", selectedTube)
testTubeStore.setTubeInfo(selectedTube)
console.log("🚀 ~ handleSampleUpdate ~ testTubeStore.$state.tubeInfo:", testTubeStore.$state.tubeInfo)
selectedProject.value = null // 选择后清空选中状态
await nextTick()
ElMessage({
message: '样本信息已更新',
type: 'success',
duration: 2000,
})
}
} else {
ElMessage({
message: '请先选择样本后再选择项目',
type: 'warning',
duration: 2000,
})
}
}
//声明组件实例
const UUID = ref<string>('')
// 当前选中的样本ID列表
const selectedSampleIdsInParent = ref<number[]>([])
// 添加一个刷新key
const componentRefreshKey = ref(0)
// 修改 handleConfirmProjectSelector 函数
const handleConfirmProjectSelector = async () => {
await updateTubeSettingsHandler()
// 清空父组件选中样本列表
selectedSampleIdsInParent.value = []
// 找到当前操作的试管架并清空其选中状态
const currentTubeRack = tubeRacks.value.find(rack => rack.uuid === UUID.value)
if (currentTubeRack) {
currentTubeRack.selectedSampleIds = []
}
// 重置其他相关状态
showProjectSelector.value = false
UUID.value = ''
ElMessage({
message: '样本已确认,选中状态已清空',
type: 'success',
duration: 2000,
})
}
const tubeRackComponentInstance = ref()
const showProjectSelector = ref(false)
// 修改关闭项目选择器的方法
const closeProjectSelector = () => {
// 找到当前操作的试管架并清空其选中状态
const currentTubeRack = tubeRacks.value.find(rack => rack.uuid === UUID.value)
if (currentTubeRack) {
currentTubeRack.selectedSampleIds = []
}
// 重置所有相关状态
selectedSampleIdsInParent.value = []
showProjectSelector.value = false
UUID.value = ''
}
// 父组件代码
const handleUpdateSelectedSamples = ({ sampleIds, uuid }: { sampleIds: number[]; uuid: string }) => {
// 更新特定试管架的选中状态
const tubeRack = tubeRacks.value.find(tube => tube.uuid === uuid)
if (tubeRack) {
// 如果是取消选中(sampleIds为空),则关闭弹窗并清空状态
if (sampleIds.length === 0) {
showProjectSelector.value = false
selectedSampleIdsInParent.value = []
tubeRack.selectedSampleIds = []
UUID.value = ''
} else {
// 如果是新选中,则更新状态并打开弹窗
tubeRack.selectedSampleIds = sampleIds
selectedSampleIdsInParent.value = sampleIds
UUID.value = uuid
showProjectSelector.value = true
}
}
}
// 添加更新试管设置的方法
const updateTubeSettingsHandler = async () => {
const { uuid, setting } = settingTestTubeStore.currentConfig
if (uuid && setting.tubeIndex >= 0) {
try {
const response = await updateTubeConfig({ uuid, setting })
if (response.success) {
ElMessage.success('设置更新成功')
console.log(tubeRacks.value)
settingTestTubeStore.clearConfig()
} else {
ElMessage.error('设置更新失败')
}
} catch (error) {
console.error('更新试管设置失败:', error)
ElMessage.error('设置更新失败')
}
}
}
</script>
<style scoped lang="less">
#configuration-container {
position: relative;
.el-message {
width: 200px;
height: 200px;
}
/* 主容器定高和滚动条样式 */
.tube-rack-list {
max-height: 1200px;
/* 根据需要设置主容器的最大高度 */
overflow-y: auto;
overflow-x: hidden;
width: 100%;
box-sizing: border-box;
/* 自定义滚动条样式 */
&::-webkit-scrollbar {
width: 8px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
}
&::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
&::-webkit-scrollbar-thumb:hover {
background: #555;
}
}
.add-tube {
width: 100%;
height: 100px;
background-color: #f6f6f6;
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 60px;
height: 100px;
margin-right: 40px;
}
.text {
font-size: 32px;
color: #73bc54;
font-weight: bold;
}
}
/* 加载状态样式 */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(255, 255, 255, 0.8);
font-size: 24px;
color: #333;
z-index: 1000;
}
}
</style>