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