From 4a364d65d24020dcacab6c1ee86f854d8de8cd36 Mon Sep 17 00:00:00 2001 From: pyt <626651354@qq.com> Date: 星期一, 19 五月 2025 09:05:19 +0800 Subject: [PATCH] feat --- culture/src/views/strain-library/strain-library-manage/index.vue | 229 ++---- culture/src/views/strain-library/strain-library-manage/components/RecordDetailDialog.vue | 58 - culture/src/components/SignatureCanvas.vue | 2 culture/src/views/strain-library/strain-library-manage/add.vue | 219 ++++--- culture/src/router/index.js | 905 +++++++++++++++------------- culture/src/views/strain-library/strain-library-manage/service.js | 41 + culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue | 210 +++--- culture/src/views/strain-library/strain-library-manage/record.vue | 56 culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue | 22 culture/src/views/strain-library/strain-library-manage/components/RecordTimeline.vue | 98 +- 10 files changed, 948 insertions(+), 892 deletions(-) diff --git a/culture/src/components/SignatureCanvas.vue b/culture/src/components/SignatureCanvas.vue index f856bc8..e996394 100644 --- a/culture/src/components/SignatureCanvas.vue +++ b/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() { diff --git a/culture/src/router/index.js b/culture/src/router/index.js index 2d85a1d..83f0c9e 100644 --- a/culture/src/router/index.js +++ b/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", ------页面地址 @@ -24,471 +24,510 @@ */ const routes = [ - { - path: "/", - redirect: "/login", + { + path: "/", + redirect: "/login", + }, + { + path: "/login", + meta: { + title: "登录", + oneself: true, + hide: true, }, - { - path: "/login", + component: () => import("../views/login"), + }, + { + path: "/projectList", + meta: { + title: "项目组管理", + }, + component: Layouts, + children: [ + { + path: "list", + name: "ProjectList", meta: { - title: "登录", - oneself: true, - hide: true, + title: "菌种库项目组管理", }, - component: () => import("../views/login"), - }, - { - path: "/projectList", + component: () => import("../views/projectList"), + }, + { + path: "addProject", + name: "AddProject", meta: { - title: "项目组管理", + title: "新增菌种库项目组", + hide: true, + keepAlive: true, }, - component: Layouts, - children: [ - { - path: "list", - name: "ProjectList", - meta: { - title: "菌种库项目组管理", - }, - component: () => import("../views/projectList"), - }, - { - path: "addProject", - name: "AddProject", - meta: { - title: "新增菌种库项目组", - hide: true, - keepAlive: true, - }, - component: () => import("../views/projectList/addProject"), - }, - { - path: "editProject", - name: "EditProject", - meta: { - title: "编辑菌种库项目组", - hide: true, - }, - component: () => import("../views/projectList/editProject"), - }, - { - path: "detailProject", - name: "DetailProject", - meta: { - title: "菌种库项目组详情", - hide: true, - }, - component: () => import("../views/projectList/detailProject"), - } - ] - }, - { - path: "/system", + component: () => import("../views/projectList/addProject"), + }, + { + path: "editProject", + name: "EditProject", meta: { - title: "系统管理", + title: "编辑菌种库项目组", + hide: true, }, - component: Layouts, - children: [ - { - path: "user", - name: "User", - meta: { - title: "人员管理", - }, - component: () => import("../views/system/user"), - }, - { - path: "role", - name: "Role", - meta: { - title: "角色管理", - }, - component: () => import("../views/system/role"), - }, - { - path: "add-role", - name: "AddRole", - meta: { - title: "新增角色", - hide: true, - }, - component: () => import("../views/system/role/add"), - }, - { - path: "edit-role", - name: "EditRole", - meta: { - title: "编辑角色", - hide: true, - }, - component: () => import("../views/system/role/edit"), - }, - { - path: "detail-role", - name: "DetailRole", - meta: { - title: "角色详情", - hide: true, - }, - component: () => import("../views/system/role/detail"), - }, - { - path: "operation-log", - meta: { - title: "操作日志", - }, - component: () => import("../views/system/operation-log"), - }, - ] - }, - { - path: "/strain", - component: Layouts, + component: () => import("../views/projectList/editProject"), + }, + { + path: "detailProject", + name: "DetailProject", meta: { - title: "菌种库", + title: "菌种库项目组详情", + hide: true, + }, + component: () => import("../views/projectList/detailProject"), + }, + ], + }, + { + path: "/system", + meta: { + title: "系统管理", + }, + component: Layouts, + children: [ + { + path: "user", + name: "User", + meta: { + title: "人员管理", + }, + component: () => import("../views/system/user"), + }, + { + path: "role", + name: "Role", + meta: { + title: "角色管理", + }, + component: () => import("../views/system/role"), + }, + { + path: "add-role", + name: "AddRole", + meta: { + title: "新增角色", + hide: true, + }, + component: () => import("../views/system/role/add"), + }, + { + path: "edit-role", + name: "EditRole", + meta: { + title: "编辑角色", + hide: true, + }, + component: () => import("../views/system/role/edit"), + }, + { + path: "detail-role", + name: "DetailRole", + meta: { + title: "角色详情", + hide: true, + }, + component: () => import("../views/system/role/detail"), + }, + { + path: "operation-log", + meta: { + title: "操作日志", + }, + component: () => import("../views/system/operation-log"), + }, + ], + }, + { + path: "/strain", + component: Layouts, + meta: { + title: "菌种库", + }, + children: [ + { + path: "/strain-library", + component: Parent, + meta: { + title: "菌种库管理", }, children: [ - { - path: "/strain-library", - component: Parent, - meta: { - title: "菌种库管理", - }, - children: [ - { - path: "strain-library-manage", - name: "StrainLibraryManage", - meta: { - title: "原始细胞库", - keepAlive: true, - }, - component: () => import("../views/strain-library/strain-library-manage"), - }, - { - path: "strain-library-manage/add", - name: "StrainLibraryManageAdd", - meta: { - title: "新增原始细胞库", - keepAlive: true, - hide: true - }, - component: () => import("../views/strain-library/strain-library-manage/add.vue"), - }, - { - path: "strain-library-manage/record", - name: "StrainRecord", - meta: { - title: "出入库记录", - keepAlive: true, - hide: true - }, - component: () => import("../views/strain-library/strain-library-manage/record.vue"), - }, - { - path: "main-cell-library", - name: "MainCellLibrary", - meta: { - title: "主细胞库", - keepAlive: true, - }, - component: () => import("../views/strain-library/main-cell-library"), - }, - { - path: "main-cell-library/add", - name: "MainCellLibraryAdd", - meta: { - title: "新增主细胞", - keepAlive: true, - hide: true - }, - component: () => import("../views/strain-library/main-cell-library/add.vue"), - }, - { - path: "production-cell-library", - name: "ProductionCellLibrary", - meta: { - title: "生产细胞库", - keepAlive: true, - }, - component: () => import("../views/strain-library/production-cell-library"), - }, - { - path: "production-cell-library/add", - name: "ProductionCellLibraryAdd", - meta: { - title: "新增生产细胞", - keepAlive: true, - hide: true - }, - component: () => import("../views/strain-library/production-cell-library/add.vue"), - } - ] - }, - { - path: 'pedigree-vhart', - name: 'PedigreeChart', - meta: { - title: "菌种传代生产谱系图", - }, - component: () => import("../views/pedigree-chart"), - }, - { - path: 'add-pedigree', - name: 'AddPedigree', - meta: { - title: "新增母代菌种传代生产谱系图", - hide: true - }, - component: () => import("../views/pedigree-chart/add"), - }, - { - path: 'add-progenitor', - name: 'AddProgenitor', - meta: { - title: "新增祖代菌种传代生产谱系图", - hide: true - }, - component: () => import("../views/pedigree-chart/addProgenitor"), - }, - // { - // path: "strain-flow-chart", - // name: "StrainFlowChart", - // meta: { - // title: "菌种传代产生流程图", - // keepAlive: true, - // }, - // component: () => import("../views/strain-library/strain-flow-chart"), - // }, - { - path: 'breeding-record', - name: 'BreedingRecord', - meta: { - title: "菌种选育保藏记录", - }, - component: () => import("../views/strain-library/breeding-record"), - }, - { - path: 'add-breeding-record', - name: 'AddBreedingRecord', - meta: { - title: "新增菌种选育保藏记录", - hide: true, - }, - component: () => import("../views/strain-library/breeding-record/add"), - }, - { - path: 'validation', - meta: { - title: "菌种验证数据资料", - }, - component: Parent, - children: [ - { - path: 'primitive-cell', - name: 'PrimitiveCell', - meta: { - title: '原始细胞库资料', - }, - component: () => import("../views/strain-library/validation/primitive-cell/index.vue") - }, - { - path: 'add-primitive-cell', - name: 'AddPrimitiveCell', - meta: { - title: '新增原始细胞库资料', - hide: true - }, - component: () => import("../views/strain-library/validation/primitive-cell/add.vue") - }, - { - path: 'confirm-detail', - name: 'ConfirmDetail', - meta: { - title: '确认原始细胞库资料', - hide: true - }, - component: () => import("../views/strain-library/validation/primitive-cell/confirm-detail.vue") - }, - { - path: 'chief-cell', - name: 'ChiefCell', - meta: { - title: '主细胞库资料' - }, - component: () => import("../views/strain-library/validation/chief-cell") - } - ] - }, - ] - }, { - path: "/strainReportLibrary", - component: Layouts, - meta: { - title: "菌种报告库", - }, - children: [{ - path: "reportLibraryOne", + { + path: "strain-library-manage", + name: "StrainLibraryManage", meta: { - title: "报告库一", - keepAlive: true, + title: "原始细胞库", + keepAlive: true, }, - component: () => import("../views/strainReportLibrary/reportLibraryOne/index.vue"), - }, - { - path: "add", + component: () => + import("../views/strain-library/strain-library-manage"), + }, + { + path: "strain-library-manage/add", + name: "StrainLibraryManageAdd", meta: { - title: "新增报告", - hide: true, - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOne/add.vue"), - }, - { - path: "reportLibraryTwo", - meta: { - title: "报告库二", - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOneTWO/index.vue"), - }, - { - path: "addTwo", - meta: { - title: "新增报告", - hide: true, - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOneTWO/add.vue"), - }, - { - path: "reportLibraryThree", - meta: { - title: "报告库三", - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOneThree/index.vue"), - }, - { - path: "addThree", - meta: { - title: "新增报告", - hide: true, - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOneThree/add.vue"), - }, - { - path: "reportLibraryFour", - meta: { - title: "报告库四", - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOneFour/index.vue"), - }, - { - path: "addFour", - meta: { - title: "新增报告", - hide: true, - keepAlive: true, - }, - component: () => import("../views/strainReportLibrary/reportLibraryOneFour/add.vue"), - }, + title: "新增原始细胞库", + keepAlive: true, + hide: true, + }, + component: () => + import("../views/strain-library/strain-library-manage/add.vue"), + }, + { + path: "strain-library-manage/record", + name: "StrainRecord", + meta: { + title: "出入库记录", + keepAlive: true, + hide: true, + }, + component: () => + import( + "../views/strain-library/strain-library-manage/record.vue" + ), + }, + { + path: "main-cell-library", + name: "MainCellLibrary", + meta: { + title: "主细胞库", + keepAlive: true, + }, + component: () => + import("../views/strain-library/main-cell-library"), + }, + { + path: "main-cell-library/add", + name: "MainCellLibraryAdd", + meta: { + title: "新增主细胞", + keepAlive: true, + hide: true, + }, + component: () => + import("../views/strain-library/main-cell-library/add.vue"), + }, + { + path: "production-cell-library", + name: "ProductionCellLibrary", + meta: { + title: "生产细胞库", + keepAlive: true, + }, + component: () => + import("../views/strain-library/production-cell-library"), + }, + { + path: "production-cell-library/add", + name: "ProductionCellLibraryAdd", + meta: { + title: "新增生产细胞", + keepAlive: true, + hide: true, + }, + component: () => + import("../views/strain-library/production-cell-library/add.vue"), + }, ], - }, - { - path: "/deliveryAssessment", - component: Layouts, + }, + { + path: "pedigree-vhart", + name: "PedigreeChart", meta: { - title: "菌种报告评定", + title: "菌种传代生产谱系图", }, - children: [{ - path: "projectTeamIntegral", + component: () => import("../views/pedigree-chart"), + }, + { + path: "add-pedigree", + name: "AddPedigree", + meta: { + title: "新增母代菌种传代生产谱系图", + hide: true, + }, + component: () => import("../views/pedigree-chart/add"), + }, + { + path: "add-progenitor", + name: "AddProgenitor", + meta: { + title: "新增祖代菌种传代生产谱系图", + hide: true, + }, + component: () => import("../views/pedigree-chart/addProgenitor"), + }, + // { + // path: "strain-flow-chart", + // name: "StrainFlowChart", + // meta: { + // title: "菌种传代产生流程图", + // keepAlive: true, + // }, + // component: () => import("../views/strain-library/strain-flow-chart"), + // }, + { + path: "breeding-record", + name: "BreedingRecord", + meta: { + title: "菌种选育保藏记录", + }, + component: () => import("../views/strain-library/breeding-record"), + }, + { + path: "add-breeding-record", + name: "AddBreedingRecord", + meta: { + title: "新增菌种选育保藏记录", + hide: true, + }, + component: () => import("../views/strain-library/breeding-record/add"), + }, + { + path: "validation", + meta: { + title: "菌种验证数据资料", + }, + component: Parent, + children: [ + { + path: "primitive-cell", + name: "PrimitiveCell", meta: { - title: "菌种项目组评定表", + title: "原始细胞库资料", }, - component: () => import("../views/deliveryAssessment/projectTeamIntegral"), - }, - { - path: "projectTeamIntegral-detail", + component: () => + import( + "../views/strain-library/validation/primitive-cell/index.vue" + ), + }, + { + path: "add-primitive-cell", + name: "AddPrimitiveCell", meta: { - title: "评定详情", - hide: true + title: "新增原始细胞库资料", + hide: true, }, - component: () => import("../views/deliveryAssessment/projectTeamIntegral/detail.vue"), + component: () => + import( + "../views/strain-library/validation/primitive-cell/add.vue" + ), + }, + { + path: "confirm-detail", + name: "ConfirmDetail", + meta: { + title: "确认原始细胞库资料", + hide: true, + }, + component: () => + import( + "../views/strain-library/validation/primitive-cell/confirm-detail.vue" + ), + }, + { + path: "chief-cell", + name: "ChiefCell", + meta: { + title: "主细胞库资料", + }, + component: () => + import("../views/strain-library/validation/chief-cell"), + }, + ], + }, + ], + }, + { + path: "/strainReportLibrary", + component: Layouts, + meta: { + title: "菌种报告库", + }, + children: [ + { + path: "reportLibraryOne", + meta: { + title: "报告库一", + keepAlive: true, }, - ] - } + component: () => + import("../views/strainReportLibrary/reportLibraryOne/index.vue"), + }, + { + path: "add", + meta: { + title: "新增报告", + hide: true, + keepAlive: true, + }, + component: () => + import("../views/strainReportLibrary/reportLibraryOne/add.vue"), + }, + { + path: "reportLibraryTwo", + meta: { + title: "报告库二", + keepAlive: true, + }, + component: () => + import("../views/strainReportLibrary/reportLibraryOneTWO/index.vue"), + }, + { + path: "addTwo", + meta: { + title: "新增报告", + hide: true, + keepAlive: true, + }, + component: () => + import("../views/strainReportLibrary/reportLibraryOneTWO/add.vue"), + }, + { + path: "reportLibraryThree", + meta: { + title: "报告库三", + keepAlive: true, + }, + component: () => + import( + "../views/strainReportLibrary/reportLibraryOneThree/index.vue" + ), + }, + { + path: "addThree", + meta: { + title: "新增报告", + hide: true, + keepAlive: true, + }, + component: () => + import("../views/strainReportLibrary/reportLibraryOneThree/add.vue"), + }, + { + path: "reportLibraryFour", + meta: { + title: "报告库四", + keepAlive: true, + }, + component: () => + import("../views/strainReportLibrary/reportLibraryOneFour/index.vue"), + }, + { + path: "addFour", + meta: { + title: "新增报告", + hide: true, + keepAlive: true, + }, + component: () => + import("../views/strainReportLibrary/reportLibraryOneFour/add.vue"), + }, + ], + }, + { + path: "/deliveryAssessment", + component: Layouts, + meta: { + title: "菌种报告评定", + }, + children: [ + { + path: "projectTeamIntegral", + meta: { + title: "菌种项目组评定表", + }, + component: () => + import("../views/deliveryAssessment/projectTeamIntegral"), + }, + { + path: "projectTeamIntegral-detail", + meta: { + title: "评定详情", + hide: true, + }, + component: () => + import("../views/deliveryAssessment/projectTeamIntegral/detail.vue"), + }, + ], + }, ]; const router = new VueRouter({ - mode: "hash", - base: process.env.BASE_URL, - routes, + mode: "hash", + base: process.env.BASE_URL, + routes, }); // 前置路由拦截器 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'); // 已登录状态访问登录页时重定向到系统首页 - return; - } - next(); - return; + // 登录验证 + // 排除登录页的校验 + if (to.path === "/login") { + if (sessionStorage.getItem("token")) { + next("/projectList"); // 已登录状态访问登录页时重定向到系统首页 + return; } + next(); + return; + } - // 登录状态校验 - const isAuthenticated = sessionStorage.getItem('token'); - if (!isAuthenticated) { - next('/login'); // 未登录用户重定向到登录页 - return; + // 登录状态校验 + const isAuthenticated = sessionStorage.getItem("token"); + if (!isAuthenticated) { + next("/login"); // 未登录用户重定向到登录页 + 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 isExist = tagList.some((item) => item.path === to.path); + if (!isExist) { + // 只保存必要的信息 + const tagInfo = { + path: to.path, + name: to.name, + meta: to.meta, + query: to.query, + }; + tagList.push(tagInfo); + sessionStorage.setItem("tagList", JSON.stringify(tagList)); + store.commit("SET_TAGLIST", tagList); } + } - // 判断是否拥有要跳转菜单权限 - let menus = store.state.menus - if (to.meta.hasOwnProperty('privilege') && !menus.includes(to.meta.privilege)) { - return + // 判断是否需要缓存 + if (to.meta.keepAlive) { + let keepAliveList = JSON.parse( + sessionStorage.getItem("keepAliveList") || "[]" + ); + // 判断是否已经缓存 + let isExist = keepAliveList.includes(to.name); + if (!isExist) { + keepAliveList.push(to.name); + sessionStorage.setItem("keepAliveList", JSON.stringify(keepAliveList)); + store.commit("SET_KEEPALIVELIST", keepAliveList); } + } - // 设置标签列表 - if (!to.meta.hide || !to.meta.oneself) { - let tagList = JSON.parse(sessionStorage.getItem('tagList') || '[]') - // 判断是否存在 - let isExist = tagList.some(item => item.path === to.path) - if (!isExist) { - // 只保存必要的信息 - const tagInfo = { - path: to.path, - name: to.name, - meta: to.meta, - query: to.query, - } - 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 isExist = keepAliveList.includes(to.name) - if (!isExist) { - keepAliveList.push(to.name) - sessionStorage.setItem('keepAliveList', JSON.stringify(keepAliveList)) - store.commit('SET_KEEPALIVELIST', keepAliveList) - } - } - - next() + next(); }); export default router; diff --git a/culture/src/views/strain-library/strain-library-manage/add.vue b/culture/src/views/strain-library/strain-library-manage/add.vue index 1894619..5c91b36 100644 --- a/culture/src/views/strain-library/strain-library-manage/add.vue +++ b/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.batchAddDialogVisible = true + 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) - } else if (this.currentAction === 'batchAdd') { - // 处理批量新增逻辑 - console.log('batch add with signature:', this.batchForm.count, 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(requestData); + + await addBatch(requestData); + } else { + await add(requestData); + } + this.signatureVisible = false; + this.$router.back(); + this.$message.success('操作成功'); + } catch (error) { + this.$message.error('操作失败'); } } } @@ -205,7 +227,7 @@ &-left { display: flex; align-items: center; - + img { width: 20px; height: 20px; @@ -219,18 +241,20 @@ } } } -.end-btn{ + +.end-btn { display: flex; align-items: center; justify-content: center; gap: 10px; - button{ + button { width: 180px; height: 36px; // background: #409EFF; } } + .strain-form { padding: 0 40px; @@ -241,14 +265,16 @@ margin-bottom: 24px; &.three-columns { - .el-form-item, .form-item-placeholder { + + .el-form-item, + .form-item-placeholder { flex: 1; min-width: 280px; - + @media screen and (max-width: 1200px) { min-width: calc(50% - 12px); } - + @media screen and (max-width: 768px) { min-width: 100%; } @@ -300,7 +326,7 @@ padding: 20px; text-align: center; border-bottom: 1px solid #EBEEF5; - + .el-dialog__title { font-size: 16px; font-weight: 600; @@ -334,6 +360,7 @@ color: #606266; font-weight: normal; padding-bottom: 8px; + &::before { color: #F56C6C; } @@ -341,8 +368,9 @@ :deep(.el-input) { width: 100%; + input { - width: 100%; + width: 100%; } } } @@ -350,6 +378,7 @@ .dialog-notice { margin-top: 16px; text-align: center; + p { margin: 0; line-height: 22px; @@ -361,7 +390,7 @@ :deep(.el-dialog__footer) { padding: 0 20px 20px; text-align: center; - + .el-button { width: 180px; height: 36px; @@ -394,4 +423,4 @@ margin: 0; } } -</style> +</style> \ No newline at end of file diff --git a/culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue b/culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue index cde2f2d..95b914d 100644 --- a/culture/src/views/strain-library/strain-library-manage/components/AddRecordDialog.vue +++ b/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 } } diff --git a/culture/src/views/strain-library/strain-library-manage/components/RecordDetailDialog.vue b/culture/src/views/strain-library/strain-library-manage/components/RecordDetailDialog.vue index dbff104..0f8aa15 100644 --- a/culture/src/views/strain-library/strain-library-manage/components/RecordDetailDialog.vue +++ b/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() { @@ -128,7 +118,7 @@ padding: 20px 24px; margin: 0; border-bottom: 1px solid #DCDFE6; - + .el-dialog__title { font-size: 16px; font-weight: 600; @@ -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; @@ -232,4 +224,4 @@ .edit-sign-btn { margin-left: 12px; } -</style> \ No newline at end of file +</style> \ No newline at end of file diff --git a/culture/src/views/strain-library/strain-library-manage/components/RecordTimeline.vue b/culture/src/views/strain-library/strain-library-manage/components/RecordTimeline.vue index 4de0a9a..4691991 100644 --- a/culture/src/views/strain-library/strain-library-manage/components/RecordTimeline.vue +++ b/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') : + 'right-block', + item.confirmTime && item.confirmTime !== '--' ? + (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; } @@ -170,12 +175,13 @@ font-size: 16px; font-weight: bold; color: #fff; - background: linear-gradient( 180deg, #0ACBCA 0%, #049C9A 100%); - letter-spacing: 8px; /* 增加字间距 */ + background: linear-gradient(180deg, #0ACBCA 0%, #049C9A 100%); + letter-spacing: 8px; + /* 增加字间距 */ } .left-block.out .type-tag { - background: linear-gradient( 180deg, #FDBF2D 0%, #FA8B14 100%); + background: linear-gradient(180deg, #FDBF2D 0%, #FA8B14 100%); } .info-main { @@ -245,10 +251,12 @@ /* 添加媒体查询,适配小屏幕设备 */ @media screen and (max-width: 1200px) { - .left-block, .right-block { + + .left-block, + .right-block { min-width: 240px; } - + .timeline-row { gap: 10px; } @@ -256,56 +264,58 @@ @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%; } - + :deep(.el-timeline-item) { position: relative; height: auto; min-height: 176px; margin-bottom: 40px; } - + :deep(.el-timeline-item__wrapper) { height: auto !important; min-height: 176px; } - + :deep(.el-timeline-item__tail) { height: calc(100% + 40px); } - + :deep(.el-timeline-item:last-of-type) { margin-bottom: 0; } - + :deep(.el-timeline-item:last-of-type .el-timeline-item__tail) { height: 34px; } - + /* 第一个元素的轴线需要特殊处理 */ :deep(.el-timeline-item:first-of-type .el-timeline-item__tail) { top: 34px; height: calc(100% + 40px - 34px); } - + /* 确保所有轴线正确连接 */ :deep(.el-timeline-item__tail) { top: 0; height: calc(100% + 40px); } - + /* 修正内容区域的高度 */ :deep(.el-timeline-item__content) { height: auto; min-height: 176px; } } -</style> \ No newline at end of file +</style> \ No newline at end of file diff --git a/culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue b/culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue index 6b64853..eaa73e3 100644 --- a/culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue +++ b/culture/src/views/strain-library/strain-library-manage/components/StrainDetail.vue @@ -1,94 +1,99 @@ <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 class="strain-info"> - <!-- 第一行信息 --> - <div class="info-row"> - <div class="info-item left-column"> - <span class="label">菌种编号:</span> - <span class="value">{{ detail.strainNo }}</span> + <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.strainCode }}</span> + </div> + <div class="info-item flex-column"> + <span class="label">鉴定方法:</span> + <span class="value">{{ detail.appraisalMethod }}</span> + </div> + <div class="info-item flex-column"> + <span class="label">保藏位置:</span> + <span class="value">{{ detail.saveLocation }}</span> + </div> </div> - <div class="info-item flex-column"> - <span class="label">鉴定方法:</span> - <span class="value">{{ detail.method }}</span> - </div> - <div class="info-item flex-column"> - <span class="label">保存位置:</span> - <span class="value">{{ detail.amount }}</span> - </div> - </div> - - <!-- 第二行信息 --> - <div class="info-row"> - <div class="info-item left-column"> - <span class="label">菌种名称:</span> - <span class="value">{{ detail.strainName }}</span> - </div> - <div class="info-item flex-column full-width"> - <span class="label">特性描述:</span> - <span class="value">{{ detail.certificate }}</span> - </div> - </div> - - <!-- 第三行信息 --> - <div class="info-row"> - <div class="info-item left-column"> - <span class="label">菌种来源:</span> - <span class="value">{{ detail.source }}</span> - </div> - <div class="info-item flex-column"> - <span class="label">菌种保存方法:</span> - <span class="value">{{ detail.storage }}</span> - </div> - <div class="info-item flex-column"> - <span class="label">出入库状态:</span> - <span class="value">{{ detail.operator }}</span> - </div> - </div> - </div> - <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="状态"> - <template #default="{ row }"> - <el-tag :type="row.status === '已确认' ? 'success' : 'warning'"> - {{ row.status }} - </el-tag> - </template> - </el-table-column> - <el-table-column label="操作" width="100"> - <template #default="{ row }"> - <el-button 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" - /> + <!-- 第二行信息 --> + <div class="info-row"> + <div class="info-item left-column"> + <span class="label">菌种名称:</span> + <span class="value">{{ detail.strainName }}</span> + </div> + <div class="info-item flex-column full-width"> + <span class="label">特性描述:</span> + <span class="value">{{ detail.features }}</span> + </div> + </div> + + <!-- 第三行信息 --> + <div class="info-row"> + <div class="info-item left-column"> + <span class="label">菌种来源:</span> + <span class="value">{{ detail.strainSource }}</span> + </div> + <div class="info-item flex-column"> + <span class="label">菌种保存方法:</span> + <span class="value">{{ detail.saveMethod }}</span> + </div> + <div class="info-item flex-column"> + <span class="label">出入库状态:</span> + <span class="value">{{ { + 1: '已出库', + 2: '出库待确认', + 3: '已入库', + 4: '入库待确认' + }[detail.status] || '' }}</span> + </div> + </div> </div> - </div> - </el-dialog> + + <div class="record-table"> + <div class="table-title">原始细胞库出/入库记录</div> + <el-table :data="detail.records" style="width: 100%"> + <el-table-column label="出库/入库"> + <template #default="{ row }"> + {{ { 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 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" /> + </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 @@ -124,7 +148,7 @@ padding: 20px; border-bottom: 1px solid #EBEEF5; margin-right: 0; - + .el-dialog__title { font-size: 18px; font-weight: bold; @@ -147,38 +171,38 @@ display: flex; flex-wrap: wrap; margin-bottom: 16px; - + &:last-child { margin-bottom: 0; } - + .info-item { display: flex; align-items: flex-start; margin-right: 24px; margin-bottom: 8px; - + &.left-column { width: 33%; min-width: 200px; } - + &.flex-column { flex: 1; min-width: 150px; } - + &.full-width { flex: 1; min-width: 300px; } - + .label { color: #606266; margin-right: 8px; white-space: nowrap; } - + .value { flex: 1; color: #303133; @@ -204,4 +228,4 @@ justify-content: center; } } -</style> \ No newline at end of file +</style> \ No newline at end of file diff --git a/culture/src/views/strain-library/strain-library-manage/index.vue b/culture/src/views/strain-library/strain-library-manage/index.vue index f5e0be6..dc579a6 100644 --- a/culture/src/views/strain-library/strain-library-manage/index.vue +++ b/culture/src/views/strain-library/strain-library-manage/index.vue @@ -1,7 +1,7 @@ <template> <div class="list"> <el-card class="header-box"> - + <div class="box-title"> <img src="@/assets/public/notice.png" class="header-icon"> <span>菌种源保藏出/入细胞库登记表说明</span> @@ -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> @@ -50,8 +45,8 @@ </el-select> </el-form-item> <el-form-item class="search-btn-box"> - <el-button type="default" @click="resetForm">重置</el-button> - <el-button type="primary" @click="searchData">查询</el-button> + <el-button type="default" @click="resetForm">重置</el-button> + <el-button type="primary" @click="searchData">查询</el-button> </el-form-item> </el-form> </template> @@ -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()) - ) - } - 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 + 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; } - }) + }).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] || '未知状态' } @@ -427,7 +353,7 @@ background: #ffffff; border-radius: 8px 8px 0px 0px; border: 1px solid #049c9a; - + } } @@ -436,7 +362,7 @@ padding: 20px; border-bottom: 1px solid #EBEEF5; margin-right: 0; - + .el-dialog__title { font-size: 18px; font-weight: bold; @@ -454,11 +380,11 @@ p { margin: 12px 0; - + &:first-child { margin-top: 0; } - + &:last-child { margin-bottom: 0; } @@ -466,5 +392,4 @@ } } } - -</style> +</style> \ No newline at end of file diff --git a/culture/src/views/strain-library/strain-library-manage/record.vue b/culture/src/views/strain-library/strain-library-manage/record.vue index 3c145dc..0db0f96 100644 --- a/culture/src/views/strain-library/strain-library-manage/record.vue +++ b/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) diff --git a/culture/src/views/strain-library/strain-library-manage/service.js b/culture/src/views/strain-library/strain-library-manage/service.js new file mode 100644 index 0000000..4ebf2fb --- /dev/null +++ b/culture/src/views/strain-library/strain-library-manage/service.js @@ -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 }) +} -- Gitblit v1.7.1