Merge branch 'main' of http://120.76.84.145:10101/gitblit/r/H5/leshan-laboratory
| | |
| | | |
| | | // 导出图片 |
| | | const signatureImage = canvas.toDataURL('image/png') |
| | | this.$emit('confirm', signatureImage) |
| | | this.$emit('confirm', 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg') |
| | | } |
| | | }, |
| | | beforeDestroy() { |
| | |
| | | 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", ------页面地址 |
| | |
| | | */ |
| | | |
| | | 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: "出入库记录", |
| | | 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; |
| | |
| | | <el-form :model="form" :rules="rules" ref="pedigreeForm" label-position="top" class="strain-form"> |
| | | <div class="card"> |
| | | <div class="form-items-row"> |
| | | <el-form-item label="菌种源" prop="strainSource" required> |
| | | <el-form-item label="菌种源" required> |
| | | <div class="flex-row"> |
| | | <div class="input-wrapper"> |
| | | <el-input v-model="form.strainSource" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | <el-form-item prop="strainSourceStart" style="margin-bottom: 0;"> |
| | | <el-input v-model="form.strainSourceStart" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | <span class="form-text">代—</span> |
| | | <div class="input-wrapper"> |
| | | <el-input v-model="form.generation" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | <el-form-item prop="strainSourceEnd" style="margin-bottom: 0;"> |
| | | <el-input v-model="form.strainSourceEnd" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | <span class="form-text">细胞库</span> |
| | | </div> |
| | |
| | | <div class="strain-flow-chart"> |
| | | <div id="mountNode"></div> |
| | | </div> |
| | | <el-button type="primary" @click="handleSubmit" style="width: 150px;">保存</el-button> |
| | | |
| | | </div> |
| | | <div class="end-btn"> |
| | | <el-button type="primary" @click="handleSubmit">提交</el-button> |
| | | <el-button @click="handleDraft">存草稿</el-button> |
| | | <el-button @click="handleCancel">取消</el-button> |
| | | <!-- <el-button @click="handleDraft">存草稿</el-button> |
| | | <el-button @click="handleCancel">取消</el-button> --> |
| | | </div> |
| | | </el-form> |
| | | |
| | |
| | | return { |
| | | signatureVisible: false, |
| | | form: { |
| | | strainSource: "", |
| | | generation: "", |
| | | strainSourceStart: "", |
| | | strainSourceEnd: "", |
| | | cellBank: "", |
| | | strainNo: "", |
| | | strainName: "", |
| | | remarks: "", |
| | | }, |
| | | rules: { |
| | | strainSource: [ |
| | | strainSourceStart: [ |
| | | { required: true, message: "请输入菌种源", trigger: "blur" }, |
| | | ], |
| | | strainSourceEnd: [ |
| | | { required: true, message: "请输入菌种源", trigger: "blur" }, |
| | | ], |
| | | strainNo: [ |
| | |
| | | }, |
| | | handleSignatureConfirm(signatureImage) { |
| | | this.confirmStorageDialogVisible = false; |
| | | console.log("submit form with signature:", signatureImage); |
| | | if (this.nodeType === 1) { |
| | | this.handleAddParent(this.nodeData) |
| | | this.handleAddParent({ ...this.nodeData, signature: signatureImage.signature }) |
| | | } else if (this.nodeType === 2) { |
| | | this.handleAddPlan(this.nodeData) |
| | | } else if (this.nodeType === 3) { |
| | |
| | | }, |
| | | initEvents() { |
| | | // 监听窗口大小变化 |
| | | window.addEventListener('resize', this.handleResize); |
| | | |
| | | // 节点点击事件 |
| | | this.graph.on('node:click', (evt) => { |
| | | window.addEventListener('resize', this.handleResize);// 添加触摸事件处理 |
| | | const handleNodeClick = (evt) => { |
| | | evt.preventDefault(); // 阻止默认触摸行为 |
| | | const node = evt.item; |
| | | const nodeModel = node.getModel(); |
| | | |
| | | // 如果节点已废弃,不允许任何操作 |
| | | if (!nodeModel.isDiscarded) { |
| | | this.$message.warning('该节点已废弃,不能进行操作'); |
| | | return; |
| | | } |
| | | |
| | | // 更新选中节点 |
| | | this.selectedNode = nodeModel; |
| | | |
| | | // 更新节点选中状态 |
| | | this.graphData.nodes.forEach(n => { |
| | | n.selected = n.id === nodeModel.id; |
| | | }); |
| | | this.graph.changeData(this.graphData); |
| | | }); |
| | | }; |
| | | this.graph.on('node:click', handleNodeClick); |
| | | this.graph.on('node:touchstart', handleNodeClick); |
| | | |
| | | // 画布点击事件,取消选中节点 |
| | | this.graph.on('canvas:click', () => { |
| | | // 画布点击事件,取消选中节点(添加触摸支持) |
| | | const handleCanvasClick = (evt) => { |
| | | evt.preventDefault(); |
| | | this.selectedNode = null; |
| | | this.graphData.nodes.forEach(n => { |
| | | n.selected = false; |
| | | }); |
| | | this.graph.changeData(this.graphData); |
| | | }); |
| | | }; |
| | | |
| | | this.graph.on('canvas:click', handleCanvasClick); |
| | | this.graph.on('canvas:touchstart', handleCanvasClick); |
| | | }, |
| | | handleResize() { |
| | | if (this.graph) { |
| | |
| | | this.$refs.parentForm.openInitData({ |
| | | strainName: this.form.strainName, |
| | | strainNo: this.form.strainNo, |
| | | strainSource: this.form.strainSource, |
| | | generation: this.form.generation, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | }); |
| | | } |
| | | }) |
| | |
| | | } |
| | | }, |
| | | handleAddParent(value) { |
| | | console.log(value); |
| | | |
| | | const parentId = `parent-${++this.nodeCount}`; |
| | | this.graphData.nodes.push({ |
| | | id: parentId, |
| | |
| | | label: nodeModel.label, |
| | | strainName: this.form.strainName, |
| | | strainNo: this.form.strainNo, |
| | | strainSource: this.form.strainSource, |
| | | generation: this.form.generation, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | }) |
| | | } else { |
| | | this.$refs.planForm.openInitData({ |
| | |
| | | label: nodeModel.label, |
| | | strainName: this.form.strainName, |
| | | strainNo: this.form.strainNo, |
| | | strainSource: this.form.strainSource, |
| | | generation: this.form.generation, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | }) |
| | | } |
| | | }, |
| | |
| | | // 监听窗口大小变化 |
| | | window.addEventListener('resize', this.handleResize); |
| | | |
| | | // 节点点击事件 |
| | | this.graph.on('node:click', (evt) => { |
| | | const handleNodeClick = (evt) => { |
| | | evt.preventDefault(); // 阻止默认触摸行为 |
| | | const node = evt.item; |
| | | const nodeModel = node.getModel(); |
| | | |
| | | // 如果节点已废弃,不允许任何操作 |
| | | if (!nodeModel.isDiscarded) { |
| | | this.$message.warning('该节点已废弃,不能进行操作'); |
| | | return; |
| | | } |
| | | |
| | | // 更新选中节点 |
| | | this.selectedNode = nodeModel; |
| | | |
| | | // 更新节点选中状态 |
| | | this.graphData.nodes.forEach(n => { |
| | | n.selected = n.id === nodeModel.id; |
| | | }); |
| | | this.graph.changeData(this.graphData); |
| | | }); |
| | | }; |
| | | this.graph.on('node:click', handleNodeClick); |
| | | this.graph.on('node:touchstart', handleNodeClick); |
| | | |
| | | // 画布点击事件,取消选中节点 |
| | | this.graph.on('canvas:click', () => { |
| | | // 画布点击事件,取消选中节点(添加触摸支持) |
| | | const handleCanvasClick = (evt) => { |
| | | evt.preventDefault(); |
| | | this.selectedNode = null; |
| | | this.graphData.nodes.forEach(n => { |
| | | n.selected = false; |
| | | }); |
| | | this.graph.changeData(this.graphData); |
| | | }); |
| | | }; |
| | | this.graph.on('canvas:click', handleCanvasClick); |
| | | this.graph.on('canvas:touchstart', handleCanvasClick); |
| | | }, |
| | | handleResize() { |
| | | if (this.graph) { |
| | |
| | | <el-dialog :title="parentForm.status === 'detail' ? '母代详情' : '新增母代'" :visible.sync="addParentDialogVisible" |
| | | width="40%" :close-on-click-modal="false"> |
| | | <el-form :model="parentForm" ref="parentForm" label-position="top"> |
| | | <el-form-item label="菌种源" prop="strainSource"> |
| | | <el-form-item label="菌种源" prop="strainSourceStart"> |
| | | <div class="flex-row"> |
| | | <div class="input-wrapper"> |
| | | <el-input disabled v-model="parentForm.strainSource" class="fixed-width-input"></el-input> |
| | | <el-input disabled v-model="parentForm.strainSourceStart" class="fixed-width-input"></el-input> |
| | | </div> |
| | | <span class="form-text">代—</span> |
| | | <div class="input-wrapper"> |
| | | <el-input disabled v-model="parentForm.generation" class="fixed-width-input"></el-input> |
| | | <el-input disabled v-model="parentForm.strainSourceEnd" class="fixed-width-input"></el-input> |
| | | </div> |
| | | <span class="form-text">细胞库</span> |
| | | </div> |
| | |
| | | <el-dialog :title="planForm.status === 'detail' ? '传代计划数详情' : '设置传代计划数'" :visible.sync="planDialogVisible" |
| | | width="40%" :close-on-click-modal="false"> |
| | | <el-form :model="planForm" :rules="planRules" ref="planForm" label-position="top"> |
| | | <el-form-item label="菌种源" prop="strainSource"> |
| | | <el-form-item label="菌种源" prop="strainSourceStart"> |
| | | <div class="flex-row"> |
| | | <div class="input-wrapper"> |
| | | <el-input disabled v-model="planForm.strainSource" class="fixed-width-input"></el-input> |
| | | <el-input disabled v-model="planForm.strainSourceStart" class="fixed-width-input"></el-input> |
| | | </div> |
| | | <span class="form-text">代—</span> |
| | | <div class="input-wrapper"> |
| | | <el-input disabled v-model="planForm.generation" class="fixed-width-input"></el-input> |
| | | <el-input disabled v-model="planForm.strainSourceEnd" class="fixed-width-input"></el-input> |
| | | </div> |
| | | <span class="form-text">细胞库</span> |
| | | </div> |
| | |
| | | <template #search> |
| | | <el-form :model="form" labelWidth="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-input v-model="form.planName" placeholder="请输入"></el-input> |
| | | <el-input v-model="form.strainCode" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.planCode" placeholder="请输入"></el-input> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="起传类型"> |
| | | <el-input v-model="form.creator" placeholder="请输入"></el-input> |
| | | <el-select v-model="form.generationType" placeholder="请选择"> |
| | | <el-option label="母代" :value="1"></el-option> |
| | | <el-option label="祖代" :value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label=""> |
| | | <el-button type="default" @click="resetForm">重置</el-button> |
| | | <el-button type="primary" @click="handleSearch">查询</el-button> |
| | | <el-button style="margin-left: 10px;" type="primary" @click="handleSearch">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { getList } from "./service"; |
| | | export default { |
| | | name: "PedigreeChart", |
| | | components: {}, |
| | |
| | | return { |
| | | currentType: "list", // 当前显示类型:list-列表,draft-草稿箱 |
| | | form: { |
| | | planName: "", |
| | | planCode: "", |
| | | creator: "", |
| | | createTime: [], |
| | | approver: "", |
| | | status: "", |
| | | strainCode: "", |
| | | strainName: "", |
| | | generationType: "", |
| | | pageNum: 1, |
| | | pageSize: 10 |
| | | }, |
| | | tableData: [], |
| | | total: 0, |
| | |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | planName: "", |
| | | planCode: "", |
| | | creator: "", |
| | | createTime: [], |
| | | approver: "", |
| | | status: "", |
| | | strainCode: "", |
| | | strainName: "", |
| | | generationType: "", |
| | | pageNum: 1, |
| | | pageSize: 10 |
| | | }; |
| | | }, |
| | | handleNewStrain() { |
| | |
| | | }); |
| | | }, |
| | | handleSearch() { |
| | | // 实现查询逻辑 |
| | | console.log("查询条件:", this.form); |
| | | this.form.pageNum = 1; |
| | | this.getTableData(); |
| | | }, |
| | | getStatusType(status) { |
| | | const statusMap = { |
| | |
| | | this.getTableData(); |
| | | }, |
| | | getTableData() { |
| | | // 根据currentType请求不同的数据 |
| | | if (this.currentType === "list") { |
| | | this.tableData = this.mockListData; |
| | | this.total = this.mockListData.length; |
| | | } else { |
| | | this.tableData = this.mockDraftData; |
| | | this.total = this.mockDraftData.length; |
| | | } |
| | | getList(this.form).then(res => { |
| | | if (res.code === 200) { |
| | | this.tableData = res.data.list; |
| | | this.total = res.data.total; |
| | | } |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
New file |
| | |
| | | import axios from '@/utils/request'; |
| | | |
| | | // 列表 |
| | | export const getList = (data) => { |
| | | return axios.post('/api/t-pedigree-chart/pageList', { ...data }) |
| | | } |
| | | |
| | | // 删除菌种库 |
| | | export const deleteStrainLibrary = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteById', { params }) |
| | | } |
| | |
| | | <template> |
| | | <Card> |
| | | <el-form |
| | | :model="form" |
| | | :rules="rules" |
| | | ref="strainForm" |
| | | label-position="top" |
| | | class="strain-form" |
| | | > |
| | | <div class="form-grid"> |
| | | <el-form-item label="菌种编号" prop="strainNo" required> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称" prop="strainName" required> |
| | | <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> |
| | | <el-form-item label="鉴定方法" prop="identificationMethod" required> |
| | | <el-input v-model="form.identificationMethod" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="特征描述" prop="characteristics" required> |
| | | <el-input v-model="form.characteristics" 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> |
| | | <el-form-item label="保存位置" prop="storageLocation" required> |
| | | <el-input v-model="form.storageLocation" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | <Card> |
| | | <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="strainCode"> |
| | | <el-input v-model="form.strainCode" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称" prop="strainName"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <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="remarks" class="full-width"> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="form.remarks" |
| | | :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 @click="handleDraft">存草稿</el-button> |
| | | </div> |
| | | </el-form> |
| | | <div class="form-row"> |
| | | <el-form-item label="鉴定方法" prop="appraisalMethod"> |
| | | <el-input v-model="form.appraisalMethod" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | |
| | | <!-- 签字确认组件 --> |
| | | <SignatureCanvas |
| | | :visible.sync="signatureVisible" |
| | | @confirm="handleSignatureConfirm" |
| | | /> |
| | | </Card> |
| | | <div class="form-row"> |
| | | <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="saveLocation"> |
| | | <el-input v-model="form.saveLocation" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <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.remark" :rows="4" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | |
| | | <div class="end-btn" style="margin-top: 38px"> |
| | | <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"> |
| | | <div class="dialog-content"> |
| | | <el-form :model="batchForm" ref="batchFormRef" label-position="top" class="batch-form"> |
| | | <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> |
| | | <div class="dialog-notice"> |
| | | <p>注意:操作批量新增后,系统会自动生成对应数量的菌种数据,</p> |
| | | <p>这些菌种的基础信息内容都是一致的,唯独菌种编号内容系统</p> |
| | | <p>不会自动生成,需要操作员自行编辑</p> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="end-btn"> |
| | | <el-button type="primary" @click="handleConfirmBatchAdd">确认新增</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 签字确认组件 --> |
| | | <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: 'AddMainCell', |
| | | components: { |
| | | SignatureCanvas |
| | | }, |
| | | data() { |
| | | return { |
| | | signatureVisible: false, |
| | | form: { |
| | | strainNo: '', |
| | | strainName: '', |
| | | source: '', |
| | | identificationMethod: '', |
| | | characteristics: '', |
| | | storageLocation: '', |
| | | preservationMethod: '', |
| | | remarks: '' |
| | | }, |
| | | rules: { |
| | | strainNo: [{ required: true, message: '请输入菌种编号', trigger: 'blur' }], |
| | | 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' }] |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | handleSubmit() { |
| | | this.$refs.strainForm.validate((valid) => { |
| | | if (valid) { |
| | | this.signatureVisible = true |
| | | } |
| | | }) |
| | | }, |
| | | handleDraft() { |
| | | // 实现存草稿逻辑 |
| | | console.log('save draft', this.form) |
| | | this.$message.success('草稿保存成功') |
| | | }, |
| | | handleSignatureConfirm(signatureImage) { |
| | | this.signatureVisible = false |
| | | // 处理提交逻辑 |
| | | console.log('submit form with signature:', this.form, signatureImage) |
| | | this.$message.success('提交成功') |
| | | this.$router.back() |
| | | } |
| | | } |
| | | name: 'StrainLibraryManageAdd', |
| | | components: { |
| | | SignatureCanvas |
| | | }, |
| | | data() { |
| | | return { |
| | | batchAddDialogVisible: false, |
| | | signatureVisible: false, |
| | | currentAction: '', // 'submit' or 'batchAdd' |
| | | batchForm: { |
| | | count: '' |
| | | }, |
| | | form: { |
| | | strainCode: '', |
| | | strainName: '', |
| | | source: '', |
| | | appraisalMethod: '', |
| | | characteristics: '', |
| | | storageLocation: '', |
| | | preservationMethod: '', |
| | | remark: '' |
| | | }, |
| | | rules: { |
| | | strainCode: [{ |
| | | validator: (rule, value, callback) => { |
| | | if (this.currentAction === 'submit' && !value) { |
| | | callback(new Error('请输入菌种编号')); |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: 'change' |
| | | }], |
| | | strainName: [{ 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(isDraft) { |
| | | this.currentAction = 'submit' |
| | | this.$refs.strainForm.validate((valid) => { |
| | | if (valid) { |
| | | this.form.isDraft = isDraft |
| | | if (isDraft == 1) { |
| | | //存草稿 |
| | | this.handleSignatureConfirm('') |
| | | } else { |
| | | this.signatureVisible = true |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | handleBatchAdd() { |
| | | this.currentAction = 'batchAdd' |
| | | this.$refs.strainForm.validate((valid) => { |
| | | if (valid) { |
| | | this.batchAddDialogVisible = true |
| | | } |
| | | }) |
| | | }, |
| | | handleConfirmBatchAdd() { |
| | | this.$refs.batchFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.batchAddDialogVisible = false |
| | | this.signatureVisible = true |
| | | } |
| | | }) |
| | | }, |
| | | 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: 2, |
| | | }; |
| | | 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') { |
| | | await addBatch(requestData); |
| | | } else { |
| | | await add(requestData); |
| | | } |
| | | this.signatureVisible = false; |
| | | this.$router.back(); |
| | | this.$message.success('操作成功'); |
| | | } catch (error) { |
| | | this.$message.error('操作失败'); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .strain-form { |
| | | padding: 0 40px; |
| | | .add-strain { |
| | | height: 100%; |
| | | background: #F5F7FA; |
| | | |
| | | .form-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 24px; |
| | | margin-bottom: 24px; |
| | | |
| | | @media screen and (max-width: 1200px) { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | } |
| | | |
| | | @media screen and (max-width: 768px) { |
| | | grid-template-columns: 1fr; |
| | | } |
| | | } |
| | | .form-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | |
| | | .form-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 24px; |
| | | margin-bottom: 24px; |
| | | .header-title { |
| | | margin-bottom: 24px; |
| | | |
| | | .el-form-item { |
| | | margin-bottom: 0; |
| | | &-left { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | &.full-width { |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | | img { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | font-weight: normal; |
| | | color: #606266; |
| | | padding-bottom: 8px; |
| | | line-height: 20px; |
| | | } |
| | | |
| | | :deep(.el-form-item__content) { |
| | | line-height: unset; |
| | | } |
| | | |
| | | :deep(.el-input__inner) { |
| | | border-radius: 4px; |
| | | height: 36px; |
| | | line-height: 36px; |
| | | } |
| | | |
| | | :deep(.el-textarea__inner) { |
| | | border-radius: 4px; |
| | | padding: 8px 12px; |
| | | min-height: 120px; |
| | | } |
| | | div { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .end-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | |
| | | :deep(.el-button) { |
| | | width: 180px; |
| | | height: 36px; |
| | | padding: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | border-radius: 4px; |
| | | margin: 0; |
| | | } |
| | | button { |
| | | width: 180px; |
| | | height: 36px; |
| | | // background: #409EFF; |
| | | } |
| | | } |
| | | </style> |
| | | |
| | | .strain-form { |
| | | padding: 0 40px; |
| | | |
| | | .form-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 24px; |
| | | margin-bottom: 24px; |
| | | |
| | | &.three-columns { |
| | | |
| | | .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%; |
| | | } |
| | | } |
| | | |
| | | .form-item-placeholder { |
| | | @media screen and (max-width: 1200px) { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .el-form-item { |
| | | margin-bottom: 0; |
| | | |
| | | &.full-width { |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | font-weight: normal; |
| | | color: #606266; |
| | | padding-bottom: 8px; |
| | | line-height: 20px; |
| | | } |
| | | |
| | | :deep(.el-form-item__content) { |
| | | line-height: unset; |
| | | } |
| | | |
| | | :deep(.el-input__inner) { |
| | | border-radius: 4px; |
| | | height: 36px; |
| | | line-height: 36px; |
| | | } |
| | | |
| | | :deep(.el-textarea__inner) { |
| | | border-radius: 4px; |
| | | padding: 8px 12px; |
| | | min-height: 120px; |
| | | } |
| | | } |
| | | |
| | | .batch-add-dialog { |
| | | :deep(.el-dialog__header) { |
| | | margin: 0; |
| | | padding: 20px; |
| | | text-align: center; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .dialog-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | .batch-form { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | |
| | | :deep(.el-form-item) { |
| | | width: 320px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | width: 100%; |
| | | color: #606266; |
| | | font-weight: normal; |
| | | padding-bottom: 8px; |
| | | |
| | | &::before { |
| | | color: #F56C6C; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-input) { |
| | | width: 100%; |
| | | |
| | | input { |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .dialog-notice { |
| | | margin-top: 16px; |
| | | text-align: center; |
| | | |
| | | p { |
| | | margin: 0; |
| | | line-height: 22px; |
| | | color: #606266; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__footer) { |
| | | padding: 0 20px 20px; |
| | | text-align: center; |
| | | |
| | | .el-button { |
| | | width: 180px; |
| | | height: 36px; |
| | | padding: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | border-radius: 4px; |
| | | margin: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .end-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | |
| | | :deep(.el-button) { |
| | | width: 180px; |
| | | height: 36px; |
| | | padding: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | border-radius: 4px; |
| | | margin: 0; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> |
| | | <span>菌种源保藏出/入主细胞库登记表说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore">查看全部 >></el-button> |
| | | </div> |
| | | <div class="header-content" :class="{ 'collapsed': true }"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入主细胞库登记表】,请分类管理。</p> |
| | | <p>1.1 接种入主细胞库(现代-M)的菌株经过培养和保藏。</p> |
| | | <p>1.2 从原始细胞库转入的菌株需要按照标准程序进行记录和管理。</p> |
| | | <p>1.3 主细胞库的菌株可用于科研项目和工业生产中的应用研究。</p> |
| | | </div> |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon" /> |
| | | <span>菌种源保藏出/入细胞库登记表说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore" |
| | | >查看全部 >></el-button |
| | | > |
| | | </div> |
| | | <div class="header-content" :class="{ collapsed: true }"> |
| | | <p> |
| | | 1. 菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,菌种来源有 3 |
| | | 条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2 |
| | | 是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3 |
| | | 是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。 |
| | | 2. |
| | | 菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1 |
| | | 原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3 |
| | | 生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1 |
| | | 细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在 |
| | | 24 年 9 月 19 |
| | | 接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1 |
| | | 传代编码方式演例:祖代:DD-O-240919-01 |
| | | 传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2 |
| | | 编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2 |
| | | 细胞库说明:3.2.1 |
| | | 直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2 |
| | | 从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3 |
| | | 主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4. |
| | | 菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 a-01、a-02 |
| | | 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2 |
| | | 接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。 |
| | | </p> |
| | | </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 |
| | | 条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2 |
| | | 是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3 |
| | | 是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。2. |
| | | 菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1 |
| | | 原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3 |
| | | 生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1 |
| | | 细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在 |
| | | 24 年 9 月 19 |
| | | 接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1 |
| | | 传代编码方式演例:祖代:DD-O-240919-01 |
| | | 传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2 |
| | | 编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2 |
| | | 细胞库说明:3.2.1 |
| | | 直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2 |
| | | 从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3 |
| | | 主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4. |
| | | 菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 |
| | | a-01、a-02 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2 |
| | | 接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。 |
| | | </p> |
| | | </div> |
| | | </el-dialog> |
| | | </el-card> |
| | | |
| | | <!-- Table --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="tableData" |
| | | :total="total" |
| | | @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange" |
| | | > |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="roleType == 4" label="状态:"> |
| | | <el-select v-model="form.status" placeholder="请选择"> |
| | | <el-option label="全部" value=""></el-option> |
| | | <el-option label="已出库" value="1"></el-option> |
| | | <el-option label="出库待确认" value="2"></el-option> |
| | | <el-option label="已入库" value="3"></el-option> |
| | | <el-option label="入库待确认" value="4"></el-option> |
| | | </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-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')" |
| | | > |
| | | <div class="dialog-content"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入主细胞库登记表】,请分类管理。</p> |
| | | <p>1.1 接种入主细胞库(现代-M)的菌株经过培养和保藏。</p> |
| | | <p>1.2 从原始细胞库转入的菌株需要按照标准程序进行记录和管理。</p> |
| | | <p>1.3 主细胞库的菌株可用于科研项目和工业生产中的应用研究。</p> |
| | | <p>1.4 菌株转出时需要严格记录去向和用途,确保可追溯性。</p> |
| | | <p>1.5 主细胞库的菌株保存应当遵循标准操作规程,确保活性和稳定性。</p> |
| | | </div> |
| | | </el-dialog> |
| | | </el-card> |
| | | 主细胞列表 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')" |
| | | > |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | | <div v-if="roleType == 4" class="flex a-center"> |
| | | <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> |
| | | |
| | | <!-- Table --> |
| | | <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="状态:"> |
| | | <el-select v-model="form.status" placeholder="请选择"> |
| | | <el-option label="全部" value=""></el-option> |
| | | <el-option label="已入库" value="1"></el-option> |
| | | <el-option label="已出库" value="2"></el-option> |
| | | <el-option label="入库待确认" value="3"></el-option> |
| | | </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-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div class="title" :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')"> |
| | | 主细胞列表</div> |
| | | <div class="drafts" :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')"> |
| | | 草稿箱</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> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table> |
| | | <el-table-column prop="strainNo" 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="当前状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <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> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <StrainDetail |
| | | :visible.sync="detailVisible" |
| | | :detail="currentDetail" |
| | | /> |
| | | </div> |
| | | <template #table> |
| | | <el-table-column prop="strainCode" label="菌种编号" /> |
| | | <el-table-column prop="strainName" 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> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button v-if="row.status == 2 || row.status == 4" type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button |
| | | v-if="currentType === 'list'" |
| | | type="text" |
| | | @click="handleRecord(row)" |
| | | >出入库记录</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <StrainDetail :visible.sync="detailVisible" :detail="currentDetail" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import StrainDetail from '../strain-library-manage/components/StrainDetail.vue' |
| | | import StrainDetail from "../strain-library-manage/components/StrainDetail.vue"; |
| | | import { getList, deleteStrainLibrary } from "../strain-library-manage/service"; |
| | | |
| | | export default { |
| | | name: 'MainCellLibrary', |
| | | components: { |
| | | StrainDetail |
| | | name: "StrainLibraryManage", |
| | | components: { |
| | | StrainDetail, |
| | | }, |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | currentType: "list", |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | total: 800, |
| | | tableData: [], |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | activated() { |
| | | this.searchData(); |
| | | // 角色类型 1=超级管理员 2=审批人 3=工程师 4=实验员 |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | }, |
| | | methods: { |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteStrainLibrary({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.searchData(); |
| | | }); |
| | | }); |
| | | }, |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | currentType: 'list', |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | }, |
| | | total: 800, |
| | | tableData: [ |
| | | { |
| | | strainNo: 'M-2024001', |
| | | strainName: '大肠杆菌BL21', |
| | | source: '原始细胞库', |
| | | method: '分子生物学鉴定', |
| | | certificate: '常用表达宿主菌,含有DE3溶源体,适合蛋白表达', |
| | | storage: '甘油冷冻', |
| | | amount: 'M区-01-001', |
| | | inventory: '100', |
| | | notes: '高效表达宿主', |
| | | status: '1' |
| | | }, |
| | | { |
| | | strainNo: 'M-2024002', |
| | | strainName: '乳酸菌L.plantarum', |
| | | source: '菌种保藏中心', |
| | | method: '16S rDNA测序', |
| | | certificate: '革兰氏阳性杆菌,产乳酸,益生特性', |
| | | storage: '冷冻保存', |
| | | amount: 'M区-02-005', |
| | | inventory: '80', |
| | | notes: '发酵剂开发', |
| | | status: '1' |
| | | }, |
| | | { |
| | | strainNo: 'M-2024003', |
| | | strainName: '酵母S.cerevisiae', |
| | | source: '原始细胞库', |
| | | method: '生理生化鉴定', |
| | | certificate: '椭圆形单细胞真菌,高效发酵能力', |
| | | storage: '斜面培养', |
| | | amount: 'M区-03-002', |
| | | inventory: '60', |
| | | notes: '酒精发酵', |
| | | status: '2' |
| | | }, |
| | | { |
| | | strainNo: 'M-2024004', |
| | | strainName: '枯草芽孢杆菌', |
| | | source: '环境样本分离', |
| | | method: '形态学观察和生化鉴定', |
| | | certificate: '革兰氏阳性芽孢杆菌,可产多种酶类', |
| | | storage: '冻干保存', |
| | | amount: 'M区-01-003', |
| | | inventory: '90', |
| | | notes: '工业酶生产', |
| | | status: '3' |
| | | }, |
| | | { |
| | | strainNo: 'M-2024005', |
| | | strainName: '链霉菌S.griseus', |
| | | source: '原始细胞库', |
| | | method: 'PCR鉴定', |
| | | certificate: '丝状菌,产生灰色气生菌丝和分生孢子', |
| | | storage: '液氮保存', |
| | | amount: 'M区-04-001', |
| | | inventory: '70', |
| | | notes: '抗生素研究', |
| | | status: '1' |
| | | } |
| | | ] |
| | | } |
| | | handleRecord(row) { |
| | | this.$router.push({ |
| | | path: `/strain-library/strain-library-manage/record?id=${row.id}`, |
| | | }); |
| | | }, |
| | | methods: { |
| | | handleViewMore() { |
| | | this.dialogVisible = true; |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | } |
| | | 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/main-cell-library/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 |
| | | } |
| | | }) |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | // Implement page change logic |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | // Implement size change logic |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | // Implement type change logic |
| | | }, |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: 'success', |
| | | 2: 'info', |
| | | 3: 'warning' |
| | | } |
| | | return types[status] || 'info' |
| | | }, |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: '已入库', |
| | | 2: '已出库', |
| | | 3: '入库待确认' |
| | | } |
| | | return texts[status] || '未知状态' |
| | | } |
| | | } |
| | | } |
| | | handleNewStrain() { |
| | | this.$router.push({ path: "/strain-library/main-cell-library/add" }); |
| | | }, |
| | | handleEdit(row) { |
| | | this.$router.push({ |
| | | path: `/strain-library/main-cell-library/add?id=${row.id}`, |
| | | }); |
| | | }, |
| | | handleDetail(row) { |
| | | this.currentDetail = row; |
| | | this.detailVisible = true; |
| | | }, |
| | | handleViewMore() { |
| | | this.dialogVisible = true; |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }; |
| | | this.searchData(); |
| | | }, |
| | | searchData() { |
| | | 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: this.form.status, |
| | | type: 2, |
| | | }; |
| | | console.log(params); |
| | | |
| | | 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; |
| | | this.searchData(); |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size; |
| | | this.searchData(); |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | this.searchData(); |
| | | }, |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: "warning", |
| | | 2: "warning", |
| | | 3: "success", |
| | | 4: "success", |
| | | }; |
| | | return types[status] || "info"; |
| | | }, |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: "已出库", |
| | | 2: "出库待确认", |
| | | 3: "已入库", |
| | | 4: "入库待确认", |
| | | }; |
| | | return texts[status] || "未知状态"; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list { |
| | | padding: 20px; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .box-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | position: relative; |
| | | .box-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | position: relative; |
| | | |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049C9A; |
| | | } |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | margin-left: 30px; |
| | | transition: max-height 0.3s ease-in-out; |
| | | overflow: hidden; |
| | | |
| | | &.collapsed { |
| | | max-height: 48px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | } |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049c9a; |
| | | } |
| | | } |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | margin-left: 30px; |
| | | transition: max-height 0.3s ease-in-out; |
| | | overflow: hidden; |
| | | |
| | | &.collapsed { |
| | | max-height: 48px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .search-form { |
| | | margin-bottom: 20px; |
| | | background: #F5F7FA; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | margin-bottom: 20px; |
| | | background: #f5f7fa; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | margin-bottom: 20px; |
| | | margin-bottom: 20px; |
| | | |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | |
| | | .tab-container { |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #DCDFE6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #F5F7FA; |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #dcdfe6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #f5f7fa; |
| | | |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049C9A; |
| | | color: #049C9A; |
| | | font-weight: bold; |
| | | } |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049c9a; |
| | | color: #049c9a; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .flex { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .a-center { |
| | | align-items: center; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | width: unset; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | width: unset; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | } |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | |
| | | } |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .view-all-dialog { |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | |
| | | .dialog-content { |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | .dialog-content { |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <template> |
| | | <div class="record-page"> |
| | | <div class="page-header"> |
| | | <div class="header-left"> |
| | | <el-page-header @back="goBack" content="主细胞出入库记录"></el-page-header> |
| | | </div> |
| | | <div class="header-right"> |
| | | <el-button type="primary" icon="el-icon-plus" @click="handleAddRecord">新增记录</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-card class="record-card"> |
| | | <div class="strain-info"> |
| | | <!-- 基本信息展示区域 --> |
| | | <el-card class="header-box"> |
| | | <div class="header-content"> |
| | | <!-- 第一行 --> |
| | | <div class="info-row"> |
| | | <div class="info-item"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种编号:</span> |
| | | <span class="value">{{ strainInfo.strainNo }}</span> |
| | | <span class="value">{{ detail.strainCode }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">菌种名称:</span> |
| | | <span class="value">{{ strainInfo.strainName }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">菌种来源:</span> |
| | | <span class="value">{{ strainInfo.source }}</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <div class="info-item"> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">鉴定方法:</span> |
| | | <span class="value">{{ strainInfo.method }}</span> |
| | | <span class="value">{{ detail.appraisalMethod }}</span> |
| | | </div> |
| | | <div class="info-item full"> |
| | | <span class="label">特征描述:</span> |
| | | <span class="value">{{ strainInfo.certificate }}</span> |
| | | <div class="info-item flex-column"> |
| | | <span class="label">保藏位置:</span> |
| | | <span class="value">{{ detail.saveLocation }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 第二行 --> |
| | | <div class="info-row"> |
| | | <div class="info-item"> |
| | | <span class="label">菌种保存方法:</span> |
| | | <span class="value">{{ strainInfo.storage }}</span> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种名称:</span> |
| | | <span class="value">{{ detail.strainName }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">保存位置:</span> |
| | | <span class="value">{{ strainInfo.amount }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">出入库状态:</span> |
| | | <span class="value status">{{ strainInfo.statusText }}</span> |
| | | <div class="info-item flex-column full-width"> |
| | | <span class="label">特性描述:</span> |
| | | <span class="value">{{ detail.features }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="record-timeline-container"> |
| | | <h3 class="section-title">出入库记录</h3> |
| | | <RecordTimeline :list="recordList" /> |
| | | |
| | | <!-- 第三行 --> |
| | | <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> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 新增记录弹窗 --> |
| | | <el-dialog |
| | | title="新增出入库记录" |
| | | :visible.sync="dialogVisible" |
| | | width="500px" |
| | | |
| | | <!-- 出入库记录表格 --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="recordList" |
| | | :total="total" |
| | | @currentChange="handlePageChange" |
| | | > |
| | | <el-form ref="recordForm" :model="recordForm" :rules="recordRules" label-width="100px"> |
| | | <el-form-item label="操作类型" prop="type"> |
| | | <el-radio-group v-model="recordForm.type"> |
| | | <el-radio label="入库">入库</el-radio> |
| | | <el-radio label="出库">出库</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="操作人" prop="operator"> |
| | | <el-input v-model="recordForm.operator" placeholder="请输入操作人"></el-input> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="操作时间" prop="operateTime"> |
| | | <el-date-picker |
| | | v-model="recordForm.operateTime" |
| | | type="datetime" |
| | | placeholder="选择日期时间" |
| | | value-format="yyyy-MM-dd HH:mm:ss" |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="保藏人" prop="reviewer"> |
| | | <el-input v-model="recordForm.reviewer" placeholder="请输入保藏人"></el-input> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="操作数量" prop="amount"> |
| | | <el-input-number v-model="recordForm.amount" :min="1" :max="100"></el-input-number> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="备注" prop="remarks"> |
| | | <el-input |
| | | type="textarea" |
| | | v-model="recordForm.remarks" |
| | | :rows="3" |
| | | placeholder="请输入备注" |
| | | ></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <span slot="footer" class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false">取 消</el-button> |
| | | <el-button type="primary" @click="submitRecord">确 定</el-button> |
| | | </span> |
| | | </el-dialog> |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'table' }" |
| | | @click="handleTypeChange('table')" |
| | | > |
| | | 原始细胞保藏出/入库登记表 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'timeline' }" |
| | | @click="handleTypeChange('timeline')" |
| | | > |
| | | 原始细胞保藏出/入库时间轴 |
| | | </div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button |
| | | v-if="roleType == 4" |
| | | @click="handleAddRecord" |
| | | class="el-icon-plus" |
| | | type="primary" |
| | | >新增出入库记录</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table v-if="currentType === 'table'"> |
| | | <el-table-column prop="type" label="出库/入库"> |
| | | <template #default="{ row }"> |
| | | <span> |
| | | {{ row.type === 1 ? "出库" : "入库" }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="boundTime" label="操作时间" /> |
| | | <el-table-column prop="handleSignature" label="操作人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.handleSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.handleSignature" |
| | | :preview-src-list="[row.handleSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="preserveSignature" label="菌种保藏人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.preserveSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.preserveSignature" |
| | | :preview-src-list="[row.preserveSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.preserveSignature ? 'success' : 'warning'"> |
| | | {{ row.preserveSignature ? "已确认" : "待确认" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="180"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | v-if="!row.preserveSignature && roleType == 3" |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleConfirm(row)" |
| | | >确认</el-button |
| | | > |
| | | <el-button |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleView(row)" |
| | | >详情</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | <template #tableCustom v-if="currentType === 'timeline'"> |
| | | <record-timeline :list="timelineList" /> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <!-- 详情弹窗 --> |
| | | <record-detail-dialog |
| | | :visible.sync="dialogVisible" |
| | | :record-data="currentRecord" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | :type="dialogType" |
| | | /> |
| | | <!-- 新增出入库记录弹窗 --> |
| | | <add-record-dialog |
| | | :visible.sync="addDialogVisible" |
| | | @confirm="handleAddRecordConfirm" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import RecordTimeline from '../strain-library-manage/components/RecordTimeline.vue' |
| | | import RecordDetailDialog from "../strain-library-manage/components/RecordDetailDialog.vue"; |
| | | import AddRecordDialog from "../strain-library-manage/components/AddRecordDialog.vue"; |
| | | import RecordTimeline from "../strain-library-manage/components/RecordTimeline.vue"; |
| | | import { |
| | | timeList, |
| | | getDetail, |
| | | addWarehousing, |
| | | getDetailById, |
| | | confirmWarehousing, |
| | | } from "./service"; |
| | | |
| | | export default { |
| | | name: 'MainCellRecord', |
| | | name: "StrainRecord", |
| | | components: { |
| | | RecordTimeline |
| | | RecordDetailDialog, |
| | | AddRecordDialog, |
| | | RecordTimeline, |
| | | }, |
| | | data() { |
| | | return { |
| | | strainId: '', |
| | | strainInfo: { |
| | | strainNo: 'M-2024001', |
| | | strainName: '大肠杆菌BL21', |
| | | source: '原始细胞库', |
| | | method: '分子生物学鉴定', |
| | | certificate: '常用表达宿主菌,含有DE3溶源体,适合蛋白表达', |
| | | storage: '甘油冷冻', |
| | | amount: 'M区-01-001', |
| | | inventory: '100', |
| | | status: '1', |
| | | statusText: '已入库' |
| | | currentType: "table", |
| | | detail: {}, |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | recordList: [ |
| | | { |
| | | type: '入库', |
| | | operator: '张三', |
| | | operateTime: '2024-05-01 10:30:00', |
| | | reviewer: '李四', |
| | | confirmTime: '2024-05-01 14:20:00' |
| | | }, |
| | | { |
| | | type: '出库', |
| | | operator: '王五', |
| | | operateTime: '2024-05-15 09:45:00', |
| | | reviewer: '赵六', |
| | | confirmTime: '2024-05-15 11:30:00' |
| | | }, |
| | | { |
| | | type: '入库', |
| | | operator: '钱七', |
| | | operateTime: '2024-05-20 14:00:00', |
| | | reviewer: '孙八', |
| | | confirmTime: '2024-05-20 16:15:00' |
| | | } |
| | | ], |
| | | recordList: [], |
| | | timelineList: [], |
| | | dialogVisible: false, |
| | | recordForm: { |
| | | type: '入库', |
| | | operator: '', |
| | | operateTime: '', |
| | | reviewer: '', |
| | | amount: 1, |
| | | remarks: '' |
| | | }, |
| | | recordRules: { |
| | | type: [ |
| | | { required: true, message: '请选择操作类型', trigger: 'change' } |
| | | ], |
| | | operator: [ |
| | | { required: true, message: '请输入操作人', trigger: 'blur' } |
| | | ], |
| | | operateTime: [ |
| | | { required: true, message: '请选择操作时间', trigger: 'change' } |
| | | ], |
| | | reviewer: [ |
| | | { required: true, message: '请输入保藏人', trigger: 'blur' } |
| | | ], |
| | | amount: [ |
| | | { required: true, message: '请输入操作数量', trigger: 'blur' } |
| | | ] |
| | | } |
| | | } |
| | | currentRecord: {}, |
| | | addDialogVisible: false, |
| | | dialogType: "detail", |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | created() { |
| | | // 获取路由参数中的菌种ID |
| | | this.strainId = this.$route.query.id |
| | | // 实际项目中这里应该根据ID加载菌种信息和记录列表 |
| | | console.log('加载菌种ID:', this.strainId) |
| | | activated() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | |
| | | // 获取路由参数中的菌种信息 |
| | | const strainId = this.$route.query.id; |
| | | this.queryForm.id = strainId; |
| | | if (strainId) { |
| | | this.getStrainDetail(strainId); |
| | | this.getRecordList(); |
| | | } |
| | | }, |
| | | methods: { |
| | | goBack() { |
| | | this.$router.push('/strain-library/main-cell-library') |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteWarehousing({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.getRecordList(); |
| | | }); |
| | | }); |
| | | }, |
| | | getStrainDetail(id) { |
| | | // 这里应该调用接口获取菌种详情 |
| | | getDetail({ id }).then((res) => { |
| | | this.detail = res; |
| | | }); |
| | | }, |
| | | getRecordList() { |
| | | // 这里应该调用接口获取出入库记录 |
| | | timeList(this.queryForm).then((res) => { |
| | | this.timelineList = res.data; |
| | | }); |
| | | getDetailById({ id: this.$route.query.id }).then((res) => { |
| | | this.recordList = res.warehousingList.records; |
| | | this.total = res.warehousingList.total; |
| | | }); |
| | | }, |
| | | handleView(row) { |
| | | this.dialogType = "detail"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | handleConfirm(row) { |
| | | this.dialogType = "confirm"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | handlePageChange(page) { |
| | | this.queryForm.pageNum = page; |
| | | // 这里应该调用接口获取对应页码的数据 |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | }, |
| | | handleAddRecord() { |
| | | this.dialogVisible = true |
| | | this.resetRecordForm() |
| | | this.addDialogVisible = true; |
| | | }, |
| | | submitRecord() { |
| | | this.$refs.recordForm.validate(valid => { |
| | | if (valid) { |
| | | // 表单验证通过,提交数据 |
| | | console.log('提交的记录数据:', this.recordForm) |
| | | |
| | | // 模拟添加记录到列表 |
| | | const newRecord = { |
| | | type: this.recordForm.type, |
| | | operator: this.recordForm.operator, |
| | | operateTime: this.recordForm.operateTime, |
| | | reviewer: this.recordForm.reviewer, |
| | | confirmTime: new Date().toLocaleString() |
| | | } |
| | | |
| | | // 添加到记录列表的开头 |
| | | this.recordList.unshift(newRecord) |
| | | |
| | | // 关闭弹窗 |
| | | this.dialogVisible = false |
| | | |
| | | // 显示成功消息 |
| | | this.$message.success('记录添加成功') |
| | | handleDialogClose() { |
| | | this.currentRecord = {}; |
| | | this.dialogVisible = false; |
| | | }, |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | confirmWarehousing({ |
| | | id: this.currentRecord.id, |
| | | preserveSignature: data.preserveSignature, |
| | | }).then((res) => { |
| | | console.log(res); |
| | | if (res.code == 200) { |
| | | this.$message.success("操作成功"); |
| | | this.dialogVisible = false; |
| | | // 刷新列表 |
| | | this.getRecordList(); |
| | | } else { |
| | | this.$message.error('请正确填写表单') |
| | | return false |
| | | this.$message.error(res.msg); |
| | | } |
| | | }) |
| | | }); |
| | | }, |
| | | resetRecordForm() { |
| | | this.recordForm = { |
| | | type: '入库', |
| | | operator: '', |
| | | operateTime: '', |
| | | reviewer: '', |
| | | amount: 1, |
| | | remarks: '' |
| | | } |
| | | } |
| | | } |
| | | } |
| | | handleAddRecordConfirm(record) { |
| | | addWarehousing({ ...record, trainLibraryId: this.$route.query.id }).then( |
| | | (res) => { |
| | | this.$message.success("操作成功"); |
| | | this.getRecordList(); |
| | | } |
| | | ); |
| | | }, |
| | | goBack() { |
| | | this.$router.go(-1); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | <style lang="less" scoped> |
| | | .record-page { |
| | | padding: 20px; |
| | | } |
| | | min-height: 100vh; |
| | | |
| | | .page-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | |
| | | .header-left { |
| | | :deep(.el-page-header__content) { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .record-card { |
| | | background: #fff; |
| | | border-radius: 16px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .strain-info { |
| | | padding: 10px 0; |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 16px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-item { |
| | | flex: 1; |
| | | min-width: 200px; |
| | | margin-right: 20px; |
| | | |
| | | &:last-child { |
| | | margin-right: 0; |
| | | } |
| | | |
| | | &.full { |
| | | flex: 2; |
| | | } |
| | | |
| | | .label { |
| | | color: #606266; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .value { |
| | | color: #333; |
| | | font-weight: 500; |
| | | |
| | | &.status { |
| | | color: #67C23A; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .record-timeline-container { |
| | | margin-top: 30px; |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | color: #333; |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | height: 130px; |
| | | overflow: hidden; |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px 30px; |
| | | } |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | |
| | | @media screen and (max-width: 768px) { |
| | | .strain-info { |
| | | .info-row { |
| | | flex-direction: column; |
| | | |
| | | .info-item { |
| | | margin-right: 0; |
| | | margin-bottom: 10px; |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 6px; |
| | | |
| | | &.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; |
| | | word-break: break-all; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 1; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .page-header { |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | |
| | | .header-right { |
| | | margin-top: 16px; |
| | | |
| | | .flex { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .timeline-container { |
| | | padding: 20px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .timeline-card { |
| | | margin-bottom: 10px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | h4 { |
| | | margin: 0 0 10px; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .operation-btn { |
| | | margin-right: 12px; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
New file |
| | |
| | | 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 }) |
| | | } |
| | | |
| | | // 确认出入库 |
| | | export const confirmWarehousing = (data) => { |
| | | return axios.post('/api/t-train-library/confirm', { ...data }) |
| | | } |
| | | |
| | | // 删除菌种库 |
| | | export const deleteStrainLibrary = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteById', { params }) |
| | | } |
| | | |
| | | // 删除菌种库出入库记录 |
| | | export const deleteWarehousing = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteWarehousingById', { params }) |
| | | } |
| | |
| | | <template> |
| | | <Card> |
| | | <el-form |
| | | :model="form" |
| | | :rules="rules" |
| | | ref="strainForm" |
| | | label-position="top" |
| | | class="strain-form" |
| | | > |
| | | <div class="form-grid"> |
| | | <el-form-item label="菌种编号" prop="strainNo" required> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | <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="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> |
| | | <el-form-item label="鉴定方法" prop="identificationMethod" required> |
| | | <el-input v-model="form.identificationMethod" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="特征描述" prop="characteristics" required> |
| | | <el-input v-model="form.characteristics" 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> |
| | | <el-form-item label="保存位置" prop="storageLocation" required> |
| | | <el-input v-model="form.storageLocation" 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="appraisalMethod"> |
| | | <el-input v-model="form.appraisalMethod" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | |
| | | <div class="form-row"> |
| | | <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="saveLocation"> |
| | | <el-input v-model="form.saveLocation" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <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 @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"> |
| | | <div class="dialog-content"> |
| | | <el-form :model="batchForm" ref="batchFormRef" label-position="top" class="batch-form"> |
| | | <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> |
| | | <div class="dialog-notice"> |
| | | <p>注意:操作批量新增后,系统会自动生成对应数量的菌种数据,</p> |
| | | <p>这些菌种的基础信息内容都是一致的,唯独菌种编号内容系统</p> |
| | | <p>不会自动生成,需要操作员自行编辑</p> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="end-btn"> |
| | | <el-button type="primary" @click="handleConfirmBatchAdd">确认新增</el-button> |
| | | </div> |
| | | </template> |
| | | </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: 'AddProductionCell', |
| | | name: 'StrainLibraryManageAdd', |
| | | components: { |
| | | SignatureCanvas |
| | | }, |
| | | data() { |
| | | return { |
| | | batchAddDialogVisible: false, |
| | | signatureVisible: false, |
| | | currentAction: '', // 'submit' or 'batchAdd' |
| | | batchForm: { |
| | | 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) { |
| | | 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.form.isDraft = isDraft |
| | | if (isDraft == 1) { |
| | | //存草稿 |
| | | this.handleSignatureConfirm('') |
| | | } else { |
| | | this.signatureVisible = true |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | handleBatchAdd() { |
| | | this.currentAction = 'batchAdd' |
| | | this.$refs.strainForm.validate((valid) => { |
| | | if (valid) { |
| | | this.batchAddDialogVisible = true |
| | | } |
| | | }) |
| | | }, |
| | | handleConfirmBatchAdd() { |
| | | this.$refs.batchFormRef.validate((valid) => { |
| | | if (valid) { |
| | | this.batchAddDialogVisible = false |
| | | this.signatureVisible = true |
| | | } |
| | | }) |
| | | }, |
| | | handleDraft() { |
| | | // 实现存草稿逻辑 |
| | | console.log('save draft', this.form) |
| | | this.$message.success('草稿保存成功') |
| | | }, |
| | | handleSignatureConfirm(signatureImage) { |
| | | this.signatureVisible = false |
| | | // 处理提交逻辑 |
| | | console.log('submit form with signature:', this.form, signatureImage) |
| | | this.$message.success('提交成功') |
| | | this.$router.back() |
| | | 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: 3, |
| | | }; |
| | | 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') { |
| | | await addBatch(requestData); |
| | | } else { |
| | | await add(requestData); |
| | | } |
| | | this.signatureVisible = false; |
| | | this.$router.back(); |
| | | this.$message.success('操作成功'); |
| | | } catch (error) { |
| | | this.$message.error('操作失败'); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .strain-form { |
| | | padding: 0 40px; |
| | | .add-strain { |
| | | height: 100%; |
| | | background: #F5F7FA; |
| | | |
| | | .form-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(3, 1fr); |
| | | gap: 24px; |
| | | margin-bottom: 24px; |
| | | |
| | | @media screen and (max-width: 1200px) { |
| | | grid-template-columns: repeat(2, 1fr); |
| | | .form-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | } |
| | | } |
| | | |
| | | .header-title { |
| | | margin-bottom: 24px; |
| | | |
| | | &-left { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | img { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | @media screen and (max-width: 768px) { |
| | | grid-template-columns: 1fr; |
| | | |
| | | div { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .end-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 10px; |
| | | |
| | | button { |
| | | width: 180px; |
| | | height: 36px; |
| | | // background: #409EFF; |
| | | } |
| | | } |
| | | |
| | | .strain-form { |
| | | padding: 0 40px; |
| | | |
| | | .form-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 24px; |
| | | margin-bottom: 24px; |
| | | |
| | | &.three-columns { |
| | | |
| | | .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%; |
| | | } |
| | | } |
| | | |
| | | .form-item-placeholder { |
| | | @media screen and (max-width: 1200px) { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .el-form-item { |
| | | margin-bottom: 0; |
| | |
| | | } |
| | | } |
| | | |
| | | .batch-add-dialog { |
| | | :deep(.el-dialog__header) { |
| | | margin: 0; |
| | | padding: 20px; |
| | | text-align: center; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .dialog-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | .batch-form { |
| | | width: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | |
| | | :deep(.el-form-item) { |
| | | width: 320px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | width: 100%; |
| | | color: #606266; |
| | | font-weight: normal; |
| | | padding-bottom: 8px; |
| | | |
| | | &::before { |
| | | color: #F56C6C; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-input) { |
| | | width: 100%; |
| | | |
| | | input { |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .dialog-notice { |
| | | margin-top: 16px; |
| | | text-align: center; |
| | | |
| | | p { |
| | | margin: 0; |
| | | line-height: 22px; |
| | | color: #606266; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__footer) { |
| | | padding: 0 20px 20px; |
| | | text-align: center; |
| | | |
| | | .el-button { |
| | | width: 180px; |
| | | height: 36px; |
| | | padding: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | border-radius: 4px; |
| | | margin: 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .end-btn { |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | margin: 0; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> |
| | | <span>【菌种源保藏出/入细胞库登记表】说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore">查看全部 >></el-button> |
| | | <img src="@/assets/public/notice.png" class="header-icon" /> |
| | | <span>菌种源保藏出/入细胞库登记表说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore" |
| | | >查看全部 >></el-button |
| | | > |
| | | </div> |
| | | <div class="header-content" :class="{ 'collapsed': true }"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p> |
| | | <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p> |
| | | <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p> |
| | | <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p> |
| | | <div class="header-content" :class="{ collapsed: true }"> |
| | | <p> |
| | | 1. 菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,菌种来源有 3 |
| | | 条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2 |
| | | 是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3 |
| | | 是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。 |
| | | 2. |
| | | 菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1 |
| | | 原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3 |
| | | 生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1 |
| | | 细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在 |
| | | 24 年 9 月 19 |
| | | 接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1 |
| | | 传代编码方式演例:祖代:DD-O-240919-01 |
| | | 传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2 |
| | | 编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2 |
| | | 细胞库说明:3.2.1 |
| | | 直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2 |
| | | 从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3 |
| | | 主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4. |
| | | 菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 a-01、a-02 |
| | | 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2 |
| | | 接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。 |
| | | </p> |
| | | </div> |
| | | |
| | | <!-- 查看全部弹窗 --> |
| | | <el-dialog |
| | | title="菌种源保藏出/入生产细胞库登记表说明" |
| | | title="菌种源保藏出/入细胞库登记表说明" |
| | | :visible.sync="dialogVisible" |
| | | width="50%" |
| | | class="view-all-dialog" |
| | | > |
| | | <div class="dialog-content"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p> |
| | | <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p> |
| | | <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p> |
| | | <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p> |
| | | <p> |
| | | 1. 菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,菌种来源有 3 |
| | | 条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2 |
| | | 是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3 |
| | | 是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。2. |
| | | 菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1 |
| | | 原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3 |
| | | 生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1 |
| | | 细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在 |
| | | 24 年 9 月 19 |
| | | 接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1 |
| | | 传代编码方式演例:祖代:DD-O-240919-01 |
| | | 传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2 |
| | | 编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2 |
| | | 细胞库说明:3.2.1 |
| | | 直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2 |
| | | 从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3 |
| | | 主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4. |
| | | 菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 |
| | | a-01、a-02 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2 |
| | | 接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。 |
| | | </p> |
| | | </div> |
| | | </el-dialog> |
| | | </el-card> |
| | | |
| | | <!-- Table --> |
| | | <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="tableData" |
| | | :total="total" |
| | | @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange" |
| | | > |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="状态:"> |
| | | <el-form-item v-if="roleType == 4" label="状态:"> |
| | | <el-select v-model="form.status" placeholder="请选择"> |
| | | <el-option label="全部" value=""></el-option> |
| | | <el-option |
| | | v-for="item in statusOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value"> |
| | | </el-option> |
| | | <el-option label="已出库" value="1"></el-option> |
| | | <el-option label="出库待确认" value="2"></el-option> |
| | | <el-option label="已入库" value="3"></el-option> |
| | | <el-option label="入库待确认" value="4"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item class="search-btn-box"> |
| | |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div class="title" :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')"> |
| | | 生产细胞列表</div> |
| | | <div class="drafts" :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')"> |
| | | 草稿箱</div> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')" |
| | | > |
| | | 生产细胞列表 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')" |
| | | > |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button @click="handleAdd" class="el-icon-plus" type="primary" style="margin-right: 12px;">新增生产细胞</el-button> |
| | | <el-button @click="handleAdd" class="el-icon-plus" type="primary" style="margin-right: 12px;">批量新增</el-button> |
| | | <div v-if="roleType == 4" class="flex a-center"> |
| | | <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 type="selection" width="55" /> |
| | | <el-table-column prop="strainNo" label="菌种编号" width="150" /> |
| | | <el-table-column prop="strainName" label="菌种名称" width="180" /> |
| | | <el-table-column prop="source" label="菌种来源" width="150" /> |
| | | <el-table-column prop="preservationMethod" label="鉴定方法" width="120" /> |
| | | <el-table-column prop="storageLocation" label="特征描述" width="150" /> |
| | | <el-table-column prop="inventory" label="菌种保存方法" width="100" /> |
| | | <el-table-column prop="inventory" label="保存位置" width="100" /> |
| | | <el-table-column prop="inventory" label="库存余量" width="100" /> |
| | | <el-table-column prop="inventory" label="备注" /> |
| | | <el-table-column prop="status" label="状态" width="100"> |
| | | <template slot-scope="scope"> |
| | | <el-tag :type="getStatusType(scope.row.status)">{{ scope.row.status }}</el-tag> |
| | | <el-table-column prop="strainCode" label="菌种编号" /> |
| | | <el-table-column prop="strainName" 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> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="150" fixed="right"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" @click="handleView(scope.row)">详情</el-button> |
| | | <el-button type="text" @click="handleEdit(scope.row)">编辑</el-button> |
| | | <el-button type="text" @click="handleDelete(scope.row)" class="delete-btn">删除</el-button> |
| | | <el-table-column label="操作" width="200"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button v-if="row.status == 2 || row.status == 4" type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button |
| | | v-if="currentType === 'list'" |
| | | type="text" |
| | | @click="handleRecord(row)" |
| | | >出入库记录</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <!-- 删除确认对话框 --> |
| | | <el-dialog |
| | | title="确认删除" |
| | | :visible.sync="deleteDialogVisible" |
| | | width="30%"> |
| | | <div class="delete-dialog-content"> |
| | | <i class="el-icon-warning-outline warning-icon"></i> |
| | | <span>确定要删除该菌种记录吗?删除后将无法恢复。</span> |
| | | </div> |
| | | <span slot="footer" class="dialog-footer"> |
| | | <el-button @click="deleteDialogVisible = false">取消</el-button> |
| | | <el-button type="danger" @click="confirmDelete">确定</el-button> |
| | | </span> |
| | | </el-dialog> |
| | | <StrainDetail :visible.sync="detailVisible" :detail="currentDetail" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import StrainDetail from "../strain-library-manage/components/StrainDetail.vue"; |
| | | import { getList, deleteStrainLibrary } from "../strain-library-manage/service"; |
| | | |
| | | export default { |
| | | name: 'ProductionCellLibrary', |
| | | name: "StrainLibraryManage", |
| | | components: { |
| | | StrainDetail, |
| | | }, |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | currentType: 'list', |
| | | currentType: "list", |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | pageNum: 1, |
| | | }, |
| | | total: 100, |
| | | loading: false, |
| | | sourceOptions: [ |
| | | { value: '主细胞库', label: '主细胞库' }, |
| | | { value: '工作细胞库', label: '工作细胞库' }, |
| | | { value: '外部来源', label: '外部来源' } |
| | | ], |
| | | statusOptions: [ |
| | | { value: '正常', label: '正常' }, |
| | | { value: '缺货', label: '缺货' }, |
| | | { value: '异常', label: '异常' }, |
| | | { value: '已停用', label: '已停用' } |
| | | ], |
| | | total: 800, |
| | | tableData: [], |
| | | selectedRows: [], |
| | | deleteDialogVisible: false, |
| | | deleteRow: null |
| | | } |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | created() { |
| | | this.fetchData(); |
| | | activated() { |
| | | this.searchData(); |
| | | // 角色类型 1=超级管理员 2=审批人 3=工程师 4=实验员 |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | }, |
| | | methods: { |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteStrainLibrary({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.searchData(); |
| | | }); |
| | | }); |
| | | }, |
| | | handleRecord(row) { |
| | | this.$router.push({ |
| | | path: `/strain-library/strain-library-manage/record?id=${row.id}`, |
| | | }); |
| | | }, |
| | | handleNewStrain() { |
| | | this.$router.push({ path: "/strain-library/production-cell-library/add" }); |
| | | }, |
| | | handleEdit(row) { |
| | | this.$router.push({ |
| | | path: `/strain-library/production-cell-library/add?id=${row.id}`, |
| | | }); |
| | | }, |
| | | handleDetail(row) { |
| | | this.currentDetail = row; |
| | | this.detailVisible = true; |
| | | }, |
| | | handleViewMore() { |
| | | this.dialogVisible = true; |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | } |
| | | this.searchData() |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }; |
| | | this.searchData(); |
| | | }, |
| | | searchData() { |
| | | this.queryForm.pageNum = 1; |
| | | this.fetchData(); |
| | | }, |
| | | // 获取数据 |
| | | fetchData() { |
| | | this.loading = true; |
| | | |
| | | // 构建请求参数 |
| | | const params = { |
| | | page: this.queryForm.pageNum, |
| | | pageNum: this.queryForm.pageNum, |
| | | pageSize: this.queryForm.pageSize, |
| | | ...this.form |
| | | strainCode: this.form.strainNo, |
| | | strainName: this.form.strainName, |
| | | isDraft: this.currentType === "draft" ? 1 : 0, |
| | | status: this.form.status, |
| | | type: 3, |
| | | }; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | const mockData = []; |
| | | for (let i = 1; i <= 10; i++) { |
| | | mockData.push({ |
| | | id: `${i}`, |
| | | strainNo: `PCLS-2023-${String(i).padStart(3, '0')}`, |
| | | strainName: `枯草芽孢杆菌生产株${i}`, |
| | | source: i % 3 === 0 ? '外部来源' : (i % 2 === 0 ? '工作细胞库' : '主细胞库'), |
| | | preservationMethod: i % 2 === 0 ? '冻干保存' : '超低温冷冻保存', |
| | | storageLocation: `A区-A-${100 + i}-冷藏柜`, |
| | | inventory: 10 + i, |
| | | status: i % 4 === 0 ? '异常' : (i % 3 === 0 ? '缺货' : (i % 2 === 0 ? '已停用' : '正常')), |
| | | preparationDate: `2023-05-${String(i).padStart(2, '0')}`, |
| | | expiryDate: `2024-05-${String(i).padStart(2, '0')}` |
| | | }); |
| | | } |
| | | |
| | | this.tableData = mockData; |
| | | this.total = 100; // 模拟总数 |
| | | this.loading = false; |
| | | }, 500); |
| | | getList(params) |
| | | .then((res) => { |
| | | if (res.code === 200) { |
| | | this.tableData = res.data.records; |
| | | this.total = res.data.total; |
| | | } |
| | | }) |
| | | .catch((err) => { |
| | | this.$message.error("数据加载失败"); |
| | | }); |
| | | }, |
| | | |
| | | // 状态标签类型 |
| | | getStatusType(status) { |
| | | switch(status) { |
| | | case '正常': |
| | | return 'success'; |
| | | case '缺货': |
| | | return 'warning'; |
| | | case '异常': |
| | | return 'danger'; |
| | | case '已停用': |
| | | return 'info'; |
| | | default: |
| | | return 'info'; |
| | | } |
| | | }, |
| | | |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | this.fetchData(); |
| | | this.queryForm.pageNum = page; |
| | | this.searchData(); |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | this.queryForm.pageNum = 1 |
| | | this.fetchData(); |
| | | this.queryForm.pageSize = size; |
| | | this.searchData(); |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | this.fetchData(); |
| | | this.searchData(); |
| | | }, |
| | | |
| | | // 表格多选 |
| | | handleSelectionChange(selection) { |
| | | this.selectedRows = selection; |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: "warning", |
| | | 2: "warning", |
| | | 3: "success", |
| | | 4: "success", |
| | | }; |
| | | return types[status] || "info"; |
| | | }, |
| | | |
| | | // 新增菌种 |
| | | handleAdd() { |
| | | this.$router.push('/strain-library/production-cell-library/add'); |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: "已出库", |
| | | 2: "出库待确认", |
| | | 3: "已入库", |
| | | 4: "入库待确认", |
| | | }; |
| | | return texts[status] || "未知状态"; |
| | | }, |
| | | |
| | | // 查看菌种详情 |
| | | handleView(row) { |
| | | this.$router.push(`/strain-library/production-cell-library/record/${row.id}`); |
| | | }, |
| | | |
| | | // 编辑菌种 |
| | | handleEdit(row) { |
| | | this.$router.push(`/strain-library/production-cell-library/edit/${row.id}`); |
| | | }, |
| | | |
| | | // 删除菌种 |
| | | handleDelete(row) { |
| | | this.deleteRow = row; |
| | | this.deleteDialogVisible = true; |
| | | }, |
| | | |
| | | // 确认删除 |
| | | confirmDelete() { |
| | | if (!this.deleteRow) return; |
| | | |
| | | // 模拟API请求 |
| | | this.$message({ |
| | | type: 'success', |
| | | message: `删除成功: ${this.deleteRow.strainNo} - ${this.deleteRow.strainName}` |
| | | }); |
| | | |
| | | // 移除本地数据 |
| | | const index = this.tableData.findIndex(item => item.id === this.deleteRow.id); |
| | | if (index !== -1) { |
| | | this.tableData.splice(index, 1); |
| | | } |
| | | |
| | | this.deleteDialogVisible = false; |
| | | this.deleteRow = null; |
| | | }, |
| | | |
| | | // 导出 |
| | | handleExport() { |
| | | this.$message.info('生产细胞库菌种导出功能开发中'); |
| | | // 实际项目中应实现导出逻辑 |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049C9A; |
| | | color: #049c9a; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | .search-btn-box { |
| | | margin-left: auto; |
| | | .search-form { |
| | | margin-bottom: 20px; |
| | | background: #f5f7fa; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | margin-bottom: 20px; |
| | | |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | |
| | | .tab-container { |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #dcdfe6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #f5f7fa; |
| | | |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049c9a; |
| | | color: #049c9a; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .flex { |
| | |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | |
| | | } |
| | | |
| | | .drafts { |
| | |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | |
| | | } |
| | | } |
| | | |
| | | .delete-dialog-content { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 20px 0; |
| | | |
| | | .warning-icon { |
| | | font-size: 24px; |
| | | color: #E6A23C; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | |
| | | .view-all-dialog { |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | border-bottom: 1px solid #ebeef5; |
| | | margin-right: 0; |
| | | |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | |
| | | |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | .delete-btn { |
| | | color: #F56C6C; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <template> |
| | | <div class="production-cell-record"> |
| | | <!-- 页面头部 --> |
| | | <div class="page-header"> |
| | | <div class="header-left"> |
| | | <el-button icon="el-icon-arrow-left" @click="$router.go(-1)">返回</el-button> |
| | | <h2>生产细胞库菌种详情</h2> |
| | | </div> |
| | | <div class="header-actions"> |
| | | <el-button type="primary" plain icon="el-icon-edit" @click="handleEdit">编辑</el-button> |
| | | <el-button type="primary" plain icon="el-icon-printer" @click="handlePrint">打印</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="record-page"> |
| | | <!-- 基本信息展示区域 --> |
| | | <el-card class="header-box"> |
| | | <div class="header-content"> |
| | | <!-- 第一行 --> |
| | | <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> |
| | | |
| | | <!-- 菌种信息卡片 --> |
| | | <el-card class="strain-card" v-loading="loading"> |
| | | <div slot="header" class="card-header"> |
| | | <span class="card-title">菌种信息</span> |
| | | <div class="status-tag"> |
| | | <el-tag :type="getStatusType(strainData.status)">{{ strainData.status }}</el-tag> |
| | | <!-- 第二行 --> |
| | | <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> |
| | | |
| | | <div class="strain-info"> |
| | | <div class="info-item"> |
| | | <span class="label">菌种编号:</span> |
| | | <span class="value">{{ strainData.strainNo }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">菌种名称:</span> |
| | | <span class="value">{{ strainData.strainName }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">菌种来源:</span> |
| | | <span class="value">{{ strainData.source }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">生产批次:</span> |
| | | <span class="value">{{ strainData.batchNo }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">保存方法:</span> |
| | | <span class="value">{{ strainData.preservationMethod }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">保存位置:</span> |
| | | <span class="value">{{ strainData.storageLocation }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">当前库存:</span> |
| | | <span class="value">{{ strainData.inventory }} 份</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">状态:</span> |
| | | <span class="value">{{ strainData.status }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">更新时间:</span> |
| | | <span class="value">{{ strainData.updateTime }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">制备日期:</span> |
| | | <span class="value">{{ strainData.preparationDate }}</span> |
| | | </div> |
| | | <div class="info-item"> |
| | | <span class="label">有效期至:</span> |
| | | <span class="value">{{ strainData.expiryDate }}</span> |
| | | </div> |
| | | <div class="info-item full-width"> |
| | | <span class="label">特征描述:</span> |
| | | <div class="value description">{{ strainData.description }}</div> |
| | | </div> |
| | | |
| | | <div class="info-item full-width" v-if="strainData.certificateUrl"> |
| | | <span class="label">质量证书:</span> |
| | | <div class="value"> |
| | | <el-button type="text" @click="handleViewCertificate">查看证书</el-button> |
| | | <el-button type="text" @click="handleDownloadCertificate">下载证书</el-button> |
| | | |
| | | <!-- 第三行 --> |
| | | <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> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 使用记录 --> |
| | | <el-card class="record-card" v-loading="loadingRecords"> |
| | | <div slot="header" class="card-header"> |
| | | <span class="card-title">使用记录</span> |
| | | <el-button type="text" @click="handleAddUsage">新增使用记录</el-button> |
| | | </div> |
| | | |
| | | <el-table |
| | | :data="usageRecords" |
| | | style="width: 100%" |
| | | :empty-text="usageRecords.length ? '' : '暂无使用记录'" |
| | | > |
| | | <el-table-column prop="date" label="使用日期" width="120"></el-table-column> |
| | | <el-table-column prop="amount" label="使用数量" width="100"></el-table-column> |
| | | <el-table-column prop="operator" label="操作人" width="120"></el-table-column> |
| | | <el-table-column prop="project" label="项目名称"></el-table-column> |
| | | <el-table-column prop="batchNo" label="生产批次" width="150"></el-table-column> |
| | | <el-table-column prop="purpose" label="使用目的"></el-table-column> |
| | | <el-table-column label="操作" width="120"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" size="small" @click="handleViewUsageDetail(scope.row)">查看</el-button> |
| | | <el-button type="text" size="small" @click="handleEditUsage(scope.row)">编辑</el-button> |
| | | <!-- 出入库记录表格 --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="recordList" |
| | | :total="total" |
| | | @currentChange="handlePageChange" |
| | | > |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'table' }" |
| | | @click="handleTypeChange('table')" |
| | | > |
| | | 原始细胞保藏出/入库登记表 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'timeline' }" |
| | | @click="handleTypeChange('timeline')" |
| | | > |
| | | 原始细胞保藏出/入库时间轴 |
| | | </div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button |
| | | v-if="roleType == 4" |
| | | @click="handleAddRecord" |
| | | class="el-icon-plus" |
| | | type="primary" |
| | | >新增出入库记录</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table v-if="currentType === 'table'"> |
| | | <el-table-column prop="type" label="出库/入库"> |
| | | <template #default="{ row }"> |
| | | <span> |
| | | {{ row.type === 1 ? "出库" : "入库" }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pagination-container" v-if="usageRecords.length"> |
| | | <el-pagination |
| | | background |
| | | layout="prev, pager, next" |
| | | :total="usageTotalCount" |
| | | :current-page.sync="usageCurrentPage" |
| | | :page-size="usagePageSize" |
| | | @current-change="handleUsagePageChange"> |
| | | </el-pagination> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 测试记录 --> |
| | | <el-card class="record-card" v-loading="loadingTests"> |
| | | <div slot="header" class="card-header"> |
| | | <span class="card-title">测试记录</span> |
| | | <el-button type="text" @click="handleAddTest">新增测试记录</el-button> |
| | | </div> |
| | | |
| | | <el-table |
| | | :data="testRecords" |
| | | style="width: 100%" |
| | | :empty-text="testRecords.length ? '' : '暂无测试记录'" |
| | | > |
| | | <el-table-column prop="date" label="测试日期" width="120"></el-table-column> |
| | | <el-table-column prop="type" label="测试类型" width="150"></el-table-column> |
| | | <el-table-column prop="operator" label="操作人" width="120"></el-table-column> |
| | | <el-table-column prop="result" label="测试结果"> |
| | | <template slot-scope="scope"> |
| | | <el-tag :type="scope.row.result === '合格' ? 'success' : scope.row.result === '不合格' ? 'danger' : 'info'"> |
| | | {{ scope.row.result }} |
| | | <el-table-column prop="boundTime" label="操作时间" /> |
| | | <el-table-column prop="handleSignature" label="操作人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.handleSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.handleSignature" |
| | | :preview-src-list="[row.handleSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="preserveSignature" label="菌种保藏人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.preserveSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.preserveSignature" |
| | | :preview-src-list="[row.preserveSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.preserveSignature ? 'success' : 'warning'"> |
| | | {{ row.preserveSignature ? "已确认" : "待确认" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="remark" label="备注"></el-table-column> |
| | | <el-table-column label="操作" width="120"> |
| | | <template slot-scope="scope"> |
| | | <el-button type="text" size="small" @click="handleViewTestDetail(scope.row)">查看</el-button> |
| | | <el-button type="text" size="small" @click="handleEditTest(scope.row)">编辑</el-button> |
| | | <el-table-column label="操作" width="180"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | v-if="!row.preserveSignature && roleType == 3" |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleConfirm(row)" |
| | | >确认</el-button |
| | | > |
| | | <el-button |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleView(row)" |
| | | >详情</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div class="pagination-container" v-if="testRecords.length"> |
| | | <el-pagination |
| | | background |
| | | layout="prev, pager, next" |
| | | :total="testTotalCount" |
| | | :current-page.sync="testCurrentPage" |
| | | :page-size="testPageSize" |
| | | @current-change="handleTestPageChange"> |
| | | </el-pagination> |
| | | </div> |
| | | </el-card> |
| | | </template> |
| | | <template #tableCustom v-if="currentType === 'timeline'"> |
| | | <record-timeline :list="timelineList" /> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <!-- 证书预览对话框 --> |
| | | <el-dialog |
| | | title="证书预览" |
| | | :visible.sync="certificateDialogVisible" |
| | | width="70%"> |
| | | <div v-if="strainData.certificateUrl" class="certificate-preview"> |
| | | <iframe v-if="strainData.certificateUrl.endsWith('.pdf')" :src="strainData.certificateUrl" width="100%" height="500"></iframe> |
| | | <img v-else :src="strainData.certificateUrl" style="max-width: 100%; max-height: 500px;" /> |
| | | </div> |
| | | </el-dialog> |
| | | <!-- 详情弹窗 --> |
| | | <record-detail-dialog |
| | | :visible.sync="dialogVisible" |
| | | :record-data="currentRecord" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | :type="dialogType" |
| | | /> |
| | | <!-- 新增出入库记录弹窗 --> |
| | | <add-record-dialog |
| | | :visible.sync="addDialogVisible" |
| | | @confirm="handleAddRecordConfirm" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import RecordDetailDialog from "../strain-library-manage/components/RecordDetailDialog.vue"; |
| | | import AddRecordDialog from "../strain-library-manage/components/AddRecordDialog.vue"; |
| | | import RecordTimeline from "../strain-library-manage/components/RecordTimeline.vue"; |
| | | import { |
| | | timeList, |
| | | getDetail, |
| | | addWarehousing, |
| | | getDetailById, |
| | | confirmWarehousing, |
| | | } from "./service"; |
| | | |
| | | export default { |
| | | name: 'ProductionCellLibraryRecord', |
| | | name: "StrainRecord", |
| | | components: { |
| | | RecordDetailDialog, |
| | | AddRecordDialog, |
| | | RecordTimeline, |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | loadingRecords: false, |
| | | loadingTests: false, |
| | | strainId: '', |
| | | strainData: { |
| | | id: '', |
| | | strainNo: '', |
| | | strainName: '', |
| | | source: '', |
| | | batchNo: '', |
| | | preservationMethod: '', |
| | | storageLocation: '', |
| | | inventory: 0, |
| | | status: '', |
| | | description: '', |
| | | preparationDate: '', |
| | | expiryDate: '', |
| | | updateTime: '', |
| | | certificateUrl: '' |
| | | currentType: "table", |
| | | detail: {}, |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | certificateDialogVisible: false, |
| | | |
| | | // 使用记录分页数据 |
| | | usageRecords: [], |
| | | usageCurrentPage: 1, |
| | | usagePageSize: 10, |
| | | usageTotalCount: 0, |
| | | |
| | | // 测试记录分页数据 |
| | | testRecords: [], |
| | | testCurrentPage: 1, |
| | | testPageSize: 10, |
| | | testTotalCount: 0 |
| | | } |
| | | recordList: [], |
| | | timelineList: [], |
| | | dialogVisible: false, |
| | | currentRecord: {}, |
| | | addDialogVisible: false, |
| | | dialogType: "detail", |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | created() { |
| | | this.strainId = this.$route.params.id; |
| | | this.fetchStrainData(); |
| | | this.fetchUsageRecords(); |
| | | this.fetchTestRecords(); |
| | | activated() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | |
| | | // 获取路由参数中的菌种信息 |
| | | const strainId = this.$route.query.id; |
| | | this.queryForm.id = strainId; |
| | | if (strainId) { |
| | | this.getStrainDetail(strainId); |
| | | this.getRecordList(); |
| | | } |
| | | }, |
| | | methods: { |
| | | // 获取菌种详情 |
| | | fetchStrainData() { |
| | | this.loading = true; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | this.strainData = { |
| | | id: this.strainId, |
| | | strainNo: 'PCLS-2023-001', |
| | | strainName: '枯草芽孢杆菌生产株', |
| | | source: '主细胞库', |
| | | batchNo: 'P20230515-001', |
| | | preservationMethod: '冻干保存', |
| | | storageLocation: 'A区-A-102-冷藏柜', |
| | | inventory: 12, |
| | | status: '正常', |
| | | description: '本菌种为工业生产级别枯草芽孢杆菌生产株,由主细胞库转入,经过严格筛选和稳定性测试。该菌株具有高产蛋白酶能力,发酵条件适应性强,适合大规模工业化生产。产品稳定性好,批次间差异小,可用于洗涤用酶制剂、食品加工酶制剂等多种产品的生产。', |
| | | preparationDate: '2023-05-10', |
| | | expiryDate: '2024-05-10', |
| | | updateTime: '2023-05-15 14:30:22', |
| | | certificateUrl: '/api/strain-library/certificates/sample.pdf' |
| | | }; |
| | | |
| | | this.loading = false; |
| | | }, 500); |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteWarehousing({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.getRecordList(); |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 获取使用记录 |
| | | fetchUsageRecords() { |
| | | this.loadingRecords = true; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | this.usageRecords = [ |
| | | { |
| | | id: '1', |
| | | date: '2023-06-05', |
| | | amount: 2, |
| | | operator: '张工', |
| | | project: '酶制剂研发项目', |
| | | batchNo: 'E20230605-001', |
| | | purpose: '小试生产' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-07-12', |
| | | amount: 3, |
| | | operator: '李工', |
| | | project: '蛋白酶产品项目', |
| | | batchNo: 'E20230712-002', |
| | | purpose: '中试生产' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-08-18', |
| | | amount: 5, |
| | | operator: '王工', |
| | | project: '工业酶制剂生产', |
| | | batchNo: 'E20230818-003', |
| | | purpose: '规模化生产' |
| | | } |
| | | ]; |
| | | |
| | | this.usageTotalCount = 3; |
| | | this.loadingRecords = false; |
| | | }, 600); |
| | | getStrainDetail(id) { |
| | | // 这里应该调用接口获取菌种详情 |
| | | getDetail({ id }).then((res) => { |
| | | this.detail = res; |
| | | }); |
| | | }, |
| | | |
| | | // 获取测试记录 |
| | | fetchTestRecords() { |
| | | this.loadingTests = true; |
| | | |
| | | // 模拟API请求 |
| | | setTimeout(() => { |
| | | // 模拟数据,实际项目中应替换为真实API调用 |
| | | this.testRecords = [ |
| | | { |
| | | id: '1', |
| | | date: '2023-05-15', |
| | | type: '活力测定', |
| | | operator: '刘工', |
| | | result: '合格', |
| | | remark: '酶活性达标,符合生产要求' |
| | | }, |
| | | { |
| | | id: '2', |
| | | date: '2023-05-15', |
| | | type: '纯度检测', |
| | | operator: '张工', |
| | | result: '合格', |
| | | remark: '纯度>98%,无杂菌污染' |
| | | }, |
| | | { |
| | | id: '3', |
| | | date: '2023-05-16', |
| | | type: '稳定性测试', |
| | | operator: '李工', |
| | | result: '合格', |
| | | remark: '常温保存7天活力下降小于5%' |
| | | } |
| | | ]; |
| | | |
| | | this.testTotalCount = 3; |
| | | this.loadingTests = false; |
| | | }, 700); |
| | | getRecordList() { |
| | | // 这里应该调用接口获取出入库记录 |
| | | timeList(this.queryForm).then((res) => { |
| | | this.timelineList = res.data; |
| | | }); |
| | | getDetailById({ id: this.$route.query.id }).then((res) => { |
| | | this.recordList = res.warehousingList.records; |
| | | this.total = res.warehousingList.total; |
| | | }); |
| | | }, |
| | | |
| | | // 状态标签类型 |
| | | getStatusType(status) { |
| | | switch(status) { |
| | | case '正常': |
| | | return 'success'; |
| | | case '缺货': |
| | | return 'warning'; |
| | | case '异常': |
| | | return 'danger'; |
| | | case '已停用': |
| | | return 'info'; |
| | | default: |
| | | return 'info'; |
| | | } |
| | | handleView(row) { |
| | | this.dialogType = "detail"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | |
| | | // 编辑菌种 |
| | | handleEdit() { |
| | | this.$router.push(`/strain-library/production-cell-library/edit/${this.strainId}`); |
| | | handleConfirm(row) { |
| | | this.dialogType = "confirm"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | |
| | | // 打印菌种信息 |
| | | handlePrint() { |
| | | window.print(); |
| | | handlePageChange(page) { |
| | | this.queryForm.pageNum = page; |
| | | // 这里应该调用接口获取对应页码的数据 |
| | | }, |
| | | |
| | | // 查看证书 |
| | | handleViewCertificate() { |
| | | this.certificateDialogVisible = true; |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | }, |
| | | |
| | | // 下载证书 |
| | | handleDownloadCertificate() { |
| | | // 实际项目中应处理文件下载逻辑 |
| | | window.open(this.strainData.certificateUrl, '_blank'); |
| | | handleAddRecord() { |
| | | this.addDialogVisible = true; |
| | | }, |
| | | |
| | | // 新增使用记录 |
| | | handleAddUsage() { |
| | | this.$message.info('功能开发中:新增使用记录'); |
| | | // 实际项目中应跳转到新增使用记录页面或打开对话框 |
| | | handleDialogClose() { |
| | | this.currentRecord = {}; |
| | | this.dialogVisible = false; |
| | | }, |
| | | |
| | | // 查看使用记录详情 |
| | | handleViewUsageDetail(row) { |
| | | this.$message.info(`查看使用记录: ${row.id}`); |
| | | // 实际项目中应跳转到使用记录详情页面或打开对话框 |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | confirmWarehousing({ |
| | | id: this.currentRecord.id, |
| | | preserveSignature: data.preserveSignature, |
| | | }).then((res) => { |
| | | console.log(res); |
| | | if (res.code == 200) { |
| | | this.$message.success("操作成功"); |
| | | this.dialogVisible = false; |
| | | // 刷新列表 |
| | | this.getRecordList(); |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 编辑使用记录 |
| | | handleEditUsage(row) { |
| | | this.$message.info(`编辑使用记录: ${row.id}`); |
| | | // 实际项目中应跳转到编辑使用记录页面或打开对话框 |
| | | handleAddRecordConfirm(record) { |
| | | addWarehousing({ ...record, trainLibraryId: this.$route.query.id }).then( |
| | | (res) => { |
| | | this.$message.success("操作成功"); |
| | | this.getRecordList(); |
| | | } |
| | | ); |
| | | }, |
| | | |
| | | // 使用记录分页切换 |
| | | handleUsagePageChange(page) { |
| | | this.usageCurrentPage = page; |
| | | this.fetchUsageRecords(); |
| | | goBack() { |
| | | this.$router.go(-1); |
| | | }, |
| | | |
| | | // 新增测试记录 |
| | | handleAddTest() { |
| | | this.$message.info('功能开发中:新增测试记录'); |
| | | // 实际项目中应跳转到新增测试记录页面或打开对话框 |
| | | }, |
| | | |
| | | // 查看测试记录详情 |
| | | handleViewTestDetail(row) { |
| | | this.$message.info(`查看测试记录: ${row.id}`); |
| | | // 实际项目中应跳转到测试记录详情页面或打开对话框 |
| | | }, |
| | | |
| | | // 编辑测试记录 |
| | | handleEditTest(row) { |
| | | this.$message.info(`编辑测试记录: ${row.id}`); |
| | | // 实际项目中应跳转到编辑测试记录页面或打开对话框 |
| | | }, |
| | | |
| | | // 测试记录分页切换 |
| | | handleTestPageChange(page) { |
| | | this.testCurrentPage = page; |
| | | this.fetchTestRecords(); |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .production-cell-record { |
| | | padding: 20px; |
| | | <style lang="less" scoped> |
| | | .record-page { |
| | | min-height: 100vh; |
| | | |
| | | .page-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 24px; |
| | | |
| | | .header-left { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | h2 { |
| | | margin: 0 0 0 12px; |
| | | font-size: 22px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .header-actions { |
| | | display: flex; |
| | | gap: 12px; |
| | | } |
| | | } |
| | | |
| | | .strain-card { |
| | | margin-bottom: 24px; |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .strain-info { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | |
| | | .info-item { |
| | | width: 33.33%; |
| | | margin-bottom: 16px; |
| | | |
| | | &.full-width { |
| | | width: 100%; |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | height: 130px; |
| | | overflow: hidden; |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .label { |
| | | font-weight: 500; |
| | | color: #606266; |
| | | } |
| | | |
| | | .value { |
| | | color: #303133; |
| | | |
| | | &.description { |
| | | white-space: pre-line; |
| | | line-height: 1.6; |
| | | padding: 8px 0; |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 6px; |
| | | |
| | | &.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; |
| | | word-break: break-all; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 1; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .record-card { |
| | | margin-bottom: 24px; |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .card-title { |
| | | font-size: 16px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | |
| | | .pagination-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-top: 20px; |
| | | } |
| | | } |
| | | |
| | | .certificate-preview { |
| | | |
| | | .flex { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | min-height: 500px; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | @media print { |
| | | .page-header, .header-actions, .record-card { |
| | | display: none; |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .strain-card { |
| | | border: none; |
| | | box-shadow: none; |
| | | |
| | | .card-header { |
| | | background-color: #fff !important; |
| | | border-bottom: 1px solid #ddd; |
| | | |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .timeline-container { |
| | | padding: 20px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .timeline-card { |
| | | margin-bottom: 10px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | h4 { |
| | | margin: 0 0 10px; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .operation-btn { |
| | | margin-right: 12px; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
New file |
| | |
| | | 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 }) |
| | | } |
| | | |
| | | // 确认出入库 |
| | | export const confirmWarehousing = (data) => { |
| | | return axios.post('/api/t-train-library/confirm', { ...data }) |
| | | } |
| | | |
| | | // 删除菌种库 |
| | | export const deleteStrainLibrary = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteById', { params }) |
| | | } |
| | | |
| | | // 删除菌种库出入库记录 |
| | | export const deleteWarehousing = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteWarehousingById', { params }) |
| | | } |
| | |
| | | <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> |
| | |
| | | </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 |
| | | }, |
| | |
| | | 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) { |
| | | 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 |
| | | if (isDraft == 1) { |
| | | //存草稿 |
| | | this.handleSignatureConfirm('') |
| | | } else { |
| | | this.signatureVisible = true |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | 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') { |
| | | await addBatch(requestData); |
| | | } else { |
| | | await add(requestData); |
| | | } |
| | | this.signatureVisible = false; |
| | | this.$router.back(); |
| | | this.$message.success('操作成功'); |
| | | } catch (error) { |
| | | this.$message.error('操作失败'); |
| | | } |
| | | } |
| | | } |
| | |
| | | &-left { |
| | | display: flex; |
| | | align-items: center; |
| | | |
| | | |
| | | img { |
| | | width: 20px; |
| | | height: 20px; |
| | |
| | | } |
| | | } |
| | | } |
| | | .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; |
| | | |
| | |
| | | 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%; |
| | | } |
| | |
| | | padding: 20px; |
| | | text-align: center; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | |
| | | color: #606266; |
| | | font-weight: normal; |
| | | padding-bottom: 8px; |
| | | |
| | | &::before { |
| | | color: #F56C6C; |
| | | } |
| | |
| | | |
| | | :deep(.el-input) { |
| | | width: 100%; |
| | | |
| | | input { |
| | | width: 100%; |
| | | width: 100%; |
| | | } |
| | | } |
| | | } |
| | |
| | | .dialog-notice { |
| | | margin-top: 16px; |
| | | text-align: center; |
| | | |
| | | p { |
| | | margin: 0; |
| | | line-height: 22px; |
| | |
| | | :deep(.el-dialog__footer) { |
| | | padding: 0 20px 20px; |
| | | text-align: center; |
| | | |
| | | |
| | | .el-button { |
| | | width: 180px; |
| | | height: 36px; |
| | |
| | | margin: 0; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <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> |
| | |
| | | <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> |
| | |
| | | data() { |
| | | return { |
| | | formData: { |
| | | type: '出库', |
| | | operatorSignature: '' |
| | | type: '1', |
| | | handleSignature: '' |
| | | }, |
| | | showSignature: false |
| | | } |
| | |
| | | this.$emit('close') |
| | | }, |
| | | handleConfirm() { |
| | | if (!this.formData.operatorSignature) { |
| | | if (!this.formData.handleSignature) { |
| | | this.$message.warning('请先签名') |
| | | return |
| | | } |
| | |
| | | this.handleClose() |
| | | }, |
| | | handleSignatureConfirm(dataUrl) { |
| | | this.formData.operatorSignature = dataUrl |
| | | this.formData.handleSignature = dataUrl |
| | | this.showSignature = false |
| | | } |
| | | } |
| | |
| | | <template> |
| | | <el-dialog |
| | | title="出/入库详情" |
| | | :visible.sync="visible" |
| | | width="520px" |
| | | :close-on-click-modal="false" |
| | | custom-class="record-detail-dialog" |
| | | @close="handleClose" |
| | | > |
| | | <el-dialog :title="type == 'detail' ? '出/入库详情' : '确认出入库'" :visible.sync="visible" width="550px" |
| | | :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 v-if="formData.type == '1'" type="primary">出库</el-button> |
| | | <el-button v-if="formData.type == '2'" type="primary">入库</el-button> |
| | | </div> |
| | | </el-form-item> |
| | | |
| | | <div class="signature-row"> |
| | | <el-form-item label="操作人签字" required class="signature-item"> |
| | | <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> |
| | |
| | | </div> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="formData.operatorSignature" |
| | | label="出库时间" |
| | | required |
| | | class="time-item" |
| | | > |
| | | <div class="time-value">{{ formData.operateTime }}</div> |
| | | <el-form-item v-if="formData.handleSignature" label="出库时间" required class="time-item"> |
| | | <div class="time-value">{{ formData.boundTime }}</div> |
| | | </el-form-item> |
| | | </div> |
| | | |
| | |
| | | <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 v-if="type != 'detail'" 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"> |
| | | <img :src="formData.reviewerSignature" alt="保藏人签字" /> |
| | | <div class="signature-area" :class="{ 'waiting': !formData.preserveSignature }"> |
| | | <template v-if="formData.preserveSignature"> |
| | | <img :src="formData.preserveSignature" alt="保藏人签字" /> |
| | | </template> |
| | | <template v-else> |
| | | <span class="waiting-text">等待确认</span> |
| | |
| | | </div> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="formData.reviewerSignature" |
| | | label="确认时间" |
| | | required |
| | | class="time-item" |
| | | > |
| | | <el-form-item v-if="formData.preserveSignature && type == 'detail'" label="确认时间" required |
| | | class="time-item"> |
| | | <div class="time-value">{{ formData.confirmTime }}</div> |
| | | </el-form-item> |
| | | </div> |
| | | </el-form> |
| | | <div class="confirm-btn" v-if="type != 'detail'" style="text-align: center;margin-top: 20px;"> |
| | | <el-button type="primary" style="width: 80px;" @click="handleOutbound">确认</el-button> |
| | | </div> |
| | | </div> |
| | | <signature-canvas :visible.sync="showSignature" @confirm="handleSignatureConfirm" @cancel="showSignature = false" /> |
| | | <signature-canvas :visible.sync="showSignature" @confirm="handleSignatureConfirm" |
| | | @cancel="showSignature = false" /> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | |
| | | recordData: { |
| | | type: Object, |
| | | default: () => ({}) |
| | | }, |
| | | type: { |
| | | type: String, |
| | | default: 'detail' |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | formData: {}, |
| | | formData: { |
| | | type: '1', |
| | | }, |
| | | showSignature: false |
| | | } |
| | | }, |
| | |
| | | } |
| | | }, |
| | | methods: { |
| | | opened() { |
| | | this.formData.type = this.recordData.type |
| | | }, |
| | | handleClose() { |
| | | this.$emit('update:visible', false) |
| | | this.$emit('close') |
| | | }, |
| | | handleOutbound() { |
| | | if (!this.formData.operatorSignature || !this.formData.reviewerSignature) { |
| | | if (!this.formData.preserveSignature) { |
| | | this.$message.warning('请等待所有签字确认后再进行出库操作') |
| | | return |
| | | } |
| | |
| | | this.handleClose() |
| | | }, |
| | | handleSignatureConfirm(dataUrl) { |
| | | this.formData.reviewerSignature = dataUrl |
| | | this.formData.preserveSignature = dataUrl |
| | | this.showSignature = false |
| | | // 可选:this.formData.confirmTime = new Date().toLocaleString() |
| | | } |
| | |
| | | padding: 20px 24px; |
| | | margin: 0; |
| | | border-bottom: 1px solid #DCDFE6; |
| | | |
| | | |
| | | .el-dialog__title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | |
| | | } |
| | | |
| | | .type-buttons { |
| | | display: flex; |
| | | |
| | | gap: 12px; |
| | | |
| | | .el-button { |
| | | width: 80px; |
| | | background: #409EFF; |
| | | border-color: #409EFF; |
| | | color: #FFFFFF; |
| | | |
| | | |
| | | &:hover { |
| | | opacity: 0.8; |
| | |
| | | .edit-sign-btn { |
| | | margin-left: 12px; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <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> |
| | |
| | | width: 12px !important; |
| | | height: 12px !important; |
| | | left: -6px; |
| | | top: 34px !important; /* 微调位置使其看起来完全居中 */ |
| | | top: 34px !important; |
| | | /* 微调位置使其看起来完全居中 */ |
| | | margin: 0 !important; |
| | | background: #ffffff; |
| | | box-shadow: none !important; |
| | |
| | | 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) { |
| | |
| | | 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; |
| | | } |
| | |
| | | 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 { |
| | |
| | | |
| | | /* 添加媒体查询,适配小屏幕设备 */ |
| | | @media screen and (max-width: 1200px) { |
| | | .left-block, .right-block { |
| | | |
| | | .left-block, |
| | | .right-block { |
| | | min-width: 240px; |
| | | } |
| | | |
| | | |
| | | .timeline-row { |
| | | gap: 10px; |
| | | } |
| | |
| | | |
| | | @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> |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <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)" |
| | | 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> |
| | | </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 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="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> |
| | | <!-- 第二行信息 --> |
| | | <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 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 v-if="!row.confirmTime && roleType == 3" style="margin-right: 10px" type="text" @click="handleConfirm(row)">确认</el-button> |
| | | <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> |
| | | </div> |
| | | </el-dialog> |
| | | <RecordDetailDialog |
| | | :visible="visibleRecordDetailDialog" |
| | | :recordData="recordData" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | :type="dialogType" |
| | | /> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { getDetailById,confirmWarehousing } from "../service"; |
| | | import RecordDetailDialog from "./RecordDetailDialog.vue"; |
| | | export default { |
| | | name: 'StrainDetail', |
| | | props: { |
| | | visible: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | detail: { |
| | | type: Object, |
| | | default: () => ({}) |
| | | } |
| | | components: { RecordDetailDialog }, |
| | | name: "StrainDetail", |
| | | props: { |
| | | visible: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | data() { |
| | | return { |
| | | currentPage: 1, |
| | | total: 0 |
| | | } |
| | | detail: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | }, |
| | | methods: { |
| | | handleView(row) { |
| | | console.log('View record:', row) |
| | | }, |
| | | handlePageChange(page) { |
| | | this.currentPage = page |
| | | this.$emit('page-change', page) |
| | | }, |
| | | data() { |
| | | return { |
| | | visibleRecordDetailDialog: false, |
| | | recordData: {}, |
| | | currentPage: 1, |
| | | total: 0, |
| | | dialogType: "", |
| | | query: { |
| | | endTime: "", |
| | | id: "", |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | startTime: "", |
| | | roleType: "", |
| | | }, |
| | | }; |
| | | }, |
| | | |
| | | methods: { |
| | | handleDialogClose() { |
| | | this.recordData = {}; |
| | | this.visibleRecordDetailDialog = false; |
| | | }, |
| | | fetchDetail() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | 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; |
| | | this.$forceUpdate(); |
| | | }); |
| | | }, |
| | | handleView(row) { |
| | | this.dialogType = "detail"; |
| | | this.recordData = row; |
| | | this.visibleRecordDetailDialog = true; |
| | | |
| | | }, |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | confirmWarehousing({ |
| | | id: this.recordData.id, |
| | | preserveSignature: data.preserveSignature, |
| | | }).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("操作成功"); |
| | | this.visibleRecordDetailDialog = false; |
| | | // 刷新列表 |
| | | this.fetchDetail(); |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | handleConfirm(row) { |
| | | this.dialogType = "confirm"; |
| | | this.recordData = row; |
| | | this.visibleRecordDetailDialog = true; |
| | | }, |
| | | handlePageChange(page) { |
| | | this.currentPage = page; |
| | | this.$emit("page-change", page); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .strain-detail-dialog { |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | margin-right: 0; |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | } |
| | | } |
| | | |
| | | .strain-info { |
| | | background: #F5F7FA; |
| | | border-radius: 4px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | background: #f5f7fa; |
| | | border-radius: 4px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | |
| | | .info-row { |
| | | 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; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | .info-row { |
| | | 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; |
| | | word-break: break-all; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .record-table { |
| | | .table-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 16px; |
| | | padding-left: 8px; |
| | | border-left: 4px solid #049C9A; |
| | | } |
| | | .table-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | margin-bottom: 16px; |
| | | padding-left: 8px; |
| | | border-left: 4px solid #049c9a; |
| | | } |
| | | |
| | | .pagination { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | .pagination { |
| | | margin-top: 20px; |
| | | display: flex; |
| | | justify-content: center; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> |
| | | <span>菌种源保藏出/入细胞库登记表说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore">查看全部 >></el-button> |
| | | </div> |
| | | <div class="header-content" :class="{ 'collapsed': true }"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p> |
| | | <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p> |
| | | <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p> |
| | | <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p> |
| | | </div> |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon" /> |
| | | <span>菌种源保藏出/入细胞库登记表说明</span> |
| | | <el-button type="text" class="view-more" @click="handleViewMore" |
| | | >查看全部 >></el-button |
| | | > |
| | | </div> |
| | | <div class="header-content" :class="{ collapsed: true }"> |
| | | <p> |
| | | 1. 菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,菌种来源有 3 |
| | | 条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2 |
| | | 是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3 |
| | | 是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。 |
| | | 2. |
| | | 菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1 |
| | | 原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3 |
| | | 生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1 |
| | | 细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在 |
| | | 24 年 9 月 19 |
| | | 接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1 |
| | | 传代编码方式演例:祖代:DD-O-240919-01 |
| | | 传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2 |
| | | 编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2 |
| | | 细胞库说明:3.2.1 |
| | | 直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2 |
| | | 从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3 |
| | | 主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4. |
| | | 菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 a-01、a-02 |
| | | 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2 |
| | | 接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。 |
| | | </p> |
| | | </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 |
| | | 条路径。1.1 是沙土管或甘油管的源头菌种;入原始细胞库(祖代-O)。1.2 |
| | | 是斜面的源头菌种;接种入主细胞库(祖代-O)。经过育种、验证后,菌种保藏为甘油管或沙土管的,入原始细胞库(祖代-0)1.3 |
| | | 是含菌物质自己分离后获得的斜面源头菌种,接种入主细胞库;经生产验证后,保藏为沙土管或甘油管,入原始细胞库(祖代-O)。2. |
| | | 菌种细胞库,分类入三库,进行传代运行管理。三类库存空间进行区分,保藏菌种。2.1 |
| | | 原始细胞库(祖代-O)、2.2 主细胞库(母代-M)、2.3 |
| | | 生产细胞库(子代-S)、(孙代-G)3. 细胞库编码规则3.1 |
| | | 细胞库编码规则:DD-M-240919-01-(O-0109-01)DD:代表项目组。M:“O”代表祖代原始细胞库,”M“代表母代主细胞库,”S“代表子代生产细胞库,“G”代表孙代生产细胞库。240919:代表在 |
| | | 24 年 9 月 19 |
| | | 接种批次的菌种;或收到外来菌种时间的入库批次。01:代表两位序列号。(O-0109-01):代表传代菌种的编号3.1.1 |
| | | 传代编码方式演例:祖代:DD-O-240919-01 |
| | | 传母代:DD-M-241017-01-(O-091901)DD-M-241017-02-(O-091901)DD-M-241017-03-(O-091901)子代:DD-S-241019-01-(M-1017-02)版权归奥利元生物所有,禁止外传。DD-S-241019-02-(M-1017-03)孙代:DD-G-241109-01-(S-1019-02)3.1.2 |
| | | 编码规则实现了编码唯一,编码可溯源,编码直观、方便。3.2 |
| | | 细胞库说明:3.2.1 |
| | | 直接购买、自行从(土壤、相关物料、商品)等分离出来菌株进入原始细胞库。3.2.2 |
| | | 从原始细胞库中选取出来再次纯化、改造、提高性能的菌株进入主细胞库。3.2.3 |
| | | 主细胞库中选取出稳定,生产性能良好的菌株扩培后保种进入生产细胞库。4. |
| | | 菌种选育-保藏过程编号说明4.1 菌种选育时,培养皿的编号可使用 |
| | | a-01、a-02 等用于清晰形态观察记录;菌落编号使用序号 1/2/3等。4.2 |
| | | 接种斜面菌种编码(-O)使用原始细胞库编码;斜面转菌种保藏使用与斜面一致的编码(-O);斜面传代入主细胞库的传代菌种,按编码器规则编码(-M)。 |
| | | </p> |
| | | </div> |
| | | </el-dialog> |
| | | </el-card> |
| | | |
| | | <!-- Table --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="tableData" |
| | | :total="total" |
| | | @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange" |
| | | > |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item v-if="roleType == 4" label="状态:"> |
| | | <el-select v-model="form.status" placeholder="请选择"> |
| | | <el-option label="全部" value=""></el-option> |
| | | <el-option label="已出库" value="1"></el-option> |
| | | <el-option label="出库待确认" value="2"></el-option> |
| | | <el-option label="已入库" value="3"></el-option> |
| | | <el-option label="入库待确认" value="4"></el-option> |
| | | </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-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')" |
| | | > |
| | | <div class="dialog-content"> |
| | | <p>1、菌种全部集中登记在【菌种源保藏出/入细胞库登记表】,请将来源有3 类菌经。</p> |
| | | <p>1.1 原净土管理日油性的源头菌种:入细胞细胞库(现代-O)。</p> |
| | | <p>1.2 是到菌的源头菌种:接种入主细胞库(现代-O),经过百种、验证后,菌种被保存日油管理沙土菌种,入细胞细胞库(现代-O)。</p> |
| | | <p>1.3 是否菌种能自己分离后获得的源头菌种,接种入主细胞库:经过产验证后,保藏为少土管理日油管,入细胞细胞库(现代-O)。</p> |
| | | </div> |
| | | </el-dialog> |
| | | </el-card> |
| | | 原始细胞列表 |
| | | </div> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')" |
| | | > |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | | <div v-if="roleType == 4" class="flex a-center"> |
| | | <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> |
| | | |
| | | <!-- Table --> |
| | | <TableCustom :queryForm="queryForm" :tableData="tableData" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="菌种编号:"> |
| | | <el-input v-model="form.strainNo" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="菌种名称:"> |
| | | <el-input v-model="form.strainName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="状态:"> |
| | | <el-select v-model="form.status" placeholder="请选择"> |
| | | <el-option label="全部" value=""></el-option> |
| | | <el-option label="已入库" value="1"></el-option> |
| | | <el-option label="已出库" value="2"></el-option> |
| | | <el-option label="入库待确认" value="3"></el-option> |
| | | </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-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div class="title" :class="{ active: currentType === 'list' }" |
| | | @click="handleTypeChange('list')"> |
| | | 原始细胞列表</div> |
| | | <div class="drafts" :class="{ active: currentType === 'draft' }" |
| | | @click="handleTypeChange('draft')"> |
| | | 草稿箱</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> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <template #table> |
| | | <el-table-column prop="strainNo" 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="当前状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <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> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <StrainDetail |
| | | :visible.sync="detailVisible" |
| | | :detail="currentDetail" |
| | | /> |
| | | </div> |
| | | <template #table> |
| | | <el-table-column prop="strainCode" label="菌种编号" /> |
| | | <el-table-column prop="strainName" 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> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button v-if="row.status == 2 || row.status == 4" type="text" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button |
| | | v-if="currentType === 'list'" |
| | | type="text" |
| | | @click="handleRecord(row)" |
| | | >出入库记录</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <StrainDetail :visible.sync="detailVisible" :detail="currentDetail" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import StrainDetail from './components/StrainDetail.vue' |
| | | import StrainDetail from "./components/StrainDetail.vue"; |
| | | import { getList, deleteStrainLibrary } from "./service"; |
| | | |
| | | export default { |
| | | name: 'StrainLibraryManage', |
| | | components: { |
| | | StrainDetail |
| | | name: "StrainLibraryManage", |
| | | components: { |
| | | StrainDetail, |
| | | }, |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | currentType: "list", |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | total: 800, |
| | | tableData: [], |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | activated() { |
| | | this.searchData(); |
| | | // 角色类型 1=超级管理员 2=审批人 3=工程师 4=实验员 |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | }, |
| | | methods: { |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteStrainLibrary({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.searchData(); |
| | | }); |
| | | }); |
| | | }, |
| | | data() { |
| | | return { |
| | | dialogVisible: false, |
| | | currentType: 'list', |
| | | detailVisible: false, |
| | | currentDetail: {}, |
| | | form: { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | }, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | 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' |
| | | } |
| | | ] |
| | | } |
| | | handleRecord(row) { |
| | | this.$router.push({ |
| | | path: `/strain-library/strain-library-manage/record?id=${row.id}`, |
| | | }); |
| | | }, |
| | | methods: { |
| | | handleViewMore() { |
| | | this.dialogVisible = true; |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: '', |
| | | strainName: '', |
| | | status: '' |
| | | } |
| | | 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 |
| | | } |
| | | }) |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | // Implement page change logic |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | // Implement size change logic |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | // Implement type change logic |
| | | }, |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: 'success', |
| | | 2: 'info', |
| | | 3: 'warning' |
| | | } |
| | | return types[status] || 'info' |
| | | }, |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: '已入库', |
| | | 2: '已出库', |
| | | 3: '入库待确认' |
| | | } |
| | | return texts[status] || '未知状态' |
| | | } |
| | | } |
| | | } |
| | | 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; |
| | | }, |
| | | resetForm() { |
| | | this.form = { |
| | | strainNo: "", |
| | | strainName: "", |
| | | status: "", |
| | | }; |
| | | this.searchData(); |
| | | }, |
| | | searchData() { |
| | | 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: this.form.status, |
| | | type: 1, |
| | | }; |
| | | 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; |
| | | this.searchData(); |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size; |
| | | this.searchData(); |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | this.searchData(); |
| | | }, |
| | | getStatusType(status) { |
| | | const types = { |
| | | 1: "warning", |
| | | 2: "warning", |
| | | 3: "success", |
| | | 4: "success", |
| | | }; |
| | | return types[status] || "info"; |
| | | }, |
| | | getStatusText(status) { |
| | | const texts = { |
| | | 1: "已出库", |
| | | 2: "出库待确认", |
| | | 3: "已入库", |
| | | 4: "入库待确认", |
| | | }; |
| | | return texts[status] || "未知状态"; |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .list { |
| | | padding: 20px; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .box-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | position: relative; |
| | | .box-title { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | position: relative; |
| | | |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049C9A; |
| | | } |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | margin-left: 30px; |
| | | transition: max-height 0.3s ease-in-out; |
| | | overflow: hidden; |
| | | |
| | | &.collapsed { |
| | | max-height: 48px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | } |
| | | .view-more { |
| | | position: absolute; |
| | | right: 0; |
| | | color: #049c9a; |
| | | } |
| | | } |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | margin-left: 30px; |
| | | transition: max-height 0.3s ease-in-out; |
| | | overflow: hidden; |
| | | |
| | | &.collapsed { |
| | | max-height: 48px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .search-form { |
| | | margin-bottom: 20px; |
| | | background: #F5F7FA; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | margin-bottom: 20px; |
| | | background: #f5f7fa; |
| | | padding: 24px; |
| | | border-radius: 8px; |
| | | |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | .el-form-item { |
| | | margin-right: 20px; |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | .el-button { |
| | | margin-left: 10px; |
| | | } |
| | | } |
| | | |
| | | .action-buttons { |
| | | margin-bottom: 20px; |
| | | margin-bottom: 20px; |
| | | |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | .el-button { |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | |
| | | .tab-container { |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | display: flex; |
| | | margin-bottom: 20px; |
| | | |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #DCDFE6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #F5F7FA; |
| | | .tab { |
| | | padding: 10px 30px; |
| | | border: 1px solid #dcdfe6; |
| | | border-bottom: none; |
| | | border-radius: 8px 8px 0 0; |
| | | cursor: pointer; |
| | | margin-right: 10px; |
| | | background: #f5f7fa; |
| | | |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049C9A; |
| | | color: #049C9A; |
| | | font-weight: bold; |
| | | } |
| | | &.active { |
| | | background: #fff; |
| | | border-color: #049c9a; |
| | | color: #049c9a; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .flex { |
| | | display: flex; |
| | | align-items: center; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | width: unset; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | width: unset; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | } |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 166px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | |
| | | } |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .view-all-dialog { |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #EBEEF5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | :deep(.el-dialog__header) { |
| | | padding: 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | margin-right: 0; |
| | | |
| | | .el-dialog__title { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | :deep(.el-dialog__body) { |
| | | padding: 20px; |
| | | |
| | | .dialog-content { |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | .dialog-content { |
| | | font-size: 14px; |
| | | line-height: 1.8; |
| | | color: #606266; |
| | | |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | p { |
| | | margin: 12px 0; |
| | | |
| | | &:first-child { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | </style> |
| | |
| | | <template> |
| | | <div class="record-page"> |
| | | <!-- 基本信息展示区域 --> |
| | | <el-card class="header-box"> |
| | | <div class="header-content"> |
| | | <!-- 第一行 --> |
| | | <div class="info-row"> |
| | | <div class="info-item left-column"> |
| | | <span class="label">菌种编号:</span> |
| | | <span class="value">{{ detail.strainNo }}</span> |
| | | </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> |
| | | <div class="record-page"> |
| | | <!-- 基本信息展示区域 --> |
| | | <el-card class="header-box"> |
| | | <div class="header-content"> |
| | | <!-- 第一行 --> |
| | | <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-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> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 出入库记录表格 --> |
| | | <TableCustom |
| | | :queryForm="queryForm" |
| | | :tableData="recordList" |
| | | :total="total" |
| | | @currentChange="handlePageChange" |
| | | > |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div |
| | | class="title" |
| | | :class="{ active: currentType === 'table' }" |
| | | @click="handleTypeChange('table')" |
| | | > |
| | | 原始细胞保藏出/入库登记表 |
| | | </div> |
| | | </el-card> |
| | | <div |
| | | class="drafts" |
| | | :class="{ active: currentType === 'timeline' }" |
| | | @click="handleTypeChange('timeline')" |
| | | > |
| | | 原始细胞保藏出/入库时间轴 |
| | | </div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button |
| | | v-if="roleType == 4" |
| | | @click="handleAddRecord" |
| | | class="el-icon-plus" |
| | | type="primary" |
| | | >新增出入库记录</el-button |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <!-- 出入库记录表格 --> |
| | | <TableCustom :queryForm="queryForm" :tableData="recordList" :total="total" @currentChange="handlePageChange"> |
| | | <template #setting> |
| | | <div class="tableTitle"> |
| | | <div class="flex a-center"> |
| | | <div class="title" :class="{ active: currentType === 'table' }" |
| | | @click="handleTypeChange('table')"> |
| | | 原始细胞保藏出/入库登记表</div> |
| | | <div class="drafts" :class="{ active: currentType === 'timeline' }" |
| | | @click="handleTypeChange('timeline')"> |
| | | 原始细胞保藏出/入库时间轴</div> |
| | | </div> |
| | | <div class="flex a-center"> |
| | | <el-button @click="handleAddRecord" class="el-icon-plus" type="primary">新增出入库记录</el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <template #table v-if="currentType === 'table'"> |
| | | <el-table-column prop="type" label="出库/入库"> |
| | | <template #default="{ row }"> |
| | | <span> |
| | | {{ row.type === 1 ? "出库" : "入库" }} |
| | | </span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="boundTime" label="操作时间" /> |
| | | <el-table-column prop="handleSignature" label="操作人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.handleSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.handleSignature" |
| | | :preview-src-list="[row.handleSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="preserveSignature" label="菌种保藏人签字"> |
| | | <template #default="{ row }"> |
| | | <el-image |
| | | v-if="row.preserveSignature" |
| | | style="width: 100px; height: 100px" |
| | | :src="row.preserveSignature" |
| | | :preview-src-list="[row.preserveSignature]" |
| | | > |
| | | </el-image> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="status" label="状态"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.preserveSignature ? 'success' : 'warning'"> |
| | | {{ row.preserveSignature ? "已确认" : "待确认" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="180"> |
| | | <template #default="{ row }"> |
| | | <el-button |
| | | v-if="!row.preserveSignature && roleType == 3" |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleConfirm(row)" |
| | | >确认</el-button |
| | | > |
| | | <el-button |
| | | type="text" |
| | | class="operation-btn" |
| | | @click="handleView(row)" |
| | | >详情</el-button |
| | | > |
| | | <el-button v-if="roleType == 1" type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | <template #tableCustom v-if="currentType === 'timeline'"> |
| | | <record-timeline :list="timelineList" /> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <template #table v-if="currentType === 'table'"> |
| | | <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="180"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" class="operation-btn" @click="handleView(row)">详情</el-button> |
| | | <el-button type="text" class="operation-btn" @click="handleEdit(row)">编辑</el-button> |
| | | <el-button type="text" @click="handleDelete(row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | <template #tableCustom v-if="currentType === 'timeline'"> |
| | | <record-timeline :list="timelineList" /> |
| | | |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <!-- 详情弹窗 --> |
| | | <record-detail-dialog |
| | | :visible.sync="dialogVisible" |
| | | :record-data="currentRecord" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | /> |
| | | |
| | | <add-record-dialog |
| | | :visible.sync="addDialogVisible" |
| | | @confirm="handleAddRecordConfirm" |
| | | /> |
| | | </div> |
| | | <!-- 详情弹窗 --> |
| | | <record-detail-dialog |
| | | :visible.sync="dialogVisible" |
| | | :record-data="currentRecord" |
| | | @close="handleDialogClose" |
| | | @confirm="handleOutbound" |
| | | :type="dialogType" |
| | | /> |
| | | <!-- 新增出入库记录弹窗 --> |
| | | <add-record-dialog |
| | | :visible.sync="addDialogVisible" |
| | | @confirm="handleAddRecordConfirm" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import RecordDetailDialog from './components/RecordDetailDialog.vue' |
| | | import AddRecordDialog from './components/AddRecordDialog.vue' |
| | | import RecordTimeline from './components/RecordTimeline.vue' |
| | | import RecordDetailDialog from "./components/RecordDetailDialog.vue"; |
| | | import AddRecordDialog from "./components/AddRecordDialog.vue"; |
| | | import RecordTimeline from "./components/RecordTimeline.vue"; |
| | | import { |
| | | timeList, |
| | | getDetail, |
| | | addWarehousing, |
| | | getDetailById, |
| | | confirmWarehousing, |
| | | } from "./service"; |
| | | |
| | | export default { |
| | | name: 'StrainRecord', |
| | | components: { |
| | | RecordDetailDialog, |
| | | AddRecordDialog, |
| | | RecordTimeline |
| | | }, |
| | | data() { |
| | | return { |
| | | currentType: 'table', |
| | | detail: {}, |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | }, |
| | | recordList: [ |
| | | { |
| | | type: '入库', |
| | | operateTime: '2025-1-21 15:46:50', |
| | | operator: '张三', |
| | | reviewer: '李四', |
| | | status: '已确认' |
| | | }, |
| | | { |
| | | type: '出库', |
| | | operateTime: '2025-1-21 15:46:50', |
| | | operator: '张三', |
| | | reviewer: '李四', |
| | | status: '已确认' |
| | | }, |
| | | { |
| | | type: '入库', |
| | | operateTime: '2025-1-21 15:46:50', |
| | | operator: '张三', |
| | | reviewer: '李四', |
| | | status: '已确认' |
| | | }, |
| | | { |
| | | type: '出库', |
| | | operateTime: '2025-1-21 15:46:50', |
| | | operator: '张三', |
| | | reviewer: '李四', |
| | | status: '已确认' |
| | | }, |
| | | { |
| | | type: '入库', |
| | | operateTime: '2025-1-21 15:46:50', |
| | | operator: '李四', |
| | | reviewer: '李四', |
| | | status: '已确认' |
| | | } |
| | | ], |
| | | dialogVisible: false, |
| | | currentRecord: {}, |
| | | addDialogVisible: false |
| | | } |
| | | }, |
| | | computed: { |
| | | timelineList() { |
| | | // 可根据需要处理数据格式,这里直接用 recordList |
| | | return this.recordList.map(item => ({ |
| | | ...item, |
| | | confirmTime: item.confirmTime || item.operateTime // 若无确认时间则用操作时间 |
| | | })) |
| | | } |
| | | }, |
| | | created() { |
| | | // 获取路由参数中的菌种信息 |
| | | const strainId = this.$route.query.id |
| | | if (strainId) { |
| | | this.getStrainDetail(strainId) |
| | | this.getRecordList() |
| | | } |
| | | }, |
| | | methods: { |
| | | getStrainDetail(id) { |
| | | // 这里应该调用接口获取菌种详情 |
| | | // 暂时使用模拟数据 |
| | | this.detail = { |
| | | strainNo: '3418732431', |
| | | strainName: '名称名称名称', |
| | | source: '来源11111111111', |
| | | method: '1231231', |
| | | certificate: '特性描述', |
| | | storage: '方法方法', |
| | | amount: '位置位置位置位置位置位置位置位置', |
| | | operator: '入库' |
| | | } |
| | | }, |
| | | getRecordList() { |
| | | // 这里应该调用接口获取出入库记录 |
| | | // 暂时使用已有模拟数据 |
| | | this.total = this.recordList.length |
| | | }, |
| | | handleView(row) { |
| | | this.currentRecord = { |
| | | ...row, |
| | | operatorSignature: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', // 模拟操作人签字图片 |
| | | reviewerSignature: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png', // 模拟保藏人签字图片 |
| | | operateTime: '2025-1-22 13:49:51', |
| | | confirmTime: '2025-1-22 14:30:00' |
| | | } |
| | | this.dialogVisible = true |
| | | }, |
| | | handlePageChange(page) { |
| | | this.queryForm.pageNum = page |
| | | // 这里应该调用接口获取对应页码的数据 |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type |
| | | }, |
| | | handleAddRecord() { |
| | | this.addDialogVisible = true |
| | | }, |
| | | handleEdit(row) { |
| | | console.log('编辑记录:', row) |
| | | // 实现编辑记录逻辑 |
| | | }, |
| | | handleDelete(row) { |
| | | this.$confirm('确认删除该记录吗?', '提示', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | console.log('删除记录:', row) |
| | | // 实际项目中这里应该调用删除API |
| | | this.$message({ |
| | | type: 'success', |
| | | message: '删除成功!' |
| | | }) |
| | | }).catch(() => { |
| | | this.$message({ |
| | | type: 'info', |
| | | message: '已取消删除' |
| | | }) |
| | | }) |
| | | }, |
| | | handleDialogClose() { |
| | | this.currentRecord = {} |
| | | this.dialogVisible = false |
| | | }, |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | console.log('出库操作:', data) |
| | | this.$message.success('出库成功') |
| | | this.dialogVisible = false |
| | | // 刷新列表 |
| | | this.getRecordList() |
| | | }, |
| | | handleAddRecordConfirm(record) { |
| | | // 这里可以将新记录添加到 recordList 或调用后端API |
| | | this.$message.success('新增出入库记录成功') |
| | | // 例如:this.recordList.push(record) |
| | | this.getRecordList() // 或刷新列表 |
| | | }, |
| | | goBack() { |
| | | this.$router.go(-1) |
| | | } |
| | | name: "StrainRecord", |
| | | components: { |
| | | RecordDetailDialog, |
| | | AddRecordDialog, |
| | | RecordTimeline, |
| | | }, |
| | | data() { |
| | | return { |
| | | currentType: "table", |
| | | detail: {}, |
| | | currentPage: 1, |
| | | pageSize: 10, |
| | | total: 0, |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | recordList: [], |
| | | timelineList: [], |
| | | dialogVisible: false, |
| | | currentRecord: {}, |
| | | addDialogVisible: false, |
| | | dialogType: "detail", |
| | | roleType: "", |
| | | }; |
| | | }, |
| | | created() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem("userInfo")).roleType; |
| | | |
| | | // 获取路由参数中的菌种信息 |
| | | const strainId = this.$route.query.id; |
| | | this.queryForm.id = strainId; |
| | | if (strainId) { |
| | | this.getStrainDetail(strainId); |
| | | this.getRecordList(); |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | | handleDelete(row) { |
| | | this.$confirm("确定删除该数据吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteWarehousing({ id: row.id }).then((res) => { |
| | | this.$message.success("删除成功"); |
| | | this.getRecordList(); |
| | | }); |
| | | }); |
| | | }, |
| | | getStrainDetail(id) { |
| | | // 这里应该调用接口获取菌种详情 |
| | | getDetail({ id }).then((res) => { |
| | | this.detail = res; |
| | | }); |
| | | }, |
| | | getRecordList() { |
| | | // 这里应该调用接口获取出入库记录 |
| | | timeList(this.queryForm).then((res) => { |
| | | this.timelineList = res.data; |
| | | }); |
| | | getDetailById({ id: this.$route.query.id }).then((res) => { |
| | | this.recordList = res.warehousingList.records; |
| | | this.total = res.warehousingList.total; |
| | | }); |
| | | }, |
| | | handleView(row) { |
| | | this.dialogType = "detail"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | handleConfirm(row) { |
| | | this.dialogType = "confirm"; |
| | | this.currentRecord = row; |
| | | this.dialogVisible = true; |
| | | }, |
| | | handlePageChange(page) { |
| | | this.queryForm.pageNum = page; |
| | | // 这里应该调用接口获取对应页码的数据 |
| | | }, |
| | | handleTypeChange(type) { |
| | | this.currentType = type; |
| | | }, |
| | | handleAddRecord() { |
| | | this.addDialogVisible = true; |
| | | }, |
| | | handleDialogClose() { |
| | | this.currentRecord = {}; |
| | | this.dialogVisible = false; |
| | | }, |
| | | handleOutbound(data) { |
| | | // 这里调用出库API |
| | | confirmWarehousing({ |
| | | id: this.currentRecord.id, |
| | | preserveSignature: data.preserveSignature, |
| | | }).then((res) => { |
| | | console.log(res); |
| | | if (res.code == 200) { |
| | | this.$message.success("操作成功"); |
| | | this.dialogVisible = false; |
| | | // 刷新列表 |
| | | this.getRecordList(); |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | } |
| | | }); |
| | | }, |
| | | handleAddRecordConfirm(record) { |
| | | addWarehousing({ ...record, trainLibraryId: this.$route.query.id }).then( |
| | | (res) => { |
| | | this.$message.success("操作成功"); |
| | | this.getRecordList(); |
| | | } |
| | | ); |
| | | }, |
| | | goBack() { |
| | | this.$router.go(-1); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .record-page { |
| | | min-height: 100vh; |
| | | min-height: 100vh; |
| | | |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | height: 130px; |
| | | overflow: hidden; |
| | | .header-box { |
| | | margin-bottom: 20px; |
| | | border-radius: 16px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | height: 130px; |
| | | overflow: hidden; |
| | | |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | .header-content { |
| | | color: rgba(0, 0, 0, 0.88); |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 8px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 6px; |
| | | |
| | | &.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; |
| | | word-break: break-all; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 1; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .flex { |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | flex-wrap: wrap; |
| | | margin-bottom: 8px; |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-right: 24px; |
| | | margin-bottom: 6px; |
| | | |
| | | &.left-column { |
| | | width: 33%; |
| | | min-width: 200px; |
| | | } |
| | | |
| | | &.flex-column { |
| | | flex: 1; |
| | | min-width: 150px; |
| | | } |
| | | |
| | | &.full-width { |
| | | flex: 1; |
| | | min-width: 300px; |
| | | } |
| | | |
| | | .label { |
| | | color: #606266; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | margin-right: 8px; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | .value { |
| | | flex: 1; |
| | | color: #303133; |
| | | word-break: break-all; |
| | | display: -webkit-box; |
| | | -webkit-line-clamp: 1; |
| | | -webkit-box-orient: vertical; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | .flex { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .tableTitle { |
| | | display: flex; |
| | | padding-bottom: 20px; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .title { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .timeline-container { |
| | | padding: 20px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .timeline-card { |
| | | margin-bottom: 10px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | h4 { |
| | | margin: 0 0 10px; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | .drafts { |
| | | background: #fafafc; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #dcdfe6; |
| | | font-weight: 400; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | margin-left: 16px; |
| | | cursor: pointer; |
| | | height: 50px; |
| | | line-height: 50px; |
| | | width: 280px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .operation-btn { |
| | | margin-right: 12px; |
| | | .active { |
| | | color: #049c9a; |
| | | background: #ffffff; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #049c9a; |
| | | } |
| | | } |
| | | |
| | | .timeline-container { |
| | | padding: 20px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | .timeline-card { |
| | | margin-bottom: 10px; |
| | | background: rgba(255, 255, 255, 0.8); |
| | | |
| | | h4 { |
| | | margin: 0 0 10px; |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | p { |
| | | margin: 5px 0; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .operation-btn { |
| | | margin-right: 12px; |
| | | } |
| | | } |
| | | </style> |
| | | </style> |
New file |
| | |
| | | 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 }) |
| | | } |
| | | |
| | | // 确认出入库 |
| | | export const confirmWarehousing = (data) => { |
| | | return axios.post('/api/t-train-library/confirm', { ...data }) |
| | | } |
| | | |
| | | // 删除菌种库 |
| | | export const deleteStrainLibrary = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteById', { params }) |
| | | } |
| | | |
| | | // 删除菌种库出入库记录 |
| | | export const deleteWarehousing = (params) => { |
| | | return axios.delete('/open/t-train-library/deleteWarehousingById', { params }) |
| | | } |
| | |
| | | { |
| | | path: "add", |
| | | meta: { |
| | | title: "新增可行报告", |
| | | title: "新增可研报告", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/reportLibrary/feasibilityStudy/add.vue"), |
| | | }, |
| | | { |
| | | path: "edit", |
| | | meta: { |
| | | title: "编辑可研报告", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/reportLibrary/feasibilityStudy/add.vue"), |
| | | }, |
| | | |
| | | { |
| | | path: "feasibilityReport", |
| | | meta: { |
| | |
| | | component: () => import("../views/reportLibrary/feasibilityReport/index.vue"), |
| | | }, |
| | | { |
| | | path: "addFeasibility", |
| | | meta: { |
| | | title: "新增可行报告", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/reportLibrary/feasibilityReport/add.vue"), |
| | | }, |
| | | { |
| | | path: "editFeasibility", |
| | | meta: { |
| | | title: "编辑可行报告", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/reportLibrary/feasibilityReport/add.vue"), |
| | | }, |
| | | |
| | | |
| | | { |
| | | path: "processDevelopment", |
| | | meta: { |
| | | title: "工艺开发工具", |
| | |
| | | }, |
| | | component: () => import("../views/reportLibrary/processDevelopment/index.vue"), |
| | | }, |
| | | |
| | | { |
| | | path: "addProcessDevelopment", |
| | | meta: { |
| | | title: "新增工艺开发工具", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/reportLibrary/processDevelopment/add.vue"), |
| | | }, |
| | | { |
| | | path: "editProcessDevelopment", |
| | | meta: { |
| | | title: "编辑工艺开发工具", |
| | | hide: true, |
| | | keepAlive: true, |
| | | }, |
| | | component: () => import("../views/reportLibrary/processDevelopment/add.vue"), |
| | | }, |
| | | |
| | | |
| | | |
| | | { |
| | | path: "verificationRelease", |
| | | meta: { |
| | |
| | | ], |
| | | approvalDialogVisible: false, |
| | | approvalDialogType: "approve", |
| | | currentApprovalData: null, |
| | | currentApprovalData: [], |
| | | // 确认弹窗相关数据 |
| | | changeStatus: false, |
| | | changeStatusTitle: "", |
New file |
| | |
| | | <template> |
| | | <div class="add-container" :loading="loading"> |
| | | <Card v-loading="loading"> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>所属项目组</div> |
| | | </div> |
| | | <div class="header-title-right"> |
| | | <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | 选择项目组</el-button> |
| | | </div> |
| | | </div> |
| | | <Table :height="null" :data="tableData" :queryForm="queryForm" :total="0"> |
| | | <template> |
| | | <el-table-column prop="teamName" label="项目组名称" /> |
| | | <el-table-column prop="personCharge" label="项目负责人" /> |
| | | <el-table-column prop="staffName" label="项目组成员" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | </template> |
| | | </Table> |
| | | <el-form ref="form" :model="form" :rules="rules" inline label-position="top" style="margin-top: 38px"> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>报告编号</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportCode" style="margin-top: 38px"> |
| | | <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>报告名称</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportName" style="margin-top: 38px"> |
| | | <el-input v-model="form.reportName" style="width: 100%;" placeholder="请输入报告名称" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>报告正文</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportText" style="margin-top: 38px"> |
| | | <ai-editor ref="materialEditor" :value="form.reportText" style="width: 100%;" |
| | | placeholder="请输入报告正文" /> |
| | | </el-form-item> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div class="noRequire">附件</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="name" style="margin-top: 38px"> |
| | | <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList"> |
| | | <el-button size="small" type="primary">点击上传</el-button> |
| | | </el-upload> |
| | | </el-form-item> |
| | | |
| | | <div class="end-btn" style="margin-top: 38px"> |
| | | <el-button type="primary" @click="submit" :loading="loading">发送</el-button> |
| | | <el-button type="default" @click="save" :loading="loading">存草稿</el-button> |
| | | </div> |
| | | </el-form> |
| | | </Card> |
| | | <chooseProject @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { Card } from 'element-ui'; |
| | | import AiEditor from '@/components/AiEditor' |
| | | import chooseProject from '@/components/chooseProject' |
| | | import { addData, getDetail, editData } from './service' |
| | | |
| | | export default { |
| | | components: { |
| | | AiEditor, |
| | | chooseProject |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | form: { |
| | | reportCode: "", |
| | | reportName: "", |
| | | reportText: "" |
| | | }, |
| | | tableData: [], |
| | | fileList: [], // 附件列表 |
| | | showChoose: false, |
| | | rules: { |
| | | reportCode: [ |
| | | { required: true, message: '请输入报告编号', trigger: 'blur' } |
| | | ], |
| | | reportName: [ |
| | | { required: true, message: '请输入报告名称', trigger: 'blur' } |
| | | ], |
| | | }, |
| | | queryForm: {} |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | if (this.$route.query.id) { |
| | | this.getDetail() |
| | | } |
| | | }, |
| | | |
| | | methods: { |
| | | getDetail() { |
| | | getDetail(this.$route.query.id).then(res => { |
| | | this.form = res |
| | | this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }] |
| | | this.fileList = res.fileList |
| | | }) |
| | | }, |
| | | getProjectData(data) { |
| | | this.tableData = [data] |
| | | this.$forceUpdate() |
| | | this.showChoose = false |
| | | }, |
| | | submit() { |
| | | if (this.tableData.length == 0) { |
| | | this.$message.error('请选择项目组') |
| | | return |
| | | } |
| | | |
| | | this.$refs.form.validate((valid) => { |
| | | if (this.$refs.materialEditor.getContent() == '<p></p>') { |
| | | this.$message.error('请输入报告正文') |
| | | return |
| | | } |
| | | let data = { |
| | | ...this.form, |
| | | reportType: 2, |
| | | status: 1, |
| | | reportText: this.$refs.materialEditor.getContent(), |
| | | teamId: this.tableData[0].id |
| | | } |
| | | if (valid) { |
| | | this.loading = true |
| | | if (this.$route.query.id) { |
| | | editData({ ...data, id: this.$route.query.id }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('修改成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }) |
| | | } else { |
| | | addData({ ...data }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('发布成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }).finally(() => { |
| | | this.loading = false |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | }, |
| | | save() { |
| | | this.$refs.form.validate((valid) => { |
| | | let data = { |
| | | ...this.form, |
| | | reportType: 2, |
| | | status: -1, |
| | | reportText: this.$refs.materialEditor.getContent(), |
| | | teamId: this.tableData[0].id |
| | | } |
| | | |
| | | delete data.id |
| | | |
| | | if (valid) { |
| | | this.loading = true |
| | | addData({ ...data }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('提交成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }).finally(() => { |
| | | this.loading = false |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | }, |
| | | } |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .header-title { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 20px; |
| | | gap: 13px; |
| | | |
| | | .header-title-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 13px; |
| | | margin-top: 38px; |
| | | |
| | | img { |
| | | width: 12px; |
| | | height: 19px; |
| | | } |
| | | |
| | | div { |
| | | flex-shrink: 0; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #222222; |
| | | line-height: 27px; |
| | | font-family: "Source Han Sans CN Bold Bold"; |
| | | |
| | | &:before { |
| | | content: "*"; |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | } |
| | | |
| | | .noRequire:before { |
| | | content: unset; |
| | | } |
| | | |
| | | span { |
| | | flex-shrink: 0; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #222222; |
| | | line-height: 27px; |
| | | font-family: "Source Han Sans CN Bold Bold"; |
| | | } |
| | | } |
| | | |
| | | .header-title-left :first-child { |
| | | margin-top: 0; |
| | | } |
| | | } |
| | | |
| | | .header-title:first-child { |
| | | .header-title-left { |
| | | margin-top: 0; |
| | | } |
| | | } |
| | | |
| | | .end-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | |
| | | button { |
| | | width: 180px; |
| | | height: 36px; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" po :close-on-click-modal="false" |
| | | <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false" |
| | | @close="handleClose"> |
| | | <div class="approval-dialog"> |
| | | <div class="approval-dialog" :style="{height: obj.isDetail ? '50vh' : '40vh'}"> |
| | | <!-- 左侧审批内容 --> |
| | | <div class="approval-content"> |
| | | <Card class="approval-content-card"> |
| | |
| | | <div>所属项目组</div> |
| | | </div> |
| | | </div> |
| | | <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <Table :height="null" :total="0" :data="tableData"> |
| | | <template> |
| | | <el-table-column prop="name" label="项目组名称" /> |
| | | <el-table-column prop="age" label="项目负责人" /> |
| | | <el-table-column prop="age" label="项目组成员" /> |
| | | <el-table-column prop="age" label="创建时间" /> |
| | | <el-table-column prop="teamName" label="项目组名称" /> |
| | | <el-table-column prop="personCharge" label="项目负责人" /> |
| | | <el-table-column prop="staffName" label="项目组成员" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | </template> |
| | | </Table> |
| | | |
| | |
| | | <div>报告编号</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportCode" style="margin-top: 38px"> |
| | | <el-input disabled v-model="form.reportCode" style="width: 100%;" |
| | | placeholder="请输入报告编号" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | <div>报告名称</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportName" style="margin-top: 38px"> |
| | | <el-input disabled v-model="form.reportName" style="width: 100%;" |
| | | placeholder="请输入报告名称" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | <div>报告正文</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportText" style="margin-top: 38px"> |
| | | <ai-editor :readOnly="true" :value="form.reportText" style="width: 100%;" |
| | | placeholder="请输入报告正文" /> |
| | | </el-form-item> |
| | | |
| | | </el-form> |
| | | </template> |
| | |
| | | <!-- 右侧审批流程 --> |
| | | <div class="approval-flow"> |
| | | <div class="flow-content"> |
| | | <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver" |
| | | :approve-time="form.approveTime" /> |
| | | <approval-process :processData="form.processData" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="approval-dialog-approve"> |
| | | <div class="approval-dialog-approve" v-if="!obj.isDetail"> |
| | | <el-row :span="24"> |
| | | <el-col :span="12"> |
| | | <div class="status"> |
| | | <div class="status-title">审批结果</div> |
| | | <div class="status-content"> |
| | | <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1"> |
| | | <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2"> |
| | | 通过 |
| | | </div> |
| | | <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2"> |
| | | <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3"> |
| | | 驳回 |
| | | </div> |
| | | </div> |
| | |
| | | |
| | | </div> |
| | | <div slot="footer" class="dialog-footer"> |
| | | <el-button @click="handleClose" >取 消</el-button> |
| | | <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button> |
| | | <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button> |
| | | <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | |
| | | <script> |
| | | import ApprovalProcess from '@/components/approvalProcess' |
| | | import AiEditor from '@/components/AiEditor' |
| | | import { getDetail } from '../../service'; |
| | | |
| | | |
| | | export default { |
| | | name: "ApprovalDialog", |
| | |
| | | type: String, |
| | | default: "approve", // approve-审批,view-查看 |
| | | }, |
| | | data: { |
| | | obj: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | default: () => { }, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | planName: "", |
| | | planCode: "", |
| | | stage: "", |
| | | creator: "", |
| | | reportCode: "", |
| | | reportName: "", |
| | | reportText: "", |
| | | teamName: "", |
| | | createBy: "", |
| | | createTime: "", |
| | | status: "", |
| | | approvalComment: "", |
| | | status: "pending", |
| | | approver: "", |
| | | approveTime: "" |
| | | approveTime: "", |
| | | processData: [], |
| | | updateBy: "", |
| | | auditRemark: "", |
| | | auditPersonName: "", |
| | | auditTime: "" |
| | | }, |
| | | radio1: 1, |
| | | tableData: [], |
| | | rules: {}, |
| | | status: "1", |
| | | status: "2", |
| | | remark: "", |
| | | }; |
| | | }, |
| | |
| | | return this.type === "approve" ? "审批" : "审批详情"; |
| | | }, |
| | | }, |
| | | watch: { |
| | | data: { |
| | | handler(val) { |
| | | if (val) { |
| | | this.form = { ...val }; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | }, |
| | | methods: { |
| | | open() { |
| | | if (!this.obj.id) { |
| | | this.$message.error('缺少必要参数'); |
| | | return; |
| | | } |
| | | |
| | | getDetail(this.obj.id).then(res => { |
| | | const data = res.data || res; |
| | | this.form = { |
| | | ...this.form, |
| | | ...data, |
| | | processData: [] |
| | | }; |
| | | |
| | | this.tableData = data.projectTeam ? |
| | | [{ ...data.projectTeam, staffName: data.staffNames || '' }] : |
| | | []; |
| | | |
| | | let processData = []; |
| | | // 提交节点 |
| | | processData.push({ |
| | | type: "primary", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "提交人:", value: data.updateBy || "" }, |
| | | { label: "提交时间:", value: data.createTime || "" }, |
| | | ] |
| | | }); |
| | | |
| | | if (data.status == 2 || data.status == 3) { |
| | | processData.push({ |
| | | type: data.status === 2 ? "primary" : "danger", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "审批意见:", value: data.auditRemark || "" }, |
| | | { label: "审核人:", value: data.auditPersonName || "" }, |
| | | { label: "审核时间:", value: data.auditTime || "" }, |
| | | ] |
| | | }); |
| | | } else { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "等待审核" }, |
| | | ], |
| | | }); |
| | | } |
| | | |
| | | if (data.status == 2) { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [{ label: "等待评定" }], |
| | | }); |
| | | } |
| | | |
| | | if (data.status == 3) { |
| | | processData.push({ |
| | | type: "success", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "已评定" }, |
| | | { label: "评定人:", value: data.evaluatePersonName || "" }, |
| | | { label: "评定时间:", value: data.evaluateTime || "" } |
| | | ], |
| | | }); |
| | | } |
| | | |
| | | this.form.processData = processData; |
| | | |
| | | }).catch(err => { |
| | | this.$message.error('获取详情失败'); |
| | | }); |
| | | }, |
| | | handleClose() { |
| | | this.$emit("close"); |
| | | this.form.approvalComment = ""; |
| | | }, |
| | | handleApprove() { |
| | | if (!this.form.approvalComment) { |
| | | this.$message.warning("请输入审批意见"); |
| | | return; |
| | | } |
| | | this.$emit("approve", { |
| | | ...this.form, |
| | | status: "approved", |
| | | statuss: this.status, |
| | | remark: this.remark |
| | | }); |
| | | }, |
| | | handleReject() { |
| | | if (!this.form.approvalComment) { |
| | | this.$message.warning("请输入审批意见"); |
| | | return; |
| | | } |
| | | this.$emit("reject", { |
| | | ...this.form, |
| | | status: "rejected", |
| | | }); |
| | | |
| | | handleCurrentChange(page) { |
| | | this.form.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.form.pageSize = size |
| | | this.getList() |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | background: #ffffff; |
| | | box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08); |
| | | border-radius: 10px; |
| | | |
| | | |
| | | .flow-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <TableCustom :queryForm="queryForm" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <el-card class="header-box" v-if="roleType == 3"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> <span>设立课题规则</span> |
| | | </div> |
| | | <div class="header-content"> |
| | | <p>1、根据可研报告、产品构思设计的工艺研究路线,一条工艺路线设立一个课题。如果一个课题中有多个化合物需要开发研究,则每个化合物作为一个分题;分题归集到该课题中,最终形成课题报告。不同课题报告中的分题不能重复使用。 |
| | | </p> |
| | | <p>2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题。</p> |
| | | </div> |
| | | </el-card> |
| | | <TableCustom :tableData="tableData" :height="null" :total="total" @handleCurrentChange="handleCurrentChanges" |
| | | @handleSizeChange="handleSizeChanges"> |
| | | <template #search> |
| | | <el-form :model="form" :label-width="auto" inline> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="所属项目组:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | <el-input v-model="form.teamName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="报告名称:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | <el-input v-model="form.reportName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="报告编号:"> |
| | | <el-input v-model="form.reportCode" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="创建日期:"> |
| | | <el-date-picker v-model="form.date" type="daterange" range-separator="至" |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="" style="margin-left: 63px;"> |
| | | <el-button type="default">重置</el-button> |
| | | <el-button type="default" style="margin-right: 10px;">重置</el-button> |
| | | <el-button type="primary">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | <template #setting> |
| | | <div class="table-title"> |
| | | 可行报告库 |
| | | <el-button v-if="roleType == 3" @click="handleAddProject" class="el-icon-plus" type="primary"> |
| | | 新增可行报告</el-button> |
| | | <div class="table-setting"> |
| | | <div :class="!isDraft ? 'table-title' : 'table-tit'" @click="changeTab('')"> |
| | | 可行报告库 |
| | | </div> |
| | | <div v-if="roleType == 3" :class="!isDraft ? 'table-tit' : 'table-title'" @click="changeTab('-1')"> |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | | |
| | | </template> |
| | | <template #table> |
| | | <el-table-column prop="name" label="所属项目组" /> |
| | | <el-table-column prop="age" label="报告编号" /> |
| | | <el-table-column prop="age" label="报告名称" /> |
| | | <el-table-column prop="age" label="创建人" /> |
| | | <el-table-column prop="age" label="创建时间" /> |
| | | <el-table-column prop="age" label="状态"> |
| | | <el-table-column prop="teamName" label="所属项目组" /> |
| | | <el-table-column prop="reportCode" label="报告编号" /> |
| | | <el-table-column prop="reportName" label="报告名称" /> |
| | | <el-table-column prop="createBy" label="创建人" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | <el-table-column prop="status" label="状态" v-if="!isDraft"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.status == 1" type="success">待审核</el-tag> |
| | | <el-tag v-else-if="row.status == 0" type="success">已通过</el-tag> |
| | | <el-tag v-else type="danger">已驳回</el-tag> |
| | | <el-tag v-if="row.status == 1">待审核</el-tag> |
| | | <el-tag v-else-if="row.status == 2">待评定</el-tag> |
| | | <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag> |
| | | <el-tag v-else-if="row.status == 3" type="success">已评定</el-tag> |
| | | <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag> |
| | | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="age" label="操作"> |
| | | <el-table-column prop="options" label="操作"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text">审核</el-button> |
| | | <el-button type="text">详情</el-button> |
| | | <el-button type="text" @click="handleApproval(row)" |
| | | v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button type="text" @click="handleDelete(row)" |
| | | v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button> |
| | | <el-button type="text" @click="handleEdit(row)" |
| | | v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button> |
| | | <el-button type="text" @click="handleRevoke(row)" |
| | | v-if="row.status == 1 && roleType == 3">撤销审批</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | <Approval :visible="showApproval" @close="showApproval = false" /> |
| | | |
| | | <Approval :visible="showApproval" @close="showApproval = false" :obj="rowData" @approve="handleApprove" /> |
| | | <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" /> |
| | | <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus" |
| | | @close="changeStatus = false" @confirm="handleChangeStatusConfirm" /> |
| | | |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import Approval from './components/approval' |
| | | import { getDataList, audit, revokeAudit, deleteData } from './service' |
| | | |
| | | export default { |
| | | name: 'ProjectList', |
| | | components: { |
| | | Approval |
| | | Approval |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | name: '' |
| | | }, |
| | | showApproval:false, |
| | | showDelConfirm: false, |
| | | rowId: '', |
| | | changeStatus: false, |
| | | showApproval: false, |
| | | changeStatusTitle: '', |
| | | changeStatusTip: '', |
| | | queryForm: { |
| | | tableData: [], |
| | | isDraft: false, |
| | | rowData: {}, |
| | | roleType: '', // 1 超级管理员 2 审批人 3 工艺工程师 4化验师 5实验员 |
| | | form: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | pageNum: 1, |
| | | teamName: '', |
| | | status: '', |
| | | startTime: '', |
| | | reportType: 2, |
| | | reportName: '', |
| | | reportCode: '', |
| | | endTime: '', |
| | | date: '' |
| | | }, |
| | | total: 0 |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem('userInfo'))?.roleType |
| | | console.log('adwqedwqeqwe', this.roleType); |
| | | |
| | | this.getList() |
| | | }, |
| | | |
| | | methods: { |
| | | handleAddProject() { |
| | | handleApproval(row) { |
| | | this.rowData = row |
| | | this.showApproval = true |
| | | }, |
| | | handleDetail(row) { |
| | | row.isDetail = true |
| | | this.rowData = row |
| | | this.showApproval = true |
| | | }, |
| | | handleEdit(row) { |
| | | this.$router.push({ |
| | | path: '/projectList/addProject' |
| | | path: '/reportLibrary/editFeasibility', |
| | | query: { |
| | | id: row.id |
| | | } |
| | | }) |
| | | }, |
| | | handleDel(row) { |
| | | handleAddProject() { |
| | | this.$router.push('/reportLibrary/addFeasibility') |
| | | }, |
| | | changeTab(status) { |
| | | if (status == -1) { |
| | | this.isDraft = true |
| | | this.form.pageNum = 1 |
| | | } else { |
| | | this.form.pageNum = 1 |
| | | this.isDraft = false |
| | | this.form.status = status |
| | | } |
| | | this.getList() |
| | | }, |
| | | handleDelete(row) { |
| | | this.rowId = row.id |
| | | this.showDelConfirm = true |
| | | }, |
| | | handleDelConfirm() { |
| | | this.showDelConfirm = false |
| | | this.msgsuccess('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }, |
| | | handleChangeStatus(row, status) { |
| | | handleRevoke(row) { |
| | | this.rowId = row.id |
| | | this.changeStatusTitle = status == 1 ? '确认要封存这个项目组吗?' : '确认要解封该项目组吗?' |
| | | this.changeStatusTip = status == 1 ? '封存后项目组内人员看不到数据,审批人仍然可见数据。' : '解封后项目组内人员数据恢复。' |
| | | this.changeStatusTitle = '确认要撤销审批吗?' |
| | | this.changeStatusTip = '撤销审批后,可研报告将被撤销。' |
| | | this.changeStatus = true |
| | | }, |
| | | handleDelConfirm() { |
| | | deleteData({ id: this.rowId }).then(res => { |
| | | this.showDelConfirm = false |
| | | this.$message.success('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }) |
| | | }, |
| | | handleChangeStatusConfirm() { |
| | | this.changeStatus = false |
| | | this.msgsuccess('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | revokeAudit({ id: this.rowId }).then(res => { |
| | | this.changeStatus = false |
| | | this.$message.success('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | this.getList() |
| | | }) |
| | | }, |
| | | handleCurrentChanges(page) { |
| | | this.form.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | handleSizeChanges(size) { |
| | | this.form.pageSize = size |
| | | this.getList() |
| | | }, |
| | | getList() { |
| | | let data = {} |
| | | if (this.isDraft) { |
| | | data = { |
| | | ...this.form, |
| | | status: -1 |
| | | } |
| | | } else { |
| | | data = this.form |
| | | } |
| | | getDataList(data).then(res => { |
| | | if (res.code === 200) { |
| | | this.tableData = res.data.records || [] |
| | | this.total = res.data.total || 0 |
| | | } |
| | | }) |
| | | }, |
| | | handleApprove(data) { |
| | | let params = { |
| | | id: data.id, |
| | | auditStatus: data.statuss, |
| | | auditRemark: data.remark |
| | | } |
| | | |
| | | audit({ ...params }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('审核成功') |
| | | this.showApproval = false |
| | | this.getList() |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .el-icon-plus { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .header-content { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: rgba(0, 0, 0, 0.88); |
| | | margin-left: 30px; |
| | | } |
| | | |
| | | .box-title { |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #222222; |
| | | line-height: 27px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | |
| | | } |
| | | |
| | | .header-box { |
| | | border-radius: 16px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .table-setting { |
| | | display: flex; |
| | | gap: 14px; |
| | | } |
| | | |
| | | .table-tit { |
| | | background: #FAFAFC; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #DCDFE6; |
| | | width: 166px; |
| | | height: 50px; |
| | | background: #FFFFFF; |
| | | border-radius: 8px 8px 0px 0px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | // margin-bottom: 21px; |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | line-height: 27px; |
| | | } |
| | | |
| | | .list { |
| | | height: 100%; |
| | | } |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-bottom: 21px; |
| | | // margin-bottom: 21px; |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
New file |
| | |
| | | import axios from '@/utils/request'; |
| | | |
| | | // 查询列表 |
| | | export function getDataList(data) { |
| | | return axios.post('/api/t-feasibility-study-report/pageList', { ...data }) |
| | | } |
| | | |
| | | // 添加 |
| | | export function addData(data) { |
| | | console.log('adwqedwqeqwe//////////////',data); |
| | | return axios.post('/api/t-feasibility-study-report/add', { ...data }) |
| | | } |
| | | |
| | | //修改 |
| | | export function editData(data) { |
| | | return axios.post('/api/t-feasibility-study-report/update', { ...data }) |
| | | } |
| | | |
| | | //获取详情 |
| | | export function getDetail(id) { |
| | | return axios.get(`/open/t-feasibility-study-report/getDetailById?id=${id}`) |
| | | } |
| | | |
| | | //审核 |
| | | export function audit(data) { |
| | | console.log(data) |
| | | return axios.post('/api/t-feasibility-study-report/auditReport', { ...data }) |
| | | } |
| | | |
| | | //撤销审批 |
| | | export function revokeAudit(data) { |
| | | return axios.put(`/open/t-feasibility-study-report/revokedReport?id=${data.id}`) |
| | | } |
| | | |
| | | //删除 |
| | | export function deleteData(data) { |
| | | return axios.delete(`/open/t-feasibility-study-report/deleteById?id=${data.id}`) |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | |
| | | <template> |
| | | <div> |
| | | <Card> |
| | | <div class="add-container" :loading="loading"> |
| | | <Card v-loading="loading"> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportName" style="margin-top: 38px"> |
| | | <el-input v-model="form.reportName" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | <el-input v-model="form.reportName" style="width: 100%;" placeholder="请输入报告名称" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportText" style="margin-top: 38px"> |
| | | <ai-editor v-model="form.reportText" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | <ai-editor ref="materialEditor" :value="form.reportText" style="width: 100%;" |
| | | placeholder="请输入报告正文" /> |
| | | </el-form-item> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | </el-form-item> |
| | | |
| | | <div class="end-btn" style="margin-top: 38px"> |
| | | <el-button type="primary" @click="submit">发送</el-button> |
| | | <el-button type="default" @clice="save">存草稿</el-button> |
| | | <el-button type="primary" @click="submit" :loading="loading">发送</el-button> |
| | | <el-button type="default" @click="save" :loading="loading">存草稿</el-button> |
| | | </div> |
| | | </el-form> |
| | | </Card> |
| | |
| | | import { Card } from 'element-ui'; |
| | | import AiEditor from '@/components/AiEditor' |
| | | import chooseProject from '@/components/chooseProject' |
| | | import { addData, getDetail, editData } from './service' |
| | | export default { |
| | | components: { |
| | | AiEditor, |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | form: { |
| | | planName: "", |
| | | planCode: "", |
| | | stage: "", |
| | | creator: "", |
| | | createTime: "", |
| | | approvalComment: "", |
| | | status: "pending", |
| | | approver: "", |
| | | approveTime: "" |
| | | reportCode: "", |
| | | reportName: "", |
| | | reportText: "" |
| | | }, |
| | | tableData: [], |
| | | fileList: [], // 附件列表 |
| | | showChoose: false, |
| | | radio1: 1, |
| | | rules: {}, |
| | | status: "1", |
| | | remark: "", |
| | | queryForm: { |
| | | |
| | | } |
| | | rules: { |
| | | reportCode: [ |
| | | { required: true, message: '请输入报告编号', trigger: 'blur' } |
| | | ], |
| | | reportName: [ |
| | | { required: true, message: '请输入报告名称', trigger: 'blur' } |
| | | ], |
| | | }, |
| | | queryForm: {} |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | if (this.$route.query.id) { |
| | | this.getDetail() |
| | | } |
| | | }, |
| | | |
| | | methods: { |
| | | getDetail() { |
| | | getDetail(this.$route.query.id).then(res => { |
| | | this.form = res |
| | | this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }] |
| | | this.fileList = res.fileList |
| | | }) |
| | | }, |
| | | //获取选择项目组数据 |
| | | getProjectData(data) { |
| | | console.log('4458454', data); |
| | | this.tableData = [data] |
| | | this.$forceUpdate() |
| | | console.log('dsadasdsad', this.tableData); |
| | | |
| | | this.showChoose = false |
| | | }, |
| | | submit(){ |
| | | |
| | | }, |
| | | save(){ |
| | | submit() { |
| | | console.log(this.$refs.materialEditor.getContent()); |
| | | if (this.tableData.length == 0) { |
| | | this.$message.error('请选择项目组') |
| | | return |
| | | } |
| | | |
| | | this.$refs.form.validate((valid) => { |
| | | if (this.$refs.materialEditor.getContent() == '<p></p>') { |
| | | this.$message.error('请输入报告正文') |
| | | return |
| | | } |
| | | let data = { |
| | | ...this.form, |
| | | reportType: 1, |
| | | status: 1, |
| | | reportText: this.$refs.materialEditor.getContent(), |
| | | teamId: this.tableData[0].id |
| | | } |
| | | if (valid) { |
| | | this.loading = true |
| | | if (this.$route.query.id) { |
| | | editData({ ...data, id: this.$route.query.id }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('修改成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }) |
| | | } else { |
| | | addData({ ...data }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('发布成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }).finally(() => { |
| | | this.loading = false |
| | | }) |
| | | } |
| | | |
| | | } |
| | | }) |
| | | }, |
| | | save() { |
| | | this.$refs.form.validate((valid) => { |
| | | let data = { |
| | | ...this.form, |
| | | reportType: 1, |
| | | status: -1, |
| | | reportText: this.$refs.materialEditor.getContent(), |
| | | teamId: this.tableData[0].id |
| | | } |
| | | |
| | | delete data.id |
| | | |
| | | if (valid) { |
| | | this.loading = true |
| | | addData({ ...data }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('提交成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }).finally(() => { |
| | | this.loading = false |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | }, |
| | | } |
| | |
| | | <template> |
| | | <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" po :close-on-click-modal="false" |
| | | <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false" |
| | | @close="handleClose"> |
| | | <div class="approval-dialog"> |
| | | <div class="approval-dialog" :style="{height: obj.isDetail ? '50vh' : '40vh'}"> |
| | | <!-- 左侧审批内容 --> |
| | | <div class="approval-content"> |
| | | <Card class="approval-content-card"> |
| | |
| | | <div>所属项目组</div> |
| | | </div> |
| | | </div> |
| | | <Table :height="null" :total="0" @handleCurrentChange="handleCurrentChange" |
| | | @handleSizeChange="handleSizeChange"> |
| | | <Table :height="null" :total="0" :data="tableData"> |
| | | <template> |
| | | <el-table-column prop="name" label="项目组名称" /> |
| | | <el-table-column prop="age" label="项目负责人" /> |
| | | <el-table-column prop="age" label="项目组成员" /> |
| | | <el-table-column prop="age" label="创建时间" /> |
| | | <el-table-column prop="teamName" label="项目组名称" /> |
| | | <el-table-column prop="personCharge" label="项目负责人" /> |
| | | <el-table-column prop="staffName" label="项目组成员" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | </template> |
| | | </Table> |
| | | |
| | |
| | | <div>报告编号</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportCode" style="margin-top: 38px"> |
| | | <el-input disabled v-model="form.reportCode" style="width: 100%;" |
| | | placeholder="请输入报告编号" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | <div>报告名称</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportName" style="margin-top: 38px"> |
| | | <el-input disabled v-model="form.reportName" style="width: 100%;" |
| | | placeholder="请输入报告名称" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | <div>报告正文</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportText" style="margin-top: 38px"> |
| | | <ai-editor :readOnly="true" :value="form.reportText" style="width: 100%;" |
| | | placeholder="请输入报告正文" /> |
| | | </el-form-item> |
| | | |
| | | </el-form> |
| | | </template> |
| | |
| | | <!-- 右侧审批流程 --> |
| | | <div class="approval-flow"> |
| | | <div class="flow-content"> |
| | | <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver" |
| | | :approve-time="form.approveTime" /> |
| | | <approval-process :processData="form.processData" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="approval-dialog-approve"> |
| | | <div class="approval-dialog-approve" v-if="!obj.isDetail"> |
| | | <el-row :span="24"> |
| | | <el-col :span="12"> |
| | | <div class="status"> |
| | | <div class="status-title">审批结果</div> |
| | | <div class="status-content"> |
| | | <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1"> |
| | | <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2"> |
| | | 通过 |
| | | </div> |
| | | <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2"> |
| | | <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3"> |
| | | 驳回 |
| | | </div> |
| | | </div> |
| | |
| | | |
| | | </div> |
| | | <div slot="footer" class="dialog-footer"> |
| | | <el-button @click="handleClose" >取 消</el-button> |
| | | <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button> |
| | | <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button> |
| | | <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | |
| | | <script> |
| | | import ApprovalProcess from '@/components/approvalProcess' |
| | | import AiEditor from '@/components/AiEditor' |
| | | import { getDetail } from '../../service'; |
| | | |
| | | |
| | | export default { |
| | | name: "ApprovalDialog", |
| | |
| | | type: String, |
| | | default: "approve", // approve-审批,view-查看 |
| | | }, |
| | | data: { |
| | | obj: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | default: () => { }, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | planName: "", |
| | | planCode: "", |
| | | stage: "", |
| | | creator: "", |
| | | reportCode: "", |
| | | reportName: "", |
| | | reportText: "", |
| | | teamName: "", |
| | | createBy: "", |
| | | createTime: "", |
| | | status: "", |
| | | approvalComment: "", |
| | | status: "pending", |
| | | approver: "", |
| | | approveTime: "" |
| | | approveTime: "", |
| | | processData: [], |
| | | updateBy: "", |
| | | auditRemark: "", |
| | | auditPersonName: "", |
| | | auditTime: "" |
| | | }, |
| | | radio1: 1, |
| | | tableData: [], |
| | | rules: {}, |
| | | status: "1", |
| | | status: "2", |
| | | remark: "", |
| | | }; |
| | | }, |
| | |
| | | return this.type === "approve" ? "审批" : "审批详情"; |
| | | }, |
| | | }, |
| | | watch: { |
| | | data: { |
| | | handler(val) { |
| | | if (val) { |
| | | this.form = { ...val }; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | }, |
| | | methods: { |
| | | open() { |
| | | if (!this.obj.id) { |
| | | this.$message.error('缺少必要参数'); |
| | | return; |
| | | } |
| | | |
| | | getDetail(this.obj.id).then(res => { |
| | | const data = res.data || res; |
| | | this.form = { |
| | | ...this.form, |
| | | ...data, |
| | | processData: [] |
| | | }; |
| | | |
| | | this.tableData = data.projectTeam ? |
| | | [{ ...data.projectTeam, staffName: data.staffNames || '' }] : |
| | | []; |
| | | |
| | | let processData = []; |
| | | // 提交节点 |
| | | processData.push({ |
| | | type: "primary", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "提交人:", value: data.updateBy || "" }, |
| | | { label: "提交时间:", value: data.createTime || "" }, |
| | | ] |
| | | }); |
| | | |
| | | if (data.status == 2 || data.status == 3) { |
| | | processData.push({ |
| | | type: data.status === 2 ? "primary" : "danger", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "审批意见:", value: data.auditRemark || "" }, |
| | | { label: "审核人:", value: data.auditPersonName || "" }, |
| | | { label: "审核时间:", value: data.auditTime || "" }, |
| | | ] |
| | | }); |
| | | } else { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "等待审核" }, |
| | | ], |
| | | }); |
| | | } |
| | | |
| | | if (data.status == 2) { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [{ label: "等待评定" }], |
| | | }); |
| | | } |
| | | |
| | | if (data.status == 3) { |
| | | processData.push({ |
| | | type: "success", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "已评定" }, |
| | | { label: "评定人:", value: data.evaluatePersonName || "" }, |
| | | { label: "评定时间:", value: data.evaluateTime || "" } |
| | | ], |
| | | }); |
| | | } |
| | | |
| | | this.form.processData = processData; |
| | | |
| | | }).catch(err => { |
| | | this.$message.error('获取详情失败'); |
| | | }); |
| | | }, |
| | | handleClose() { |
| | | this.$emit("close"); |
| | | this.form.approvalComment = ""; |
| | | }, |
| | | handleApprove() { |
| | | if (!this.form.approvalComment) { |
| | | this.$message.warning("请输入审批意见"); |
| | | return; |
| | | } |
| | | this.$emit("approve", { |
| | | ...this.form, |
| | | status: "approved", |
| | | statuss: this.status, |
| | | remark: this.remark |
| | | }); |
| | | }, |
| | | handleReject() { |
| | | if (!this.form.approvalComment) { |
| | | this.$message.warning("请输入审批意见"); |
| | | return; |
| | | } |
| | | this.$emit("reject", { |
| | | ...this.form, |
| | | status: "rejected", |
| | | }); |
| | | }, |
| | | |
| | | |
| | | handleCurrentChange(page) { |
| | | this.form.pageNum = page |
| | | this.getList() |
| | |
| | | background: #ffffff; |
| | | box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08); |
| | | border-radius: 10px; |
| | | |
| | | |
| | | .flow-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <el-card class="header-box"> |
| | | <el-card class="header-box" v-if="roleType == 3"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> <span>设立课题规则</span> |
| | | </div> |
| | |
| | | <p>2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题。</p> |
| | | </div> |
| | | </el-card> |
| | | <TableCustom :tableData="tableData" :total="total" @handleCurrentChange="handleCurrentChanges" |
| | | <TableCustom :tableData="tableData" :height="null" :total="total" @handleCurrentChange="handleCurrentChanges" |
| | | @handleSizeChange="handleSizeChanges"> |
| | | <template #search> |
| | | <el-form :model="form" label-width="auto" inline> |
| | |
| | | </el-form> |
| | | </template> |
| | | <template #setting> |
| | | <el-button @click="handleAddProject" class="el-icon-plus" type="primary"> |
| | | <el-button v-if="roleType == 3" @click="handleAddProject" class="el-icon-plus" type="primary"> |
| | | 新增可研报告</el-button> |
| | | <div class="table-setting"> |
| | | <div class="table-title"> |
| | | <div :class="!isDraft ? 'table-title' : 'table-tit'" @click="changeTab('')"> |
| | | 可研报告库 |
| | | </div> |
| | | <div class="table-tit"> |
| | | <div v-if="roleType == 3" :class="!isDraft ? 'table-tit' : 'table-title'" @click="changeTab('-1')"> |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | |
| | | <el-table-column prop="reportName" label="报告名称" /> |
| | | <el-table-column prop="createBy" label="创建人" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | <el-table-column prop="status" label="状态"> |
| | | <el-table-column prop="status" label="状态" v-if="!isDraft"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.status == 1" type="success">待审核</el-tag> |
| | | <el-tag v-else-if="row.status == 0" type="success">已通过</el-tag> |
| | | <el-tag v-else type="danger">已驳回</el-tag> |
| | | <el-tag v-if="row.status == 1">待审核</el-tag> |
| | | <el-tag v-else-if="row.status == 2">待评定</el-tag> |
| | | <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag> |
| | | <el-tag v-else-if="row.status == 3" type="success">已评定</el-tag> |
| | | <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag> |
| | | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="options" label="操作"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text">审核</el-button> |
| | | <el-button type="text">详情</el-button> |
| | | <el-button type="text" @click="handleApproval(row)" |
| | | v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button type="text" @click="handleDelete(row)" |
| | | v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button> |
| | | <el-button type="text" @click="handleEdit(row)" |
| | | v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button> |
| | | <el-button type="text" @click="handleRevoke(row)" |
| | | v-if="row.status == 1 && roleType == 3">撤销审批</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <Approval :visible="showApproval" @close="showApproval = false" /> |
| | | <Approval :visible="showApproval" @close="showApproval = false" :obj="rowData" @approve="handleApprove" /> |
| | | <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" /> |
| | | <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus" |
| | | @close="changeStatus = false" @confirm="handleChangeStatusConfirm" /> |
| | |
| | | |
| | | <script> |
| | | import Approval from './components/approval' |
| | | import { getDataList } from './service' |
| | | import { getDataList, audit, revokeAudit, deleteData } from './service' |
| | | |
| | | export default { |
| | | name: 'ProjectList', |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | name: '' |
| | | }, |
| | | showDelConfirm: false, |
| | | rowId: '', |
| | | changeStatus: false, |
| | | showApproval: false, |
| | | changeStatusTitle: '', |
| | | changeStatusTip: '', |
| | | tableData:[], |
| | | tableData: [], |
| | | isDraft: false, |
| | | rowData: {}, |
| | | roleType: '', // 1 超级管理员 2 审批人 3 工艺工程师 4化验师 5实验员 |
| | | form: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | teamName:'', |
| | | status:'', |
| | | startTime:'', |
| | | reportType:1, |
| | | reportName:'', |
| | | reportCode:'', |
| | | endTime:'', |
| | | date:'' |
| | | teamName: '', |
| | | status: '', |
| | | startTime: '', |
| | | reportType: 1, |
| | | reportName: '', |
| | | reportCode: '', |
| | | endTime: '', |
| | | date: '' |
| | | }, |
| | | total: 0 |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem('userInfo'))?.roleType |
| | | console.log('adwqedwqeqwe', this.roleType); |
| | | |
| | | this.getList() |
| | | }, |
| | | |
| | | |
| | | methods: { |
| | | handleApproval(row) { |
| | | this.rowData = row |
| | | this.showApproval = true |
| | | }, |
| | | handleDetail(row) { |
| | | row.isDetail = true |
| | | this.rowData = row |
| | | this.showApproval = true |
| | | }, |
| | | handleEdit(row) { |
| | | this.$router.push({ |
| | | path: '/reportLibrary/edit', |
| | | query: { |
| | | id: row.id |
| | | } |
| | | }) |
| | | }, |
| | | handleAddProject() { |
| | | this.$router.push('/reportLibrary/add') |
| | | }, |
| | | handleDel(row) { |
| | | changeTab(status) { |
| | | if (status == -1) { |
| | | this.isDraft = true |
| | | this.form.pageNum = 1 |
| | | } else { |
| | | this.form.pageNum = 1 |
| | | this.isDraft = false |
| | | this.form.status = status |
| | | } |
| | | this.getList() |
| | | }, |
| | | handleDelete(row) { |
| | | this.rowId = row.id |
| | | this.showDelConfirm = true |
| | | }, |
| | | handleDelConfirm() { |
| | | this.showDelConfirm = false |
| | | this.msgsuccess('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }, |
| | | handleChangeStatus(row, status) { |
| | | handleRevoke(row) { |
| | | this.rowId = row.id |
| | | this.changeStatusTitle = status == 1 ? '确认要封存这个项目组吗?' : '确认要解封该项目组吗?' |
| | | this.changeStatusTip = status == 1 ? '封存后项目组内人员看不到数据,审批人仍然可见数据。' : '解封后项目组内人员数据恢复。' |
| | | this.changeStatusTitle = '确认要撤销审批吗?' |
| | | this.changeStatusTip = '撤销审批后,可研报告将被撤销。' |
| | | this.changeStatus = true |
| | | }, |
| | | handleDelConfirm() { |
| | | deleteData({ id: this.rowId }).then(res => { |
| | | this.showDelConfirm = false |
| | | this.$message.success('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }) |
| | | }, |
| | | handleChangeStatusConfirm() { |
| | | this.changeStatus = false |
| | | this.msgsuccess('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | this.getList() |
| | | revokeAudit({ id: this.rowId }).then(res => { |
| | | this.changeStatus = false |
| | | this.$message.success('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | this.getList() |
| | | }) |
| | | }, |
| | | handleCurrentChanges(page) { |
| | | this.form.pageNum = page |
| | |
| | | this.getList() |
| | | }, |
| | | getList() { |
| | | getDataList(this.form).then(res => { |
| | | console.log('sdasdasdqweqw',res); |
| | | this.tableData = res.records || [] |
| | | this.total = res.total || 0 |
| | | let data = {} |
| | | if (this.isDraft) { |
| | | data = { |
| | | ...this.form, |
| | | status: -1 |
| | | } |
| | | } else { |
| | | data = this.form |
| | | } |
| | | getDataList(data).then(res => { |
| | | if (res.code === 200) { |
| | | this.tableData = res.data.records || [] |
| | | this.total = res.data.total || 0 |
| | | } |
| | | }) |
| | | }, |
| | | handleApprove(data) { |
| | | let params = { |
| | | id: data.id, |
| | | auditStatus: data.statuss, |
| | | auditRemark: data.remark |
| | | } |
| | | |
| | | audit({ ...params }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('审核成功') |
| | | this.showApproval = false |
| | | this.getList() |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .el-icon-plus{ |
| | | .el-icon-plus { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .header-content { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 400; |
| | |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #049C9A; |
| | | color: #606266; |
| | | line-height: 27px; |
| | | } |
| | | |
| | |
| | | import axios from '@/utils/request'; |
| | | |
| | | // 添加项目课题方案 |
| | | // 查询列表 |
| | | export function getDataList(data) { |
| | | return axios.post('/api/t-feasibility-study-report/pageList', { ...data }) |
| | | } |
| | | |
| | | // 添加 |
| | | export function addData(data) { |
| | | return axios.post('/api/t-feasibility-study-report/add', { ...data }) |
| | | } |
| | | |
| | | //修改 |
| | | export function editData(data) { |
| | | return axios.post('/api/t-feasibility-study-report/update', { ...data }) |
| | | } |
| | | |
| | | //获取详情 |
| | | export function getDetail(id) { |
| | | return axios.get(`/open/t-feasibility-study-report/getDetailById?id=${id}`) |
| | | } |
| | | |
| | | //审核 |
| | | export function audit(data) { |
| | | console.log(data) |
| | | return axios.post('/api/t-feasibility-study-report/auditReport', { ...data }) |
| | | } |
| | | |
| | | //撤销审批 |
| | | export function revokeAudit(data) { |
| | | return axios.put(`/open/t-feasibility-study-report/revokedReport?id=${data.id}`) |
| | | } |
| | | |
| | | //删除 |
| | | export function deleteData(data) { |
| | | return axios.delete(`/open/t-feasibility-study-report/deleteById?id=${data.id}`) |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
New file |
| | |
| | | <template> |
| | | <div class="add-container" :loading="loading"> |
| | | <Card v-loading="loading"> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>所属项目组</div> |
| | | </div> |
| | | <div class="header-title-right"> |
| | | <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary"> |
| | | 选择项目组</el-button> |
| | | </div> |
| | | |
| | | </div> |
| | | <Table :height="null" :data="tableData" :queryForm="queryForm" :total="0"> |
| | | <template> |
| | | <el-table-column prop="teamName" label="项目组名称" /> |
| | | <el-table-column prop="personCharge" label="项目负责人" /> |
| | | <el-table-column prop="staffName" label="项目组成员" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | </template> |
| | | </Table> |
| | | <el-form ref="form" :model="form" :rules="rules" inline label-position="top" style="margin-top: 38px"> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>报告编号</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportCode" style="margin-top: 38px"> |
| | | <el-input v-model="form.reportCode" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>报告名称</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportName" style="margin-top: 38px"> |
| | | <el-input v-model="form.reportName" style="width: 100%;" placeholder="请输入报告名称" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div>报告正文</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="reportText" style="margin-top: 38px"> |
| | | <ai-editor ref="materialEditor" :value="form.reportText" style="width: 100%;" |
| | | placeholder="请输入报告正文" /> |
| | | </el-form-item> |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | | <img src="@/assets/public/headercard.png" /> |
| | | <div class="noRequire">附件</div> |
| | | </div> |
| | | </div> |
| | | <el-form-item prop="name" style="margin-top: 38px"> |
| | | <el-upload action="https://jsonplaceholder.typicode.com/posts/" :file-list="fileList"> |
| | | <el-button size="small" type="primary">点击上传</el-button> |
| | | </el-upload> |
| | | </el-form-item> |
| | | |
| | | <div class="end-btn" style="margin-top: 38px"> |
| | | <el-button type="primary" @click="submit" :loading="loading">发送</el-button> |
| | | <el-button type="default" @click="save" :loading="loading">存草稿</el-button> |
| | | </div> |
| | | </el-form> |
| | | </Card> |
| | | <chooseProject @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject> |
| | | </div> |
| | | |
| | | </template> |
| | | <script> |
| | | import { Card } from 'element-ui'; |
| | | import AiEditor from '@/components/AiEditor' |
| | | import chooseProject from '@/components/chooseProject' |
| | | import { addData, getDetail, editData } from './service' |
| | | export default { |
| | | components: { |
| | | AiEditor, |
| | | chooseProject |
| | | }, |
| | | data() { |
| | | return { |
| | | loading: false, |
| | | form: { |
| | | reportCode: "", |
| | | reportName: "", |
| | | reportText: "" |
| | | }, |
| | | tableData: [], |
| | | fileList: [], // 附件列表 |
| | | showChoose: false, |
| | | rules: { |
| | | reportCode: [ |
| | | { required: true, message: '请输入报告编号', trigger: 'blur' } |
| | | ], |
| | | reportName: [ |
| | | { required: true, message: '请输入报告名称', trigger: 'blur' } |
| | | ], |
| | | }, |
| | | queryForm: {} |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | if (this.$route.query.id) { |
| | | this.getDetail() |
| | | } |
| | | }, |
| | | |
| | | methods: { |
| | | getDetail() { |
| | | getDetail(this.$route.query.id).then(res => { |
| | | this.form = res |
| | | this.tableData = [{ ...res.projectTeam, staffName: res.staffNames }] |
| | | this.fileList = res.fileList |
| | | }) |
| | | }, |
| | | //获取选择项目组数据 |
| | | getProjectData(data) { |
| | | this.tableData = [data] |
| | | this.$forceUpdate() |
| | | this.showChoose = false |
| | | }, |
| | | submit() { |
| | | console.log(this.$refs.materialEditor.getContent()); |
| | | if (this.tableData.length == 0) { |
| | | this.$message.error('请选择项目组') |
| | | return |
| | | } |
| | | |
| | | this.$refs.form.validate((valid) => { |
| | | if (this.$refs.materialEditor.getContent() == '<p></p>') { |
| | | this.$message.error('请输入报告正文') |
| | | return |
| | | } |
| | | let data = { |
| | | ...this.form, |
| | | reportType: 3, |
| | | status: 1, |
| | | reportText: this.$refs.materialEditor.getContent(), |
| | | teamId: this.tableData[0].id |
| | | } |
| | | if (valid) { |
| | | this.loading = true |
| | | if (this.$route.query.id) { |
| | | editData({ ...data, id: this.$route.query.id }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('修改成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }) |
| | | } else { |
| | | addData({ ...data }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('发布成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }).finally(() => { |
| | | this.loading = false |
| | | }) |
| | | } |
| | | |
| | | } |
| | | }) |
| | | }, |
| | | save() { |
| | | this.$refs.form.validate((valid) => { |
| | | let data = { |
| | | ...this.form, |
| | | reportType: 3, |
| | | status: -1, |
| | | reportText: this.$refs.materialEditor.getContent(), |
| | | teamId: this.tableData[0].id |
| | | } |
| | | |
| | | delete data.id |
| | | |
| | | if (valid) { |
| | | this.loading = true |
| | | addData({ ...data }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('提交成功') |
| | | this.$router.back() |
| | | } else { |
| | | this.$message.error(res.message) |
| | | } |
| | | }).finally(() => { |
| | | this.loading = false |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | }, |
| | | } |
| | | |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .header-title { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | margin-bottom: 20px; |
| | | gap: 13px; |
| | | |
| | | .header-title-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 13px; |
| | | margin-top: 38px; |
| | | |
| | | img { |
| | | width: 12px; |
| | | height: 19px; |
| | | } |
| | | |
| | | div { |
| | | flex-shrink: 0; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #222222; |
| | | line-height: 27px; |
| | | font-family: "Source Han Sans CN Bold Bold"; |
| | | |
| | | &:before { |
| | | content: "*"; |
| | | color: #f56c6c; |
| | | margin-right: 4px; |
| | | } |
| | | } |
| | | |
| | | .noRequire:before { |
| | | content: unset; |
| | | // color: #f56c6c; |
| | | // margin-right: 4px; |
| | | |
| | | } |
| | | |
| | | span { |
| | | flex-shrink: 0; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #222222; |
| | | line-height: 27px; |
| | | font-family: "Source Han Sans CN Bold Bold"; |
| | | } |
| | | } |
| | | |
| | | .header-title-left :first-child { |
| | | margin-top: 0; |
| | | } |
| | | } |
| | | |
| | | .header-title:first-child { |
| | | .header-title-left { |
| | | margin-top: 0; |
| | | } |
| | | } |
| | | |
| | | .end-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 10px; |
| | | |
| | | button { |
| | | width: 180px; |
| | | height: 36px; |
| | | // background: #409EFF; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" po :close-on-click-modal="false" |
| | | <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false" |
| | | @close="handleClose"> |
| | | <div class="approval-dialog"> |
| | | <div class="approval-dialog" :style="{height: obj.isDetail ? '50vh' : '40vh'}"> |
| | | <!-- 左侧审批内容 --> |
| | | <div class="approval-content"> |
| | | <Card class="approval-content-card"> |
| | |
| | | <div>所属项目组</div> |
| | | </div> |
| | | </div> |
| | | <Table :height="null" :queryForm="queryForm" :total="0" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <Table :height="null" :total="0" :data="tableData"> |
| | | <template> |
| | | <el-table-column prop="name" label="项目组名称" /> |
| | | <el-table-column prop="age" label="项目负责人" /> |
| | | <el-table-column prop="age" label="项目组成员" /> |
| | | <el-table-column prop="age" label="创建时间" /> |
| | | <el-table-column prop="teamName" label="项目组名称" /> |
| | | <el-table-column prop="personCharge" label="项目负责人" /> |
| | | <el-table-column prop="staffName" label="项目组成员" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | </template> |
| | | </Table> |
| | | |
| | |
| | | <div>报告编号</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportCode" style="margin-top: 38px"> |
| | | <el-input disabled v-model="form.reportCode" style="width: 100%;" |
| | | placeholder="请输入报告编号" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | <div>报告名称</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <el-input v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportName" style="margin-top: 38px"> |
| | | <el-input disabled v-model="form.reportName" style="width: 100%;" |
| | | placeholder="请输入报告名称" /> |
| | | </el-form-item> |
| | | |
| | | <div class="header-title" style="width: 100%;"> |
| | | <div class="header-title-left"> |
| | |
| | | <div>报告正文</div> |
| | | </div> |
| | | </div> |
| | | <form-item prop="name" style="margin-top: 38px"> |
| | | <ai-editor v-model="form.name" style="width: 100%;" placeholder="请输入报告编号" /> |
| | | </form-item> |
| | | <el-form-item prop="reportText" style="margin-top: 38px"> |
| | | <ai-editor :readOnly="true" :value="form.reportText" style="width: 100%;" |
| | | placeholder="请输入报告正文" /> |
| | | </el-form-item> |
| | | |
| | | </el-form> |
| | | </template> |
| | |
| | | <!-- 右侧审批流程 --> |
| | | <div class="approval-flow"> |
| | | <div class="flow-content"> |
| | | <approval-process :status="form.status" :submit-time="form.createTime" :approver="form.approver" |
| | | :approve-time="form.approveTime" /> |
| | | <approval-process :processData="form.processData" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="approval-dialog-approve"> |
| | | <div class="approval-dialog-approve" v-if="!obj.isDetail"> |
| | | <el-row :span="24"> |
| | | <el-col :span="12"> |
| | | <div class="status"> |
| | | <div class="status-title">审批结果</div> |
| | | <div class="status-content"> |
| | | <div class="resolve" :class="status == '1' && 'activeStatus'" @click.stop="status = 1"> |
| | | <div class="resolve" :class="status == '2' && 'activeStatus'" @click.stop="status = 2"> |
| | | 通过 |
| | | </div> |
| | | <div class="reject" :class="status == '2' && 'activeStatus'" @click.stop="status = 2"> |
| | | <div class="reject" :class="status == '3' && 'activeStatus'" @click.stop="status = 3"> |
| | | 驳回 |
| | | </div> |
| | | </div> |
| | |
| | | |
| | | </div> |
| | | <div slot="footer" class="dialog-footer"> |
| | | <el-button @click="handleClose" >取 消</el-button> |
| | | <el-button type="primary" @click="handleApprove" v-if="type === 'approve'">通过</el-button> |
| | | <el-button @click="handleClose">{{obj.isDetail ? '关闭' : '取 消'}}</el-button> |
| | | <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button> |
| | | </div> |
| | | </el-dialog> |
| | | </template> |
| | |
| | | <script> |
| | | import ApprovalProcess from '@/components/approvalProcess' |
| | | import AiEditor from '@/components/AiEditor' |
| | | import { getDetail } from '../../service'; |
| | | |
| | | |
| | | export default { |
| | | name: "ApprovalDialog", |
| | |
| | | type: String, |
| | | default: "approve", // approve-审批,view-查看 |
| | | }, |
| | | data: { |
| | | obj: { |
| | | type: Object, |
| | | default: () => ({}), |
| | | default: () => { }, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | planName: "", |
| | | planCode: "", |
| | | stage: "", |
| | | creator: "", |
| | | reportCode: "", |
| | | reportName: "", |
| | | reportText: "", |
| | | teamName: "", |
| | | createBy: "", |
| | | createTime: "", |
| | | status: "", |
| | | approvalComment: "", |
| | | status: "pending", |
| | | approver: "", |
| | | approveTime: "" |
| | | approveTime: "", |
| | | processData: [], |
| | | updateBy: "", |
| | | auditRemark: "", |
| | | auditPersonName: "", |
| | | auditTime: "" |
| | | }, |
| | | radio1: 1, |
| | | tableData: [], |
| | | rules: {}, |
| | | status: "1", |
| | | status: "2", |
| | | remark: "", |
| | | }; |
| | | }, |
| | |
| | | return this.type === "approve" ? "审批" : "审批详情"; |
| | | }, |
| | | }, |
| | | watch: { |
| | | data: { |
| | | handler(val) { |
| | | if (val) { |
| | | this.form = { ...val }; |
| | | } |
| | | }, |
| | | immediate: true, |
| | | }, |
| | | }, |
| | | methods: { |
| | | open() { |
| | | if (!this.obj.id) { |
| | | this.$message.error('缺少必要参数'); |
| | | return; |
| | | } |
| | | |
| | | getDetail(this.obj.id).then(res => { |
| | | const data = res.data || res; |
| | | this.form = { |
| | | ...this.form, |
| | | ...data, |
| | | processData: [] |
| | | }; |
| | | |
| | | this.tableData = data.projectTeam ? |
| | | [{ ...data.projectTeam, staffName: data.staffNames || '' }] : |
| | | []; |
| | | |
| | | let processData = []; |
| | | // 提交节点 |
| | | processData.push({ |
| | | type: "primary", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "提交人:", value: data.updateBy || "" }, |
| | | { label: "提交时间:", value: data.createTime || "" }, |
| | | ] |
| | | }); |
| | | |
| | | if (data.status == 2 || data.status == 3) { |
| | | processData.push({ |
| | | type: data.status === 2 ? "primary" : "danger", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "审批意见:", value: data.auditRemark || "" }, |
| | | { label: "审核人:", value: data.auditPersonName || "" }, |
| | | { label: "审核时间:", value: data.auditTime || "" }, |
| | | ] |
| | | }); |
| | | } else { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "等待审核" }, |
| | | ], |
| | | }); |
| | | } |
| | | |
| | | if (data.status == 2) { |
| | | processData.push({ |
| | | type: "warning", |
| | | mode: "list", |
| | | fields: [{ label: "等待评定" }], |
| | | }); |
| | | } |
| | | |
| | | if (data.status == 3) { |
| | | processData.push({ |
| | | type: "success", |
| | | mode: "list", |
| | | fields: [ |
| | | { label: "已评定" }, |
| | | { label: "评定人:", value: data.evaluatePersonName || "" }, |
| | | { label: "评定时间:", value: data.evaluateTime || "" } |
| | | ], |
| | | }); |
| | | } |
| | | |
| | | this.form.processData = processData; |
| | | |
| | | }).catch(err => { |
| | | this.$message.error('获取详情失败'); |
| | | }); |
| | | }, |
| | | handleClose() { |
| | | this.$emit("close"); |
| | | this.form.approvalComment = ""; |
| | | }, |
| | | handleApprove() { |
| | | if (!this.form.approvalComment) { |
| | | this.$message.warning("请输入审批意见"); |
| | | return; |
| | | } |
| | | this.$emit("approve", { |
| | | ...this.form, |
| | | status: "approved", |
| | | statuss: this.status, |
| | | remark: this.remark |
| | | }); |
| | | }, |
| | | handleReject() { |
| | | if (!this.form.approvalComment) { |
| | | this.$message.warning("请输入审批意见"); |
| | | return; |
| | | } |
| | | this.$emit("reject", { |
| | | ...this.form, |
| | | status: "rejected", |
| | | }); |
| | | |
| | | handleCurrentChange(page) { |
| | | this.form.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.form.pageSize = size |
| | | this.getList() |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | background: #ffffff; |
| | | box-shadow: 0px 4px 12px 4px rgba(0, 0, 0, 0.08); |
| | | border-radius: 10px; |
| | | |
| | | |
| | | .flow-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | |
| | | <template> |
| | | <div class="list"> |
| | | <TableCustom :queryForm="queryForm" :total="total" @currentChange="handleCurrentChange" |
| | | @sizeChange="handleSizeChange"> |
| | | <el-card class="header-box" v-if="roleType == 3"> |
| | | <div class="box-title"> |
| | | <img src="@/assets/public/notice.png" class="header-icon"> <span>设立课题规则</span> |
| | | </div> |
| | | <div class="header-content"> |
| | | <p>1、根据可研报告、产品构思设计的工艺研究路线,一条工艺路线设立一个课题。如果一个课题中有多个化合物需要开发研究,则每个化合物作为一个分题;分题归集到该课题中,最终形成课题报告。不同课题报告中的分题不能重复使用。 |
| | | </p> |
| | | <p>2、在可行研究阶段,工艺开发升级,重新规划工艺研究路线,则以新规划的工艺路线方案来设定课题。</p> |
| | | </div> |
| | | </el-card> |
| | | <TableCustom :tableData="tableData" :height="null" :total="total" @handleCurrentChange="handleCurrentChanges" |
| | | @handleSizeChange="handleSizeChanges"> |
| | | <template #search> |
| | | <el-form :model="form" :label-width="auto" inline> |
| | | <el-form :model="form" label-width="auto" inline> |
| | | <el-form-item label="所属项目组:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | <el-input v-model="form.teamName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="报告名称:"> |
| | | <el-input v-model="form.name" placeholder="请输入"></el-input> |
| | | <el-input v-model="form.reportName" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="报告编号:"> |
| | | <el-input v-model="form.reportCode" placeholder="请输入"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="创建日期:"> |
| | | <el-date-picker v-model="form.date" type="daterange" range-separator="至" |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="" style="margin-left: 63px;"> |
| | | <el-button type="default">重置</el-button> |
| | | <el-button type="default" style="margin-right: 10px;">重置</el-button> |
| | | <el-button type="primary">查询</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | <template #setting> |
| | | <div class="table-title"> |
| | | 工艺开发工具 |
| | | <el-button v-if="roleType == 3" @click="handleAddProject" class="el-icon-plus" type="primary"> |
| | | 新增工艺开发工具</el-button> |
| | | <div class="table-setting"> |
| | | <div :class="!isDraft ? 'table-title' : 'table-tit'" @click="changeTab('')"> |
| | | 工艺开发工具 |
| | | </div> |
| | | <div v-if="roleType == 3" :class="!isDraft ? 'table-tit' : 'table-title'" @click="changeTab('-1')"> |
| | | 草稿箱 |
| | | </div> |
| | | </div> |
| | | |
| | | </template> |
| | | <template #table> |
| | | <el-table-column prop="name" label="所属项目组" /> |
| | | <el-table-column prop="age" label="报告编号" /> |
| | | <el-table-column prop="age" label="报告名称" /> |
| | | <el-table-column prop="age" label="创建人" /> |
| | | <el-table-column prop="age" label="创建时间" /> |
| | | <el-table-column prop="age" label="状态"> |
| | | <el-table-column prop="teamName" label="所属项目组" /> |
| | | <el-table-column prop="reportCode" label="报告编号" /> |
| | | <el-table-column prop="reportName" label="报告名称" /> |
| | | <el-table-column prop="createBy" label="创建人" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | <el-table-column prop="status" label="状态" v-if="!isDraft"> |
| | | <template #default="{ row }"> |
| | | <el-tag v-if="row.status == 1" type="success">待审核</el-tag> |
| | | <el-tag v-else-if="row.status == 0" type="success">已通过</el-tag> |
| | | <el-tag v-else type="danger">已驳回</el-tag> |
| | | <el-tag v-if="row.status == 1">待审核</el-tag> |
| | | <el-tag v-else-if="row.status == 2">待评定</el-tag> |
| | | <el-tag v-else-if="row.status == 4" type="danger">已驳回</el-tag> |
| | | <el-tag v-else-if="row.status == 3" type="success">已评定</el-tag> |
| | | <el-tag v-else-if="row.status == 5" type="info">已撤回</el-tag> |
| | | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="age" label="操作"> |
| | | <el-table-column prop="options" label="操作"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text">审核</el-button> |
| | | <el-button type="text">详情</el-button> |
| | | <el-button type="text" @click="handleApproval(row)" |
| | | v-if="row.status == 1 && [1, 2].includes(roleType)">审核</el-button> |
| | | <el-button type="text" @click="handleDetail(row)">详情</el-button> |
| | | <el-button type="text" @click="handleDelete(row)" |
| | | v-if="[4, 5].includes(row.status) && roleType == 3">删除</el-button> |
| | | <el-button type="text" @click="handleEdit(row)" |
| | | v-if="[4, 5].includes(row.status) && roleType == 3">编辑</el-button> |
| | | <el-button type="text" @click="handleRevoke(row)" |
| | | v-if="row.status == 1 && roleType == 3">撤销审批</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </template> |
| | | </TableCustom> |
| | | |
| | | <Approval :visible="showApproval" @close="showApproval = false" :obj="rowData" @approve="handleApprove" /> |
| | | <ShowDelConfirm :show="showDelConfirm" @close="showDelConfirm = false" @confirm="handleDelConfirm" /> |
| | | <ShowDelConfirm :title="changeStatusTitle" :tip="changeStatusTip" :show="changeStatus" |
| | | @close="changeStatus = false" @confirm="handleChangeStatusConfirm" /> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import Approval from './components/approval' |
| | | import { getDataList, audit, revokeAudit, deleteData } from './service' |
| | | |
| | | export default { |
| | | name: 'ProjectList', |
| | | components: { |
| | | Approval |
| | | }, |
| | | data() { |
| | | return { |
| | | form: { |
| | | name: '' |
| | | }, |
| | | showDelConfirm: false, |
| | | rowId: '', |
| | | changeStatus: false, |
| | | showApproval: false, |
| | | changeStatusTitle: '', |
| | | changeStatusTip: '', |
| | | queryForm: { |
| | | tableData: [], |
| | | isDraft: false, |
| | | rowData: {}, |
| | | roleType: '', // 1 超级管理员 2 审批人 3 工艺工程师 4化验师 5实验员 |
| | | form: { |
| | | pageSize: 10, |
| | | pageNum: 1 |
| | | pageNum: 1, |
| | | teamName: '', |
| | | status: '', |
| | | startTime: '', |
| | | reportType: 3, |
| | | reportName: '', |
| | | reportCode: '', |
| | | endTime: '', |
| | | date: '' |
| | | }, |
| | | total: 0 |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | this.roleType = JSON.parse(sessionStorage.getItem('userInfo'))?.roleType |
| | | console.log('adwqedwqeqwe', this.roleType); |
| | | |
| | | this.getList() |
| | | }, |
| | | |
| | | methods: { |
| | | handleAddProject() { |
| | | handleApproval(row) { |
| | | this.rowData = row |
| | | this.showApproval = true |
| | | }, |
| | | handleDetail(row) { |
| | | row.isDetail = true |
| | | this.rowData = row |
| | | this.showApproval = true |
| | | }, |
| | | handleEdit(row) { |
| | | this.$router.push({ |
| | | path: '/projectList/addProject' |
| | | path: '/reportLibrary/edit', |
| | | query: { |
| | | id: row.id |
| | | } |
| | | }) |
| | | }, |
| | | handleDel(row) { |
| | | handleAddProject() { |
| | | this.$router.push('/reportLibrary/add') |
| | | }, |
| | | changeTab(status) { |
| | | if (status == -1) { |
| | | this.isDraft = true |
| | | this.form.pageNum = 1 |
| | | } else { |
| | | this.form.pageNum = 1 |
| | | this.isDraft = false |
| | | this.form.status = status |
| | | } |
| | | this.getList() |
| | | }, |
| | | handleDelete(row) { |
| | | this.rowId = row.id |
| | | this.showDelConfirm = true |
| | | }, |
| | | handleDelConfirm() { |
| | | this.showDelConfirm = false |
| | | this.msgsuccess('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }, |
| | | handleChangeStatus(row, status) { |
| | | handleRevoke(row) { |
| | | this.rowId = row.id |
| | | this.changeStatusTitle = status == 1 ? '确认要封存这个项目组吗?' : '确认要解封该项目组吗?' |
| | | this.changeStatusTip = status == 1 ? '封存后项目组内人员看不到数据,审批人仍然可见数据。' : '解封后项目组内人员数据恢复。' |
| | | this.changeStatusTitle = '确认要撤销审批吗?' |
| | | this.changeStatusTip = '撤销审批后,可研报告将被撤销。' |
| | | this.changeStatus = true |
| | | }, |
| | | handleDelConfirm() { |
| | | deleteData({ id: this.rowId }).then(res => { |
| | | this.showDelConfirm = false |
| | | this.$message.success('删除成功') |
| | | this.rowId = '' |
| | | this.getList() |
| | | }) |
| | | }, |
| | | handleChangeStatusConfirm() { |
| | | this.changeStatus = false |
| | | this.msgsuccess('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | revokeAudit({ id: this.rowId }).then(res => { |
| | | this.changeStatus = false |
| | | this.$message.success('操作成功') |
| | | this.rowId = '' |
| | | this.changeStatusTitle = '' |
| | | this.changeStatusTip = '' |
| | | this.getList() |
| | | }) |
| | | }, |
| | | handleCurrentChanges(page) { |
| | | this.form.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleCurrentChange(page) { |
| | | this.queryForm.pageNum = page |
| | | this.getList() |
| | | }, |
| | | handleSizeChange(size) { |
| | | this.queryForm.pageSize = size |
| | | handleSizeChanges(size) { |
| | | this.form.pageSize = size |
| | | this.getList() |
| | | }, |
| | | getList() { |
| | | let data = {} |
| | | if (this.isDraft) { |
| | | data = { |
| | | ...this.form, |
| | | status: -1 |
| | | } |
| | | } else { |
| | | data = this.form |
| | | } |
| | | getDataList(data).then(res => { |
| | | if (res.code === 200) { |
| | | this.tableData = res.data.records || [] |
| | | this.total = res.data.total || 0 |
| | | } |
| | | }) |
| | | }, |
| | | handleApprove(data) { |
| | | let params = { |
| | | id: data.id, |
| | | auditStatus: data.statuss, |
| | | auditRemark: data.remark |
| | | } |
| | | |
| | | audit({ ...params }).then(res => { |
| | | if (res.code === 200) { |
| | | this.$message.success('审核成功') |
| | | this.showApproval = false |
| | | this.getList() |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="less"> |
| | | .el-icon-plus { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .header-content { |
| | | font-family: PingFangSC, PingFang SC; |
| | | font-weight: 400; |
| | | font-size: 14px; |
| | | color: rgba(0, 0, 0, 0.88); |
| | | margin-left: 30px; |
| | | } |
| | | |
| | | .box-title { |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #222222; |
| | | line-height: 27px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .header-icon { |
| | | width: 20px; |
| | | height: 20px; |
| | | margin-right: 10px; |
| | | |
| | | } |
| | | |
| | | .header-box { |
| | | border-radius: 16px; |
| | | margin-bottom: 30px; |
| | | } |
| | | |
| | | .table-setting { |
| | | display: flex; |
| | | gap: 14px; |
| | | } |
| | | |
| | | .table-tit { |
| | | background: #FAFAFC; |
| | | border-radius: 8px 8px 0px 0px; |
| | | border: 1px solid #DCDFE6; |
| | | width: 166px; |
| | | height: 50px; |
| | | background: #FFFFFF; |
| | | border-radius: 8px 8px 0px 0px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | // margin-bottom: 21px; |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
| | | color: #606266; |
| | | line-height: 27px; |
| | | } |
| | | |
| | | .list { |
| | | height: 100%; |
| | | } |
| | |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-bottom: 21px; |
| | | // margin-bottom: 21px; |
| | | font-family: SourceHanSansCN, SourceHanSansCN; |
| | | font-weight: bold; |
| | | font-size: 18px; |
New file |
| | |
| | | import axios from '@/utils/request'; |
| | | |
| | | // 查询列表 |
| | | export function getDataList(data) { |
| | | return axios.post('/api/t-feasibility-study-report/pageList', { ...data }) |
| | | } |
| | | |
| | | // 添加 |
| | | export function addData(data) { |
| | | return axios.post('/api/t-feasibility-study-report/add', { ...data }) |
| | | } |
| | | |
| | | //修改 |
| | | export function editData(data) { |
| | | return axios.post('/api/t-feasibility-study-report/update', { ...data }) |
| | | } |
| | | |
| | | //获取详情 |
| | | export function getDetail(id) { |
| | | return axios.get(`/open/t-feasibility-study-report/getDetailById?id=${id}`) |
| | | } |
| | | |
| | | //审核 |
| | | export function audit(data) { |
| | | console.log(data) |
| | | return axios.post('/api/t-feasibility-study-report/auditReport', { ...data }) |
| | | } |
| | | |
| | | //撤销审批 |
| | | export function revokeAudit(data) { |
| | | return axios.put(`/open/t-feasibility-study-report/revokedReport?id=${data.id}`) |
| | | } |
| | | |
| | | //删除 |
| | | export function deleteData(data) { |
| | | return axios.delete(`/open/t-feasibility-study-report/deleteById?id=${data.id}`) |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |