forked from gzt/A8000
15 changed files with 741 additions and 761 deletions
-
3src/assets/icon_cross.svg
-
3src/assets/icon_cross_gray.svg
-
2src/pages/Index/Index.vue
-
212src/pages/Index/Regular/TestTube.vue
-
435src/pages/Index/TestTube/ChangeUser.vue
-
374src/pages/Index/TestTube/TubeUserId.vue
-
4src/pages/Index/components/Running/EmergencyResultDialog.vue
-
93src/pages/Index/components/TestTube/TestTubeRack.vue
-
80src/pages/Index/components/TestTube/Tube.vue
-
2src/router/router.ts
-
2src/services/Index/index.ts
-
11src/services/Index/testTube.ts
-
39src/store/modules/testTube.ts
-
24src/types/Index/TestTube.ts
@ -0,0 +1,3 @@ |
|||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> |
|||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.3571 11L22 19.6429L19.6429 22L11 13.3571L2.35714 22L0 19.6429L8.64286 11L1.40497e-06 2.35714L2.35714 0L11 8.64286L19.6429 0L22 2.35714L13.3571 11Z" fill="#FA5151"/> |
|||
</svg> |
@ -0,0 +1,3 @@ |
|||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> |
|||
<path fill-rule="evenodd" clip-rule="evenodd" d="M13.3571 11L22 19.6429L19.6429 22L11 13.3571L2.35714 22L0 19.6429L8.64286 11L1.40497e-06 2.35714L2.35714 0L11 8.64286L19.6429 0L22 2.35714L13.3571 11Z" fill="#999999"/> |
|||
</svg> |
@ -1,435 +0,0 @@ |
|||
<template> |
|||
<div id="changeUser-container" :key="refreshKey"> |
|||
<!-- 顶部导航 --> |
|||
<div class="header"> |
|||
<div class="header-left"> |
|||
<img src="@/assets/Index/left.svg" alt="返回" @click.stop="goBack" /> |
|||
<span class="title">患者信息</span> |
|||
<div class="divider"></div> |
|||
<span class="tube-type">试管类型({{ tubeType }})</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 主要内容区域 --> |
|||
<div class="content"> |
|||
<!-- 上半部分样本 --> |
|||
<div class="sample-section" v-for="box in boxes" :key="box.id"> |
|||
<!-- 左侧标题栏 --> |
|||
<div class="section-labels"> |
|||
<div class="label-column"> |
|||
<div class="label-item"> |
|||
<span class="label">序号</span> |
|||
</div> |
|||
<div class="label-item"> |
|||
<span class="label">试管信息</span> |
|||
</div> |
|||
<div class="label-item"> |
|||
<span class="label">样本条形码</span> |
|||
</div> |
|||
<div class="label-item"> |
|||
<span class="label">用户ID</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 右侧样本展示 --> |
|||
<div class="samples-grid"> |
|||
<div v-for="item in box.samples" :key="item.tubeIndex" class="sample-item" |
|||
:class="{ 'selected': selectedSampleId === item.tubeIndex }" @click="selectSample(item.tubeIndex)"> |
|||
<div class="sample-content"> |
|||
<!-- 序号 --> |
|||
<div class="item-index">{{ item.tubeIndex + 1 }}</div> |
|||
|
|||
<!-- 试管圆圈 --> |
|||
<div class="sample-circle" |
|||
:style="generateSampleBackground(item.projId!.filter(proj => proj !== null) as ReactionPlate[])"> |
|||
<span class="blood-type">{{ item.bloodType }}</span> |
|||
</div> |
|||
|
|||
<!-- 输入框组 --> |
|||
<div class="inputs"> |
|||
<input class="input-field" v-model="item.sampleBarcode" placeholder="条形码" |
|||
@focus="showKeyboard('barcode', item)" readonly /> |
|||
<input class="input-field" v-model="item.userid" placeholder="用户ID" |
|||
@focus="showKeyboard('userid', item)" readonly /> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 底部按钮 --> |
|||
<div class="footer"> |
|||
<button class="btn cancel" @click="goBack">取消</button> |
|||
<button class="btn confirm" @click="confirmChange">确定</button> |
|||
</div> |
|||
<!-- 键盘组件 --> |
|||
<transition name="slide-up"> |
|||
<div class="keyboard-container"> |
|||
<SimpleKeyboard v-if="keyboardVisible" :input="currentInputValue" @onChange="handleKeyboardInput" |
|||
@onKeyPress="handleKeyPress" /> |
|||
</div> |
|||
</transition> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import { onMounted, ref, watchEffect, onUnmounted, onActivated } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import { useTestTubeStore, useConsumablesStore, useSettingTestTubeStore } from '../../../store' |
|||
import SimpleKeyboard from '../../../components/SimpleKeyboard.vue' |
|||
import type { |
|||
DataItem, |
|||
ReactionPlate, |
|||
TubeRack, |
|||
handleTube, |
|||
} from '../../../types/Index' |
|||
import { |
|||
getBloodTypeLabel, |
|||
processTubeSettings, |
|||
generateSampleBackground, |
|||
} from '../Utils' |
|||
import { updateTubeConfig } from '../../../services' |
|||
import { ElMessage } from 'element-plus' |
|||
import { ConsumableGroupBase } from '../../../websocket/socket' |
|||
const testTubeStore = useTestTubeStore() |
|||
const consumableStore = useConsumablesStore() |
|||
const router = useRouter() |
|||
const tubeInfo = ref<DataItem>({} as DataItem) //试管架信息 |
|||
const processedTubeInfo = ref<handleTube>({} as handleTube) //经过清洗的试管架信息 |
|||
const tubeSettings = ref<TubeRack[]>([]) //获取到的试管信息 |
|||
const tubeType = ref<string>(testTubeStore.type || '自动') //导航栏的试管类型 |
|||
const plates = ref<ConsumableGroupBase[]>(consumableStore.plates) //反应板信息 |
|||
const selectedSampleId = ref<number | null>(null) //选中的试管 |
|||
const keyboardVisible = ref(false) |
|||
const currentInputValue = ref('') |
|||
const currentInput = ref<{ |
|||
type: 'barcode' | 'userid', |
|||
item: any |
|||
}>({ |
|||
type: 'barcode', |
|||
item: null |
|||
}) |
|||
const settingTestTubeStore = useSettingTestTubeStore() |
|||
const refreshKey = ref(0) |
|||
const modifiedTubes = ref(new Map<number, any>()) |
|||
onMounted(() => { |
|||
tubeInfo.value = testTubeStore.tubeInfo |
|||
console.log("🚀 ~ onMounted ~ tubeInfo.value:", tubeInfo.value) |
|||
tubeSettings.value = processTubeSettings( |
|||
tubeInfo.value.tubeSettings, |
|||
plates.value, |
|||
getBloodTypeLabel, |
|||
) |
|||
processedTubeInfo.value = { |
|||
...tubeInfo.value, |
|||
tubeSettings: tubeSettings.value, |
|||
} |
|||
}) |
|||
onActivated(() => { |
|||
tubeInfo.value = testTubeStore.tubeInfo |
|||
console.log("🚀 ~ onActivated ~ tubeInfo.value:", tubeInfo.value) |
|||
tubeSettings.value = processTubeSettings( |
|||
tubeInfo.value.tubeSettings, |
|||
plates.value, |
|||
getBloodTypeLabel, |
|||
) |
|||
processedTubeInfo.value = { |
|||
...tubeInfo.value, |
|||
tubeSettings: tubeSettings.value, |
|||
} |
|||
}) |
|||
//返回试管页面 |
|||
const goBack = () => { |
|||
router.push('/index/regular/test-tube') |
|||
} |
|||
// 选择样本的函数 |
|||
const selectSample = (id: number) => { |
|||
if (selectedSampleId.value === id) { |
|||
selectedSampleId.value = null |
|||
} else { |
|||
selectedSampleId.value = id |
|||
} |
|||
} |
|||
const boxes = ref([ |
|||
{ |
|||
id: 1, |
|||
samples: [] as TubeRack[], |
|||
}, |
|||
{ |
|||
id: 2, |
|||
samples: [] as TubeRack[], |
|||
}, |
|||
]) |
|||
watchEffect(() => { |
|||
boxes.value.forEach((item) => { |
|||
if (item.id === 1) { |
|||
item.samples = tubeSettings.value.slice(0, 5) |
|||
} else { |
|||
item.samples = tubeSettings.value.slice(5, 10) |
|||
} |
|||
}) |
|||
}) |
|||
//确认事件 |
|||
const confirmChange = async () => { |
|||
const modifiedSettings = Array.from(modifiedTubes.value.values()) |
|||
|
|||
if (modifiedSettings.length > 0) { |
|||
try { |
|||
const updatePromises = modifiedSettings.map(setting => |
|||
updateTubeConfig({ |
|||
uuid: processedTubeInfo.value.uuid, |
|||
setting |
|||
}) |
|||
) |
|||
const results = await Promise.all(updatePromises) |
|||
|
|||
const allSuccess = results.every(res => res && res.success) |
|||
|
|||
if (allSuccess) { |
|||
ElMessage.success('所有修改已保存') |
|||
goBack() |
|||
} else { |
|||
ElMessage.error('部分修改保存失败') |
|||
} |
|||
} catch (error) { |
|||
console.error('保存修改失败:', error) |
|||
ElMessage.error('保存失败') |
|||
} |
|||
} else { |
|||
ElMessage.warning('没有需要保存的修改') |
|||
} |
|||
} |
|||
|
|||
// 显示键盘 |
|||
const showKeyboard = (type: 'barcode' | 'userid', item: any) => { |
|||
keyboardVisible.value = true |
|||
currentInput.value = { type, item } |
|||
currentInputValue.value = type === 'barcode' ? item.sampleBarcode : item.userid |
|||
} |
|||
|
|||
// 处理键盘输入 |
|||
const handleKeyboardInput = (input: string) => { |
|||
if (!currentInput.value.item) return |
|||
|
|||
if (currentInput.value.type === 'barcode') { |
|||
currentInput.value.item.sampleBarcode = input |
|||
} else { |
|||
currentInput.value.item.userid = input |
|||
} |
|||
|
|||
currentInputValue.value = input |
|||
|
|||
modifiedTubes.value.set(currentInput.value.item.tubeIndex, { |
|||
tubeIndex: currentInput.value.item.tubeIndex, |
|||
userid: currentInput.value.item.userid, |
|||
sampleBarcode: currentInput.value.item.sampleBarcode, |
|||
projId: currentInput.value.item.projId?.map((p: ReactionPlate) => p.projId) || [], |
|||
bloodType: currentInput.value.item.bloodType, |
|||
}) |
|||
|
|||
settingTestTubeStore.updateTubeSetting(tubeInfo.value.uuid, { |
|||
tubeIndex: currentInput.value.item.tubeIndex, |
|||
[currentInput.value.type === 'userid' ? 'userid' : 'sampleBarcode']: input |
|||
}) |
|||
} |
|||
|
|||
// 处理键盘按键 |
|||
const handleKeyPress = (button: string) => { |
|||
if (button === '{enter}') { |
|||
keyboardVisible.value = false |
|||
currentInputValue.value = '' |
|||
} |
|||
} |
|||
|
|||
// 在组件卸载时清理 |
|||
onUnmounted(() => { |
|||
modifiedTubes.value.clear() |
|||
}) |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
#changeUser-container { |
|||
width: 100%; |
|||
height: 95vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
position: relative; |
|||
background-color: #f5f7fa; |
|||
overflow: hidden; |
|||
|
|||
.header { |
|||
height: 80px; |
|||
background-color: #fff; |
|||
padding: 0 20px; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.header-left { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 12px; |
|||
|
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 28px; |
|||
color: #303133; |
|||
} |
|||
|
|||
.tube-type { |
|||
font-size: 24px; |
|||
color: #606266; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
padding: 16px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20px; |
|||
overflow: hidden; |
|||
|
|||
.sample-section { |
|||
background-color: #fff; |
|||
border-radius: 8px; |
|||
padding: 20px; |
|||
display: flex; |
|||
height: 380px; |
|||
|
|||
.section-labels { |
|||
width: 120px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
padding-top: 20px; |
|||
|
|||
.label-column { |
|||
.label-item { |
|||
margin-bottom: 16px; |
|||
|
|||
.label { |
|||
font-size: 24px; |
|||
color: #606266; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.samples-grid { |
|||
flex: 1; |
|||
display: grid; |
|||
grid-template-columns: repeat(5, 1fr); |
|||
gap: 12px; |
|||
|
|||
.sample-item { |
|||
background-color: #f5f7fa; |
|||
border-radius: 4px; |
|||
padding: 12px; |
|||
|
|||
.sample-content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
|
|||
.item-index { |
|||
font-size: 22px; |
|||
color: #606266; |
|||
margin-bottom: 8px; |
|||
} |
|||
|
|||
.sample-circle { |
|||
width: 60px; |
|||
height: 60px; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin: 8px 0; |
|||
|
|||
.blood-type { |
|||
font-size: 20px; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.inputs { |
|||
width: 100%; |
|||
margin-top: 12px; |
|||
|
|||
.input-field { |
|||
width: 100%; |
|||
height: 36px; |
|||
border: 1px solid #dcdfe6; |
|||
border-radius: 4px; |
|||
margin-bottom: 8px; |
|||
font-size: 20px; |
|||
text-align: center; |
|||
background-color: #fff; |
|||
|
|||
&::placeholder { |
|||
color: #c0c4cc; |
|||
font-size: 18px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.footer { |
|||
height: 80px; |
|||
padding: 10px 20px; |
|||
background-color: #fff; |
|||
display: flex; |
|||
justify-content: center; |
|||
gap: 16px; |
|||
|
|||
.btn { |
|||
width: 320px; |
|||
height: 60px; |
|||
border-radius: 30px; |
|||
font-size: 24px; |
|||
font-weight: normal; |
|||
|
|||
&.cancel { |
|||
background-color: #f5f7fa; |
|||
color: #606266; |
|||
border: 1px solid #dcdfe6; |
|||
} |
|||
|
|||
&.confirm { |
|||
background-color: #409eff; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.keyboard-container { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 20vh; |
|||
background-color: #fff; |
|||
} |
|||
|
|||
// 键盘动画 |
|||
.slide-up-enter-active, |
|||
.slide-up-leave-active { |
|||
transition: transform 0.3s ease; |
|||
} |
|||
|
|||
.slide-up-enter-from, |
|||
.slide-up-leave-to { |
|||
transform: translateY(100%); |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,374 @@ |
|||
<template> |
|||
<div id="changeUser-container"> |
|||
<!-- 顶部导航 --> |
|||
<div class="header"> |
|||
<div class="header-left" @click.stop="goBack"> |
|||
<img src="@/assets/Index/left.svg" alt="返回" /> |
|||
<span class="title">患者信息</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 主要内容区域 --> |
|||
<div class="content"> |
|||
<div class="sample-section" v-for="(group, idx) in tubeGroups" :key="idx"> |
|||
<!-- 左侧标题栏 --> |
|||
<div class="section-labels"> |
|||
<div class="label-column"> |
|||
<div class="label-item"> |
|||
<span class="label">条形码</span> |
|||
</div> |
|||
<div class="label-item"> |
|||
<span class="label">用户ID</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 右侧样本展示 --> |
|||
<div class="samples-grid"> |
|||
<div class="sample-item" v-for="item in group" :key="item.tubeIndex"> |
|||
<div class="sample-content"> |
|||
<!-- 序号 --> |
|||
<div class="item-index">{{ item.tubeIndex + 1 }}</div> |
|||
|
|||
<!-- 试管圆圈 --> |
|||
<div class="tube-circle"> |
|||
<Tube |
|||
:tube="item" |
|||
:index="item.tubeIndex" |
|||
:projects="projectsAvailable" |
|||
:bloodTypes="tubeStore.bloodTypes" |
|||
:showNum="false" |
|||
@clickTubeItem="" |
|||
/> |
|||
</div> |
|||
|
|||
<!-- 输入框组 --> |
|||
<div class="inputs"> |
|||
<input |
|||
class="input-field" |
|||
:class="{ onFocus: isFocused('barcode', item) }" |
|||
v-model="item.sampleBarcode" |
|||
placeholder="条形码" |
|||
@focus="showKeyboard('barcode', item)" |
|||
readonly |
|||
/> |
|||
<input |
|||
class="input-field" |
|||
:class="{ onFocus: isFocused('userid', item) }" |
|||
v-model="item.userid" |
|||
placeholder="用户ID" |
|||
@focus="showKeyboard('userid', item)" |
|||
readonly |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 底部按钮 --> |
|||
<div class="footer"> |
|||
<button class="btn cancel" @click="goBack">取消</button> |
|||
<button class="btn confirm" @click="confirmChange">确定</button> |
|||
</div> |
|||
<!-- 键盘组件 --> |
|||
<transition name="slide-up"> |
|||
<div class="keyboard-container"> |
|||
<SimpleKeyboard |
|||
v-if="keyboardVisible" |
|||
:input="currentInputValue" |
|||
@onChange="handleKeyboardInput" |
|||
@onKeyPress="handleKeyPress" |
|||
/> |
|||
</div> |
|||
</transition> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { computed, onActivated, ref, watch } from 'vue' |
|||
import { useRouter } from 'vue-router' |
|||
import * as R from 'ramda' |
|||
import { useTestTubeStore, useConsumablesStore } from '../../../store' |
|||
import SimpleKeyboard from '../../../components/SimpleKeyboard.vue' |
|||
import Tube from '../Components/TestTube/Tube.vue' |
|||
import { updateTubeConfig } from '../../../services' |
|||
import { ElMessage } from 'element-plus' |
|||
|
|||
const router = useRouter() |
|||
|
|||
const consumables = useConsumablesStore() |
|||
const tubeStore = useTestTubeStore() |
|||
|
|||
defineOptions({ |
|||
name: 'TubeUserId', |
|||
}) |
|||
const tubeGroups = ref([ |
|||
R.clone(tubeStore.tubeRack.tubeSettings.slice(0, 5)), |
|||
R.clone(tubeStore.tubeRack.tubeSettings.slice(5, 10)), |
|||
]) |
|||
|
|||
const projectsAvailable = computed(() => { |
|||
const group = R.groupBy((p) => p.projName, consumables.plates) |
|||
const pNames = R.keys(group) |
|||
|
|||
const projArr = pNames.map((n) => |
|||
R.reduce( |
|||
(acc, curr) => { |
|||
return { ...curr, num: acc.num + curr.num } |
|||
}, |
|||
{ num: 0 }, |
|||
group[n], |
|||
), |
|||
) |
|||
|
|||
return projArr |
|||
}) |
|||
|
|||
const keyboardVisible = ref(false) |
|||
const currentInputValue = ref('') |
|||
const currentInput = ref({ |
|||
type: 'barcode', |
|||
item: null, |
|||
}) |
|||
|
|||
const isFocused = (type, item) => { |
|||
if ( |
|||
currentInput.value.item && |
|||
item.tubeIndex === currentInput.value.item.tubeIndex && |
|||
type === currentInput.value.type |
|||
) { |
|||
return true |
|||
} |
|||
return false |
|||
} |
|||
|
|||
//返回试管页面 |
|||
const goBack = () => { |
|||
//router.push('/index/regular/test-tube') |
|||
router.back() |
|||
} |
|||
|
|||
//确认事件 |
|||
const confirmChange = async () => { |
|||
const settings = R.flatten(tubeGroups.value) |
|||
const res = await updateTubeConfig({ |
|||
uuid: tubeStore.tubeRack.uuid, |
|||
setting: settings, |
|||
}) |
|||
if (res.success) { |
|||
tubeStore.tubeRack.tubeSettings = settings |
|||
goBack() |
|||
} else { |
|||
ElMessage.error('更新失败') |
|||
} |
|||
} |
|||
|
|||
// 显示键盘 |
|||
const showKeyboard = (type, item) => { |
|||
keyboardVisible.value = true |
|||
currentInput.value = { type, item } |
|||
currentInputValue.value = |
|||
type === 'barcode' ? item.sampleBarcode : item.userid |
|||
} |
|||
|
|||
// 处理键盘输入 |
|||
const handleKeyboardInput = (input) => { |
|||
if (!currentInput.value.item) return |
|||
|
|||
const groupIdx = currentInput.value.item.tubeIndex < 5 ? 0 : 1 |
|||
const idxOffset = groupIdx === 1 ? 5 : 0 |
|||
const tubeIdx = currentInput.value.item.tubeIndex - idxOffset |
|||
if (currentInput.value.type === 'barcode') { |
|||
currentInput.value.item.sampleBarcode = input |
|||
tubeGroups.value[groupIdx][tubeIdx].sampleBarcode = input |
|||
} else { |
|||
currentInput.value.item.userid = input |
|||
tubeGroups.value[groupIdx][tubeIdx].userid = input |
|||
} |
|||
currentInputValue.value = input |
|||
// console.log(tubeGroups.value[groupIdx]) |
|||
} |
|||
|
|||
// 处理键盘按键 |
|||
const handleKeyPress = (button) => { |
|||
if (button === '{enter}') { |
|||
keyboardVisible.value = false |
|||
currentInputValue.value = '' |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="less" scoped> |
|||
#changeUser-container { |
|||
width: 100%; |
|||
height: 95vh; |
|||
display: flex; |
|||
flex-direction: column; |
|||
position: relative; |
|||
overflow: hidden; |
|||
|
|||
.header { |
|||
height: 80px; |
|||
background-color: #fff; |
|||
padding: 0 20px; |
|||
display: flex; |
|||
align-items: center; |
|||
|
|||
.header-left { |
|||
display: flex; |
|||
align-items: center; |
|||
gap: 12px; |
|||
|
|||
img { |
|||
width: 24px; |
|||
height: 24px; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 28px; |
|||
color: #303133; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.content { |
|||
padding: 16px; |
|||
display: flex; |
|||
flex-direction: column; |
|||
gap: 20px; |
|||
overflow: hidden; |
|||
|
|||
.sample-section { |
|||
border-radius: 8px; |
|||
padding: 20px; |
|||
display: flex; |
|||
// height: 380px; |
|||
|
|||
.section-labels { |
|||
width: 100px; |
|||
display: flex; |
|||
flex-direction: column-reverse; |
|||
padding-bottom: 16px; |
|||
|
|||
.label-column { |
|||
> * { |
|||
box-sizing: border-box; |
|||
} |
|||
.label-item { |
|||
margin-bottom: 16px; |
|||
.label { |
|||
font-size: 24px; |
|||
font-weight: 600; |
|||
color: #606266; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.samples-grid { |
|||
flex: 1; |
|||
display: grid; |
|||
grid-template-columns: repeat(5, 1fr); |
|||
gap: 12px; |
|||
|
|||
.sample-item { |
|||
// background-color: #f5f7fa; |
|||
border-radius: 12px; |
|||
padding: 12px; |
|||
|
|||
.sample-content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
|
|||
.item-index { |
|||
font-size: 22px; |
|||
color: #333; |
|||
margin-bottom: 8px; |
|||
} |
|||
.tube-circle { |
|||
height: 80px; |
|||
} |
|||
|
|||
.inputs { |
|||
width: 100%; |
|||
margin-top: 24px; |
|||
|
|||
.input-field { |
|||
&.onFocus { |
|||
border: solid 2px #333; |
|||
} |
|||
width: 100%; |
|||
height: 36px; |
|||
border: 1px solid #aaa; |
|||
border-radius: 4px; |
|||
margin-bottom: 14px; |
|||
font-size: 20px; |
|||
font-weight: 600; |
|||
text-align: center; |
|||
background-color: #fff; |
|||
|
|||
&::placeholder { |
|||
color: #c0c4cc; |
|||
font-size: 18px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.footer { |
|||
height: 80px; |
|||
padding: 10px 20px; |
|||
background-color: #fff; |
|||
display: flex; |
|||
justify-content: center; |
|||
gap: 16px; |
|||
|
|||
.btn { |
|||
width: 320px; |
|||
height: 60px; |
|||
border-radius: 30px; |
|||
font-size: 24px; |
|||
font-weight: normal; |
|||
|
|||
&.cancel { |
|||
background-color: #f5f7fa; |
|||
color: #606266; |
|||
border: 1px solid #dcdfe6; |
|||
} |
|||
|
|||
&.confirm { |
|||
background-color: #409eff; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.keyboard-container { |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 0; |
|||
width: 100%; |
|||
height: 20vh; |
|||
background-color: #fff; |
|||
} |
|||
|
|||
// 键盘动画 |
|||
.slide-up-enter-active, |
|||
.slide-up-leave-active { |
|||
transition: transform 0.3s ease; |
|||
} |
|||
|
|||
.slide-up-enter-from, |
|||
.slide-up-leave-to { |
|||
transform: translateY(100%); |
|||
} |
|||
} |
|||
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue