forked from gzt/A8000
10 changed files with 234 additions and 722 deletions
-
2package.json
-
262src/pages/Index/Regular/TestTube.vue
-
1src/pages/Index/components/Consumables/BallGrid.vue
-
165src/pages/Index/components/TestTube/ProjectSetting.vue
-
466src/pages/Index/components/TestTube/TestTubeRack.vue
-
33src/pages/Index/components/TestTube/Tube.vue
-
2src/pages/Index/components/TestTube/index.ts
-
1src/pages/Index/components/index.ts
-
22src/services/Index/Test-tube/test-tube.ts
-
2src/types/Index/TestTube.ts
@ -1,165 +0,0 @@ |
|||||
<template> |
|
||||
<teleport to="body"> |
|
||||
<div v-if="visible" class="overlay" @click="close"> |
|
||||
<div class="dialog" @click.stop> |
|
||||
<div class="dialog-header"> |
|
||||
<h3>请选择修改的试管类型</h3> |
|
||||
</div> |
|
||||
|
|
||||
<!-- 标签选择 --> |
|
||||
<div class="tab-container"> |
|
||||
<div v-for="(option, index) in options" :key="index" class="tab" |
|
||||
:class="{ active: selectedOption === option }" @click="selectOption(option)"> |
|
||||
{{ option }} |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- 按钮区域 --> |
|
||||
<div class="button-container"> |
|
||||
<button class="cancel-button" @click="cancel">取消</button> |
|
||||
<button class="confirm-button" @click="confirm">确认</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
</teleport> |
|
||||
</template> |
|
||||
|
|
||||
<script lang="ts" setup> |
|
||||
import { ref, watch } from 'vue' |
|
||||
import { useTestTubeStore } from '../../../../store' |
|
||||
const testTubeStore = useTestTubeStore() |
|
||||
const props = defineProps({ |
|
||||
visible: Boolean, |
|
||||
selectedProject: String, // 新增选中的项目 |
|
||||
}) |
|
||||
watch( |
|
||||
() => props.selectedProject, |
|
||||
(newValue) => { |
|
||||
if (newValue === null) { |
|
||||
selectedOption.value = options.value[0] // 重置为初始选项 |
|
||||
} |
|
||||
}, |
|
||||
) |
|
||||
const emit = defineEmits(['update:visible', 'confirm', 'clearSelection']) |
|
||||
|
|
||||
const options = ref(['自动', 'BT', 'Epp.0.5', 'Epp.1.5', 'mini', 'Ctip']) |
|
||||
const selectedOption = ref(options.value[0]) |
|
||||
|
|
||||
const selectOption = (option: string) => { |
|
||||
selectedOption.value = option |
|
||||
//更新到pinia中 |
|
||||
testTubeStore.setTypeInfo(option) |
|
||||
} |
|
||||
|
|
||||
const close = () => { |
|
||||
emit('update:visible', false) |
|
||||
} |
|
||||
|
|
||||
const cancel = () => { |
|
||||
close() |
|
||||
} |
|
||||
|
|
||||
const confirm = () => { |
|
||||
emit('confirm', selectedOption.value) |
|
||||
emit('clearSelection') |
|
||||
close() |
|
||||
} |
|
||||
</script> |
|
||||
|
|
||||
<style lang="less" scoped> |
|
||||
.overlay { |
|
||||
position: fixed; |
|
||||
top: 0; |
|
||||
left: 0; |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
background: rgba(0, 0, 0, 0.5); |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: center; |
|
||||
z-index: 1000; |
|
||||
} |
|
||||
|
|
||||
.dialog { |
|
||||
background-color: #fff; |
|
||||
width: 800px; |
|
||||
height: 400px; |
|
||||
padding: 40px; |
|
||||
border-radius: 10px; |
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: space-around; |
|
||||
|
|
||||
.dialog-header { |
|
||||
h3 { |
|
||||
margin: 0; |
|
||||
font-size: 32px; |
|
||||
font-weight: 600; |
|
||||
text-align: center; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.tab-container { |
|
||||
display: flex; |
|
||||
justify-content: space-around; |
|
||||
margin-top: 20px; |
|
||||
|
|
||||
.tab { |
|
||||
width: 200px; |
|
||||
height: 100px; |
|
||||
line-height: 100px; |
|
||||
text-align: center; |
|
||||
background-color: #f5f5f5; |
|
||||
border-radius: 20px; |
|
||||
cursor: pointer; |
|
||||
font-size: 32px; |
|
||||
color: #478ffe; |
|
||||
transition: background 0.3s; |
|
||||
margin: 10px; |
|
||||
|
|
||||
&.active { |
|
||||
background-color: #478ffe; |
|
||||
color: #fff; |
|
||||
} |
|
||||
|
|
||||
&:nth-child(1) { |
|
||||
background-color: #fff; |
|
||||
color: #478ffe; |
|
||||
border: 2px solid #478ffe; |
|
||||
|
|
||||
&.active { |
|
||||
background-color: #478ffe; |
|
||||
color: #fff; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.button-container { |
|
||||
display: flex; |
|
||||
justify-content: space-around; |
|
||||
margin-top: 30px; |
|
||||
|
|
||||
.cancel-button, |
|
||||
.confirm-button { |
|
||||
width: 380px; |
|
||||
height: 100px; |
|
||||
border-radius: 20px; |
|
||||
font-size: 45px; |
|
||||
cursor: pointer; |
|
||||
border: none; |
|
||||
|
|
||||
&.cancel-button { |
|
||||
background-color: #ebebeb; |
|
||||
color: #333; |
|
||||
} |
|
||||
|
|
||||
&.confirm-button { |
|
||||
background-color: #478ffe; |
|
||||
color: #fff; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
@ -1,442 +1,68 @@ |
|||||
<template> |
<template> |
||||
<div id="tube-container"> |
|
||||
<div class="tube-box"> |
|
||||
<div class="tube-rack"> |
|
||||
<!-- 状态面板 --> |
|
||||
<div class="status-panel" @click="toggleSetting"> |
|
||||
<div class="title">{{ projectSetting }}</div> |
|
||||
<div class="status-icon"> |
|
||||
<img src="@/assets/Vector.svg" alt="Status Icon" v-if="!isActivated" /> |
|
||||
<img src="@/assets/Active-Vector.svg" alt="Status Icon" v-else /> |
|
||||
</div> |
|
||||
<div class="status-text"> |
|
||||
<span class="subtitle">{{ handleTip() }}</span> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- 样本展示区域 --> |
|
||||
<div class="samples"> |
|
||||
<el-popover v-for="(sample, index) in processedTubeSettings" :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.projId!.filter(proj => proj !== null) as ReactionPlate[]), |
|
||||
getActiveStyle(sample.tubeIndex), |
|
||||
]" @click="toggleSampleSelection(sample.tubeIndex)" @dblclick="showPopover(index)"> |
|
||||
<div class="sample-number">{{ index + 1 }}</div> |
|
||||
<div class="sample-blood-type">{{ sample.bloodType }}</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
<template #default> |
|
||||
<div class="item-detail"> |
|
||||
<div v-for="(project, index) in sample.projId" :key="index"> |
|
||||
<button :style="{ |
|
||||
backgroundColor: project.color, |
|
||||
color: 'white', |
|
||||
border: 'none', |
|
||||
padding: '10px 20px', |
|
||||
borderRadius: '5px', |
|
||||
margin: '2px', |
|
||||
cursor: 'pointer', |
|
||||
}"> |
|
||||
{{ project.projName }} |
|
||||
</button> |
|
||||
</div> |
|
||||
</div> |
|
||||
</template> |
|
||||
</el-popover> |
|
||||
</div> |
|
||||
</div> |
|
||||
<!-- 功能按钮区域 --> |
|
||||
<div class="function-buttons" v-if="isSetting"> |
|
||||
<div class="active-button" @click="toggleActivate"> |
|
||||
<div class="icon"> |
|
||||
<img src="@/assets/outer-ring.svg" alt="" class="outer-ring" /> |
|
||||
<img src="@/assets/inner-ring.svg" alt="" class="inner-ring" /> |
|
||||
</div> |
|
||||
<div class="text"> |
|
||||
{{ isActivated ? '取消激活' : '激活试管架' }} |
|
||||
</div> |
|
||||
</div> |
|
||||
<!-- 其他功能按钮可继续扩展 --> |
|
||||
<div class="update-button" @click="showSelector = true"> |
|
||||
<div class="icon"> |
|
||||
<img src="@/assets/update-tube-icon.svg" alt="" /> |
|
||||
</div> |
|
||||
<div class="text">修改试管类型</div> |
|
||||
</div> |
|
||||
<div class="change-user-button" @click="turnChangeUser(tubeRack.uuid)"> |
|
||||
<div class="icon"> |
|
||||
<img src="@/assets/update-icon.svg" alt="" /> |
|
||||
</div> |
|
||||
<div class="text">编辑患者信息</div> |
|
||||
</div> |
|
||||
<div class="del-button" @click="deleteTube(tubeRack.uuid)"> |
|
||||
<div class="icon"> |
|
||||
<img src="@/assets/del-icon.svg" alt="" /> |
|
||||
</div> |
|
||||
<div class="text">删除试管架</div> |
|
||||
</div> |
|
||||
|
<div class="test-tube-rack"> |
||||
|
<!--状态--> |
||||
|
<div class="tube-rack-state"> |
||||
|
<div class="status-icon"> |
||||
|
<img src="@/assets/Vector.svg" alt="Status Icon" v-if="tubeRack.state==='INACTIVE'" /> |
||||
|
<img src="@/assets/Active-Vector.svg" alt="Status Icon" v-else /> |
||||
</div> |
</div> |
||||
</div> |
</div> |
||||
<ProjectSetting v-model:visible="showSelector" @confirm="handleConfirm" /> |
|
||||
|
<i class="split"></i> |
||||
|
<!--试管区--> |
||||
|
<section class="tube-list"> |
||||
|
<div v-for="(tube, idx) in tubeRack.tubeSettings"> |
||||
|
<Tube :tube="tube" :index="idx" /> |
||||
|
</div> |
||||
|
</section> |
||||
|
</div> |
||||
|
<div class="test-tube-rack-op"> |
||||
|
<div>修改试管架</div> |
||||
|
<div>编辑患者信息</div> |
||||
|
<div>删除试管架</div> |
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref, onMounted } from 'vue' |
|
||||
import ProjectSetting from './ProjectSetting.vue' |
|
||||
import { ReactionPlate, TubeRack, handleTube, DataItem } from '../../../../types/Index' |
|
||||
import { |
|
||||
getBloodTypeLabel, |
|
||||
processTubeSettings, |
|
||||
generateSampleBackground, |
|
||||
} from '../../Utils' |
|
||||
import { useTestTubeStore } from '../../../../store' |
|
||||
import { updateTubeActivationStatus } from '../../../../services/index' |
|
||||
import { ConsumableGroupBase } from '../../../../websocket/socket' |
|
||||
const testTubeStore = useTestTubeStore() |
|
||||
// 接收父组件传入的单个试管架数据 |
|
||||
const props = defineProps<{ |
|
||||
tubeRack: DataItem |
|
||||
plates: ConsumableGroupBase[] |
|
||||
}>() |
|
||||
onMounted(() => { |
|
||||
processedTubeSettings.value = processTubeSettings( |
|
||||
props.tubeRack.tubeSettings, |
|
||||
props.plates as ConsumableGroupBase[], |
|
||||
getBloodTypeLabel, |
|
||||
) |
|
||||
projectSetting.value = testTubeStore.getProjectSetting(props.tubeRack.uuid) |
|
||||
isActivated.value = props.tubeRack.active // 同步激活状态 |
|
||||
}) |
|
||||
//编辑患者信息 |
|
||||
const turnChangeUser = (uuid: string) => { |
|
||||
emits('changeUser', uuid) |
|
||||
} |
|
||||
//删除试管架 |
|
||||
const deleteTube = (uuid: string) => { |
|
||||
emits('deleteTubeRack', uuid) |
|
||||
} |
|
||||
// 获取选中样本的样式 |
|
||||
const getActiveStyle = (tubeIndex: number) => { |
|
||||
return props.tubeRack.selectedSampleIds!.includes(tubeIndex) |
|
||||
? selectedStyle |
|
||||
: {} |
|
||||
} |
|
||||
|
|
||||
const processedTubeSettings = ref<TubeRack[]>([]) |
|
||||
|
|
||||
const showSelector = ref(false) |
|
||||
// 发出事件,告知父组件更新激活状态 |
|
||||
const emits = defineEmits<{ |
|
||||
(e: 'updateActivate', update: { uuid: string; active: boolean }): void |
|
||||
(e: 'changeUser', uuid: string): void |
|
||||
(e: 'deleteTubeRack', uuid: string): void |
|
||||
( |
|
||||
e: 'updateSelectedSamples', |
|
||||
{ sampleIds, uuid }: { sampleIds: number[]; uuid: string }, |
|
||||
): void |
|
||||
}>() |
|
||||
// 样本选中样式 |
|
||||
const selectedStyle = { |
|
||||
outline: '3px solid #4A90E2', // 使用 outline 避免调整大小 |
|
||||
boxShadow: '0 0 10px rgba(74, 144, 226, 0.6)', |
|
||||
} |
|
||||
|
|
||||
// 切换样本选中状态 |
|
||||
const toggleSampleSelection = (sampleId: number) => { |
|
||||
const currentSelected = [...(props.tubeRack.selectedSampleIds || [])] |
|
||||
const index = currentSelected.indexOf(sampleId) |
|
||||
|
|
||||
if (index === -1) { |
|
||||
currentSelected.push(sampleId) |
|
||||
} else { |
|
||||
currentSelected.splice(index, 1) |
|
||||
} |
|
||||
|
|
||||
// 发送更新事件到父组件 |
|
||||
emits('updateSelectedSamples', { |
|
||||
sampleIds: currentSelected, |
|
||||
uuid: props.tubeRack.uuid, |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// 状态变量 |
|
||||
const isActivated = ref(props.tubeRack.active) |
|
||||
const isSetting = ref(false) |
|
||||
const projectSetting = ref(testTubeStore.getProjectSetting(props.tubeRack.uuid)) |
|
||||
|
|
||||
// 根据状态面板点击事件切换状态 |
|
||||
const toggleSetting = () => { |
|
||||
isSetting.value = !isSetting.value |
|
||||
} |
|
||||
|
|
||||
// 激活或取消激活试管架 |
|
||||
const toggleActivate = async () => { |
|
||||
// 切换激活状态 |
|
||||
isActivated.value = !isActivated.value |
|
||||
|
|
||||
// 创建符合 handleTube 类型的数据对象,只更新 active 字段 |
|
||||
const updatedData: handleTube = { |
|
||||
uuid: props.tubeRack.uuid, |
|
||||
active: isActivated.value, |
|
||||
lock: props.tubeRack.lock, |
|
||||
tubeSettings: processedTubeSettings.value, // 使用当前试管的完整设置 |
|
||||
} |
|
||||
|
|
||||
// 调用 updateTubeInfo 接口更新激活状态 |
|
||||
const response = await updateTubeActivationStatus(updatedData) |
|
||||
|
|
||||
if (response && response.success) { |
|
||||
emits('updateActivate', { |
|
||||
uuid: props.tubeRack.uuid, |
|
||||
active: isActivated.value, |
|
||||
}) |
|
||||
} else { |
|
||||
console.error('Failed to update activation status') |
|
||||
// 还原状态 |
|
||||
isActivated.value = !isActivated.value |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// 提示信息 |
|
||||
const handleTip = () => { |
|
||||
if (isSetting.value) return '正在配置' |
|
||||
return isActivated.value ? '已激活' : '未激活' |
|
||||
} |
|
||||
// 获取弹出框元素并触发 click 事件 |
|
||||
const showPopover = (index: number) => { |
|
||||
const popover = 'popover-' + index |
|
||||
const popoverElement = document.querySelector( |
|
||||
`[aria-describedby="${popover}"]`, |
|
||||
) |
|
||||
// 使用 HTMLElement 类型断言,确保可以调用 click 方法 |
|
||||
if (popoverElement instanceof HTMLElement) { |
|
||||
popoverElement.click() |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
const handleConfirm = (selectedOption: string) => { |
|
||||
console.log("选中的数据有", selectedOption) |
|
||||
projectSetting.value = selectedOption |
|
||||
showSelector.value = false |
|
||||
// 更新当前试管架的项目设置到 store |
|
||||
testTubeStore.setProjectSetting(props.tubeRack.uuid, selectedOption) |
|
||||
|
|
||||
// 清除选中状态并通知组件 |
|
||||
emits('updateSelectedSamples', { |
|
||||
sampleIds: [], |
|
||||
uuid: props.tubeRack.uuid, |
|
||||
}) |
|
||||
} |
|
||||
const getPopoverStyle = () => ({ |
|
||||
width: '100px', |
|
||||
display: 'flex', |
|
||||
justifyContent: 'space-between', |
|
||||
alignItems: 'center', |
|
||||
}) |
|
||||
|
|
||||
// 清空选中状态的方法 |
|
||||
const clearSelectedSamples = () => { |
|
||||
if (props.tubeRack.selectedSampleIds) { |
|
||||
props.tubeRack.selectedSampleIds = [] |
|
||||
} |
|
||||
emits('updateSelectedSamples', { |
|
||||
sampleIds: [], |
|
||||
uuid: props.tubeRack.uuid |
|
||||
}) |
|
||||
} |
|
||||
|
|
||||
// 暴露方法给父组件 |
|
||||
defineExpose({ |
|
||||
clearSelectedSamples |
|
||||
}) |
|
||||
|
<script setup> |
||||
|
import Tube from './Tube.vue' |
||||
|
const props = defineProps(['tubeRack', 'index']) |
||||
</script> |
</script> |
||||
|
|
||||
<style lang="less" scoped> |
|
||||
#tube-container { |
|
||||
|
<style scoped lang="less"> |
||||
|
.test-tube-rack { |
||||
|
background-color: rgb(248, 248, 248); |
||||
|
height: 150px; |
||||
display: flex; |
display: flex; |
||||
align-items: center; |
align-items: center; |
||||
width: 100%; |
|
||||
box-sizing: border-box; |
|
||||
flex-direction: column; |
|
||||
|
|
||||
.tube-box { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
flex-direction: column; |
|
||||
width: 100%; |
|
||||
background-color: #fafafa; |
|
||||
border-radius: 10px; |
|
||||
|
|
||||
.tube-rack { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
width: 100%; |
|
||||
background-color: #fafafa; |
|
||||
border-radius: 10px; |
|
||||
|
|
||||
// 状态面板 |
|
||||
.status-panel { |
|
||||
width: 10%; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
position: relative; |
|
||||
padding: 20px 20px; |
|
||||
|
|
||||
.title { |
|
||||
font-size: 32px; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
|
|
||||
.status-icon { |
|
||||
img { |
|
||||
width: 80px; |
|
||||
height: 80px; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.status-text { |
|
||||
.subtitle { |
|
||||
font-size: 30px; |
|
||||
font-weight: 400; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
&::after { |
|
||||
content: ''; |
|
||||
display: block; |
|
||||
width: 2px; |
|
||||
height: 60%; |
|
||||
margin-top: 20px; |
|
||||
background-color: #000; |
|
||||
position: absolute; |
|
||||
right: 0; |
|
||||
} |
|
||||
} |
|
||||
|
.tube-rack-state { |
||||
|
width: 100px; |
||||
|
.status-icon img { |
||||
|
width: 56px; |
||||
} |
} |
||||
|
} |
||||
|
|
||||
// 试管架 |
|
||||
.samples { |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
background-color: #fafafa; |
|
||||
margin-left: 20px; |
|
||||
|
|
||||
.item-detail { |
|
||||
width: 800px; |
|
||||
height: 500px; |
|
||||
} |
|
||||
|
|
||||
.sample-item { |
|
||||
width: 65px; |
|
||||
height: 65px; |
|
||||
border-radius: 50%; |
|
||||
border: 2px solid black; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: center; |
|
||||
margin-right: 10px; |
|
||||
position: relative; |
|
||||
flex-direction: column; |
|
||||
|
|
||||
.sample-number { |
|
||||
position: absolute; |
|
||||
top: -28px; |
|
||||
font-size: 20px; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
|
|
||||
.sample-blood-type { |
|
||||
color: black; |
|
||||
font-size: 20px; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
.split { |
||||
|
width: 1px; |
||||
|
height: 80px; |
||||
|
background-color: rgb(192,192,192); |
||||
|
margin-right: 10px; |
||||
} |
} |
||||
|
|
||||
// 功能按钮 |
|
||||
.function-buttons { |
|
||||
|
.tube-list { |
||||
|
flex: 1 1 auto; |
||||
display: flex; |
display: flex; |
||||
align-items: center; |
|
||||
background-color: #ebebeb; |
|
||||
justify-content: space-evenly; |
|
||||
width: 100%; |
|
||||
padding: 20px 0; |
|
||||
|
|
||||
.active-button, |
|
||||
.update-button, |
|
||||
.change-user-button, |
|
||||
.del-button { |
|
||||
width: 200px; |
|
||||
height: 80px; |
|
||||
border-radius: 40px; |
|
||||
margin-right: 10px; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
justify-content: center; |
|
||||
cursor: pointer; |
|
||||
border: none; |
|
||||
position: relative; |
|
||||
|
|
||||
.outer-ring { |
|
||||
position: absolute; |
|
||||
width: 30px; |
|
||||
height: 30px; |
|
||||
z-index: 1; |
|
||||
top: 25px; |
|
||||
left: 25px; |
|
||||
} |
|
||||
|
|
||||
.text { |
|
||||
font-size: 20px; |
|
||||
margin-left: 20px; |
|
||||
} |
|
||||
|
|
||||
.inner-ring { |
|
||||
position: absolute; |
|
||||
width: 20px; |
|
||||
height: 20px; |
|
||||
z-index: 2; |
|
||||
top: 30px; |
|
||||
left: 30px; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.active-button, |
|
||||
.update-button, |
|
||||
.change-user-button { |
|
||||
background-color: #478ffe; |
|
||||
color: #fff; |
|
||||
} |
|
||||
|
|
||||
.del-button { |
|
||||
background-color: #cd4143; |
|
||||
color: #fff; |
|
||||
} |
|
||||
|
justify-content: space-around; |
||||
} |
} |
||||
|
|
||||
.add-tube { |
|
||||
width: 100%; |
|
||||
height: 100px; |
|
||||
background-color: #f6f6f6; |
|
||||
|
} |
||||
|
.test-tube-rack-op { |
||||
|
height: 68px; |
||||
|
background-color: rgb(235,235,235); |
||||
display: flex; |
display: flex; |
||||
|
justify-content: space-between; |
||||
align-items: center; |
align-items: center; |
||||
justify-content: center; |
|
||||
|
padding: 0 40px; |
||||
|
|
||||
.icon { |
|
||||
width: 86px; |
|
||||
height: 86px; |
|
||||
} |
|
||||
|
|
||||
.text { |
|
||||
font-size: 32px; |
|
||||
color: #73bc54; |
|
||||
font-weight: bold; |
|
||||
} |
|
||||
} |
|
||||
|
font-size: 22px; |
||||
|
font-weight: 600; |
||||
} |
} |
||||
</style> |
</style> |
@ -0,0 +1,33 @@ |
|||||
|
<template> |
||||
|
<div class="tube-item"> |
||||
|
<span class="order">{{ index + 1 }}</span> |
||||
|
<div class="tube-circle"> |
||||
|
<span class="add-symbol">+</span> |
||||
|
</div> |
||||
|
<span class="user-id">111</span> |
||||
|
<!-- <div>{{ tube.bloodType }}</div> --> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
const props = defineProps(['tube', 'index']) |
||||
|
</script> |
||||
|
|
||||
|
<style scoped lang="less"> |
||||
|
.tube-circle { |
||||
|
width: 72px; |
||||
|
height: 72px; |
||||
|
border-radius: 999px; |
||||
|
border: solid 1px gray; |
||||
|
|
||||
|
background-color: #fff; |
||||
|
|
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
.add-symbol { |
||||
|
color: black; |
||||
|
font-size: 20px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -1,2 +0,0 @@ |
|||||
export { default as ProjectSetting } from './ProjectSetting.vue' |
|
||||
export { default as TestTubeRack } from './TestTubeRack.vue' |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue