pyt
3 天以前 4a364d65d24020dcacab6c1ee86f854d8de8cd36
feat
9个文件已修改
1个文件已添加
964 ■■■■ 已修改文件
culture/src/components/SignatureCanvas.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/router/index.js 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/add.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/components/RecordDetailDialog.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/components/RecordTimeline.vue 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/index.vue 213 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/record.vue 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/views/strain-library/strain-library-manage/service.js 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
culture/src/components/SignatureCanvas.vue
@@ -186,7 +186,7 @@
      
      // 导出图片
      const signatureImage = canvas.toDataURL('image/png')
      this.$emit('confirm', signatureImage)
      this.$emit('confirm', 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg')
    }
  },
  beforeDestroy() {
culture/src/router/index.js
@@ -1,14 +1,14 @@
import Vue from "vue";
import VueRouter from "vue-router";
import Layouts from "../layouts";
import Parent from "../layouts/components/AppContent"
import Parent from "../layouts/components/AppContent";
import store from "../store";
Vue.use(VueRouter);
const originalPush = VueRouter.prototype.push
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
    return originalPush.call(this, location).catch(err => err)
}
  return originalPush.call(this, location).catch((err) => err);
};
/**
 *  path: "/login",   ------页面地址
@@ -79,8 +79,8 @@
                    hide: true,
                },
                component: () => import("../views/projectList/detailProject"),
            }
        ]
      },
    ],
    },
    {
        path: "/system",
@@ -139,7 +139,7 @@
                },
                component: () => import("../views/system/operation-log"),
            },
        ]
    ],
    },
    {
        path: "/strain",
@@ -162,7 +162,8 @@
                            title: "原始细胞库",
                            keepAlive: true,
                        },
                        component: () => import("../views/strain-library/strain-library-manage"),
            component: () =>
              import("../views/strain-library/strain-library-manage"),
                    },
                    {
                        path: "strain-library-manage/add",
@@ -170,9 +171,11 @@
                        meta: {
                            title: "新增原始细胞库",
                            keepAlive: true,
                            hide: true
              hide: true,
                        },
                        component: () => import("../views/strain-library/strain-library-manage/add.vue"),
            component: () =>
              import("../views/strain-library/strain-library-manage/add.vue"),
                    },
                    {
                        path: "strain-library-manage/record",
@@ -180,9 +183,12 @@
                        meta: {
                            title: "出入库记录",
                            keepAlive: true,
                            hide: true
              hide: true,
                        },
                        component: () => import("../views/strain-library/strain-library-manage/record.vue"),
            component: () =>
              import(
                "../views/strain-library/strain-library-manage/record.vue"
              ),
                    },
                    {
                        path: "main-cell-library",
@@ -191,7 +197,8 @@
                            title: "主细胞库",
                            keepAlive: true,
                        },
                        component: () => import("../views/strain-library/main-cell-library"),
            component: () =>
              import("../views/strain-library/main-cell-library"),
                    },
                    {
                        path: "main-cell-library/add",
@@ -199,9 +206,10 @@
                        meta: {
                            title: "新增主细胞",
                            keepAlive: true,
                            hide: true
              hide: true,
                        },
                        component: () => import("../views/strain-library/main-cell-library/add.vue"),
            component: () =>
              import("../views/strain-library/main-cell-library/add.vue"),
                    },
                    {
                        path: "production-cell-library",
@@ -210,7 +218,8 @@
                            title: "生产细胞库",
                            keepAlive: true,
                        },
                        component: () => import("../views/strain-library/production-cell-library"),
            component: () =>
              import("../views/strain-library/production-cell-library"),
                    },
                    {
                        path: "production-cell-library/add",
@@ -218,35 +227,36 @@
                        meta: {
                            title: "新增生产细胞",
                            keepAlive: true,
                            hide: true
              hide: true,
                        },
                        component: () => import("../views/strain-library/production-cell-library/add.vue"),
                    }
                ]
            component: () =>
              import("../views/strain-library/production-cell-library/add.vue"),
          },
        ],
            },
            {
                path: 'pedigree-vhart',
                name: 'PedigreeChart',
        path: "pedigree-vhart",
        name: "PedigreeChart",
                meta: {
                    title: "菌种传代生产谱系图",
                },
                component: () => import("../views/pedigree-chart"),
            },
            {
                path: 'add-pedigree',
                name: 'AddPedigree',
        path: "add-pedigree",
        name: "AddPedigree",
                meta: {
                    title: "新增母代菌种传代生产谱系图",
                    hide: true
          hide: true,
                },
                component: () => import("../views/pedigree-chart/add"),
            },
            {
                path: 'add-progenitor',
                name: 'AddProgenitor',
        path: "add-progenitor",
        name: "AddProgenitor",
                meta: {
                    title: "新增祖代菌种传代生产谱系图",
                    hide: true
          hide: true,
                },
                component: () => import("../views/pedigree-chart/addProgenitor"),
            },
@@ -260,16 +270,16 @@
            //     component: () => import("../views/strain-library/strain-flow-chart"),
            // },
            {
                path: 'breeding-record',
                name: 'BreedingRecord',
        path: "breeding-record",
        name: "BreedingRecord",
                meta: {
                    title: "菌种选育保藏记录",
                },
                component: () => import("../views/strain-library/breeding-record"),
            },
            {
                path: 'add-breeding-record',
                name: 'AddBreedingRecord',
        path: "add-breeding-record",
        name: "AddBreedingRecord",
                meta: {
                    title: "新增菌种选育保藏记录",
                    hide: true,
@@ -277,62 +287,75 @@
                component: () => import("../views/strain-library/breeding-record/add"),
            },
            {
                path: 'validation',
        path: "validation",
                meta: {
                    title: "菌种验证数据资料",
                },
                component: Parent,
                children: [
                    {
                        path: 'primitive-cell',
                        name: 'PrimitiveCell',
            path: "primitive-cell",
            name: "PrimitiveCell",
                        meta: {
                            title: '原始细胞库资料',
              title: "原始细胞库资料",
                        },
                        component: () => import("../views/strain-library/validation/primitive-cell/index.vue")
            component: () =>
              import(
                "../views/strain-library/validation/primitive-cell/index.vue"
              ),
                    },
                    {
                        path: 'add-primitive-cell',
                        name: 'AddPrimitiveCell',
            path: "add-primitive-cell",
            name: "AddPrimitiveCell",
                        meta: {
                            title: '新增原始细胞库资料',
                            hide: true
              title: "新增原始细胞库资料",
              hide: true,
                        },
                        component: () => import("../views/strain-library/validation/primitive-cell/add.vue")
            component: () =>
              import(
                "../views/strain-library/validation/primitive-cell/add.vue"
              ),
                    },
                    {
                        path: 'confirm-detail',
                        name: 'ConfirmDetail',
            path: "confirm-detail",
            name: "ConfirmDetail",
                        meta: {
                            title: '确认原始细胞库资料',
                            hide: true
              title: "确认原始细胞库资料",
              hide: true,
                        },
                        component: () => import("../views/strain-library/validation/primitive-cell/confirm-detail.vue")
            component: () =>
              import(
                "../views/strain-library/validation/primitive-cell/confirm-detail.vue"
              ),
                    },
                    {
                        path: 'chief-cell',
                        name: 'ChiefCell',
            path: "chief-cell",
            name: "ChiefCell",
                        meta: {
                            title: '主细胞库资料'
              title: "主细胞库资料",
                        },
                        component: () => import("../views/strain-library/validation/chief-cell")
                    }
                ]
            component: () =>
              import("../views/strain-library/validation/chief-cell"),
            },
        ]
    }, {
        ],
      },
    ],
  },
  {
        path: "/strainReportLibrary",
        component: Layouts,
        meta: {
            title: "菌种报告库",
        },
        children: [{
    children: [
      {
            path: "reportLibraryOne",
            meta: {
                title: "报告库一",
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOne/index.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOne/index.vue"),
        },
        {
            path: "add",
@@ -341,7 +364,8 @@
                hide: true,
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOne/add.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOne/add.vue"),
        },
        {
            path: "reportLibraryTwo",
@@ -349,7 +373,8 @@
                title: "报告库二",
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOneTWO/index.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOneTWO/index.vue"),
        },
        {
            path: "addTwo",
@@ -358,7 +383,8 @@
                hide: true,
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOneTWO/add.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOneTWO/add.vue"),
        },
        {
            path: "reportLibraryThree",
@@ -366,7 +392,10 @@
                title: "报告库三",
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOneThree/index.vue"),
        component: () =>
          import(
            "../views/strainReportLibrary/reportLibraryOneThree/index.vue"
          ),
        },
        {
            path: "addThree",
@@ -375,7 +404,8 @@
                hide: true,
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOneThree/add.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOneThree/add.vue"),
        },
        {
            path: "reportLibraryFour",
@@ -383,7 +413,8 @@
                title: "报告库四",
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOneFour/index.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOneFour/index.vue"),
        },
        {
            path: "addFour",
@@ -392,9 +423,9 @@
                hide: true,
                keepAlive: true,
            },
            component: () => import("../views/strainReportLibrary/reportLibraryOneFour/add.vue"),
        component: () =>
          import("../views/strainReportLibrary/reportLibraryOneFour/add.vue"),
        },
        ],
    },
    {
@@ -403,23 +434,26 @@
        meta: {
            title: "菌种报告评定",
        },
        children: [{
    children: [
      {
            path: "projectTeamIntegral",
            meta: {
                title: "菌种项目组评定表",
            },
            component: () => import("../views/deliveryAssessment/projectTeamIntegral"),
        component: () =>
          import("../views/deliveryAssessment/projectTeamIntegral"),
        },
        {
            path: "projectTeamIntegral-detail",
            meta: {
                title: "评定详情",
                hide: true
          hide: true,
            },
            component: () => import("../views/deliveryAssessment/projectTeamIntegral/detail.vue"),
        component: () =>
          import("../views/deliveryAssessment/projectTeamIntegral/detail.vue"),
        },
        ]
    }
    ],
  },
];
const router = new VueRouter({
@@ -431,13 +465,13 @@
// 前置路由拦截器
router.beforeEach((to, from, next) => {
    // 设置当前页签名称
    document.title = to.meta.title || '实验室流程';
  document.title = to.meta.title || "实验室流程";
    // 登录验证
    // 排除登录页的校验
    if (to.path === "/login") {
        if (sessionStorage.getItem('token')) {
            next('/projectList');  // 已登录状态访问登录页时重定向到系统首页
    if (sessionStorage.getItem("token")) {
      next("/projectList"); // 已登录状态访问登录页时重定向到系统首页
            return;
        }
        next();
@@ -445,23 +479,26 @@
    }
    // 登录状态校验
    const isAuthenticated = sessionStorage.getItem('token');
  const isAuthenticated = sessionStorage.getItem("token");
    if (!isAuthenticated) {
        next('/login');  // 未登录用户重定向到登录页
    next("/login"); // 未登录用户重定向到登录页
        return;
    }
    // 判断是否拥有要跳转菜单权限
    let menus = store.state.menus
    if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) {
        return
  let menus = store.state.menus;
  if (
    to.meta.hasOwnProperty("privilege") &&
    !menus.includes(to.meta.privilege)
  ) {
    return;
    }
    // 设置标签列表
    if (!to.meta.hide || !to.meta.oneself) {
        let tagList = JSON.parse(sessionStorage.getItem('tagList') || '[]')
    let tagList = JSON.parse(sessionStorage.getItem("tagList") || "[]");
        // 判断是否存在
        let isExist = tagList.some(item => item.path === to.path)
    let isExist = tagList.some((item) => item.path === to.path);
        if (!isExist) {
            // 只保存必要的信息
            const tagInfo = {
@@ -469,26 +506,28 @@
                name: to.name,
                meta: to.meta,
                query: to.query,
            }
            tagList.push(tagInfo)
            sessionStorage.setItem('tagList', JSON.stringify(tagList))
            store.commit('SET_TAGLIST', tagList)
      };
      tagList.push(tagInfo);
      sessionStorage.setItem("tagList", JSON.stringify(tagList));
      store.commit("SET_TAGLIST", tagList);
        }
    }
    // 判断是否需要缓存
    if (to.meta.keepAlive) {
        let keepAliveList = JSON.parse(sessionStorage.getItem('keepAliveList') || '[]')
    let keepAliveList = JSON.parse(
      sessionStorage.getItem("keepAliveList") || "[]"
    );
        // 判断是否已经缓存
        let isExist = keepAliveList.includes(to.name)
    let isExist = keepAliveList.includes(to.name);
        if (!isExist) {
            keepAliveList.push(to.name)
            sessionStorage.setItem('keepAliveList', JSON.stringify(keepAliveList))
            store.commit('SET_KEEPALIVELIST', keepAliveList)
      keepAliveList.push(to.name);
      sessionStorage.setItem("keepAliveList", JSON.stringify(keepAliveList));
      store.commit("SET_KEEPALIVELIST", keepAliveList);
        }
    }
    next()
  next();
});
export default router;
culture/src/views/strain-library/strain-library-manage/add.vue
@@ -1,92 +1,60 @@
<template>
    <Card>
        <!-- <div class="header-title">
            <div class="header-title-left">
                <img src="@/assets/public/headercard.png" />
                <div>新增原始细胞</div>
            </div>
        </div> -->
        <el-form
            :model="form"
            :rules="rules"
            ref="strainForm"
            label-position="top"
            class="strain-form"
        >
        <el-form :model="form" :rules="rules" ref="strainForm" label-position="top" class="strain-form">
            <div class="form-row three-columns">
                <el-form-item label="菌种编号" prop="strainNo" required>
                    <el-input v-model="form.strainNo" placeholder="请输入"></el-input>
                <el-form-item label="菌种编号" prop="strainCode">
                    <el-input v-model="form.strainCode" placeholder="请输入"></el-input>
                </el-form-item>
                <el-form-item label="菌种名称" prop="strainName" required>
                <el-form-item label="菌种名称" prop="strainName">
                    <el-input v-model="form.strainName" placeholder="请输入"></el-input>
                </el-form-item>
                <el-form-item label="菌种来源" prop="source" required>
                    <el-input v-model="form.source" placeholder="请输入"></el-input>
                <el-form-item label="菌种来源" prop="strainSource">
                    <el-input v-model="form.strainSource" placeholder="请输入"></el-input>
                </el-form-item>
            </div>
            <div class="form-row">
                <el-form-item label="鉴定方法" prop="identificationMethod" required>
                    <el-input v-model="form.identificationMethod" placeholder="请输入"></el-input>
                <el-form-item label="鉴定方法" prop="appraisalMethod">
                    <el-input v-model="form.appraisalMethod" placeholder="请输入"></el-input>
                </el-form-item>
            </div>
            <div class="form-row">
                <el-form-item label="特征描述" prop="characteristics" required class="full-width">
                    <el-input
                        type="textarea"
                        v-model="form.characteristics"
                        :rows="4"
                        placeholder="请输入"
                    ></el-input>
                <el-form-item label="特征描述" prop="features" class="full-width">
                    <el-input type="textarea" v-model="form.features" :rows="4" placeholder="请输入"></el-input>
                </el-form-item>
            </div>
            <div class="form-row three-columns">
                <el-form-item label="保存位置" prop="storageLocation" required>
                    <el-input v-model="form.storageLocation" placeholder="请输入"></el-input>
                <el-form-item label="保藏位置" prop="saveLocation">
                    <el-input v-model="form.saveLocation" placeholder="请输入"></el-input>
                </el-form-item>
                <el-form-item label="菌种保存方法" prop="preservationMethod" required>
                    <el-input v-model="form.preservationMethod" placeholder="请输入"></el-input>
                <el-form-item label="菌种保存方法" prop="saveMethod">
                    <el-input v-model="form.saveMethod" placeholder="请输入"></el-input>
                </el-form-item>
                <div class="form-item-placeholder"></div>
            </div>
            <div class="form-row">
                <el-form-item label="备注" prop="remarks" class="full-width">
                    <el-input
                        type="textarea"
                        v-model="form.remarks"
                        :rows="4"
                        placeholder="请输入"
                    ></el-input>
                    <el-input type="textarea" v-model="form.remark" :rows="4" placeholder="请输入"></el-input>
                </el-form-item>
            </div>
            <div class="end-btn" style="margin-top: 38px">
                <el-button type="primary" @click="handleSubmit">提交</el-button>
                <el-button type="primary" @click="handleBatchAdd">批量新增</el-button>
                <el-button @click="handleDraft">存草稿</el-button>
                <el-button type="primary" @click="handleSubmit(0)">提交</el-button>
                <el-button v-if="!$route.query.id" type="primary" @click="handleBatchAdd">批量新增</el-button>
                <el-button @click="handleSubmit(1)">存草稿</el-button>
            </div>
        </el-form>
        <!-- 批量新增弹窗 -->
        <el-dialog
            title="批量新增"
            :visible.sync="batchAddDialogVisible"
            width="520px"
            :close-on-click-modal="false"
            :close-on-press-escape="false"
            custom-class="batch-add-dialog"
        >
        <el-dialog title="批量新增" :visible.sync="batchAddDialogVisible" width="520px" :close-on-click-modal="false"
            :close-on-press-escape="false" custom-class="batch-add-dialog">
            <div class="dialog-content">
                <el-form :model="batchForm" ref="batchFormRef" label-position="top" class="batch-form">
                    <el-form-item
                        label="批量新增数量"
                        prop="count"
                        required
                        :rules="[{ required: true, message: '请输入批量新增数量', trigger: 'blur' }]"
                    >
                    <el-form-item label="批量新增数量" prop="count"
                        :rules="[{ required: true, message: '请输入批量新增数量', trigger: 'blur' }]">
                        <el-input v-model.number="batchForm.count" placeholder="请输入" />
                    </el-form-item>
                </el-form>
@@ -104,18 +72,16 @@
        </el-dialog>
        <!-- 签字确认组件 -->
        <SignatureCanvas
            :visible.sync="signatureVisible"
            @confirm="handleSignatureConfirm"
        />
        <SignatureCanvas :visible.sync="signatureVisible" @confirm="handleSignatureConfirm" />
    </Card>
</template>
<script>
import SignatureCanvas from '@/components/SignatureCanvas.vue'
import { add, edit, getDetail, addBatch } from './service'
export default {
    name: 'AddStrain',
    name: 'StrainLibraryManageAdd',
    components: {
        SignatureCanvas
    },
@@ -128,60 +94,116 @@
                count: ''
            },
            form: {
                strainNo: '',
                strainCode: '',
                strainName: '',
                source: '',
                identificationMethod: '',
                appraisalMethod: '',
                characteristics: '',
                storageLocation: '',
                preservationMethod: '',
                remarks: ''
                remark: ''
            },
            rules: {
                strainNo: [{ required: true, message: '请输入菌种编号', trigger: 'blur' }],
                strainCode: [{
                    validator: (rule, value, callback) => {
                        if (this.currentAction === 'submit' && !value.trim()) {
                            callback(new Error('请输入菌种编号'));
                        } else {
                            callback();
                        }
                    },
                    trigger: 'change'
                }],
                strainName: [{ required: true, message: '请输入菌种名称', trigger: 'blur' }],
                source: [{ required: true, message: '请输入菌种来源', trigger: 'blur' }],
                identificationMethod: [{ required: true, message: '请输入鉴定方法', trigger: 'blur' }],
                characteristics: [{ required: true, message: '请输入特征描述', trigger: 'blur' }],
                storageLocation: [{ required: true, message: '请输入保存位置', trigger: 'blur' }],
                preservationMethod: [{ required: true, message: '请输入菌种保存方法', trigger: 'blur' }]
                strainSource: [{ required: true, message: '请输入菌种来源', trigger: 'blur' }],
                appraisalMethod: [{ required: true, message: '请输入鉴定方法', trigger: 'blur' }],
                features: [{ required: true, message: '请输入特征描述', trigger: 'blur' }],
                saveLocation: [{ required: true, message: '请输入保存位置', trigger: 'blur' }],
                saveMethod: [{ required: true, message: '请输入菌种保存方法', trigger: 'blur' }]
            }
        }
    },
    activated() {
        if (this.$route.query.id) {
            getDetail({ id: this.$route.query.id }).then(res => {
                this.form = res
            })
        }
    },
    watch: {
        '$route.query.id'() {
            this.form = {
                strainCode: '',
                strainName: '',
                source: '',
                appraisalMethod: '',
                characteristics: '',
                storageLocation: '',
                preservationMethod: '',
                remark: ''
            }
        }
    },
    methods: {
        handleSubmit() {
        handleSubmit(isDraft) {
            this.currentAction = 'submit'
            this.$refs.strainForm.validate((valid) => {
                if (valid) {
                    this.currentAction = 'submit'
                    this.signatureVisible = true
                    this.form.isDraft = isDraft
                }
            })
        },
        handleBatchAdd() {
            this.currentAction = 'batchAdd'
            this.$refs.strainForm.validate((valid) => {
                if (valid) {
            this.batchAddDialogVisible = true
                }
            })
        },
        handleConfirmBatchAdd() {
            this.$refs.batchFormRef.validate((valid) => {
                if (valid) {
                    this.currentAction = 'batchAdd'
                    this.batchAddDialogVisible = false
                    this.signatureVisible = true
                }
            })
        },
        handleDraft() {
            // 实现存草稿逻辑
            console.log('save draft', this.form)
        },
        handleSignatureConfirm(signatureImage) {
            this.signatureVisible = false
            this.$router.back()
            if (this.currentAction === 'submit') {
                // 处理提交逻辑
                console.log('submit form with signature:', this.form, signatureImage)
        async handleSignatureConfirm(signatureImage) {
            let requestData = {
                strainCode: this.form.strainCode,
                strainName: this.form.strainName,
                strainSource: this.form.strainSource,
                appraisalMethod: this.form.appraisalMethod,
                features: this.form.features,
                saveLocation: this.form.saveLocation,
                saveMethod: this.form.saveMethod,
                remark: this.form.remark,
                signature: signatureImage,
                type: 1,
            };
            if (this.currentAction === 'batchAdd') {
                requestData.batchCount = this.batchForm.count;
            } else {
                requestData.isDraft = this.form.isDraft
            }
            try {
                if (this.$route.query.id) {
                    requestData.id = this.$route.query.id;
                    await edit(requestData);
            } else if (this.currentAction === 'batchAdd') {
                // 处理批量新增逻辑
                console.log('batch add with signature:', this.batchForm.count, signatureImage)
                    console.log(requestData);
                    await addBatch(requestData);
                } else {
                    await add(requestData);
                }
                this.signatureVisible = false;
                this.$router.back();
                this.$message.success('操作成功');
            } catch (error) {
                this.$message.error('操作失败');
            }
        }
    }
@@ -219,6 +241,7 @@
        }
    }
}
.end-btn{
    display: flex;
    align-items: center;
@@ -231,6 +254,7 @@
        // background: #409EFF; 
    }
}
.strain-form {
    padding: 0 40px;
@@ -241,7 +265,9 @@
        margin-bottom: 24px;
        &.three-columns {
            .el-form-item, .form-item-placeholder {
            .el-form-item,
            .form-item-placeholder {
                flex: 1;
                min-width: 280px;
                
@@ -334,6 +360,7 @@
            color: #606266;
            font-weight: normal;
            padding-bottom: 8px;
            &::before {
                color: #F56C6C;
            }
@@ -341,6 +368,7 @@
        :deep(.el-input) {
            width: 100%;
            input {
            width: 100%;
            }
@@ -350,6 +378,7 @@
    .dialog-notice {
        margin-top: 16px;
        text-align: center;
        p {
            margin: 0;
            line-height: 22px;
culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue
@@ -12,12 +12,12 @@
        <el-form-item label="出库/入库" required>
          <div class="type-buttons">
            <el-button
              :type="formData.type === '出库' ? 'primary' : 'default'"
              @click="formData.type = '出库'"
              :type="formData.type === '1' ? 'primary' : 'default'"
              @click="formData.type = '1'"
            >出库</el-button>
            <el-button
              :type="formData.type === '入库' ? 'primary' : 'default'"
              @click="formData.type = '入库'"
              :type="formData.type === '2' ? 'primary' : 'default'"
              @click="formData.type = '2'"
            >入库</el-button>
          </div>
        </el-form-item>
@@ -27,9 +27,9 @@
            <span>操作人签字</span>
            <el-button type="primary" class="sign-btn" @click="showSignature = true">签名</el-button>
          </template>
          <div class="signature-area" :class="{ 'waiting': !formData.operatorSignature }">
            <template v-if="formData.operatorSignature">
              <img :src="formData.operatorSignature" alt="操作人签字" />
          <div class="signature-area" :class="{ 'waiting': !formData.handleSignature }">
            <template v-if="formData.handleSignature">
              <img :src="formData.handleSignature" alt="操作人签字" />
            </template>
            <template v-else>
              <span class="waiting-text">等待确认</span>
@@ -60,8 +60,8 @@
  data() {
    return {
      formData: {
        type: '出库',
        operatorSignature: ''
        type: '1',
        handleSignature: ''
      },
      showSignature: false
    }
@@ -72,7 +72,7 @@
      this.$emit('close')
    },
    handleConfirm() {
      if (!this.formData.operatorSignature) {
      if (!this.formData.handleSignature) {
        this.$message.warning('请先签名')
        return
      }
@@ -80,7 +80,7 @@
      this.handleClose()
    },
    handleSignatureConfirm(dataUrl) {
      this.formData.operatorSignature = dataUrl
      this.formData.handleSignature = dataUrl
      this.showSignature = false
    }
  }
culture/src/views/strain-library/strain-library-manage/components/RecordDetailDialog.vue
@@ -1,20 +1,14 @@
<template>
    <el-dialog
        title="出/入库详情"
        :visible.sync="visible"
        width="520px"
        :close-on-click-modal="false"
        custom-class="record-detail-dialog"
        @close="handleClose"
    >
    <el-dialog title="出/入库详情" :visible.sync="visible" width="520px" :close-on-click-modal="false"
        custom-class="record-detail-dialog" @close="handleClose" @opened="opened">
        <div class="dialog-content">
            <el-form :model="formData" label-position="top">
                <el-form-item label="出库/入库" required>
                    <div class="type-buttons">
                        <el-button
                            type="primary"
                            @click="handleOutbound"
                        >出库</el-button>
                        <el-button :type="formData.type == '1' ? 'primary' : 'default'"
                            @click="formData.type = '1'">出库</el-button>
                        <el-button :type="formData.type == '2' ? 'primary' : 'default'"
                            @click="formData.type = '2'">入库</el-button>
                    </div>
                </el-form-item>
@@ -30,12 +24,7 @@
                        </div>
                    </el-form-item>
                    <el-form-item
                        v-if="formData.operatorSignature"
                        label="出库时间"
                        required
                        class="time-item"
                    >
                    <el-form-item v-if="formData.operatorSignature" label="出库时间" required class="time-item">
                        <div class="time-value">{{ formData.operateTime }}</div>
                    </el-form-item>
                </div>
@@ -44,7 +33,8 @@
                    <el-form-item required class="signature-item">
                        <template #label>
                            <span>保藏人签字</span>
                            <el-button type="primary" class="edit-sign-btn" @click="showSignature = true">修改签名</el-button>
                            <el-button type="primary" class="edit-sign-btn"
                                @click="showSignature = true">修改签名</el-button>
                        </template>
                        <div class="signature-area" :class="{ 'waiting': !formData.reviewerSignature }">
                            <template v-if="formData.reviewerSignature">
@@ -56,18 +46,14 @@
                        </div>
                    </el-form-item>
                    <el-form-item
                        v-if="formData.reviewerSignature"
                        label="确认时间"
                        required
                        class="time-item"
                    >
                    <el-form-item v-if="formData.reviewerSignature" label="确认时间" required class="time-item">
                        <div class="time-value">{{ formData.confirmTime }}</div>
                    </el-form-item>
                </div>
            </el-form>
        </div>
        <signature-canvas :visible.sync="showSignature" @confirm="handleSignatureConfirm" @cancel="showSignature = false" />
        <signature-canvas :visible.sync="showSignature" @confirm="handleSignatureConfirm"
            @cancel="showSignature = false" />
    </el-dialog>
</template>
@@ -88,7 +74,9 @@
    },
    data() {
        return {
            formData: {},
            formData: {
                type: '1',
            },
            showSignature: false
        }
    },
@@ -101,8 +89,10 @@
        }
    },
    methods: {
        opened() {
            this.formData.type = this.recordData.type
        },
        handleClose() {
            this.$emit('update:visible', false)
            this.$emit('close')
        },
        handleOutbound() {
@@ -156,11 +146,13 @@
    }
    .type-buttons {
        display: flex;
        gap: 12px;
        .el-button {
            width: 80px;
            background: #409EFF;
            border-color: #409EFF;
            color: #FFFFFF;
            &:hover {
                opacity: 0.8;
culture/src/views/strain-library/strain-library-manage/components/RecordTimeline.vue
@@ -1,29 +1,23 @@
<template>
  <div class="record-timeline">
    <el-timeline>
      <el-timeline-item
        v-for="(item, idx) in list"
        :key="idx"
        :type="item.type === '入库' ? 'primary' : 'warning'"
        :color="item.type === '入库' ? '#04A9A7' : '#FF9900'"
        :icon="''"
        :timestamp="''"
      >
      <el-timeline-item v-for="(item, idx) in list" :key="idx" :type="item.type == '2' ? 'primary' : 'warning'"
        :color="item.type == '2' ? '#04A9A7' : '#FF9900'" :icon="''" :timestamp="''">
        <div class="timeline-row">
          <div :class="['left-block', item.type === '入库' ? 'in' : 'out']">
            <div class="type-tag">{{ item.type }}</div>
          <div :class="['left-block', item.type == '2' ? 'in' : 'out']">
            <div class="type-tag">{{ item.type == 2 ? '入库' : '出库' }}</div>
            <div class="info-main">
              <div class="info-title">操作人:{{ item.operator || '--' }}</div>
              <div class="info-time">操作时间:{{ item.operateTime || '--' }}</div>
              <div class="info-title">操作人:{{ item.handleName || '--' }}</div>
              <div class="info-time">操作时间:{{ item.boundTime || '--' }}</div>
            </div>
          </div>
          <div :class="[
            'right-block', 
            item.confirmTime && item.confirmTime !== '--' ? 
              (item.type === '入库' ? 'confirmed-in' : 'confirmed-out') :
              (item.type === '2' ? 'confirmed-in' : 'confirmed-out') :
              'unconfirmed'
          ]">
            <div class="info-title">保藏人:{{ item.reviewer || '--' }}</div>
            <div class="info-title">保藏人:{{ item.preserveName || '--' }}</div>
            <div class="info-time">确认时间:{{ item.confirmTime || '--' }}</div>
          </div>
        </div>
@@ -71,7 +65,8 @@
  width: 12px !important;
  height: 12px !important;
  left: -6px;
  top: 34px !important; /* 微调位置使其看起来完全居中 */
  top: 34px !important;
  /* 微调位置使其看起来完全居中 */
  margin: 0 !important;
  background: #ffffff;
  box-shadow: none !important;
@@ -83,18 +78,23 @@
  border-left: 3px solid #e6e6e6;
  left: -1px;
  top: 0;
  height: 114px; /* 84px + 30px */
  height: 114px;
  /* 84px + 30px */
  z-index: 1;
}
:deep(.el-timeline-item:first-child .el-timeline-item__tail) {
  top: 34px; /* 与节点位置对应 */
  height: 80px; /* 调整为与新节点位置匹配 */
  top: 34px;
  /* 与节点位置对应 */
  height: 80px;
  /* 调整为与新节点位置匹配 */
}
:deep(.el-timeline-item:last-child .el-timeline-item__tail) {
  height: 34px; /* 调整为与新节点位置匹配 */
  display: block !important; /* 确保显示 */
  height: 34px;
  /* 调整为与新节点位置匹配 */
  display: block !important;
  /* 确保显示 */
}
:deep(.el-timeline-item__content) {
@@ -113,18 +113,23 @@
  gap: 14px;
  height: 84px;
  width: 100%;
  flex-wrap: wrap; /* 允许在小屏幕上换行 */
  flex-wrap: wrap;
  /* 允许在小屏幕上换行 */
}
.left-block, .right-block {
.left-block,
.right-block {
  width: 330px;
  border-radius: 10px;
  padding: 0;
  background: #f5f7fa;
  display: flex;
  min-width: 270px; /* 减小最小宽度 */
  max-width: 330px; /* 设置最大宽度 */
  width: 100%; /* 使用百分比宽度 */
  min-width: 270px;
  /* 减小最小宽度 */
  max-width: 330px;
  /* 设置最大宽度 */
  width: 100%;
  /* 使用百分比宽度 */
  height: 84px;
  box-sizing: border-box;
}
@@ -171,7 +176,8 @@
  font-weight: bold;
  color: #fff;
  background: linear-gradient( 180deg, #0ACBCA 0%, #049C9A 100%);
  letter-spacing: 8px; /* 增加字间距 */
  letter-spacing: 8px;
  /* 增加字间距 */
}
.left-block.out .type-tag {
@@ -245,7 +251,9 @@
/* 添加媒体查询,适配小屏幕设备 */
@media screen and (max-width: 1200px) {
  .left-block, .right-block {
  .left-block,
  .right-block {
    min-width: 240px;
  }
  
@@ -256,12 +264,14 @@
@media screen and (max-width: 992px) {
  .timeline-row {
    flex-direction: column; /* 垂直排列 */
    flex-direction: column;
    /* 垂直排列 */
    height: auto;
    gap: 8px;
  }
  
  .left-block, .right-block {
  .left-block,
  .right-block {
    width: 100%;
    max-width: 100%;
  }
culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue
@@ -1,27 +1,21 @@
<template>
    <el-dialog
        title="原始细胞库详情"
        :visible.sync="visible"
        width="70%"
        :close-on-click-modal="false"
        custom-class="strain-detail-dialog"
        append-to-body
        @close="$emit('update:visible', false)"
    >
    <div>
        <el-dialog title="原始细胞库详情" :visible.sync="visible" width="70%" :close-on-click-modal="false"
            custom-class="strain-detail-dialog" @close="$emit('update:visible', false)" @opened="fetchDetail">
        <div class="strain-info">
            <!-- 第一行信息 -->
            <div class="info-row">
                <div class="info-item left-column">
                    <span class="label">菌种编号:</span>
                    <span class="value">{{ detail.strainNo }}</span>
                        <span class="value">{{ detail.strainCode }}</span>
                </div>
                <div class="info-item flex-column">
                    <span class="label">鉴定方法:</span>
                    <span class="value">{{ detail.method }}</span>
                        <span class="value">{{ detail.appraisalMethod }}</span>
                </div>
                <div class="info-item flex-column">
                    <span class="label">保存位置:</span>
                    <span class="value">{{ detail.amount }}</span>
                        <span class="label">保藏位置:</span>
                        <span class="value">{{ detail.saveLocation }}</span>
                </div>
            </div>
            
@@ -33,7 +27,7 @@
                </div>
                <div class="info-item flex-column full-width">
                    <span class="label">特性描述:</span>
                    <span class="value">{{ detail.certificate }}</span>
                        <span class="value">{{ detail.features }}</span>
                </div>
            </div>
            
@@ -41,15 +35,20 @@
            <div class="info-row">
                <div class="info-item left-column">
                    <span class="label">菌种来源:</span>
                    <span class="value">{{ detail.source }}</span>
                        <span class="value">{{ detail.strainSource }}</span>
                </div>
                <div class="info-item flex-column">
                    <span class="label">菌种保存方法:</span>
                    <span class="value">{{ detail.storage }}</span>
                        <span class="value">{{ detail.saveMethod }}</span>
                </div>
                <div class="info-item flex-column">
                    <span class="label">出入库状态:</span>
                    <span class="value">{{ detail.operator }}</span>
                        <span class="value">{{ {
                            1: '已出库',
                            2: '出库待确认',
                            3: '已入库',
                            4: '入库待确认'
                            }[detail.status] || '' }}</span>
                </div>
            </div>
        </div>
@@ -57,38 +56,44 @@
        <div class="record-table">
            <div class="table-title">原始细胞库出/入库记录</div>
            <el-table :data="detail.records" style="width: 100%">
                <el-table-column prop="type" label="出库/入库" />
                <el-table-column prop="operateTime" label="操作时间" />
                <el-table-column prop="operator" label="操作人姓名" />
                <el-table-column prop="reviewer" label="签核确认人姓名" />
                <el-table-column prop="status" label="状态">
                    <el-table-column label="出库/入库">
                    <template #default="{ row }">
                        <el-tag :type="row.status === '已确认' ? 'success' : 'warning'">
                            {{ row.status }}
                            {{ { 1: '出库', 2: '入库' }[row.type] || '' }}
                        </template>
                    </el-table-column>
                    <el-table-column prop="boundTime" label="操作时间" />
                    <el-table-column prop="handleName" label="操作人姓名" />
                    <el-table-column prop="preserveName" label="签核确认人姓名" />
                    <el-table-column label="状态">
                        <template #default="{ row }">
                            <el-tag :type="row.confirmTime ? 'success' : 'warning'">
                                {{ row.confirmTime ? '已确认' : '待确认' }}
                        </el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="100">
                    <template #default="{ row }">
                        <el-button type="text" @click="handleView(row)">详情</el-button>
                            <el-button type="text" @click="handleView(row)">确认</el-button>
                            <el-button style="margin-left: 10px;" type="text" @click="handleView(row)">详情</el-button>
                    </template>
                </el-table-column>
            </el-table>
            <div class="pagination">
                <el-pagination
                    :current-page.sync="currentPage"
                    :page-size="10"
                    layout="total, prev, pager, next"
                    :total="total"
                    @current-change="handlePageChange"
                />
                    <el-pagination :current-page.sync="currentPage" :page-size="10" layout="total, prev, pager, next"
                        :total="total" @current-change="handlePageChange" />
            </div>
        </div>
    </el-dialog>
        <RecordDetailDialog :visible="visibleRecordDetailDialog" :recordData="recordData" @close="visibleRecordDetailDialog = false" />
    </div>
</template>
<script>
import { getDetailById } from '../service'
import RecordDetailDialog from './RecordDetailDialog.vue'
export default {
    components: { RecordDetailDialog },
    name: 'StrainDetail',
    props: {
        visible: {
@@ -102,13 +107,32 @@
    },
    data() {
        return {
            visibleRecordDetailDialog: false,
            recordData: {},
            currentPage: 1,
            total: 0
            total: 0,
            query: {
                endTime: '',
                id: '',
                pageNum: 1,
                pageSize: 10,
                startTime: ''
            }
        }
    },
    methods: {
        fetchDetail() {
            this.query.id = this.detail.id
            getDetailById(this.query).then(res => {
                this.detail.records = res.warehousingList?.records || [];
                this.total = res.warehousingList?.total || 0;
                this.currentPage = res.warehousingList?.current || 1;
            })
        },
        handleView(row) {
            console.log('View record:', row)
            this.visibleRecordDetailDialog = true;
            this.recordData = row;
        },
        handlePageChange(page) {
            this.currentPage = page
culture/src/views/strain-library/strain-library-manage/index.vue
@@ -15,12 +15,7 @@
            </div>
            <!-- 查看全部弹窗 -->
            <el-dialog
                title="菌种源保藏出/入细胞库登记表说明"
                :visible.sync="dialogVisible"
                width="50%"
                class="view-all-dialog"
            >
            <el-dialog title="菌种源保藏出/入细胞库登记表说明" :visible.sync="dialogVisible" width="50%" class="view-all-dialog">
                <div class="dialog-content">
                    <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p>
                    <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p>
@@ -67,23 +62,24 @@
                            草稿箱</div>
                    </div>
                    <div class="flex a-center">
                        <el-button @click="handleNewStrain" class="el-icon-plus" type="primary" style="margin-right: 12px;">新增原始细胞</el-button>
                        <el-button @click="handleBatchAdd" class="el-icon-plus" type="primary">批量新增</el-button>
                        <el-button @click="handleNewStrain" class="el-icon-plus" type="primary"
                            style="margin-right: 12px;">新增原始细胞</el-button>
                        <el-button @click="handleNewStrain" class="el-icon-plus" type="primary">批量新增</el-button>
                    </div>
                </div>
            </template>
            <template #table>
                <el-table-column prop="strainNo" label="菌种编号" />
                <el-table-column prop="strainCode" label="菌种编号" />
                <el-table-column prop="strainName" label="菌种名称" />
                <el-table-column prop="source" label="菌种来源" />
                <el-table-column prop="method" label="鉴定方法" />
                <el-table-column prop="certificate" label="特征描述" />
                <el-table-column prop="storage" label="菌种保存方法" />
                <el-table-column prop="amount" label="保存位置" />
                <el-table-column prop="inventory" label="库存余量" />
                <el-table-column prop="notes" label="备注" />
                <el-table-column prop="status" label="当前状态">
                <el-table-column prop="strainSource" label="菌种来源" />
                <el-table-column prop="appraisalMethod" label="鉴定方法" />
                <el-table-column prop="features" label="特征描述" />
                <el-table-column prop="saveMethod" label="菌种保存方法" />
                <el-table-column prop="saveLocation" label="保藏位置" />
                <el-table-column prop="stock" label="库存余量" />
                <el-table-column prop="remark" label="备注" />
                <el-table-column v-if="currentType === 'list'" prop="status" label="当前状态">
                    <template #default="{ row }">
                        <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag>
                    </template>
@@ -92,25 +88,23 @@
                    <template #default="{ row }">
                        <el-button type="text" @click="handleDetail(row)">详情</el-button>
                        <el-button type="text" @click="handleEdit(row)">编辑</el-button>
                        <el-button type="text" @click="handleRecord(row)">出入库记录</el-button>
                        <el-button v-if="currentType === 'list'" type="text" @click="handleRecord(row)">出入库记录</el-button>
                    </template>
                </el-table-column>
            </template>
        </TableCustom>
        <StrainDetail
            :visible.sync="detailVisible"
            :detail="currentDetail"
        />
        <StrainDetail :visible.sync="detailVisible" :detail="currentDetail" />
    </div>
</template>
<script>
import StrainDetail from './components/StrainDetail.vue'
import { getList } from './service'
export default {
    name: 'StrainLibraryManage',
    components: {
        StrainDetail
        StrainDetail,
    },
    data() {
        return {
@@ -121,78 +115,34 @@
            form: {
                strainNo: '',
                strainName: '',
                status: ''
                status: '',
                type: 1
            },
            queryForm: {
                pageSize: 10,
                pageNum: 1
                pageNum: 1,
            },
            total: 800,
            tableData: [
                {
                    strainNo: 'YX-2024001',
                    strainName: '大肠杆菌',
                    source: '实验室分离',
                    method: '形态学鉴定、生理生化试验',
                    certificate: '革兰氏阴性杆菌,可发酵葡萄糖产酸产气,IMViC试验++--',
                    storage: '斜面培养',
                    amount: 'A区-01-001',
                    inventory: '50',
                    notes: '用于质粒转化',
                    status: '1'
                },
                {
                    strainNo: 'YX-2024002',
                    strainName: '枯草芽孢杆菌',
                    source: '菌种保藏中心',
                    method: '16S rDNA测序',
                    certificate: '革兰氏阳性芽孢杆菌,可水解淀粉,产生溶菌素',
                    storage: '冷冻保存',
                    amount: 'B区-02-005',
                    inventory: '30',
                    notes: '工业发酵菌种',
                    status: '1'
                },
                {
                    strainNo: 'YX-2024003',
                    strainName: '酿酒酵母',
                    source: '发酵工厂',
                    method: '显微镜观察、生理特性',
                    certificate: '椭圆形单细胞真菌,可发酵葡萄糖产生乙醇',
                    storage: '甘油管保存',
                    amount: 'A区-03-002',
                    inventory: '40',
                    notes: '发酵工艺优化',
                    status: '2'
                },
                {
                    strainNo: 'YX-2024004',
                    strainName: '乳酸菌',
                    source: '乳制品分离',
                    method: '生化鉴定、API条',
                    certificate: '革兰氏阳性球菌,产生乳酸,耐酸性强',
                    storage: '冷冻干燥',
                    amount: 'C区-01-003',
                    inventory: '25',
                    notes: '益生菌研究',
                    status: '3'
                },
                {
                    strainNo: 'YX-2024005',
                    strainName: '青霉菌',
                    source: '环境样本',
                    method: '形态学特征、ITS测序',
                    certificate: '丝状真菌,产生蓝绿色分生孢子,可产青霉素',
                    storage: '斜面培养',
                    amount: 'B区-04-001',
                    inventory: '35',
                    notes: '次级代谢产物研究',
                    status: '1'
            tableData: []
                }
            ]
        }
    },
    activated() {
        this.searchData()
    },
    methods: {
        handleRecord(row) {
            this.$router.push({ path: `/strain-library/strain-library-manage/record?id=${row.id}` })
        },
        handleNewStrain() {
            this.$router.push({ path: '/strain-library/strain-library-manage/add' })
        },
        handleEdit(row) {
            this.$router.push({ path: `/strain-library/strain-library-manage/add?id=${row.id}` })
        },
        handleDetail(row) {
            this.currentDetail = row;
            this.detailVisible = true;
        },
        handleViewMore() {
            this.dialogVisible = true;
        },
@@ -205,78 +155,54 @@
            this.searchData()
        },
        searchData() {
            // 模拟搜索逻辑
            const { strainNo, strainName, status } = this.form
            let filteredData = [...this.tableData]
            if (strainNo) {
                filteredData = filteredData.filter(item =>
                    item.strainNo.toLowerCase().includes(strainNo.toLowerCase())
                )
            const params = {
                pageNum: this.queryForm.pageNum,
                pageSize: this.queryForm.pageSize,
                strainCode: this.form.strainNo,
                strainName: this.form.strainName,
                isDraft: this.currentType === 'draft' ? 1 : 0,
                status: {
                    '1': 3,
                    '2': 1,
                    '3': 4
                }[this.form.status] || ''
            };
            getList(params).then(res => {
                if (res.code === 200) {
                    this.tableData = res.data.records;
                    this.total = res.data.total;
            }
            if (strainName) {
                filteredData = filteredData.filter(item =>
                    item.strainName.toLowerCase().includes(strainName.toLowerCase())
                )
            }
            if (status) {
                filteredData = filteredData.filter(item =>
                    item.status === status
                )
            }
            this.total = filteredData.length
            // 实际项目中这里应该调用API
            console.log('搜索条件:', this.form)
            console.log('分页信息:', this.queryForm)
        },
        handleNewStrain() {
            this.$router.push('/strain-library/strain-library-manage/add')
            // Implement new strain logic
        },
        handleBatchAdd() {
            // Implement batch add logic
        },
        handleDetail(row) {
            this.currentDetail = row;
            this.detailVisible = true;
        },
        handleEdit(row) {
            // Implement edit logic
        },
        handleRecord(row) {
            this.$router.push({
                path: '/strain-library/strain-library-manage/record',
                query: {
                    id: row.strainNo
                }
            })
            }).catch(err => {
                this.$message.error('数据加载失败');
            });
        },
        handleCurrentChange(page) {
            this.queryForm.pageNum = page
            // Implement page change logic
            this.queryForm.pageNum = page;
            this.searchData();
        },
        handleSizeChange(size) {
            this.queryForm.pageSize = size
            // Implement size change logic
            this.queryForm.pageSize = size;
            this.searchData();
        },
        handleTypeChange(type) {
            this.currentType = type;
            // Implement type change logic
            this.searchData()
        },
        getStatusType(status) {
            const types = {
                1: 'success',
                2: 'info',
                3: 'warning'
                1: 'warning',
                2: 'warning',
                3: 'success',
                4: 'success'
            }
            return types[status] || 'info'
        },
        getStatusText(status) {
            const texts = {
                1: '已入库',
                2: '已出库',
                3: '入库待确认'
                1: '已出库',
                2: '出库待确认',
                3: '已入库',
                4: '入库待确认'
            }
            return texts[status] || '未知状态'
        }
@@ -466,5 +392,4 @@
        }
    }
}
</style>
culture/src/views/strain-library/strain-library-manage/record.vue
@@ -7,15 +7,15 @@
                <div class="info-row">
                    <div class="info-item left-column">
                        <span class="label">菌种编号:</span>
                        <span class="value">{{ detail.strainNo }}</span>
                        <span class="value">{{ detail.strainCode }}</span>
                    </div>
                    <div class="info-item flex-column">
                        <span class="label">鉴定方法:</span>
                        <span class="value">{{ detail.method }}</span>
                        <span class="value">{{ detail.appraisalMethod }}</span>
                    </div>
                    <div class="info-item flex-column">
                        <span class="label">保藏位置:</span>
                        <span class="value">{{ detail.amount }}</span>
                        <span class="value">{{ detail.saveLocation }}</span>
                    </div>
                </div>
                
@@ -27,7 +27,7 @@
                    </div>
                    <div class="info-item flex-column full-width">
                        <span class="label">特性描述:</span>
                        <span class="value">{{ detail.certificate }}</span>
                        <span class="value">{{ detail.features }}</span>
                    </div>
                </div>
                
@@ -35,11 +35,11 @@
                <div class="info-row">
                    <div class="info-item left-column">
                        <span class="label">菌种来源:</span>
                        <span class="value">{{ detail.source }}</span>
                        <span class="value">{{ detail.strainSource }}</span>
                    </div>
                    <div class="info-item flex-column">
                        <span class="label">菌种保存方法:</span>
                        <span class="value">{{ detail.storage }}</span>
                        <span class="value">{{ detail.saveMethod }}</span>
                    </div>
                </div>
            </div>
@@ -85,7 +85,6 @@
            </template> 
            <template #tableCustom v-if="currentType === 'timeline'">
                <record-timeline :list="timelineList" />
            </template>
        </TableCustom>
@@ -108,6 +107,7 @@
import RecordDetailDialog from './components/RecordDetailDialog.vue'
import AddRecordDialog from './components/AddRecordDialog.vue'
import RecordTimeline from './components/RecordTimeline.vue'
import { timeList,getDetail,addWarehousing } from './service'
export default {
    name: 'StrainRecord',
@@ -164,23 +164,25 @@
                    status: '已确认'
                }
            ],
            timelineList: [],
            dialogVisible: false,
            currentRecord: {},
            addDialogVisible: false
        }
    },
    computed: {
        timelineList() {
            // 可根据需要处理数据格式,这里直接用 recordList
            return this.recordList.map(item => ({
                ...item,
                confirmTime: item.confirmTime || item.operateTime // 若无确认时间则用操作时间
            }))
        }
        // timelineList() {
        //     // 可根据需要处理数据格式,这里直接用 recordList
        //     return this.recordList.map(item => ({
        //         ...item,
        //         confirmTime: item.confirmTime || item.operateTime // 若无确认时间则用操作时间
        //     }))
        // }
    },
    created() {
        // 获取路由参数中的菌种信息
        const strainId = this.$route.query.id
        this.queryForm.id = strainId
        if (strainId) {
            this.getStrainDetail(strainId)
            this.getRecordList()
@@ -189,21 +191,15 @@
    methods: {
        getStrainDetail(id) {
            // 这里应该调用接口获取菌种详情
            // 暂时使用模拟数据
            this.detail = {
                strainNo: '3418732431',
                strainName: '名称名称名称',
                source: '来源11111111111',
                method: '1231231',
                certificate: '特性描述',
                storage: '方法方法',
                amount: '位置位置位置位置位置位置位置位置',
                operator: '入库'
            }
            getDetail({id}).then(res => {
                this.detail = res
            })
        },
        getRecordList() {
            // 这里应该调用接口获取出入库记录
            // 暂时使用已有模拟数据
            timeList(this.queryForm).then(res => {
               this.timelineList = res.data
            })
            this.total = this.recordList.length
        },
        handleView(row) {
@@ -262,10 +258,10 @@
            this.getRecordList()
        },
        handleAddRecordConfirm(record) {
            // 这里可以将新记录添加到 recordList 或调用后端API
            this.$message.success('新增出入库记录成功')
            // 例如:this.recordList.push(record)
            this.getRecordList() // 或刷新列表
            addWarehousing({...record,trainLibraryId: this.$route.query.id}).then(res => {
                this.$message.success('操作成功')
                this.getRecordList()
            })
        },
        goBack() {
            this.$router.go(-1)
culture/src/views/strain-library/strain-library-manage/service.js
New file
@@ -0,0 +1,41 @@
import axios from '@/utils/request';
// 列表
export const getList = (data) => {
  return axios.post('/api/t-train-library/pageList', { ...data })
}
// 新增
export const add = (data) => {
  return axios.post('/api/t-train-library/add', { ...data })
}
// 编辑
export const edit = (data) => {
  return axios.post('/api/t-train-library/update', { ...data })
}
// 查看详情
export const getDetail = (params) => {
  return axios.get('/open/t-train-library/getDetailEditById', { params })
}
// 批量新增
export const addBatch = (data) => {
  return axios.post('/api/t-train-library/addBatch', data)
}
// 查看菌种库详情
export const getDetailById = (data) => {
  return axios.post('/open/t-train-library/getDetailById', { ...data })
}
// 获取菌种库出入库时间轴列表
export const timeList = (data) => {
  return axios.post('/api/t-train-library/timeList?id='+data.id, { ...data })
}
// 新增菌种库出入记录
export const addWarehousing = (data) => {
  return axios.post('/open/t-train-library/addWarehousing', { ...data })
}