|
|
<template> <div id="configuration-container" v-loading="loading"> <!-- 渲染试管架列表 --> <div class="tube-rack-list"> <div v-for="(tubeRack, index) in testTubeStore.tubeRacks" :key="tubeRack.uuid" class="tube-rack-container" > <TestTubeRackComponent :tubeRack="tubeRack" :index="index" :projects="consumablesStore.projectsAvailable" :bloodTypes="settingTubeStore.bloodTypes" @delete:rack="deleteTubeRack" @active:rack="handleActivateChange" @patient:edit="handleChangeUser" @clickTubeItem="updateTubeSettings" /> </div> <!-- 添加试管架按钮 --> <div class="add-tube" @click="addTubeRack"> <div class="icon"> <img src="@/assets/add.svg" alt="Add Icon" /> </div> <div class="text">添加试管架</div> </div> </div> <div class="setting-panel"> <section class="project-area"> <h2 class="title">项目选择</h2> <div class="project-list"> <div v-for="proj in consumablesStore.projectsAvailable" :key="proj.projName" > <div class="project-item" :class="{ active: isProjElemActive(proj) }" :style="styleOfProjElem(proj)" @click="clickProjectItem(proj)" > <span class="proj-name">{{ proj.projName }}</span> <span class="proj-num">{{ `${projIdCntMap[proj.projId || 1] || 0}/${proj.num}` }}</span> </div> </div> </div> </section> <section class="blood-type-area"> <h2 class="title">血液类型</h2> <div class="blood-list"> <div v-for="type in settingTubeStore.bloodTypes" :key="type.key"> <div class="blood-item" :class="{ active: selectedBloodTypeKey === type.key }" @click="clickBloodTypeItem(type)" > {{ type.name }} </div> </div> </div> </section> </div> <ConfirmModal v-if="confirmVisible" :confirmInfo="confirmInfo"/> </div> </template>
<script setup lang="ts"> import { ref, computed } from 'vue' import * as R from 'ramda' import { useRouter } from 'vue-router' import TestTubeRackComponent from '../components/TestTube/TestTubeRack.vue' import { addTestTube, deleteTube, updateTubeConfig, updateTubeActivationStatus, } from '../../../services/Index/testTube'
import { useConsumablesStore, useTestTubeStore, useSettingTestTubeStore,
} from '../../../store' import { BloodType, ReactionPlateGroup, TestTubeRack } from '@/websocket/socket' import { eMessage } from '../utils' const router = useRouter()
const settingTubeStore = useSettingTestTubeStore() const testTubeStore = useTestTubeStore() const consumablesStore = useConsumablesStore()
const loading = ref(false) // 控制加载状态
const selectedProjIds = ref<number[]>([]) const selectedBloodTypeKey = ref<BloodType | undefined>('WHOLE_BLOOD')
const isProjElemActive = (proj: ReactionPlateGroup) => { return selectedProjIds.value.includes(proj.projId!) }
const styleOfProjElem = (proj: ReactionPlateGroup) => { const active = isProjElemActive(proj) if (active) { return { border: 'solid 1px transparent', backgroundColor: consumablesStore.projIdColorMap[proj.projId!], color: '#FFF', } } else { return { border: `solid 1px ${consumablesStore.projIdColorMap[proj.projId!]}`, backgroundColor: '#FFF', color: consumablesStore.projIdColorMap[proj.projId!], } } }
const clickProjectItem = (proj: ReactionPlateGroup) => { if (selectedProjIds.value.includes(proj.projId!)) { selectedProjIds.value = selectedProjIds.value.filter( (pId) => pId !== proj.projId, ) } else { selectedProjIds.value = [...selectedProjIds.value, proj.projId!].sort() } }
const clickBloodTypeItem = (type) => { if (selectedBloodTypeKey.value === type.key) { selectedBloodTypeKey.value = undefined } else { selectedBloodTypeKey.value = type.key } }
const projIdCntMap = computed(() => { let projMap = R.reduce( (acc, curr) => { const projIdCntRack = R.reduce( (ac, cur) => { cur.projId.forEach((pId) => { ac[pId] = (ac[pId] || 0) + 1 }) return ac }, {}, curr.tubeSettings, ) Object.keys(projIdCntRack).forEach((k) => { acc[k] = (acc[k] || 0) + projIdCntRack[k] }) return acc }, {}, testTubeStore.tubeRacks, ) return projMap; })
//编辑患者信息
const handleChangeUser = async (index: number) => { const rack = testTubeStore.tubeRacks[index] if (rack.state !== 'INACTIVE') { eMessage.error('试管架处理激活状态,不可修改') return } testTubeStore.setTubeRack(rack) router.push({ path: '/index/change-user', }) }
const existValidProject = (tubeRack: TestTubeRack) => { return tubeRack.tubeSettings.some( (s) => (s.projId || []).length > 0 && !!s.bloodType, ) }
let confirmDeleteRackUuid: string | undefined = undefined
const confirmDeleteTube = async () => { const res = await deleteTube(confirmDeleteRackUuid!) if (res.success) { eMessage.success('删除成功') } else { eMessage.error('删除失败') } }
//删除试管架
const confirmVisible = ref(false) const confirmInfo = ref({}) const deleteTubeRack = async (idx: number) => { const rack = testTubeStore.tubeRacks[idx] if (rack.state !== 'INACTIVE') { eMessage.error('试管架处理激活状态,不可删除') return } confirmDeleteRackUuid = rack.uuid if (existValidProject(rack)) { confirmVisible.value = true; confirmInfo.value = { title: '确认删除', message: '存在配置了检测项目的试管,确定删除?', cancelText: '取消', confirmText: '确认', onCancel:()=>{ confirmVisible.value = false }, onConfirm:async()=>{ await confirmDeleteTube() confirmVisible.value = false } } return }
confirmVisible.value = true; confirmInfo.value = { title: '确认删除', message: '请确认是否删除?', cancelText: '取消', confirmText: '确认', onCancel:()=>{ confirmVisible.value = false }, onConfirm:async()=>{ await confirmDeleteTube() confirmVisible.value = false } } } // 添加新试管架
const addTubeRack = async () => { loading.value = true
const response = await addTestTube() if (response && response.success) { // do nothing
} else { eMessage.error('试管架添加失败') } loading.value = false }
const projIdsOfTube = (tube) => { return tube ? (tube.projId || tube.projIds || []) : [] }
// 处理试管架激活状态变化
const handleActivateChange = async (index: number) => { const rack = testTubeStore.tubeRacks[index] console.log('---', rack) if(rack.tubeSettings.every((tube) => projIdsOfTube(tube).length === 0)) { eMessage.error('请为试管配置检测项目') return } if (rack.state === 'LOCKED') { eMessage.error('试管已锁定,不能修改') return } let destState = rack.state === 'INACTIVE' ? 'ACTIVE' : 'INACTIVE' // if (destState === 'ACTIVE' && !existValidProject(rack)) {
// eMessage.error('请为试管配置检测项目')
// return
// }
const res = await updateTubeActivationStatus({ uuid: rack.uuid, active: destState === 'ACTIVE', }) if (res.success) { // do nothing
} else { eMessage.error('更改激活状态失败') } }
const updateTubeSettings = async (rackIdx: number, tubeIdx: number) => { const rack = testTubeStore.tubeRacks[rackIdx] if (!consumablesStore.projectsAvailable.length) { eMessage.error('请先添加项目') return } if (!selectedProjIds.value.length && (!rack.tubeSettings[tubeIdx].projId || !rack.tubeSettings[tubeIdx].projId.length)) { eMessage.error('请选择项目') return } if (!selectedBloodTypeKey.value) { eMessage.error('请选择血液类型') return }
if (rack.state !== 'INACTIVE') { eMessage.error('试管架已激活,不能修改') return } if (tubeIdx < rack.tubeSettings.length) { const setting = rack.tubeSettings[tubeIdx] const updSetting = { ...setting, projId: selectedProjIds.value, bloodType: selectedBloodTypeKey.value, } try { const response = await updateTubeConfig({ uuid: rack.uuid, setting: [updSetting], }) if (response.success) { // do nothing
} else { eMessage.error('设置更新失败') } } catch (error) { console.error('更新试管设置失败:', error) eMessage.error('设置更新失败') } } } </script>
<style scoped lang="less"> #configuration-container { > * { box-sizing: border-box; } @active-color: rgb(82, 140, 254); @setting-panel-height: 13.5625rem;
box-sizing: border-box; position: relative; height: calc(100vh - @setting-panel-height);
.el-message { width: 200px; height: 200px; }
/* 主容器定高和滚动条样式 */ .tube-rack-list { height: calc(100% - @setting-panel-height); /* 根据需要设置主容器的最大高度 */ overflow-y: auto; overflow-x: hidden; width: 100%;
/* 自定义滚动条样式 */ &::-webkit-scrollbar { width: 8px; }
&::-webkit-scrollbar-track { background: #f1f1f1; }
&::-webkit-scrollbar-thumb { background: #888; border-radius: 4px; }
&::-webkit-scrollbar-thumb:hover { background: #555; } }
.setting-panel { @line-color: rgb(200, 200, 200);
position: absolute; bottom: 0; width: 100%; height: @setting-panel-height; padding: 0 40px; border-top: solid 1px @line-color; border-bottom: solid 1px @line-color; .title { font-size: 24px; font-weight: bold; margin-right: 40px; } .project-area { display: flex; align-items: center; .project-list { display: flex; .project-item { border-radius: 8px; padding: 4px 10px; margin-right: 8px; display: flex; flex-direction: column; align-items: center; min-width: 50px; .proj-name { font-weight: 600; font-size: 1.2rem; } } } } .blood-type-area { display: flex; align-items: center; .blood-list { display: flex; .blood-item { border: solid 1px @active-color; border-radius: 4px; padding: 10px; margin-right: 8px; color: @active-color; font-weight: 600; font-size: 1.2rem; &.active { color: #fff; background-color: @active-color; } } } } }
.add-tube { width: 100%; height: 100px; background-color: #f6f6f6; display: flex; align-items: center; justify-content: center;
.icon { img { width: 60px; } margin-right: 10px; display: flex; align-items: center; justify-content: center; }
.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>
|