forked from gzt/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.
255 lines
5.6 KiB
255 lines
5.6 KiB
<script setup lang="ts">
|
|
import { onMounted, onUnmounted, ref } from 'vue'
|
|
import { dropTipBlock, getConfig, getConfig1, startTest, submitConfig, submitConfig1, testOnce } from '@/services/debug'
|
|
import { eMessage } from '@/pages/Index/utils'
|
|
|
|
const tubeData = ref<any[]>([])
|
|
|
|
const takeTipEachTime = ref(false)
|
|
onMounted(async () => {
|
|
const res = await getConfig();
|
|
const res1 = await getConfig1();
|
|
tubeData.value = res.data.tubeExConfigs
|
|
takeTipEachTime.value = res1.data.takeTipEachTime || false
|
|
})
|
|
onUnmounted(() => {
|
|
hideKeyboard()
|
|
})
|
|
|
|
const keyboardVisible = ref(false)
|
|
const currentInputValue = ref('')
|
|
|
|
const handleKeyboardInput = (inputValue: string) => {
|
|
currentInputValue.value = inputValue;
|
|
tubeData.value[inputNum.value].repeatTimes = currentInputValue.value;
|
|
}
|
|
|
|
// 处理键盘按键
|
|
const handleKeyPress = (button: string) => {
|
|
if (button === '{enter}') {
|
|
hideKeyboard()
|
|
} else if (button === '{bksp}') {
|
|
// 处理退格键
|
|
const value = currentInputValue.value
|
|
if (value.length > 0) {
|
|
const newValue = value.slice(0, -1)
|
|
handleKeyboardInput(newValue)
|
|
}
|
|
}
|
|
}
|
|
// 隐藏键盘
|
|
const hideKeyboard = () => {
|
|
keyboardVisible.value = false
|
|
currentInputValue.value = ''
|
|
}
|
|
|
|
const inputNum = ref(0);
|
|
const showKeyboard = (index: number) => {
|
|
layout.value = numericLayout;
|
|
inputNum.value = index;
|
|
keyboardVisible.value = false
|
|
setTimeout(() => {
|
|
keyboardVisible.value = true
|
|
}, 200)
|
|
// 清空当前输入值,避免累加
|
|
currentInputValue.value = tubeData.value[index].repeatTimes;
|
|
|
|
}
|
|
|
|
const layout = ref()
|
|
|
|
const numericLayout = {
|
|
default: [
|
|
'1 2 3',
|
|
'4 5 6',
|
|
'7 8 9',
|
|
'{bksp} 0 {enter}' // 包含删除和确认键
|
|
],
|
|
}
|
|
|
|
|
|
const start = async () => {
|
|
// 保存配置
|
|
const data = tubeData.value.filter((item) => item.repeatTimes > 10);
|
|
if (data.length) {
|
|
eMessage.error('请输入正确的试管次数');
|
|
return;
|
|
}
|
|
const res = await submitConfig({tubeExConfigs: tubeData.value.map(item => {
|
|
return {
|
|
repeatTimes: Number(item.repeatTimes) || 0
|
|
}
|
|
})});
|
|
if (res && res.success) {
|
|
const res1 = await startTest();
|
|
if (res1 && res1.success) {
|
|
eMessage.success('已开始测试')
|
|
}
|
|
}
|
|
|
|
}
|
|
const moveLiquid = [
|
|
{
|
|
label: '取一次10ul',
|
|
value: 10
|
|
},
|
|
{
|
|
label: '取一次75ul',
|
|
value: 75
|
|
}
|
|
]
|
|
|
|
const move = ref(10)
|
|
|
|
const lostTip = async () => {
|
|
const res = await dropTipBlock();
|
|
if (res.success) {
|
|
eMessage.success('操作成功')
|
|
}
|
|
}
|
|
|
|
const checkboxHandle = async () => {
|
|
const res = await submitConfig1({takeTipEachTime: takeTipEachTime.value})
|
|
if (res.success) {
|
|
eMessage.success('保存成功')
|
|
}
|
|
}
|
|
|
|
const start1 = async () => {
|
|
const res = await testOnce(move.value);
|
|
if (res.success) {
|
|
eMessage.success('已开始移液')
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div id="debug-view">
|
|
<div class="content-box">
|
|
<div class="title">
|
|
<span>一致性测试</span>
|
|
<div>
|
|
<el-button type="primary" @click="start">开始测试</el-button>
|
|
</div>
|
|
</div>
|
|
<div class="content">
|
|
<div v-for="(item, index) in tubeData" :key="index" class="tube-item">
|
|
<span>试管{{index + 1}}</span>
|
|
<el-input
|
|
style="width: 80px"
|
|
v-model="item.repeatTimes"
|
|
type="number"
|
|
@focus="showKeyboard(index)"
|
|
readonly
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<div class="content-box">
|
|
<div class="title">
|
|
<span>加样准确度与重复性</span>
|
|
<div>
|
|
<el-button @click="lostTip">丢弃tip</el-button>
|
|
<el-button type="primary" @click="start1">移液操作</el-button>
|
|
</div></div>
|
|
<div class="content1">
|
|
<div>移液操作: </div>
|
|
<el-select v-model="move" style="width: 150px">
|
|
<el-option
|
|
v-for="(item, index) in moveLiquid"
|
|
:key="index"
|
|
:label="item.label"
|
|
:value="item.value"
|
|
/>
|
|
</el-select>
|
|
<el-checkbox v-model="takeTipEachTime" @change="checkboxHandle"> 每次丢弃tip</el-checkbox>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
</div>
|
|
<!-- 键盘 -->
|
|
<transition name="slide-up">
|
|
<div class="keyboard" v-if="keyboardVisible">
|
|
<SimpleKeyboard
|
|
:input="currentInputValue"
|
|
:layout
|
|
@onChange="handleKeyboardInput"
|
|
@onKeyPress="handleKeyPress"
|
|
/>
|
|
</div>
|
|
</transition>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped lang="less">
|
|
#debug-view {
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: #DDE4E9;
|
|
padding: 20px;
|
|
box-sizing: border-box;
|
|
.content-box {
|
|
margin-bottom: 20px;
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
background: #fff;
|
|
padding: 20px;
|
|
border-radius: 10px;
|
|
.content1 {
|
|
display: flex;
|
|
padding: 10px;
|
|
align-items: center;
|
|
.el-select {
|
|
margin: 0 20px;
|
|
}
|
|
}
|
|
.content {
|
|
.tube-item {
|
|
float: left;
|
|
height: 50px;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 10px 0;
|
|
box-sizing: border-box;
|
|
span {
|
|
width: 80px;
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.title {
|
|
font-weight: 800;
|
|
font-size: 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding-bottom: 10px;
|
|
box-sizing: border-box;
|
|
border-bottom: 1px solid #ccc;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
.keyboard {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 300px;
|
|
background-color: #f5f7fa;
|
|
border-top-left-radius: 16px;
|
|
border-top-right-radius: 16px;
|
|
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.1);
|
|
z-index: 1000;
|
|
}
|
|
</style>
|