14 changed files with 397 additions and 130 deletions
-
4.env.test
-
3src/apis/system.ts
-
12src/components/SavePosition/index.vue
-
45src/components/check/index.vue
-
178src/components/home/ExtractLiquid/index.vue
-
4src/components/home/FillSolution/index.vue
-
2src/components/home/Tube/index.vue
-
50src/layouts/default.vue
-
14src/libs/utils.ts
-
2src/router/index.ts
-
1src/stores/systemStore.ts
-
2src/types/home.d.ts
-
1src/types/system.d.ts
-
209src/views/home/index.vue
@ -0,0 +1,178 @@ |
|||||
|
<script setup lang="ts"> |
||||
|
import { getSolsList } from 'apis/solution' |
||||
|
import { FtMessage } from 'libs/message' |
||||
|
import { socket } from 'libs/socket' |
||||
|
import { useHomeStore } from 'stores/homeStore' |
||||
|
import { useSystemStore } from 'stores/systemStore' |
||||
|
import { computed, onMounted, onUnmounted, ref } from 'vue' |
||||
|
|
||||
|
const emits = defineEmits(['ok', 'cancel']) |
||||
|
|
||||
|
const homeStore = useHomeStore() |
||||
|
const systemStore = useSystemStore() |
||||
|
|
||||
|
onMounted(() => { |
||||
|
getSols() |
||||
|
socket.init(receiveMessage, 'cmd_debug') |
||||
|
socket.init(receiveMessage, 'cmd_response') |
||||
|
}) |
||||
|
|
||||
|
onUnmounted(() => { |
||||
|
socket.unregisterCallback(receiveMessage, 'cmd_debug') |
||||
|
socket.unregisterCallback(receiveMessage, 'cmd_response') |
||||
|
}) |
||||
|
|
||||
|
let currentCommandId = '' |
||||
|
const receiveMessage = (data: Socket.cmdData) => { |
||||
|
data.commandId === currentCommandId && systemStore.pushSystemList(data) |
||||
|
} |
||||
|
|
||||
|
const form = ref<{ |
||||
|
columns?: number[] |
||||
|
solutionId?: number |
||||
|
volume?: number |
||||
|
}>({}) |
||||
|
const formRef = ref() |
||||
|
|
||||
|
const validateHandle = (rule: any, value: any, callback: any) => { |
||||
|
if (!value?.length) { |
||||
|
callback(new Error('请选择试管')) |
||||
|
} |
||||
|
else { |
||||
|
callback() |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const rules = { |
||||
|
columns: [ |
||||
|
{ required: true, message: '请选择试管', trigger: 'change', validator: validateHandle }, |
||||
|
], |
||||
|
} |
||||
|
|
||||
|
const okHandle = async () => { |
||||
|
try { |
||||
|
const valid = await formRef.value.validate() |
||||
|
if (!valid) { |
||||
|
return |
||||
|
} |
||||
|
currentCommandId = Date.now().toString() |
||||
|
const params = { |
||||
|
commandId: currentCommandId, |
||||
|
command: 'liquid_reduce', |
||||
|
params: form.value, |
||||
|
} |
||||
|
await homeStore.sendControl(params) |
||||
|
emits('ok') |
||||
|
} |
||||
|
catch (error) { |
||||
|
console.log(error) |
||||
|
} |
||||
|
} |
||||
|
const cancel = () => { |
||||
|
emits('cancel') |
||||
|
} |
||||
|
|
||||
|
const solsList = ref<Solution.SolutionItem[]>([]) |
||||
|
|
||||
|
const getSols = async () => { |
||||
|
const res = await getSolsList() |
||||
|
solsList.value = res.list |
||||
|
} |
||||
|
|
||||
|
const tubes = computed(() => { |
||||
|
const tray = systemStore.systemStatus.trays?.find(item => item.inSolutionPositon) |
||||
|
return tray?.tubes || [] |
||||
|
}) |
||||
|
|
||||
|
const selectedColumns = ref(Array.from({ length: 5 }).fill(false)) |
||||
|
|
||||
|
const mousedownHandle = async (index: number) => { |
||||
|
if (!tubes.value.find(item => item.columnNum === index)?.exists) { |
||||
|
FtMessage.error('该列没有试管') |
||||
|
return |
||||
|
} |
||||
|
selectedColumns.value[index - 1] = !selectedColumns.value[index - 1] |
||||
|
form.value.columns = selectedColumns.value.map((item, index) => { |
||||
|
return item ? index + 1 : false |
||||
|
}).filter(item => item !== false) |
||||
|
formRef.value.validateField('columns') |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<template> |
||||
|
<FtDialog visible title="抽取溶液" width="40%" :ok-handle="okHandle" @cancel="cancel"> |
||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="auto"> |
||||
|
<el-form-item label="选择试管" prop="columns"> |
||||
|
<div class="tube-item"> |
||||
|
<div |
||||
|
v-for="item in 5" |
||||
|
:key="item" |
||||
|
class="tube-line" |
||||
|
:class="{ 'tube-line-active': selectedColumns[item - 1], 'tube-line-disable': !tubes.find(tu => tu.columnNum === item)?.exists }" |
||||
|
|
||||
|
@click.prevent="() => mousedownHandle(item)" |
||||
|
@touch.prevent="() => mousedownHandle(item)" |
||||
|
> |
||||
|
<span v-for="i in 8" :key="i" class="tube-line-inner" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
</FtDialog> |
||||
|
</template> |
||||
|
|
||||
|
<style scoped lang="scss"> |
||||
|
.el-tag { |
||||
|
margin-right: 5px; |
||||
|
} |
||||
|
.el-row { |
||||
|
height: 450px; |
||||
|
.el-col { |
||||
|
height: 100%; |
||||
|
overflow: auto; |
||||
|
:deep(.el-tag) { |
||||
|
width: 100%; |
||||
|
margin-bottom: 5px; |
||||
|
.el-tag__content { |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.tube-item { |
||||
|
padding: 5px; |
||||
|
background: #384D5D; |
||||
|
border-radius: 10px; |
||||
|
display: grid; |
||||
|
grid-template-columns: repeat(5, 1fr); |
||||
|
grid-template-rows: repeat(1, 1fr); |
||||
|
grid-gap: 5px; |
||||
|
position: relative; |
||||
|
.tube-line { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
.tube-line-inner { |
||||
|
display: inline-block; |
||||
|
width: 25px; |
||||
|
height: 25px; |
||||
|
border-radius: 50%; |
||||
|
background: #fff; |
||||
|
margin: 2px; |
||||
|
transition: background 0.5s; |
||||
|
} |
||||
|
} |
||||
|
.tube-line-disable { |
||||
|
.tube-line-inner { |
||||
|
background: #C6C6C6; |
||||
|
} |
||||
|
} |
||||
|
.tube-line-active { |
||||
|
.tube-line-inner { |
||||
|
background: #26D574; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
</style> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue