feat 方案模板 和 项目管理

This commit is contained in:
Asoka.Wang 2025-06-20 13:34:35 +08:00
parent 66a0121ca3
commit 35018c3e3f
6 changed files with 265 additions and 86 deletions

View File

@ -1,21 +1,21 @@
import { RequestParams } from './http-client' import { RequestParams } from './http-client'
import { ContentType, HttpClient } from './http-client' import { ContentType, HttpClient } from './http-client'
import type { import type {
CultureProtocolDto, ProtocolDto,
CultureProtocolPageInput, ProtocolPageInput,
CultureProtocolPageResponse, ProtocolPageResponse,
CultureProtocolOutput, ProtocolOutput,
CultureProtocolAddInput, ProtocolAddInput,
CultureProtocolUpdateInput ProtocolUpdateInput
} from '/@/api/types/cultureprotocol' } from '/@/api/types/protocolType'
export class CultureProtocolApi extends HttpClient { export class ProtocolApi extends HttpClient {
/** /**
* *
*/ */
getPage = (data: CultureProtocolPageInput, params: RequestParams = {}) => getPage = (data: ProtocolPageInput, params: RequestParams = {}) =>
this.request<CultureProtocolPageResponse>({ this.request<ProtocolPageResponse>({
path: `/api/admin/culture-protocol/get-page`, path: `/api/admin/protocol/get-page`,
method: 'POST', method: 'POST',
body: data, body: data,
type: ContentType.Json, type: ContentType.Json,
@ -26,8 +26,8 @@ export class CultureProtocolApi extends HttpClient {
* *
*/ */
get = (params: { id: number }, requestParams: RequestParams = {}) => get = (params: { id: number }, requestParams: RequestParams = {}) =>
this.request<CultureProtocolOutput>({ this.request<ProtocolOutput>({
path: `/api/admin/culture-protocol/get`, path: `/api/admin/protocol/get`,
method: 'GET', method: 'GET',
query: { id: params.id }, query: { id: params.id },
...requestParams, ...requestParams,
@ -36,9 +36,9 @@ export class CultureProtocolApi extends HttpClient {
/** /**
* *
*/ */
add = (data: CultureProtocolAddInput, params: RequestParams = {}) => add = (data: ProtocolAddInput, params: RequestParams = {}) =>
this.request<any>({ this.request<any>({
path: `/api/admin/culture-protocol/add`, path: `/api/admin/protocol/add`,
method: 'POST', method: 'POST',
body: data, body: data,
type: ContentType.Json, type: ContentType.Json,
@ -48,9 +48,9 @@ export class CultureProtocolApi extends HttpClient {
/** /**
* *
*/ */
update = (data: CultureProtocolUpdateInput, params: RequestParams = {}) => update = (data: ProtocolUpdateInput, params: RequestParams = {}) =>
this.request<any>({ this.request<any>({
path: `/api/admin/culture-protocol/update`, path: `/api/admin/protocol/update`,
method: 'PUT', method: 'PUT',
body: data, body: data,
type: ContentType.Json, type: ContentType.Json,
@ -62,7 +62,7 @@ export class CultureProtocolApi extends HttpClient {
*/ */
softDelete = (params: { id: number }, requestParams: RequestParams = {}) => softDelete = (params: { id: number }, requestParams: RequestParams = {}) =>
this.request<any>({ this.request<any>({
path: `/api/admin/culture-protocol/soft-delete`, path: `/api/admin/protocol/soft-delete`,
method: 'DELETE', method: 'DELETE',
query: params, query: params,
...requestParams, ...requestParams,
@ -73,7 +73,7 @@ export class CultureProtocolApi extends HttpClient {
*/ */
copy = (params: { id: number; reactorId: number }, requestParams: RequestParams = {}) => copy = (params: { id: number; reactorId: number }, requestParams: RequestParams = {}) =>
this.request<any>({ this.request<any>({
path: `/api/admin/culture-protocol/copy`, path: `/api/admin/protocol/copy`,
method: 'POST', method: 'POST',
body: params, body: params,
type: ContentType.Json, type: ContentType.Json,
@ -85,7 +85,7 @@ export class CultureProtocolApi extends HttpClient {
*/ */
toggleStatus = (params: { id: number; isEnabled: boolean }, requestParams: RequestParams = {}) => toggleStatus = (params: { id: number; isEnabled: boolean }, requestParams: RequestParams = {}) =>
this.request<any>({ this.request<any>({
path: `/api/admin/culture-protocol/toggle-status`, path: `/api/admin/protocol/toggle-status`,
method: 'POST', method: 'POST',
query: params, query: params,
...requestParams, ...requestParams,

View File

@ -3,7 +3,7 @@ import { ServiceRequestPage } from './pageInput'
import { PageResponse } from './pageResponse' import { PageResponse } from './pageResponse'
// 过滤条件 // 过滤条件
export interface CultureProtocolFilter { export interface ProtocolFilter {
/** 设备编号 */ /** 设备编号 */
keyWord?: string | null keyWord?: string | null
/** 开始时间 */ /** 开始时间 */
@ -18,11 +18,11 @@ export interface CultureProtocolFilter {
/** /**
* *
*/ */
export interface CultureProtocolPageDto { export interface ProtocolPageDto {
/** 主键ID */ /** 主键ID */
id: number id: number
/** 培养方案名称 */ /** 培养方案名称 */
cultureProtocolName: string ProtocolName: string
/** 反应器ID */ /** 反应器ID */
equReactorId: number equReactorId: number
/** 补料秤ID */ /** 补料秤ID */
@ -51,11 +51,11 @@ export interface CultureProtocolPageDto {
feedingTaskCount: number feedingTaskCount: number
} }
export interface CultureProtocolDto { export interface ProtocolDto {
/** 主键ID */ /** 主键ID */
id: number id: number
/** 培养方案名称 */ /** 培养方案名称 */
cultureProtocolName: string protocolName: string
/** 反应器ID */ /** 反应器ID */
equReactorId?: number equReactorId?: number
/** 补料秤ID */ /** 补料秤ID */
@ -87,7 +87,7 @@ export interface AutoGlucoseFeedingRule {
/** 主键ID */ /** 主键ID */
id: number id: number
/** 培养方案ID */ /** 培养方案ID */
cultureProtocolId: number protocolId: number
/** 培养开始天数 */ /** 培养开始天数 */
cultureDayStarting: number cultureDayStarting: number
/** 培养结束天数 */ /** 培养结束天数 */
@ -107,7 +107,7 @@ export interface FeedingTask {
/** 主键ID */ /** 主键ID */
id: number id: number
/** 培养方案ID */ /** 培养方案ID */
cultureProtocolId: number protocolId: number
/** 补料泵编号 */ /** 补料泵编号 */
feedingPumpNo: number feedingPumpNo: number
/** 培养天数 */ /** 培养天数 */
@ -127,7 +127,7 @@ export interface FixedFeedingPump {
/** 主键ID */ /** 主键ID */
id: number id: number
/** 培养方案ID */ /** 培养方案ID */
cultureProtocolId?: number protocolId?: number
/** 配置ID */ /** 配置ID */
configId?: number configId?: number
/** 补料泵编号 */ /** 补料泵编号 */
@ -146,9 +146,9 @@ export interface FixedFeedingPump {
isGlucose?: boolean isGlucose?: boolean
} }
export type CultureProtocolPageInput = ServiceRequestPage<CultureProtocolFilter> export type ProtocolPageInput = ServiceRequestPage<ProtocolFilter>
export type CultureProtocolPageResponse = ServiceResponse<PageResponse<CultureProtocolPageDto>>; export type ProtocolPageResponse = ServiceResponse<PageResponse<ProtocolPageDto>>;
export type CultureProtocolOutput = ServiceResponse<CultureProtocolDto>; export type ProtocolOutput = ServiceResponse<ProtocolDto>;
export type CultureProtocolAddInput = CultureProtocolDto; export type ProtocolAddInput = ProtocolDto;
export type CultureProtocolUpdateInput = CultureProtocolDto; export type ProtocolUpdateInput = ProtocolDto;

View File

@ -207,6 +207,8 @@ const getPrincipalOptions = async () => {
id: item.id, id: item.id,
name: item.name name: item.name
})) || [] })) || []
} catch (error) { } catch (error) {
console.error('获取用户列表失败:', error) console.error('获取用户列表失败:', error)
} }

View File

@ -9,9 +9,9 @@
<div class="form-section"> <div class="form-section">
<el-row :gutter="25"> <el-row :gutter="25">
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12"> <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
<el-form-item label="模板名称" prop="cultureProtocolName" <el-form-item label="模板名称" prop="protocolName"
:rules="[{ required: true, message: '请输入模板名称', trigger: ['blur', 'change'] }]"> :rules="[{ required: true, message: '请输入模板名称', trigger: ['blur', 'change'] }]">
<el-input v-model="form.cultureProtocolName" clearable placeholder="请输入模板名称" /> <el-input v-model="form.protocolName" clearable placeholder="请输入模板名称" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12"> <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
@ -298,16 +298,16 @@
</div> </div>
</template> </template>
<script lang="ts" setup name="admin/culture-protocol/form"> <script lang="ts" setup name="admin/protocol/form">
import { reactive, toRefs, ref, getCurrentInstance, onMounted, watch, computed, nextTick } from 'vue' import { reactive, toRefs, ref, getCurrentInstance, onMounted, watch, computed, nextTick } from 'vue'
import { CultureProtocolApi } from '/@/api/admin/CultureProtocolApi' import { ProtocolApi } from '/@/api/admin/ProtocolApi'
import { ReactorApi } from '/@/api/admin/ReactorApi' import { ReactorApi } from '/@/api/admin/ReactorApi'
import { UspscaleApi } from '/@/api/admin/UspscaleApi' import { UspscaleApi } from '/@/api/admin/UspscaleApi'
import { ItemDefFeedingMediumApi } from '/@/api/admin/item-def-feeding-medium' import { ItemDefFeedingMediumApi } from '/@/api/admin/item-def-feeding-medium'
import { ItemDefBagApi } from '/@/api/admin/item-def-bag' import { ItemDefBagApi } from '/@/api/admin/item-def-bag'
import { PumpApi } from '/@/api/admin/PumpApi' 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 { ProtocolDto } from '/@/api/types/protocolType'
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import { toOptionsByValue } from '/@/utils/enum' import { toOptionsByValue } from '/@/utils/enum'
import { EnumFeedingType, EnumFeedingOperator, EnumFeedingCalculationMode } from '/@/api/admin/enum-contracts' import { EnumFeedingType, EnumFeedingOperator, EnumFeedingCalculationMode } from '/@/api/admin/enum-contracts'
@ -335,7 +335,7 @@ const state = reactive({
id: 0, id: 0,
form: { form: {
id: 0, id: 0,
cultureProtocolName: '', protocolName: '',
equReactorId: undefined, equReactorId: undefined,
equFeedingScaleId: undefined, equFeedingScaleId: undefined,
days: 0, days: 0,
@ -349,7 +349,7 @@ const state = reactive({
autoGlucoseFeedingRules: [], autoGlucoseFeedingRules: [],
feedingTasks: [], feedingTasks: [],
fixedFeedingPumps: [] fixedFeedingPumps: []
} as CultureProtocolDto, } as ProtocolDto,
reactorOptions: [] as Array<{ id: number; name: string; needExternalPump: boolean; spec: string; pumpSpeed1: number; pumpSpeed2: number; pumpSpeed3: number; pumpSpeed4: number; pumpSpeed5: number; pumpSpeed6: number; pumpSpeed7: number; pumpSpeed8: number; pump1ConfigId: number; pump2ConfigId: number; pump3ConfigId: number; pump4ConfigId: number; pump5ConfigId: number; pump6ConfigId: number; pump7ConfigId: number; pump8ConfigId: number }>, reactorOptions: [] as Array<{ id: number; name: string; needExternalPump: boolean; spec: string; pumpSpeed1: number; pumpSpeed2: number; pumpSpeed3: number; pumpSpeed4: number; pumpSpeed5: number; pumpSpeed6: number; pumpSpeed7: number; pumpSpeed8: number; pump1ConfigId: number; pump2ConfigId: number; pump3ConfigId: number; pump4ConfigId: number; pump5ConfigId: number; pump6ConfigId: number; pump7ConfigId: number; pump8ConfigId: number }>,
scaleOptions: [] as Array<{ id: number; name: string }>, scaleOptions: [] as Array<{ id: number; name: string }>,
mediumOptions: [] as Array<{ id: number; name: string; glucoseConc: number; isGlucose: boolean; }>, mediumOptions: [] as Array<{ id: number; name: string; glucoseConc: number; isGlucose: boolean; }>,
@ -361,7 +361,7 @@ const state = reactive({
feedingTypeOptions: toOptionsByValue(EnumFeedingType), feedingTypeOptions: toOptionsByValue(EnumFeedingType),
feedingOperatorOptions: toOptionsByValue(EnumFeedingOperator), feedingOperatorOptions: toOptionsByValue(EnumFeedingOperator),
feedingCalculationModeOptions: toOptionsByValue(EnumFeedingCalculationMode), feedingCalculationModeOptions: toOptionsByValue(EnumFeedingCalculationMode),
cultureProtocol: null as any Protocol: null as any
}) })
const { form } = toRefs(state) const { form } = toRefs(state)
@ -369,14 +369,14 @@ const activeTab = ref('basic')
const lastActiveTab = ref('basic') const lastActiveTab = ref('basic')
const feedingTaskActiveTab = ref('') const feedingTaskActiveTab = ref('')
const defaultPumps = [ const defaultPumps = [
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 1, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 1, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 2, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 2, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 3, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 3, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 4, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 4, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 5, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 5, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 6, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 6, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 7, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }, { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 7, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false },
{ id: 0, feedingPumpName: '', cultureProtocolId: undefined, configId: undefined, feedingPumpNo: 8, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false } { id: 0, feedingPumpName: '', ProtocolId: undefined, configId: undefined, feedingPumpNo: 8, itemDefBagID: undefined, itemDefFeedingMediumID: undefined, equPumpId: undefined, isGlucose: false }
] ]
onMounted(() => { onMounted(() => {
@ -402,9 +402,9 @@ const open = async (id?: number) => {
// //
if (id) { if (id) {
const res = await new CultureProtocolApi().get({ id: id }, { loading: true }) const res = await new ProtocolApi().get({ id: id }, { loading: true })
if (res?.success) { if (res?.success) {
const formData = { ...res.data } as CultureProtocolDto const formData = { ...res.data } as ProtocolDto
formData.feedingTasks = formData.feedingTasks || [] formData.feedingTasks = formData.feedingTasks || []
formData.autoGlucoseFeedingRules = formData.autoGlucoseFeedingRules || [] formData.autoGlucoseFeedingRules = formData.autoGlucoseFeedingRules || []
formData.fixedFeedingPumps = formData.fixedFeedingPumps || [] formData.fixedFeedingPumps = formData.fixedFeedingPumps || []
@ -418,7 +418,7 @@ const open = async (id?: number) => {
// //
state.form = { state.form = {
id: 0, id: 0,
cultureProtocolName: '', protocolName: '',
equReactorId: undefined, equReactorId: undefined,
equFeedingScaleId: undefined, equFeedingScaleId: undefined,
days: 0, days: 0,
@ -456,7 +456,7 @@ const onSure = async () => {
if (valid) { if (valid) {
state.sureLoading = true state.sureLoading = true
try { try {
const api = new CultureProtocolApi() const api = new ProtocolApi()
const res = state.form.id const res = state.form.id
? await api.update(state.form) ? await api.update(state.form)
: await api.add(state.form) : await api.add(state.form)
@ -489,7 +489,7 @@ const reset = () => {
} }
state.form = { state.form = {
id: 0, id: 0,
cultureProtocolName: '', protocolName: '',
equReactorId: undefined, equReactorId: undefined,
equFeedingScaleId: undefined, equFeedingScaleId: undefined,
days: 0, days: 0,
@ -540,7 +540,7 @@ const handleTabClick = async (tab: any, event: any) => {
function addTaskByPump(pumpNo: number) { function addTaskByPump(pumpNo: number) {
state.form.feedingTasks.push({ state.form.feedingTasks.push({
id: 0, id: 0,
cultureProtocolId: 0, protocolId: 0,
feedingPumpNo: pumpNo, feedingPumpNo: pumpNo,
day: 0, day: 0,
feedingTime: '', feedingTime: '',
@ -564,7 +564,7 @@ function removeTaskByPump(pumpNo: number, index: number) {
const addRule = () => { const addRule = () => {
state.form.autoGlucoseFeedingRules.push({ state.form.autoGlucoseFeedingRules.push({
id: 0, id: 0,
cultureProtocolId: 0, protocolId: 0,
cultureDayStarting: 0, cultureDayStarting: 0,
cultureDayEnding: 0, cultureDayEnding: 0,
lowerLimit: 0, lowerLimit: 0,
@ -610,7 +610,7 @@ const checkPumps = () => {
const checkGlucose = () => { const checkGlucose = () => {
let valid = true let valid = true
state.form.autoGlucoseFeedingRules.forEach(rule => { state.form.autoGlucoseFeedingRules.forEach((rule: any) => {
if (rule.cultureDayStarting > rule.cultureDayEnding) { if (rule.cultureDayStarting > rule.cultureDayEnding) {
valid = false valid = false
proxy.$modal.msgError('培养天数(开始)不能大于培养天数(结束)') proxy.$modal.msgError('培养天数(开始)不能大于培养天数(结束)')
@ -678,9 +678,8 @@ const handleMediumChange = (index: number) => {
}) })
} }
} }
// //
const medium = state.form.fixedFeedingPumps.find(item => const medium = state.form.fixedFeedingPumps.find((item: any) =>
item.itemDefFeedingMediumID !== undefined && item.itemDefFeedingMediumID !== undefined &&
item.itemDefFeedingMediumID === row.itemDefFeedingMediumID && item.itemDefFeedingMediumID === row.itemDefFeedingMediumID &&
item.feedingPumpNo !== row.feedingPumpNo item.feedingPumpNo !== row.feedingPumpNo
@ -733,8 +732,8 @@ function addDayCopy(row: any, pumpNo: number) {
newRow.feedingPumpNo = pumpNo; newRow.feedingPumpNo = pumpNo;
state.form.feedingTasks.push(newRow); state.form.feedingTasks.push(newRow);
// //
const tasks = state.form.feedingTasks.filter(t => t.feedingPumpNo === pumpNo); const tasks = state.form.feedingTasks.filter((t: any) => t.feedingPumpNo === pumpNo);
tasks.sort((a, b) => Number(a.day) - Number(b.day)); tasks.sort((a: any, b: any) => Number(a.day) - Number(b.day));
// //
let i = 0; let i = 0;
for (let idx = 0; idx < state.form.feedingTasks.length; idx++) { for (let idx = 0; idx < state.form.feedingTasks.length; idx++) {
@ -747,7 +746,7 @@ function addDayCopy(row: any, pumpNo: number) {
// //
function pasteFeedingTime(row: any, pumpNo: number) { function pasteFeedingTime(row: any, pumpNo: number) {
const time = row.feedingTime; const time = row.feedingTime;
state.form.feedingTasks.forEach(task => { state.form.feedingTasks.forEach((task: any) => {
if (task.feedingPumpNo === pumpNo && task !== row) { if (task.feedingPumpNo === pumpNo && task !== row) {
task.feedingTime = time; task.feedingTime = time;
} }
@ -757,7 +756,7 @@ function pasteFeedingTime(row: any, pumpNo: number) {
// //
function pasteFeedingType(row: any, pumpNo: number) { function pasteFeedingType(row: any, pumpNo: number) {
const type = row.feedingType; const type = row.feedingType;
state.form.feedingTasks.forEach(task => { state.form.feedingTasks.forEach((task: any) => {
if (task.feedingPumpNo === pumpNo && task !== row) { if (task.feedingPumpNo === pumpNo && task !== row) {
task.feedingType = type; task.feedingType = type;
handleFeedingTypeChange(task, type); // handleFeedingTypeChange(task, type); //
@ -768,7 +767,7 @@ function pasteFeedingType(row: any, pumpNo: number) {
// //
function pasteFeedingVolume(row: any, pumpNo: number) { function pasteFeedingVolume(row: any, pumpNo: number) {
const volume = row.feedingVolume; const volume = row.feedingVolume;
state.form.feedingTasks.forEach(task => { state.form.feedingTasks.forEach((task: any) => {
if (task.feedingPumpNo === pumpNo && task !== row) { if (task.feedingPumpNo === pumpNo && task !== row) {
task.feedingVolume = volume; task.feedingVolume = volume;
} }
@ -915,7 +914,7 @@ const getConfigOptions = async () => {
} }
function getTasksByPumpNo(pumpNo: number) { function getTasksByPumpNo(pumpNo: number) {
return state.form.feedingTasks.filter(task => task.feedingPumpNo === pumpNo) return state.form.feedingTasks.filter((task: any) => task.feedingPumpNo === pumpNo)
} }
// //

View File

@ -0,0 +1,132 @@
<template>
<el-dialog
v-model="visible"
:title="title"
width="500px"
:before-close="handleClose"
destroy-on-close
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="反应器" prop="reactorId">
<el-select
v-model="form.reactorId"
placeholder="请选择反应器"
style="width: 100%"
filterable
>
<el-option
v-for="item in reactorOptions"
:key="item.id"
:label="`${item.name} - ${item.spec}`"
:value="item.id"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="handleConfirm" :loading="loading">
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, nextTick } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
interface ReactorOption {
id: number
name: string
spec: string
}
interface FormData {
reactorId: number | null
remark: string
}
interface Props {
title?: string
reactorOptions?: ReactorOption[]
}
const props = withDefaults(defineProps<Props>(), {
title: '选择反应器',
reactorOptions: () => []
})
const emit = defineEmits<{
confirm: [data: FormData]
}>()
const visible = ref(false)
const loading = ref(false)
const formRef = ref<FormInstance>()
const form = reactive<FormData>({
reactorId: null,
remark: ''
})
const rules: FormRules = {
reactorId: [
{ required: true, message: '请选择反应器', trigger: 'change' }
]
}
const open = () => {
visible.value = true
//
nextTick(() => {
form.reactorId = null
form.remark = ''
formRef.value?.clearValidate()
})
}
const handleClose = () => {
visible.value = false
loading.value = false
}
const handleConfirm = async () => {
try {
await formRef.value?.validate()
loading.value = true
console.log('弹窗确认, 发送的数据:', {
reactorId: form.reactorId,
remark: form.remark
})
emit('confirm', {
reactorId: form.reactorId,
remark: form.remark
})
} catch (error) {
console.error('表单验证失败:', error)
}
}
const closeDialog = () => {
loading.value = false
visible.value = false
}
defineExpose({
open,
closeDialog
})
</script>
<style scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@ -35,7 +35,7 @@
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="ele-Search" @click="onQuery">查询</el-button> <el-button type="primary" icon="ele-Search" @click="onQuery">查询</el-button>
<el-button v-auth="'api:admin:culture-protocol:add'" type="primary" icon="ele-Plus" @click="onAdd">新增</el-button> <el-button v-auth="'api:admin:protocol:add'" type="primary" icon="ele-Plus" @click="onAdd">新增</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
</el-card> </el-card>
@ -53,7 +53,7 @@
row-key="id" row-key="id"
border border
> >
<el-table-column prop="cultureProtocolName" label="模板名称" min-width="150" show-overflow-tooltip /> <el-table-column prop="protocolName" label="模板名称" min-width="150" show-overflow-tooltip />
<el-table-column prop="equReactorId" label="反应器" width="120" align="center" show-overflow-tooltip> <el-table-column prop="equReactorId" label="反应器" width="120" align="center" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
{{ getReactorDescription(row.equReactorId) }} {{ getReactorDescription(row.equReactorId) }}
@ -77,7 +77,7 @@
<el-table-column label="操作" width="240" fixed="right" header-align="center" align="center"> <el-table-column label="操作" width="240" fixed="right" header-align="center" align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-button <el-button
v-if="auth('api:admin:culture-protocol:update')" v-if="auth('api:admin:protocol:update')"
icon="ele-EditPen" icon="ele-EditPen"
size="small" size="small"
text text
@ -86,7 +86,7 @@
>编辑</el-button >编辑</el-button
> >
<el-button <el-button
v-if="auth('api:admin:culture-protocol:copy')" v-if="auth('api:admin:protocol:copy')"
icon="ele-CopyDocument" icon="ele-CopyDocument"
size="small" size="small"
text text
@ -95,7 +95,7 @@
>复制</el-button >复制</el-button
> >
<el-button <el-button
v-if="auth('api:admin:culture-protocol:soft-delete')" v-if="auth('api:admin:protocol:soft-delete')"
icon="ele-Delete" icon="ele-Delete"
size="small" size="small"
text text
@ -122,28 +122,41 @@
</div> </div>
</el-card> </el-card>
<culture-protocol-form ref="protocolFormRef" :title="state.protocolFormTitle" @ok="Query" /> <protocol-form ref="protocolFormRef" :title="state.protocolFormTitle" @ok="Query" />
<!-- 反应器选择弹窗 -->
<reactor-select-dialog
ref="reactorSelectDialogRef"
:title="state.reactorDialogTitle"
:reactor-options="state.reactorOptions"
@confirm="handleReactorSelect"
/>
</MyLayout> </MyLayout>
</template> </template>
<script lang="ts" setup name="admin/culture-protocol"> <script lang="ts" setup name="admin/protocol">
import { ref, reactive, onMounted, getCurrentInstance, onBeforeMount, defineAsyncComponent } from 'vue' import { ref, reactive, onMounted, getCurrentInstance, onBeforeMount, defineAsyncComponent } from 'vue'
import { CultureProtocolApi } from '/@/api/admin/CultureProtocolApi' import { ProtocolApi } from '/@/api/admin/ProtocolApi'
import type { CultureProtocolDto, CultureProtocolPageInput, CultureProtocolPageDto } from '/@/api/types/cultureprotocol' import type { ProtocolDto, ProtocolPageInput, ProtocolPageDto } from '/@/api/types/protocolType'
import eventBus from '/@/utils/mitt' import eventBus from '/@/utils/mitt'
import { auth } from '/@/utils/authFunction' import { auth } from '/@/utils/authFunction'
import { ReactorApi } from '/@/api/admin/ReactorApi' import { ReactorApi } from '/@/api/admin/ReactorApi'
// //
const CultureProtocolForm = defineAsyncComponent(() => import('./components/culture-protocol-form.vue')) const ProtocolForm = defineAsyncComponent(() => import('./components/protocol-form.vue'))
const ReactorSelectDialog = defineAsyncComponent(() => import('./components/reactor-select-dialog.vue'))
const { proxy } = getCurrentInstance() as any const { proxy } = getCurrentInstance() as any
const protocolFormRef = ref() const protocolFormRef = ref()
const reactorSelectDialogRef = ref()
const state = reactive({ const state = reactive({
loading: false, loading: false,
protocolFormTitle: '', protocolFormTitle: '',
reactorDialogTitle: '',
copyId: null as number | null,
currentOperation: null as { type: 'copy' | 'delete', row: ProtocolDto } | null,
filter: { filter: {
keyWord: '', keyWord: '',
stDate: '', stDate: '',
@ -154,8 +167,8 @@ const state = reactive({
pageInput: { pageInput: {
currentPage: 1, currentPage: 1,
pageSize: 20, pageSize: 20,
} as CultureProtocolPageInput, } as ProtocolPageInput,
protocolListData: [] as Array<CultureProtocolPageDto>, protocolListData: [] as Array<ProtocolPageDto>,
showQuery: true, showQuery: true,
showProtocolList: true, showProtocolList: true,
reactorOptions: [] as Array<{ id: number; name: string; spec: string }>, reactorOptions: [] as Array<{ id: number; name: string; spec: string }>,
@ -173,7 +186,7 @@ const onQuery = () => {
const Query = async () => { const Query = async () => {
state.loading = true state.loading = true
state.pageInput.filter = state.filter state.pageInput.filter = state.filter
const res = await new CultureProtocolApi().getPage(state.pageInput).catch(() => { const res = await new ProtocolApi().getPage(state.pageInput).catch(() => {
state.loading = false state.loading = false
}) })
@ -183,24 +196,26 @@ const Query = async () => {
} }
const onAdd = () => { const onAdd = () => {
state.protocolFormTitle = '新增培养方案' state.protocolFormTitle = '新增方案模板'
protocolFormRef.value?.open() protocolFormRef.value?.open()
} }
const onEdit = (row: CultureProtocolDto) => { const onEdit = (row: ProtocolDto) => {
state.protocolFormTitle = '编辑培养方案' state.protocolFormTitle = '编辑方案模板'
protocolFormRef.value?.open(row) protocolFormRef.value?.open(row)
} }
const onCopy = (row: CultureProtocolDto) => { const onCopy = (row: ProtocolDto) => {
state.protocolFormTitle = '复制培养方案' state.reactorDialogTitle = '复制方案模板 - 选择目标反应器'
protocolFormRef.value?.open(row, true) state.currentOperation = { type: 'copy', row }
state.copyId = row.id
reactorSelectDialogRef.value?.open()
} }
const onDelete = (row: CultureProtocolDto) => { const onDelete = (row: ProtocolDto) => {
proxy.$modal.confirm('确认要删除该记录吗?').then(async () => { proxy.$modal.confirm('确认要删除该记录吗?').then(async () => {
try { try {
const res = await new CultureProtocolApi().softDelete({ id: row.id! }) const res = await new ProtocolApi().softDelete({ id: row.id! })
if (res.success) { if (res.success) {
proxy.$modal.msgSuccess('删除成功') proxy.$modal.msgSuccess('删除成功')
Query() Query()
@ -259,6 +274,37 @@ const onReset = () => {
} }
onQuery() onQuery()
} }
//
const handleReactorSelect = async (data: { reactorId: number | null, remark: string }) => {
if (!state.currentOperation) return
try {
const { type, row } = state.currentOperation
if (type === 'copy' && data.reactorId) {
const res = await new ProtocolApi().copy({
id: state.copyId!,
reactorId: data.reactorId
})
console.log('API 调用结果:', res)
if (res.success) {
proxy.$modal.msgSuccess('复制成功')
Query()
}
}
//
reactorSelectDialogRef.value?.closeDialog()
state.currentOperation = null
} catch (error) {
console.error('操作失败:', error)
reactorSelectDialogRef.value?.closeDialog()
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>