Browse Source

fix:工艺加液

master
guoapeng 2 months ago
parent
commit
f59c582483
  1. 299
      src/components/craft/AddCraft/index.vue
  2. 5
      src/components/home/Tube/index.vue

299
src/components/craft/AddCraft/index.vue

@ -5,6 +5,7 @@ import { getSolsList } from 'apis/solution'
import emptyIcon from 'assets/images/empty.svg'
import { FtMessage } from 'libs/message'
import { allPropertiesDefined } from 'libs/utils'
import { cloneDeep } from 'lodash'
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
@ -34,6 +35,10 @@ onMounted(async () => {
step.params.minutes = Math.floor(step.params.second / 60)
step.params.seconds = step.params.second % 60
}
if (step.params.coolingSecond) {
step.params.coolingMinutes = Math.floor(step.params.coolingSecond / 60)
step.params.coolingSeconds = step.params.coolingSecond % 60
}
})
}
loading.value = false
@ -64,15 +69,19 @@ const okHandle = async () => {
}
//
const invalidStepIndex = form.value.stepList?.findIndex(
(step: any) => {
(step: any, index) => {
if (['startHeating', 'shaking'].includes(step.method)) {
if (step.params.minutes || step.params.seconds) {
step.params.second = (step.params.minutes || 0) * 60 + (step.params.seconds || 0) || undefined
}
if (step.params.coolingMinutes || step.params.coolingSeconds) {
step.params.coolingSecond = (step.params.coolingMinutes || 0) * 60 + (step.params.coolingSeconds || 0) || undefined
}
}
step.params.description = `${index + 1}.`
switch (step.method) {
case 'addLiquid':
step.params.description = step.params.addLiquidList.map((liquid: { containerId: number, volume: number }) => `添加${solutionList.value.find(s => s.id === containerList.value.find(c => c.id === liquid.containerId)?.solutionId)?.name}-${liquid.volume}ml `).join(';')
step.params.description = '添加溶液'
break
case 'startHeating':
step.params.description = `加热: ${step.params.temperature}度, 保持${step.params.minutes || 0}${step.params.seconds || 0}`
@ -115,7 +124,7 @@ const cancel = () => {
}
const stepMap: Record<string, CraftTypes.StepItem> = {
addLiquid: { name: '加液', method: 'addLiquid', params: { addLiquidList: [{ containerId: undefined, volume: undefined }], description: undefined } },
// addLiquid: { name: '', method: 'addLiquid', params: { addLiquidList: [{ containerId: undefined, volume: undefined }], description: undefined } },
startHeating: { name: '加热', method: 'startHeating', params: { temperature: undefined, second: undefined, description: undefined, minutes: undefined, seconds: undefined } },
shaking: { name: '摇匀', method: 'shaking', params: { second: undefined } },
takePhoto: { name: '拍照', method: 'takePhoto', params: { } },
@ -124,13 +133,93 @@ const stepMap: Record<string, CraftTypes.StepItem> = {
const addStep = (data: CraftTypes.StepItem) => {
form.value.stepList?.push(data)
}
const addLiquidForm = ref<any>({
tubeNums: [],
solutionList: [
{
solutionId: undefined,
volume: undefined,
offset: undefined,
},
],
})
const addLiquidRules = {
tubeNums: [
{ required: true, message: '请选择试管', trigger: 'change' },
],
}
const addLiquidFormRef = ref()
const activeTube = ref(Array.from({ length: 16 }).fill(false))
const selectVisible = ref(false)
const checkChange = () => {
activeTube.value = Array.from({ length: 16 }).fill(selectVisible.value)
addLiquidForm.value.tubeNums = activeTube.value.map((item, index) => index + 1).filter(item => activeTube.value[item - 1])
addLiquidFormRef.value.validateField('tubeNums')
}
const mousedownHandle = async (e: Event) => {
let event
if ('touches' in e) {
event = (e.touches as TouchList)[0]
}
else {
event = e
}
if (event.target!.classList!.contains('tube-inner')) {
const num = event.target!.getAttribute('index')
activeTube.value[Number(num) - 1] = !activeTube.value[Number(num) - 1]
addLiquidForm.value.tubeNums = activeTube.value.map((item, index) => index + 1).filter(item => activeTube.value[item - 1])
}
}
const addHandle = async () => {
try {
const valid = await addLiquidFormRef.value.validate()
if (!valid) {
return
}
console.log(addLiquidForm.value)
// addList.value!.push(addLiquidForm)
const index = form.value.stepList?.findIndex(item => item.method === 'addLiquid')
if (index !== -1) {
form.value.stepList?.[index || 0].params?.push(cloneDeep(addLiquidForm.value))
}
else {
form.value.stepList?.push({
name: '加液',
method: 'addLiquid',
params: [cloneDeep(addLiquidForm.value)],
} as CraftTypes.StepItem)
}
addLiquidForm.value = {
tubeNums: [],
solutionList: [
{
solutionId: undefined,
volume: undefined,
offset: undefined,
},
],
}
activeTube.value = Array.from({ length: 16 }).fill(false)
selectVisible.value = false
addLiquidFormRef.value.resetFields()
}
catch (error) {
console.log(error)
}
}
</script>
<template>
<FtDialog visible :loading :title="form.id ? '编辑工艺' : '新增工艺'" width="80%" :ok-handle="okHandle" @cancel="cancel">
<FtDialog visible :loading :title="form.id ? '编辑工艺' : '新增工艺'" width="90%" :ok-handle="okHandle" @cancel="cancel">
<el-form ref="formRef" label-width="auto" :model="form" :rules="rules" class="form-box">
<el-row :gutter="30">
<el-col :span="10">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="工艺名称" prop="name">
<el-input v-model="form.name" placeholder="请输入工艺名称" />
</el-form-item>
@ -143,37 +232,126 @@ const addStep = (data: CraftTypes.StepItem) => {
</div>
</el-tag>
</div>
<el-form ref="addLiquidFormRef" :model="addLiquidForm" :rules="addLiquidRules" label-width="auto" class="liquid-box">
<p>加液</p>
<el-form-item label="" prop="tubeNums">
<el-checkbox v-model="selectVisible" style="margin-right: 10px" @change="checkChange">
全选
</el-checkbox>
<div class="tube-item" @click.prevent="mousedownHandle" @touch.prevent="mousedownHandle">
<span v-for="item in 16" :key="item" class="tube-inner" :class="{ 'tube-inner-active': activeTube[item - 1] }" :index="item" />
</div>
</el-form-item>
<el-row>
<el-col :span="7" style="text-align: center">
溶液
</el-col>
<el-col :span="14">
<div v-if="form.stepList?.length" class="step-box">
<div v-for="(item, index) in form.stepList" :key="index" class="step-item">
<el-form-item :label="`${index + 1}: ${item.name}`">
<div v-if="item.method === 'addLiquid'" class="list-box">
<div v-for="(liquid, liquidIndex) in item.params.addLiquidList" :key="liquidIndex" class="list-item">
<el-select v-model="liquid.containerId" size="small" placeholder="请选择溶液">
<el-option v-for="c in containerList" :key="c.id" :label="solutionList.find(s => s.id === c.solutionId)?.name" :value="c.id" />
<el-col :span="7" style="text-align: center">
容量
</el-col>
<el-col :span="7" style="text-align: center">
偏移量
</el-col>
</el-row>
<div class="solution-list">
<el-row v-for="(s, index) in addLiquidForm.solutionList" :key="index" :gutter="5" class="solution-item">
<el-col :span="7">
<el-form-item
label=""
:prop="`solutionList.${index}.solutionId`"
:rules="{
required: true,
message: '请选择溶液',
trigger: 'change',
}"
>
<el-select v-model="s.solutionId" size="small" style="width: 100%" placeholder="溶液">
<el-option v-for="item in solutionList" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
<el-input v-model.number="liquid.volume" type="number" size="small" placeholder="请输入容量">
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item
label="" :prop="`solutionList.${index}.volume`" :rules="{
required: true,
message: '请输入容量',
trigger: 'blur',
}"
>
<el-input v-model.number="s.volume" size="small" type="number" style="width: 100%" placeholder="容量">
<template #append>
ml
</template>
</el-input>
<el-icon color="red" @click="item.params.addLiquidList.splice(liquidIndex, 1)">
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item
label="" :prop="`solutionList.${index}.offset`" :rules="{
required: true,
message: '请输入偏移量',
trigger: 'blur',
}"
>
<el-input v-model.number="s.offset" size="small" type="number" style="width: 100%" placeholder="偏移量">
<template #append>
ml
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="3" class="icon-box">
<el-icon v-if="addLiquidForm.solutionList.length > 1" color="red" @click="addLiquidForm.solutionList.splice(index, 1)">
<RemoveFilled />
</el-icon>
<el-icon v-if="liquidIndex === item.params.addLiquidList.length - 1" color="green" @click="item.params.addLiquidList.push({ containerId: undefined, volume: undefined })">
<el-icon
v-if="index === addLiquidForm.solutionList.length - 1" color="green" @click="addLiquidForm.solutionList.push({ solutionId: undefined,
volume: undefined,
offset: undefined })"
>
<CirclePlusFilled />
</el-icon>
</el-col>
</el-row>
</div>
<el-form-item>
<div style="width: 100%;display: flex;justify-content: center">
<ft-button type="primary" @click="addHandle">
添加
</ft-button>
</div>
<template v-else-if="['startHeating'].includes(item.method)">
</el-form-item>
</el-form>
</el-form-item>
</el-col>
<el-col :span="12">
<div v-if="form.stepList?.length" class="step-box">
<div v-for="(item, index) in form.stepList" :key="index" class="step-item">
<el-form-item :label="`${index + 1}: ${item.name}`">
<div v-if="item.method === 'addLiquid'" class="list-box">
<div v-for="(liquid, liquidIndex) in item.params" :key="liquidIndex">
<span>试管: {{ liquid.tubeNums.length === 16 ? '全部' : liquid.tubeNums.join(',') }} </span>
<div v-for="(s, sIndex) in liquid.solutionList" :key="sIndex">
<span>添加</span>
<span>{{ solutionList.find(solution => solution.id === s.solutionId)?.name }}</span>
<span>{{ s.volume }}</span>
<span>ml-</span>
<span>偏移量</span>
<span>{{ s.offset }}</span>
<span>ml</span>
</div>
</div>
</div>
<div v-else-if="['startHeating'].includes(item.method)">
<el-input v-model.number="item.params.temperature" type="number" size="small" placeholder="加热温度">
<template #append>
</template>
</el-input>
<br>
<div>
<span>保持时间</span>
<el-select v-model="item.params.minutes" style="width: 70px" clearable size="small" placeholder="分钟">
<el-option v-for="i in 60" :key="i" :label="i" :value="i" />
</el-select>
@ -182,7 +360,19 @@ const addStep = (data: CraftTypes.StepItem) => {
<el-option v-for="i in 60" :key="i" :label="i" :value="i" />
</el-select>
<span class="unit-text"></span>
</template>
</div>
<div>
<span>冷却时间</span>
<el-select v-model="item.params.coolingMinutes" style="width: 70px" clearable size="small" placeholder="分钟">
<el-option v-for="i in 60" :key="i" :label="i" :value="i" />
</el-select>
<span class="unit-text"></span>
<el-select v-model="item.params.coolingSeconds" style="width: 70px" clearable size="small" placeholder="秒">
<el-option v-for="i in 60" :key="i" :label="i" :value="i" />
</el-select>
<span class="unit-text"></span>
</div>
</div>
<template v-else-if="['shaking'].includes(item.method)">
<el-select v-model="item.params.minutes" style="width: 70px" clearable size="small" placeholder="请选择">
<el-option v-for="i in 60" :key="i" :label="i" :value="i" />
@ -211,7 +401,7 @@ const addStep = (data: CraftTypes.StepItem) => {
<style scoped lang="scss">
.form-box {
height: 50vh;
height: 70vh;
.el-row {
height: 100%;
.el-col:first-child {
@ -230,8 +420,9 @@ const addStep = (data: CraftTypes.StepItem) => {
width: 100%;
display: grid;
grid-template-columns: repeat(2, 1fr); /* 创建3列等宽轨道 */
grid-template-rows: repeat(4, auto); /* 创建2行自动高度 */
gap: 20px;
grid-template-rows: repeat(2, auto); /* 创建2行自动高度 */
gap: 10px;
margin-bottom: 10px;
}
:deep(.el-tag__content) {
width: 100%;
@ -287,4 +478,66 @@ const addStep = (data: CraftTypes.StepItem) => {
font-size: 12px;
line-height: 25px;
}
.tube-item {
padding: 5px;
background: #384D5D;
border-radius: 10px;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(4, 1fr);
grid-gap: 5px;
position: relative;
.tube-disable {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: rgba(255,255,255,0.9);
border-radius: 9px;
}
.tube-inner {
display: inline-block;
width: 25px;
height: 25px;
border-radius: 50%;
background: #fff;
margin: 2px;
transition: background 0.5s;
}
.tube-inner-active {
background: #26D574;
}
}
.liquid-box {
background: #ecf5ff;
padding: 0 10px;
p {
text-align: center;
color: #1989fa;
}
}
.solution-list {
max-height: 100px;
overflow: hidden;
overflow-y: auto;
}
.solution-item {
margin-bottom: 10px;
}
.el-form-item .el-form-item {
margin-bottom: 10px;
}
.icon-box {
display: flex;
margin-top: 4px;
justify-content: space-between;
.el-icon {
font-size: 18px;
line-height: 100%;
}
}
</style>

5
src/components/home/Tube/index.vue

@ -133,9 +133,8 @@ defineExpose({
<span v-if="craft?.state === 'ERROR'" class="status-text">工艺执行错误</span>
<span v-if="craft?.state === 'FINISHED'" class="status-text">工艺执行完毕</span>
<el-tooltip v-if="craft?.state === 'RUNNING' && craftSteps && craftSteps[craft.currentIndex || 0]?.params?.description" :content="`${(craft.currentIndex || 0) + 1}.${craftSteps[craft.currentIndex || 0].params.description}`" placement="top" trigger="click">
<el-tooltip v-if="craft?.state === 'RUNNING' && craftSteps && craftSteps[craft.currentIndex || 0]?.params?.description" :content="`${craftSteps[craft.currentIndex || 0].params.description}`" placement="top" trigger="click">
<div class="status-description">
{{ (craft.currentIndex || 0) + 1 }}.
{{ craftSteps[craft.currentIndex || 0].params.description }}
</div>
</el-tooltip>
@ -146,7 +145,7 @@ defineExpose({
<ft-button v-if="craft?.state === 'PAUSED'" type="primary" size="small" :click-handle="resumeCraftHandle">
继续
</ft-button>
<ft-button v-if="!['READY', 'ERROR', 'FINISHED'].includes(craft?.state)" size="small" :click-handle="stopCraftHandle">
<ft-button v-if="!['RUNNING', 'PAUSED'].includes(craft?.state)" size="small" :click-handle="stopCraftHandle">
停止
</ft-button>
<span v-if="craft?.state === 'FINISHED'">请取走托盘</span>

Loading…
Cancel
Save