Browse Source

移除废弃文件

relver
zhangjiming 7 months ago
parent
commit
3900ac8fc1
  1. 2
      src/pages/Index/Regular/Running.vue
  2. 2
      src/pages/Index/Regular/TestTube.vue
  3. 245
      src/pages/Index/components/Consumables/ChangeNum.vue
  4. 1
      src/pages/Index/components/Consumables/index.ts
  5. 187
      src/pages/Index/components/Running/SampleDisplay.vue
  6. 2
      src/pages/Index/components/Running/index.ts
  7. 7
      src/pages/Index/components/TestTube/Tube.vue
  8. 35
      src/pages/Index/utils/generateSampleBackground.ts
  9. 15
      src/pages/Index/utils/getBloodTypeLabel.ts
  10. 3
      src/pages/Index/utils/index.ts
  11. 45
      src/pages/Index/utils/processTubeSettings.ts
  12. 8
      src/types/Index/TestTube.ts
  13. 2
      src/websocket/socket.ts

2
src/pages/Index/Regular/Running.vue

@ -93,8 +93,6 @@
<tube-item :tube="canSetEmergency ? undefined : emergencyStore.emergencyInfo" :showNum="false" />
</div>
<div class="tube-items">
<!-- <SampleDisplay :samples="tubeHolderState.tubes" :selectedSamples="selectedSamples"
@updateSelectedSamples="updateSelectedSamples" /> -->
<div class="tube-container">
<tube-item
v-for="(tube, index) in runningStore.tubeHolderState?.tubes ||

2
src/pages/Index/Regular/TestTube.vue

