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' }, Psi: { name: 'psi', value: 'psi', desc: 'psi' },
Kpa: { name: 'kPa', value: 'kPa', desc: 'kPa' }, 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" v-if="state.form.equReactorId && state.reactorOptions.find(r => r.id === state.form.equReactorId)?.needExternalPump === true"
label="外置泵" prop="equPumpId" min-width="100"> label="外置泵" prop="equPumpId" min-width="100">
<template #default="scope"> <template #default="scope">
<el-select v-model="scope.row.equPumpId" placeholder="请选择外置泵" style="width: 100%" clearable filterable <el-select v-model="scope.row.equPumpId" placeholder="请选择外置泵" style="width: 100%" clearable
@change="() => handlePumpChange(scope.$index)"> filterable @change="() => handlePumpChange(scope.$index)">
<el-option v-for="item in state.pumpOptions" :key="item.id" :label="item.name" :value="item.id" /> <el-option v-for="item in state.pumpOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select> </el-select>
</template> </template>
@ -110,39 +110,87 @@
<!-- 补料任务 --> <!-- 补料任务 -->
<el-tab-pane label="补料任务" name="tasks"> <el-tab-pane label="补料任务" name="tasks">
<div class="form-section"> <div class="form-section">
<el-tabs v-model="feedingTaskActiveTab" type="card" v-if="feedingPumpTabs.length"> <el-tabs v-model="feedingTaskActiveTab" type="border-card" class="feeding-task-tabs"
<el-tab-pane v-if="feedingPumpTabs.length">
v-for="pump in feedingPumpTabs" <el-tab-pane v-for="pump in feedingPumpTabs" :key="pump.feedingPumpNo"
:key="pump.feedingPumpNo" :label="`${pump.feedingPumpName}${pump.mediumName ? ' / ' + pump.mediumName : ''}`"
:label="pump.feedingPumpName + (pump.mediumName ? '' + pump.mediumName + '' : '')" :name="String(pump.feedingPumpNo)">
: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>
<el-table :data="getTasksByPumpNo(pump.feedingPumpNo)" border style="width: 100%"> </div>
<el-table-column label="培养天数" prop="day" width="100"> <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"> <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> </template>
</el-table-column> </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"> <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> </template>
</el-table-column> </el-table-column>
<el-table-column label="补料体积" prop="feedingVolume" width="120">
<el-table-column label="补料类型" prop="feedingType" min-width="100">
<template #default="scope"> <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> </template>
</el-table-column> </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"> <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> </template>
</el-table-column> </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-table>
<el-button type="primary" icon="ele-Plus" class="mt-2" @click="addTaskByPump(pump.feedingPumpNo)">添加任务</el-button>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<div v-else>请先在"固定补料泵"选择补料培养基</div> <div v-else style="color:#bbb;text-align:center;padding:30px 0;">请先在"固定补料泵"选择补料培养基</div>
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -209,6 +257,10 @@ import { PumpApi } from '/@/api/admin/PumpApi'
import { UspFeedingConfigApi } from '/@/api/admin/UspFeedingConfigApi' import { UspFeedingConfigApi } from '/@/api/admin/UspFeedingConfigApi'
import type { CultureProtocolDto } from '/@/api/types/cultureprotocol' import type { CultureProtocolDto } from '/@/api/types/cultureprotocol'
import { ElMessageBox, ElMessage } from 'element-plus' 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 const { proxy } = getCurrentInstance() as any
defineProps({ defineProps({
@ -251,6 +303,7 @@ const state = reactive({
cellTypeOptions: [], cellTypeOptions: [],
configOptions: [] as Array<{ id: number; name: string; isTwo: number; }>, configOptions: [] as Array<{ id: number; name: string; isTwo: number; }>,
selectedReactor: null as any, selectedReactor: null as any,
feedingTypeOptions: toOptionsByValue(EnumFeedingType)
}) })
const { form } = toRefs(state) const { form } = toRefs(state)
@ -296,7 +349,7 @@ function addTaskByPump(pumpNo: number) {
feedingPumpNo: pumpNo, feedingPumpNo: pumpNo,
day: 0, day: 0,
feedingTime: '', feedingTime: '',
feedingType: 0, feedingType: 1,
feedingVolumePercent: 0, feedingVolumePercent: 0,
feedingVolume: 0 feedingVolume: 0
}) })
@ -489,6 +542,25 @@ const checkPumps = () => {
// //
const onSure = async () => { const onSure = async () => {
if (!formRef.value) return 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) => { await formRef.value.validate(async (valid: boolean) => {
if (valid) { if (valid) {
state.sureLoading = true 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({ defineExpose({
open 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, .rule-item,
.task-item, .task-item,
.pump-item { .pump-item {
@ -750,4 +919,36 @@ defineExpose({
.mt-2 { .mt-2 {
margin-top: 8px; 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> </style>