add 补料任务添加2

This commit is contained in:
Asoka.Wang 2025-06-18 16:48:27 +08:00
parent 1396148d98
commit 915ca512f5
2 changed files with 227 additions and 21 deletions

View File

@ -131,3 +131,8 @@ export const EnumPressureUnit = {
Psi: { name: 'psi', value: 'psi', desc: 'psi' },
Kpa: { name: 'kPa', value: 'kPa', desc: 'kPa' },
}
export const EnumFeedingType = {
Percentage: { name: 'Percentage', value: 1, desc: '百分比' },
Volume: { name: 'Volume', value: 2, desc: '体积' },
}

View File

@ -62,8 +62,8 @@
v-if="state.form.equReactorId && state.reactorOptions.find(r => r.id === state.form.equReactorId)?.needExternalPump === true"
label="外置泵" prop="equPumpId" min-width="100">
<template #default="scope">
<el-select v-model="scope.row.equPumpId" placeholder="请选择外置泵" style="width: 100%" clearable filterable
@change="() => handlePumpChange(scope.$index)">
<el-select v-model="scope.row.equPumpId" placeholder="请选择外置泵" style="width: 100%" clearable
filterable @change="() => handlePumpChange(scope.$index)">
<el-option v-for="item in state.pumpOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</template>
@ -110,39 +110,87 @@
<!-- 补料任务 -->
<el-tab-pane label="补料任务" name="tasks">
<div class="form-section">
<el-tabs v-model="feedingTaskActiveTab" type="card" v-if="feedingPumpTabs.length">
<el-tab-pane
v-for="pump in feedingPumpTabs"
:key="pump.feedingPumpNo"
:label="pump.feedingPumpName + (pump.mediumName ? '' + pump.mediumName + '' : '')"
:name="String(pump.feedingPumpNo)"
>
<el-table :data="getTasksByPumpNo(pump.feedingPumpNo)" border style="width: 100%">
<el-table-column label="培养天数" prop="day" width="100">
<el-tabs v-model="feedingTaskActiveTab" type="border-card" class="feeding-task-tabs"
v-if="feedingPumpTabs.length">
<el-tab-pane v-for="pump in feedingPumpTabs" :key="pump.feedingPumpNo"
:label="`${pump.feedingPumpName}${pump.mediumName ? ' / ' + pump.mediumName : ''}`"
:name="String(pump.feedingPumpNo)">
<div style="text-align: left; margin-bottom: 6px;">
<el-button type="primary" icon="ele-Plus" @click="addTaskByPump(pump.feedingPumpNo)">添加任务</el-button>
</div>
<el-table :data="getTasksByPumpNo(pump.feedingPumpNo)" border stripe size="small"
style="width: 100%; margin-bottom: 10px; border-radius: 8px; box-shadow: 0 2px 8px #e0e7ef; overflow: hidden; max-height: 400px;"
class="pretty-table" :height="400">
<el-table-column label="天数" prop="day" width="200" align="center" header-align="center">
<template #default="scope">
<el-input-number v-model="scope.row.day" :min="1" style="width: 100%" placeholder="天数" />
<div style="display: flex; align-items: center; justify-content: center; gap: 6px; height: 32px;">
<el-input-number v-model="scope.row.day" :min="1" style="width: 190px; height: 28px;" placeholder="天数" />
<el-button size="mini" type="primary" style="padding: 0 8px; height: 28px; display: flex; align-items: center; justify-content: center; font-size: 13px;" @click="addDayCopy(scope.row, pump.feedingPumpNo)">
<el-icon style="margin-right:2px;"><Plus /></el-icon>
</el-button>
</div>
</template>
</el-table-column>
<el-table-column label="补料时间" prop="feedingTime" width="120">
<el-table-column label="补料时间" prop="feedingTime" min-width="100" align="center"
header-align="center">
<template #default="scope">
<el-time-picker v-model="scope.row.feedingTime" format="HH:mm" style="width: 100%" placeholder="补料时间" />
<div style="display: flex; align-items: center; gap: 4px; justify-content: center;">
<el-time-picker v-model="scope.row.feedingTime" format="HH:mm:ss" style="width: 100%;" placeholder="补料时间" />
<el-tooltip content="将当前时间批量赋值给本泵所有任务" placement="top">
<el-button size="mini" style="padding: 0 6px; height: 28px; display: flex; align-items: center; justify-content: center;" @click="pasteFeedingTime(scope.row, pump.feedingPumpNo)">
<el-icon><DocumentCopy /></el-icon>
</el-button>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column label="补料体积" prop="feedingVolume" width="120">
<el-table-column label="补料类型" prop="feedingType" min-width="100">
<template #default="scope">
<el-input-number v-model="scope.row.feedingVolume" :min="0" :precision="2" style="width: 100%" placeholder="补料体积" />
<div style="display: flex; align-items: center; gap: 4px; justify-content: center;">
<el-select v-model="scope.row.feedingType" placeholder="请选择补料类型" clearable style="width: 100%"
@change="handleFeedingTypeChange(scope.row, $event)">
<el-option v-for="item in state.feedingTypeOptions" :key="item.value"
:label="item.label" :value="item.value" />
</el-select>
<el-tooltip content="将当前类型批量赋值给本泵所有任务" placement="top">
<el-button size="mini" style="padding: 0 6px; height: 28px; display: flex; align-items: center;" @click="pasteFeedingType(scope.row, pump.feedingPumpNo)">
<el-icon><DocumentCopy /></el-icon>
</el-button>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="80">
<el-table-column label="补料体积" prop="feedingVolume" min-width="100" align="center"
header-align="center">
<template #default="scope">
<el-button type="danger" icon="ele-Delete" circle @click="removeTaskByPump(pump.feedingPumpNo, scope.$index)" v-if="getTasksByPumpNo(pump.feedingPumpNo).length > 1" />
<div style="display: flex; align-items: center; gap: 4px; justify-content: center;">
<el-input-number v-model="scope.row.feedingVolume"
v-bind="getFeedingVolumeProps(scope.row)"
style="width: 100%" placeholder="补料体积" />
<el-tooltip content="将当前体积批量赋值给本泵所有任务" placement="top">
<el-button size="mini" style="padding: 0 6px; height: 28px; display: flex; align-items: center;" @click="pasteFeedingVolume(scope.row, pump.feedingPumpNo)">
<el-icon><DocumentCopy /></el-icon>
</el-button>
</el-tooltip>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="80" align="right" header-align="center">
<template #default="scope">
<el-button type="danger" icon="ele-Delete" circle size="mini"
@click="removeTaskByPump(pump.feedingPumpNo, scope.$index)"
v-if="getTasksByPumpNo(pump.feedingPumpNo).length > 1" class="pretty-delete-btn" />
</template>
</el-table-column>
<template #empty>
<div style="text-align:center;color:#bbb;padding:20px 0;">暂无任务</div>
</template>
</el-table>
<el-button type="primary" icon="ele-Plus" class="mt-2" @click="addTaskByPump(pump.feedingPumpNo)">添加任务</el-button>
</el-tab-pane>
</el-tabs>
<div v-else>请先在"固定补料泵"选择补料培养基</div>
<div v-else style="color:#bbb;text-align:center;padding:30px 0;">请先在"固定补料泵"选择补料培养基</div>
</div>
</el-tab-pane>
@ -209,6 +257,10 @@ import { PumpApi } from '/@/api/admin/PumpApi'
import { UspFeedingConfigApi } from '/@/api/admin/UspFeedingConfigApi'
import type { CultureProtocolDto } from '/@/api/types/cultureprotocol'
import { ElMessageBox, ElMessage } from 'element-plus'
import { toOptionsByValue } from '/@/utils/enum'
import { EnumFeedingType } from '/@/api/admin/enum-contracts'
import { DocumentCopy, Plus } from '@element-plus/icons-vue'
const { proxy } = getCurrentInstance() as any
defineProps({
@ -251,6 +303,7 @@ const state = reactive({
cellTypeOptions: [],
configOptions: [] as Array<{ id: number; name: string; isTwo: number; }>,
selectedReactor: null as any,
feedingTypeOptions: toOptionsByValue(EnumFeedingType)
})
const { form } = toRefs(state)
@ -296,7 +349,7 @@ function addTaskByPump(pumpNo: number) {
feedingPumpNo: pumpNo,
day: 0,
feedingTime: '',
feedingType: 0,
feedingType: 1,
feedingVolumePercent: 0,
feedingVolume: 0
})
@ -489,6 +542,25 @@ const checkPumps = () => {
//
const onSure = async () => {
if (!formRef.value) return
state.form.feedingTasks.forEach(task => {
if (task.feedingTime) {
// Date
let dateObj = typeof task.feedingTime === 'string'
? new Date(`1970-01-01T${task.feedingTime}`)
: task.feedingTime;
if (dateObj instanceof Date && !isNaN(dateObj.getTime())) {
const h = String(dateObj.getHours()).padStart(2, '0');
const m = String(dateObj.getMinutes()).padStart(2, '0');
const s = String(dateObj.getSeconds()).padStart(2, '0');
task.feedingTime = `${h}:${m}:${s}`;
} else if (typeof task.feedingTime === 'string' && task.feedingTime.length >= 8) {
//
task.feedingTime = task.feedingTime.slice(0, 8);
}
}
});
await formRef.value.validate(async (valid: boolean) => {
if (valid) {
state.sureLoading = true
@ -710,6 +782,91 @@ const handleMediumChange = (index: number) => {
}
}
// feedingType
function handleFeedingTypeChange(row: any, val: number | string | undefined): void {
const type = Number(val);
if (type === 1) {
// 0-100
if (typeof row.feedingVolume === 'number') {
let v = Math.round(row.feedingVolume * 100) / 100;
if (v < 0) v = 0;
if (v > 100) v = 100;
row.feedingVolume = v;
} else {
row.feedingVolume = 0;
}
} else if (type === 2) {
//
if (typeof row.feedingVolume === 'number') {
let v = Math.floor(row.feedingVolume);
if (v < 0) v = 0;
row.feedingVolume = v;
} else {
row.feedingVolume = 0;
}
}
}
//
function getFeedingVolumeProps(row: any) {
if (row.feedingType === 1) {
return { min: 0, max: 100, precision: 2, step: 0.01 };
return { min: 0, max: 100, precision: 2 };
} else if (row.feedingType === 2) {
return { min: 0, precision: 0 };
}
return { min: 0 };
}
// +1
function addDayCopy(row: any, pumpNo: number) {
const newRow = { ...row, day: Number(row.day) + 1 };
newRow.id = 0;
newRow.feedingPumpNo = pumpNo;
state.form.feedingTasks.push(newRow);
//
const tasks = state.form.feedingTasks.filter(t => t.feedingPumpNo === pumpNo);
tasks.sort((a, b) => Number(a.day) - Number(b.day));
//
let i = 0;
for (let idx = 0; idx < state.form.feedingTasks.length; idx++) {
if (state.form.feedingTasks[idx].feedingPumpNo === pumpNo) {
state.form.feedingTasks[idx] = tasks[i++];
}
}
}
//
function pasteFeedingTime(row: any, pumpNo: number) {
const time = row.feedingTime;
state.form.feedingTasks.forEach(task => {
if (task.feedingPumpNo === pumpNo && task !== row) {
task.feedingTime = time;
}
});
}
//
function pasteFeedingType(row: any, pumpNo: number) {
const type = row.feedingType;
state.form.feedingTasks.forEach(task => {
if (task.feedingPumpNo === pumpNo && task !== row) {
task.feedingType = type;
handleFeedingTypeChange(task, type); //
}
});
}
//
function pasteFeedingVolume(row: any, pumpNo: number) {
const volume = row.feedingVolume;
state.form.feedingTasks.forEach(task => {
if (task.feedingPumpNo === pumpNo && task !== row) {
task.feedingVolume = volume;
}
});
}
defineExpose({
open
})
@ -730,6 +887,18 @@ defineExpose({
}
}
.feeding-task-tabs {
margin-bottom: 0;
.el-tabs__header {
margin-bottom: 10px;
}
.el-tab-pane {
padding: 0 0 10px 0;
}
}
.rule-item,
.task-item,
.pump-item {
@ -750,4 +919,36 @@ defineExpose({
.mt-2 {
margin-top: 8px;
}
.pretty-table {
border-radius: 8px;
box-shadow: 0 2px 8px #e0e7ef;
overflow: hidden;
margin-bottom: 10px;
.el-table__header th {
background: #f0f3fa;
color: #333;
font-weight: bold;
font-size: 15px;
border-bottom: 1.5px solid #e0e7ef;
}
.el-table__body tr:hover>td {
background: #e6f7ff !important;
}
.el-table__cell {
padding: 6px 0;
}
}
.pretty-delete-btn {
transition: background 0.2s;
&:hover {
background: #ffeded !important;
color: #f56c6c !important;
}
}
</style>