@ -290,7 +290,7 @@ const updateTubeSettings = async (rackIdx: number, tubeIdx: number) => {
}
if (tubeIdx < rack.tubeSettings.length) {
const setting = rack.tubeSettings[tubeIdx]
const updSetting:any = {
const updSetting = {
...setting,
projId: selectedProjIds.value,
bloodType: selectedBloodTypeKey.value,

245
src/pages/Index/components/Consumables/ChangeNum.vue

@ -1,245 +0,0 @@
<template>
<div>
<!-- 使用 teleport 渲染到 body -->
<teleport to="body">
<div v-if="isOpen" class="modal-overlay">
<div class="modal">
<div class="modal-header">
<span class="modal-title">{{ dialogTitle }}</span>
<button class="close-btn" @click="handleCancel">X</button>
</div>
<!-- 主体内容 -->
<div class="modal-body">
<div class="input-box">
<input id="slider" type="range" v-model="value" @change="handleSliderChange" min="0" max="25" step="1"
class="slider" />
<div class="change-num">
<button class="minus" @click="handleMinus">-</button>
<input type="text" v-model="value" class="input" />
<button class="plus" @click="handlePlus">+</button>
</div>
</div>
</div>
<!-- 底部按钮 -->
<div class="modal-footer">
<button class="footer-btn" @click="handleCancel">取消</button>
<button class="footer-btn primary" @click="handleConfirm">
确认
</button>
</div>
</div>
</div>
</teleport>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { updateConsumables } from '../../../../services'
import { eventBus } from '../../../../eventBus'
const isOpen = ref(false)
const value = ref(0)
const title = ref('')
const dialogTitle = ref(`请选择${title.value || ''}数值`)
const plateIndex = ref(0)
// 使 query value
const query = ref({
group: '',
num: 0
})
// value query
watch(value, (newVal) => {
query.value = {
group: `CG${ plateIndex.value + 1 }`,
num: Number(newVal)
}
})
const handleSliderChange = (e) => {
value.value = Number(e.target.value)
}
//
const openDialog = (plate, index) => {
isOpen.value = true
value.value = Number(plate.num)
plateIndex.value = index
title.value = plate.projShortName || ''
dialogTitle.value = `请选择${ title.value } 数值`
// query
query.value = {
group: `CG${index+1}`,
num: Number(plate.num)
}
}
defineExpose({
openDialog,
})
const handleCancel = () => {
isOpen.value = false
}
const handlePlus = () => {
if (value.value < 25) {
value.value = Number(value.value) + 1
}
}
const handleMinus = () => {
if (value.value > 0) {
value.value = Number(value.value) - 1
}
}
//
const handleConfirm = async () => {
try {
const res = await updateConsumables(query.value)
if (res.success) {
eventBus.emit('confirm', {
type: 'Plate',
value: Number(value.value),
index: plateIndex.value,
})
isOpen.value = false
}
} catch (error) {
console.error('更新失败:', error)
}
}
</script>
<style scoped lang="less">
/* 背景遮罩 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
/* 对话框容器 */
.modal {
background-color: white;
border-radius: 8px;
width: 700px;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
font-size: 32px;
display: flex;
flex-direction: column;
align-items: flex-start;
}
/* 对话框标题 */
.modal-header {
display: flex;
justify-content: space-between;
width: 100%;
font-size: 32px;
font-weight: bold;
margin-bottom: 10px;
}
/* 关闭按钮 */
.close-btn {
background: none;
border: none;
font-size: 20px;
cursor: pointer;
}
/* 对话框主体内容 */
.modal-body {
width: 100%;
margin-bottom: 20px;
.input-box {
display: flex;
align-items: center;
/* Slider 样式 */
.slider {
width: 70%;
margin: 10px 0;
}
.change-num {
width: 30%;
border: 1px solid #ccc;
display: flex;
justify-content: space-around;
margin-left: 20px;
button {
width: 52px;
height: 46px;
background-color: #f5f7fa;
font-size: 26px;
}
.minus {
border-right: 1px solid #ccc;
}
.plus {
border-left: 1px solid #ccc;
}
.input {
width: 100px;
outline-color: #66b1ff;
border: none;
font-size: 32px;
text-align: center;
}
}
}
}
/* 底部按钮 */
.modal-footer {
display: flex;
justify-content: flex-end;
width: 100%;
.footer-btn {
width: 100px;
height: 60px;
margin-left: 10px;
font-size: 26px;
cursor: pointer;
border: none;
border-radius: 5px;
}
.primary {
background-color: #409eff;
color: white;
}
.primary:hover {
background-color: #66b1ff;
}
.footer-btn:hover {
background-color: #f1f1f1;
}
}
</style>

1
src/pages/Index/components/Consumables/index.ts

@ -1,5 +1,4 @@
//导出所有组件
export { default as ChangeNum } from './ChangeNum.vue'
export { default as IdCardInfo } from './IdCardInfo.vue'
export { default as InfoBar } from './InfoBar.vue'
export { default as MainComponent } from './MainComponent.vue'

187
src/pages/Index/components/Running/SampleDisplay.vue

@ -1,187 +0,0 @@
<template>
<div class="samples">
<el-popover v-for="(sample, index) in samples" :key="index" trigger="click" placement="bottom-start"
:ref="'popover-' + index" popper-class="custom-popover" :popper-style="getPopoverStyle()">
<template #reference>
<div class="sample-item" :style="[
generateSampleBackground(sample.projInfo),
getActiveStyle(sample.pos),
]" @click="toggleSampleSelection(sample.pos)" @dblclick="showPopover(index)">
<div class="sample-number">{{ index + 1 }}</div>
<div class="sample-blood-type">
{{ getBloodTypeLabel(sample.bloodType) || '未知类型' }}
</div>
</div>
</template>
<template #default>
<div class="item-detail">
<div v-if="sample.projInfo && sample.projInfo.length > 0">
<div v-for="(project, projIndex) in sample.projInfo" :key="projIndex">
<button :style="{
backgroundColor: project.color || '#ccc',
color: 'white',
border: 'none',
padding: '10px 20px',
borderRadius: '5px',
margin: '2px',
cursor: 'pointer',
}">
{{ project.projName || '未知项目' }}
</button>
</div>
</div>
<div v-else>
<span>没有项目信息</span>
</div>
</div>
</template>
</el-popover>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { generateSampleBackground, getBloodTypeLabel } from '../../utils'
import type { TubeHolderStateMessage } from '../../../../websocket/socket'
defineProps<{
samples: TubeHolderStateMessage['data']['tubes'] //
selectedSamples: number[] //
}>()
const emits = defineEmits<{
(e: 'updateSelectedSamples', sampleIds: number[]): void
}>()
// ID
const selectedSampleIds = ref<number[]>([])
//
const selectedStyle = {
outline: '3px solid #4A90E2', //
boxShadow: '0 0 10px rgba(74, 144, 226, 0.6)',
}
//
const toggleSampleSelection = (sampleId: number) => {
const index = selectedSampleIds.value.indexOf(sampleId)
if (index === -1) {
selectedSampleIds.value.push(sampleId) //
} else {
selectedSampleIds.value.splice(index, 1) //
}
emits('updateSelectedSamples', selectedSampleIds.value)
}
//
const getActiveStyle = (tubeIndex: number) => {
return selectedSampleIds.value.includes(tubeIndex) ? selectedStyle : {}
}
//
// const formatState = (state: TubeState): string => {
// const stateMap: Record<TubeState, string> = {
// EMPTY: '',
// TO_BE_PROCESSED: '',
// PENDING: '',
// RESOURCE_IS_READY: '',
// PRE_PROCESSING: '',
// PRE_PROCESSED: '',
// PROCESSING: '',
// PROCESSED: '',
// POST_PROCESSING: '',
// POST_PROCESSED: '',
// PROCESS_COMPLETE: '',
// ERROR: '',
// }
// return stateMap[state] || ''
// }
//
const getPopoverStyle = () => ({
width: '150px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
alignItems: 'center',
})
//
const showPopover = (index: number) => {
const popover = 'popover-' + index
const popoverElement = document.querySelector(
`[aria-describedby="${popover}"]`,
)
if (popoverElement instanceof HTMLElement) {
popoverElement.click()
}
}
</script>
<style scoped lang="less">
.samples {
display: flex;
align-items: center;
flex-wrap: nowrap;
background-color: #fafafa;
padding: 10px;
&::-webkit-scrollbar {
height: 6px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
&:hover {
background: #a8a8a8;
}
}
.item-detail {
width: 100%;
height: auto;
display: flex;
flex-direction: column;
gap: 5px;
margin: 10px 0;
}
.sample-item {
width: 70px;
height: 70px;
border-radius: 50%;
border: 2px solid black;
display: flex;
align-items: center;
justify-content: center;
position: relative;
margin: 1.5px;
flex-direction: column;
.sample-number {
position: absolute;
top: -28px;
font-size: 14px;
font-weight: bold;
color: #333;
}
.sample-blood-type {
color: black;
font-size: 26px;
font-weight: bold;
}
.sample-state {
font-size: 16px;
color: gray;
}
}
}
</style>

2
src/pages/Index/components/Running/index.ts

@ -1,4 +1,4 @@
export { default as SampleDisplay } from './SampleDisplay.vue'
export { default as PlateDisplay } from './PlateDisplay.vue'
export { default as LittleBufferDisplay } from './LittleBufferDisplay.vue'
export { default as EmergencyResultDialog } from './EmergencyResultDialog.vue'

7
src/pages/Index/components/TestTube/Tube.vue

@ -43,7 +43,7 @@
<script setup>
import { ref, watch, useTemplateRef, nextTick, computed } from 'vue'
import * as R from 'ramda'
import { useSettingTestTubeStore } from '@/store'
import { useConsumablesStore, useSettingTestTubeStore } from '@/store'
/*
tube: {userid,projId:number[],bloodType}
@ -57,6 +57,7 @@ const props = defineProps({
})
const emit = defineEmits(['clickTubeItem'])
const settingTubeStore = useSettingTestTubeStore()
const consumablesStore = useConsumablesStore()
const projIdsOfTube = (tube) => {
return tube ? (tube.projId || tube.projIds || []) : []
@ -73,9 +74,7 @@ watch(
if (canvas.value) {
const data = projIds.map((p) => ({
value: 1,
color: settingTubeStore.projectIdMap[p]
? settingTubeStore.projectIdMap[p].color
: '#FFF',
color: consumablesStore.projIdColorMap[p] || '#FFF',
}))
const ctx = canvas.value.getContext('2d')
drawPieChart(ctx, data)

35
src/pages/Index/utils/generateSampleBackground.ts

@ -1,35 +0,0 @@
import type { ReactionPlate, ProjectInfo } from '../../../types/Index'
/**
* ReactionPlate ProjectInfo
* @param projects - ReactionPlate[] ProjectInfo[]
* @param defaultColor -
* @returns
*/
export const generateSampleBackground = (
projects: ReactionPlate[] | ProjectInfo[],
defaultColor = '#e9e9e9',
): { backgroundColor?: string; background?: string } => {
// 提取颜色信息,兼容两种数据结构
const colors = projects.map((item) => item.color)
if (!colors.length) return { backgroundColor: defaultColor }
if (colors.length === 1) {
// 只有一种颜色时,直接设置背景颜色
return { backgroundColor: colors[0] }
} else {
// 多种颜色时,生成等分颜色显示
const colorStops = colors
.map((color, index) => {
const start = (index / colors.length) * 100
const end = ((index + 1) / colors.length) * 100
return `${color} ${start}% ${end}%`
})
.join(', ')
return {
background: `conic-gradient(${colorStops})`,
}
}
}

15
src/pages/Index/utils/getBloodTypeLabel.ts

@ -1,15 +0,0 @@
/**
*
* @param bloodType -
* @param bloodTypeMap -
* @returns
*/
export const getBloodTypeLabel = (
bloodType: string,
bloodTypeMap: { [key: string]: string } = {
WHOLE_BLOOD: '全血',
SERUM_OR_PLASMA: '血清/血浆',
},
): string => {
return bloodTypeMap[bloodType] || '空'
}

3
src/pages/Index/utils/index.ts

@ -1,6 +1,3 @@
export * from './getBloodTypeLabel'
export * from './processTubeSettings'
export * from './generateSampleBackground'
export function formatRemainTime(seconds: number) {
const min = Math.floor(seconds / 60).toFixed()

45
src/pages/Index/utils/processTubeSettings.ts

@ -1,45 +0,0 @@
import { TubeRack, TubeSetting } from '../../../types/Index'
import { ConsumableGroupBase } from '../../../websocket/socket'
/**
* `projId` `ReactionPlate`
* @param tubeSettings - tubeSettings
* @param plates - ReactionPlate projId
* @param getBloodTypeLabel - bloodType
* @returns
*/
export function processTubeSettings(
tubeSettings: TubeSetting[],
plates: ConsumableGroupBase[],
getBloodTypeLabel: (bloodType: string) => string,
): TubeRack[] {
//@ts-ignore
return tubeSettings.map((setting) => {
const newProjId = setting.projId.map((id) => {
// 如果 id 是对象,直接返回;否则查找匹配的 ReactionPlate
if (typeof id === 'object') {
return id
}
const project = plates.find((plate) => plate.projId === id)
return (
project || {
projId: id,
projName: '',
projShortName: '',
lotId: '',
color: '#e9e9e9',
enable: false,
num: 0,
}
)
})
return {
...setting,
projId: newProjId,
bloodType: getBloodTypeLabel(setting.bloodType),
}
})
}

8
src/types/Index/TestTube.ts

@ -36,11 +36,3 @@ export interface UpdateTubeSettingsResponse {
message?: string
data?: any
}
export interface TubeSetting {
tubeIndex: number
userid: string
sampleBarcode: string
projId: number[]
bloodType: 'WHOLE_BLOOD' | 'SERUM_OR_PLASMA'
}

2
src/websocket/socket.ts

@ -91,7 +91,7 @@ export type EmergencyTubeState =
| 'PROCESSING'
| 'PROCESS_COMPLETE'
| 'ERROR'
| ''
| '' //todo del
// 急诊位状态消息
interface EmergencyPosStateMessage extends BaseMessage {
type: 'EmergencyPosState'

Loading…
Cancel
Save