| | |
| | | <template> |
| | | <div> |
| | | <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" :disabled="!!$route.query.id" class="el-icon-circle-plus-outline" type="primary"> |
| | | 选择项目组</el-button> |
| | | </div> |
| | | </div> |
| | | <Table :height="null" :queryForm="queryForm" :total="0" :data="projectData" style="margin-bottom: 20px"> |
| | | <template> |
| | | <el-table-column prop="teamName" label="项目组名称" /> |
| | | <el-table-column prop="personCharge" label="项目负责人" /> |
| | | <el-table-column prop="staff" label="项目组成员" /> |
| | | <el-table-column prop="createTime" label="创建时间" /> |
| | | </template> |
| | | </Table> |
| | | <el-form :model="form" :rules="rules" ref="pedigreeForm" label-position="top" class="strain-form"> |
| | | <div class="card"> |
| | | <div class="form-items-row"> |
| | |
| | | <div class="flex-row"> |
| | | <div class="input-wrapper"> |
| | | <el-form-item prop="strainSourceStart" style="margin-bottom: 0"> |
| | | <el-input v-model="form.strainSourceStart" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | <el-input v-model="form.strainSourceStart" placeholder="请输入" :disabled="!!$route.query.id" |
| | | class="fixed-width-input"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | <span class="form-text">代—</span> |
| | | <div class="input-wrapper"> |
| | | <el-form-item prop="strainSourceEnd" style="margin-bottom: 0"> |
| | | <el-input v-model="form.strainSourceEnd" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | <el-input v-model="form.strainSourceEnd" placeholder="请输入" :disabled="!!$route.query.id" |
| | | class="fixed-width-input"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | <span class="form-text">细胞库</span> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="传代菌种编号" prop="strainCode" required> |
| | | <el-input v-model="form.strainCode" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | <el-input v-model="form.strainCode" placeholder="请输入" :disabled="!!$route.query.id" |
| | | class="fixed-width-input"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="传代菌种名称" prop="strainName" required> |
| | | <el-input v-model="form.strainName" placeholder="请输入" class="fixed-width-input"></el-input> |
| | | <el-input v-model="form.strainName" placeholder="请输入" :disabled="!!$route.query.id" |
| | | class="fixed-width-input"></el-input> |
| | | </el-form-item> |
| | | </div> |
| | | </div> |
| | | <div class="card" v-if="roleType != 4" style="margin-top: 30px; display: block"> |
| | | <div class="title" style="padding: 25px 0">待确认传代计划数</div> |
| | | <Table :height="null" :total="newTotal" :data="newTableData" :queryForm="newQueryForm" |
| | | @handleCurrentChange="handleNewCurrentChange" @handleSizeChange="handleNewSizeChange"> |
| | | <el-table-column label="菌种工程师" prop="createBy" /> |
| | | <el-table-column label="菌种编号" prop="strainCode" /> |
| | | <el-table-column label="菌种名称" prop="strainName" /> |
| | | <el-table-column label="传代计划数量" prop="generationCount" /> |
| | | <el-table-column label="操作" v-if="roleType == 2"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleNewConfirm(row)">确认</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </Table> |
| | | <div class="title" style="padding: 25px 0">待确认入库菌种列表</div> |
| | | <Table :height="null" :total="total" :data="tableData" :queryForm="queryForm" |
| | | @handleCurrentChange="handleCurrentChange" @handleSizeChange="handleSizeChange"> |
| | | <el-table-column label="菌种实验员" prop="experimenter" /> |
| | | <el-table-column label="菌种工程师" prop="experimenter" /> |
| | | <el-table-column label="菌种编号" prop="strainCode" /> |
| | | <el-table-column label="菌种名称" prop="strainName" /> |
| | | <el-table-column label="保存/废弃"> |
| | |
| | | {{ row.status === 1 ? "保存" : "废弃" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="菌种入库时间/菌种废弃时间" prop="storageTime" /> |
| | | <el-table-column v-if="roleType == 3" label="操作"> |
| | | <el-table-column label="菌种入库时间/菌种废弃时间" prop="createTime" /> |
| | | <el-table-column v-if="roleType == 2" label="操作"> |
| | | <template #default="{ row }"> |
| | | <el-button type="text" @click="handleConfirm(row)">确认入库</el-button> |
| | | </template> |
| | |
| | | <div class="header"> |
| | | <div class="title">菌种传代生产谱系图</div> |
| | | <div class="option-btn"> |
| | | <el-button type="primary" v-if="$route.query.type != 1" class="el-icon-plus" @click="addNode"> |
| | | <el-button type="primary" v-if="!isReadOnly && (roleType == 3 || roleType == 1)" class="el-icon-plus" @click="addNode" :disabled="editBoolean"> |
| | | 新增</el-button> |
| | | |
| | | <el-button type="primary" v-if="$route.query.type != 1" @click="setGenerationPlan">设置传代计划数</el-button> |
| | | <el-button type="primary" v-if="!isReadOnly && (roleType == 3 || roleType == 1)" |
| | | @click="setGenerationPlan" :disabled="editBoolean">设置传代计划数</el-button> |
| | | <el-button type="primary" @click="showDetail">详情</el-button> |
| | | <el-button type="primary" @click="handleEdit" v-if="roleType == 1">编辑</el-button> |
| | | <el-button type="primary" @click="handleDelete" v-if="roleType == 1">删除</el-button> |
| | | <el-button type="primary" @click="handleEdit" v-if="!isReadOnly && (roleType == 1 || roleType == 3)" :disabled="editBoolean">编辑</el-button> |
| | | <el-button type="primary" @click="handleDelete" v-if="!isReadOnly && (roleType == 1 || roleType == 3)" :disabled="editBoolean">删除</el-button> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="strain-flow-chart"> |
| | | <div id="mountNode"></div> |
| | | <div ref="mountNode" class="mount-node"></div> |
| | | </div> |
| | | |
| | | <el-button type="primary" v-if="!$route.query.id || (roleType == 1 && $route.query.id)" @click="handleSubmit" |
| | | style="width: 150px">保存</el-button> |
| | | <!-- v-if="!$route.query.id || (roleType == 1 && $route.query.id)" --> |
| | | <div v-if="!isReadOnly && (roleType == 1 || roleType == 3)"> |
| | | <el-button type="primary" @click="handleSubmit('1')" style="width: 150px" :disabled="editBoolean">保存</el-button> |
| | | <el-button type="primary" @click="handleSubmit('2')" style="width: 150px; margin-left: 20px" :disabled="editBoolean">提交</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="end-btn"> |
| | | <!-- <el-button @click="handleDraft">存草稿</el-button> |
| | |
| | | </div> |
| | | </el-form> |
| | | |
| | | <ParentForm ref="parentForm" @addNodeSign="addNodeSign" /> |
| | | <PlanForm ref="planForm" @addNodeSign="addNodeSign" /> |
| | | <AddSublevelForm ref="addSublevelForm" @addNodeSign="addNodeSign" /> |
| | | <AddSublevelPlan ref="addSublevelPlan" @addNodeSign="addNodeSign" /> |
| | | <ConfirmStorageDialog name="接种操作人签字" :visible.sync="confirmStorageDialogVisible" |
| | | <ParentForm :key="pageInstanceKey" ref="parentForm" @addNodeSign="addNodeSign" /> |
| | | <PlanForm :key="pageInstanceKey" ref="planForm" @addNodeSign="addNodeSign" /> |
| | | <AddSublevelForm :key="pageInstanceKey" ref="addSublevelForm" @addNodeSign="addNodeSign" /> |
| | | <AddSublevelPlan :key="pageInstanceKey" ref="addSublevelPlan" @addNodeSign="addNodeSign" /> |
| | | <ConfirmStorageDialog :key="`signature-${pageInstanceKey}`" name="接种操作人签字" :visible.sync="confirmStorageDialogVisible" |
| | | @confirm="handleSignatureConfirm" /> |
| | | <!-- 菌种工程师 --> |
| | | <ConfirmStorageDialog name="菌种保藏人签字" text="是否确认该项菌种信息入库" :visible.sync="storageVisible" |
| | | <ConfirmStorageDialog :key="`storage-${pageInstanceKey}`" name="菌种保藏人签字" text="是否确认该项菌种信息入库" :visible.sync="storageVisible" |
| | | @confirm="handleSignatureConfirm1" /> |
| | | |
| | | <!-- 传代数审批 --> |
| | | <ApprovalCount :key="`approval-${pageInstanceKey}`" ref="approvalCount" @addNodeSign="sureApprovalCountSign" /> |
| | | |
| | | <chooseProject :key="`project-${pageInstanceKey}`" @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import AddSublevelForm from "./components/AddSublevelForm.vue"; |
| | | import AddSublevelPlan from "./components/AddSublevelPlan.vue"; |
| | | import ConfirmStorageDialog from "@/components/confirm-storage-dialog"; |
| | | import ApprovalCount from "./progenitorComponents/approvalCount.vue"; |
| | | import { |
| | | add, |
| | | getDetail, |
| | | addCount, |
| | | addProgenitorChild, |
| | | addProgenitor, |
| | | pageListDetail, |
| | |
| | | deleteNode, |
| | | updateChild, |
| | | edit, |
| | | confirmCount, |
| | | pageListCountDetail |
| | | } from "./service"; |
| | | import ChooseProject from "@/components/chooseProject/index.vue"; |
| | | export default { |
| | | name: "AddPedigree", |
| | | components: { |
| | | ChooseProject, |
| | | ParentForm, |
| | | PlanForm, |
| | | AddSublevelForm, |
| | | AddSublevelPlan, |
| | | ConfirmStorageDialog, |
| | | ApprovalCount, |
| | | }, |
| | | data() { |
| | | return { |
| | | showChoose: false, |
| | | projectData: [], // 存储选中的项目组数据 |
| | | queryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | |
| | | nodeData: {}, |
| | | nodeType: "", //1母代 2计划数 3子孙代 |
| | | tableData: [], |
| | | cacheData: null, // 👈 添加这一行 |
| | | activeRouteKey: "", |
| | | graphLoadId: 0, |
| | | pageInstanceKey: 0, |
| | | confirmStorageDialogVisible: false, |
| | | storageVisible: false, |
| | | editBoolean: false, |
| | | treeData: [], |
| | | total: 0, |
| | | roleType: JSON.parse(sessionStorage.getItem('userInfo')).roleType || 1, // 1.超级管理员 2.审批人 3.工程师 4.实验员 |
| | | roleType: JSON.parse(sessionStorage.getItem("userInfo")).roleType || 1, // 1.超级管理员 2.审批人 3.工程师 4.实验员 |
| | | |
| | | // 新增2.0 |
| | | nodeTreeStatus: 1, //1.未提交 2.已提交 |
| | | newTotal: 0, |
| | | newCurrent: 1, |
| | | newSize: 10, |
| | | newTableData: [], |
| | | newQueryForm: { |
| | | pageSize: 10, |
| | | pageNum: 1, |
| | | }, |
| | | }; |
| | | }, |
| | | computed: { |
| | | isReadOnly() { |
| | | return this.$route.path.includes('detail') || this.$route.query.mode === 'detail'; |
| | | }, |
| | | canAddNode() { |
| | | // 如果没有节点,可以新增母代 |
| | | if (this.graphData.nodes.length === 0) { |
| | |
| | | }, |
| | | }, |
| | | mounted() { |
| | | this.initGraph(); |
| | | this.initEvents(); |
| | | this.resetMountNode(); |
| | | }, |
| | | created() { |
| | | deactivated() { |
| | | // 缓存数据 |
| | | this.cacheData = { |
| | | form: JSON.parse(JSON.stringify(this.form)), |
| | | graphData: JSON.parse(JSON.stringify(this.graphData)), |
| | | nodeCount: this.nodeCount, |
| | | selectedNode: this.selectedNode ? JSON.parse(JSON.stringify(this.selectedNode)) : null, |
| | | tableData: JSON.parse(JSON.stringify(this.tableData)), |
| | | newTableData: JSON.parse(JSON.stringify(this.newTableData)), |
| | | total: this.total, |
| | | newTotal: this.newTotal, |
| | | projectData: JSON.parse(JSON.stringify(this.projectData)), |
| | | treeData: JSON.parse(JSON.stringify(this.treeData)), |
| | | nodeTreeStatus: this.nodeTreeStatus, |
| | | routeKey: this.activeRouteKey |
| | | }; |
| | | }, |
| | | activated() { |
| | | if (this.cacheData && this.cacheData.routeKey === this.$route.fullPath) { |
| | | // 恢复数据 |
| | | this.form = JSON.parse(JSON.stringify(this.cacheData.form)); |
| | | this.graphData = JSON.parse(JSON.stringify(this.cacheData.graphData)); |
| | | this.nodeCount = this.cacheData.nodeCount; |
| | | this.selectedNode = this.cacheData.selectedNode; |
| | | this.tableData = this.cacheData.tableData || []; |
| | | this.newTableData = this.cacheData.newTableData || []; |
| | | this.total = this.cacheData.total || 0; |
| | | this.newTotal = this.cacheData.newTotal || 0; |
| | | this.projectData = this.cacheData.projectData || []; |
| | | this.treeData = this.cacheData.treeData || []; |
| | | this.nodeTreeStatus = this.cacheData.nodeTreeStatus || 1; |
| | | |
| | | // 更新图表 |
| | | this.resetMountNode(); |
| | | if (this.graphData.nodes.length > 0) { |
| | | this.updateGraphData(); |
| | | } |
| | | return; |
| | | } |
| | | this.cacheData = null; |
| | | if (this.$route.query.id) { |
| | | this.reloadData(); |
| | | } else { |
| | | this.resetPageState(); |
| | | } |
| | | if (this.$route.query.status !== undefined && this.$route.query.status != 1 && this.roleType != 1){ |
| | | this.editBoolean = true |
| | | }else { |
| | | this.editBoolean = false |
| | | } |
| | | }, |
| | | watch: { |
| | | '$route': { |
| | | immediate: true, |
| | | handler(to) { |
| | | if (!["AddPedigree", "DetailPedigree"].includes(to.name)) { |
| | | return; |
| | | } |
| | | console.log('变动'); |
| | | const routeKey = to.fullPath; |
| | | const routeChanged = this.activeRouteKey && this.activeRouteKey !== routeKey; |
| | | this.activeRouteKey = routeKey; |
| | | if (routeChanged || !to.query.id) { |
| | | this.cacheData = null; |
| | | this.resetPageState(); |
| | | } |
| | | if (to.query.id) { |
| | | this.reloadData(); |
| | | } |
| | | |
| | | this.editBoolean = this.shouldDisableEditing(to.query); |
| | | } |
| | | } |
| | | }, |
| | | beforeDestroy() { |
| | | this.graph?.destroy(); |
| | | window.removeEventListener("resize", this.handleResize); |
| | | this.destroyGraph(); |
| | | }, |
| | | methods: { |
| | | shouldDisableEditing(query = this.$route.query) { |
| | | const status = query && query.status; |
| | | return Number(this.roleType) !== 1 |
| | | && status !== undefined |
| | | && status !== null |
| | | && status !== "" |
| | | && Number(status) !== 1; |
| | | }, |
| | | destroyGraph() { |
| | | window.removeEventListener("resize", this.handleResize); |
| | | if (this.graph && !this.graph.get("destroyed")) { |
| | | this.graph.destroy(); |
| | | } |
| | | this.graph = null; |
| | | |
| | | const container = this.$refs.mountNode; |
| | | if (container) { |
| | | while (container.firstChild) { |
| | | container.removeChild(container.firstChild); |
| | | } |
| | | } |
| | | }, |
| | | resetMountNode() { |
| | | this.destroyGraph(); |
| | | if (!this.$refs.mountNode) return; |
| | | this.initGraph(); |
| | | this.initEvents(); |
| | | }, |
| | | resetPageState() { |
| | | this.pageInstanceKey += 1; |
| | | this.form = { |
| | | strainSourceStart: "", |
| | | strainSourceEnd: "", |
| | | cellBank: "", |
| | | strainCode: "", |
| | | strainName: "", |
| | | remarks: "", |
| | | }; |
| | | this.projectData = []; |
| | | this.tableData = []; |
| | | this.newTableData = []; |
| | | this.total = 0; |
| | | this.current = 1; |
| | | this.size = 10; |
| | | this.newTotal = 0; |
| | | this.newCurrent = 1; |
| | | this.newSize = 10; |
| | | this.queryForm = { pageSize: 10, pageNum: 1 }; |
| | | this.newQueryForm = { pageSize: 10, pageNum: 1 }; |
| | | this.showChoose = false; |
| | | this.dialogVisible = false; |
| | | this.confirmStorageDialogVisible = false; |
| | | this.storageVisible = false; |
| | | this.nodeData = {}; |
| | | this.nodeType = ""; |
| | | this.isAddingNode = false; |
| | | this.showDiscarded = false; |
| | | this.nodeTreeStatus = 1; |
| | | this.editBoolean = this.shouldDisableEditing(); |
| | | this.resetGraphData(); |
| | | this.$nextTick(() => { |
| | | this.$refs.pedigreeForm && this.$refs.pedigreeForm.clearValidate(); |
| | | }); |
| | | }, |
| | | resetGraphData() { |
| | | this.graphLoadId += 1; |
| | | this.graphData = { |
| | | nodes: [], |
| | | edges: [], |
| | | }; |
| | | this.treeData = []; |
| | | this.selectedNode = null; |
| | | this.nodeCount = 0; |
| | | |
| | | if (this.graph) { |
| | | this.graph.changeData({ nodes: [], edges: [] }); |
| | | this.graph.render(); |
| | | } |
| | | }, |
| | | getProjectData(data) { |
| | | this.projectData = [data]; // 将选中的项目组数据存储到数组中 |
| | | this.showChoose = false; |
| | | this.form.projectId = this.projectData[0].id; |
| | | }, |
| | | handleEdit() { |
| | | if (!this.selectedNode) { |
| | | this.$message.warning("请先选择节点"); |
| | | return; |
| | | } |
| | | if ( |
| | | this.selectedNode && |
| | | this.selectedNode.data && |
| | | this.selectedNode.data.codeStatus != null && |
| | | this.selectedNode.data.codeStatus == 2 |
| | | ) { |
| | | this.$message.warning("谱系图已提交,不能编辑"); |
| | | return |
| | | } |
| | | const nodeModel = this.selectedNode; |
| | | |
| | |
| | | ); |
| | | if (this.graphData.nodes[nodeIndex - 1].label === "子代") { |
| | | this.$refs.addSublevelPlan.openInitData({ |
| | | ...nodeModel.data, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainCode1: this.form.strainCode, |
| | | strainName1: this.form.strainName, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | confirmTime: this.form.confirmTime, |
| | | parentId: nodeModel.id, |
| | | generationCount: nodeModel.data.generationCount || nodeModel.planCount, |
| | | formStatus: "edit", |
| | | }); |
| | | } else { |
| | |
| | | strainCode1: this.form.strainCode, |
| | | strainName1: this.form.strainName, |
| | | ...nodeModel.data, |
| | | generationCount: nodeModel.data.generationCount || nodeModel.planCount, |
| | | formStatus: "edit", |
| | | }); |
| | | } |
| | |
| | | this.$message.warning("请先选择节点"); |
| | | return; |
| | | } |
| | | if ( |
| | | this.selectedNode && |
| | | this.selectedNode.data && |
| | | this.selectedNode.data.codeStatus != null && |
| | | this.selectedNode.data.codeStatus == 2 |
| | | ) { |
| | | this.$message.warning("谱系图已提交,不能删除"); |
| | | return |
| | | } |
| | | |
| | | this.$confirm("确定删除该节点吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }).then(() => { |
| | | deleteNode({ id: this.selectedNode.id }).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("删除成功"); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | // 判断是新增模式还是编辑模式 |
| | | if (!this.$route.query.id) { |
| | | // 新增模式:前端直接删除节点 |
| | | this.deleteNodeFromGraph(this.selectedNode.nodeId); |
| | | this.$message.success("删除成功"); |
| | | } else { |
| | | // 编辑模式:调用后端删除接口 |
| | | deleteNode({ id: this.selectedNode.id }).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("删除成功"); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 前端删除节点方法 |
| | | deleteNodeFromGraph(nodeId) { |
| | | // 找到要删除的节点 |
| | | const nodeIndex = this.graphData.nodes.findIndex(n => n.nodeId === nodeId); |
| | | if (nodeIndex === -1) { |
| | | return; |
| | | } |
| | | |
| | | // 递归收集所有需要删除的节点ID(包括子节点) |
| | | const collectNodeIds = (currentNodeId) => { |
| | | const nodeIds = [currentNodeId]; |
| | | const childEdges = this.graphData.edges.filter(e => e.source === currentNodeId); |
| | | childEdges.forEach(edge => { |
| | | nodeIds.push(...collectNodeIds(edge.target)); |
| | | }); |
| | | return nodeIds; |
| | | }; |
| | | |
| | | const nodeIdsToDelete = collectNodeIds(nodeId); |
| | | |
| | | // 删除所有相关的边 |
| | | this.graphData.edges = this.graphData.edges.filter(edge => { |
| | | return !nodeIdsToDelete.includes(edge.source) && !nodeIdsToDelete.includes(edge.target); |
| | | }); |
| | | |
| | | // 删除所有相关的节点 |
| | | this.graphData.nodes = this.graphData.nodes.filter(node => { |
| | | return !nodeIdsToDelete.includes(node.nodeId); |
| | | }); |
| | | |
| | | // 如果删除的节点的父节点是传代计划数,需要更新其当前数量 |
| | | const parentEdge = this.graphData.edges.find(e => e.target === nodeId); |
| | | if (parentEdge) { |
| | | const parentNode = this.graphData.nodes.find(n => n.nodeId === parentEdge.source); |
| | | if (parentNode && parentNode.label === '传代计划数') { |
| | | // 重新计算当前数量 |
| | | const childCount = this.graphData.edges.filter(e => e.source === parentNode.nodeId).length; |
| | | parentNode.currentCount = childCount; |
| | | } |
| | | } |
| | | |
| | | // 清空选中节点 |
| | | this.selectedNode = null; |
| | | |
| | | // 更新图表显示 |
| | | this.updateGraphData(); |
| | | }, |
| | | handleConfirm(row) { |
| | | this.comfirmId = row.id; |
| | |
| | | this.$message.error("数据加载失败"); |
| | | } |
| | | }, |
| | | reloadData() { |
| | | this.getList(); |
| | | getDetail({ id: this.$route.query.id }).then((res) => { |
| | | handleNewConfirm(row) { |
| | | console.log("row row", row); |
| | | this.$refs.approvalCount.openInitData(row); |
| | | }, |
| | | // 处理每页显示数量变化 |
| | | handleNewSizeChange(val) { |
| | | this.newSize = val; |
| | | this.newQueryForm.pageSize = val; |
| | | this.getNewList(); |
| | | }, |
| | | |
| | | // 处理页码变化 |
| | | handleNewCurrentChange(val) { |
| | | this.newCurrent = val; |
| | | this.newQueryForm.pageNum = val; |
| | | this.getNewList(); |
| | | }, |
| | | async getNewList() { |
| | | try { |
| | | // 获取列表数据 |
| | | const listRes = await pageListCountDetail({ |
| | | id: this.$route.query.id, |
| | | current: this.current, |
| | | size: this.size, |
| | | }); |
| | | console.log("待确认传代计划数 待确认传代计划数", listRes); |
| | | if (listRes.code === 200) { |
| | | this.newTableData = listRes.data.records; |
| | | this.newTotal = listRes.data.total; |
| | | this.newCurrent = listRes.data.current; |
| | | this.newSize = listRes.data.size; |
| | | } |
| | | |
| | | // ... 其他现有的 reloadData 代码 ... |
| | | } catch (error) { |
| | | console.error("Failed to reload data:", error); |
| | | this.$message.error("数据加载失败"); |
| | | } |
| | | }, |
| | | reloadData() { |
| | | this.resetPageState(); |
| | | this.resetMountNode(); |
| | | const graphLoadId = this.graphLoadId; |
| | | const routeKey = this.$route.fullPath; |
| | | this.getList(); |
| | | this.getNewList() |
| | | if (!this.$route.query.id) { |
| | | return |
| | | } |
| | | getDetail({ id: this.$route.query.id }).then((res) => { |
| | | if (graphLoadId !== this.graphLoadId || routeKey !== this.$route.fullPath) { |
| | | return; |
| | | } |
| | | const nodeMap = new Map(); |
| | | const calculateLevel = (node) => { |
| | | if (node.parentId === "0") return 0; |
| | |
| | | currentCount: 0, |
| | | style: { |
| | | fill: node.status === 1 ? "#00B5AA" : "#999", |
| | | opacity: node.status === 1 ? (level === 0 ? 1 : level === 1 ? 0.6 : 0.4) : 0.3, |
| | | opacity: |
| | | node.status === 1 |
| | | ? level === 0 |
| | | ? 1 |
| | | : level === 1 |
| | | ? 0.6 |
| | | : 0.4 |
| | | : 0.3, |
| | | }, |
| | | }; |
| | | }; |
| | |
| | | this.graphData.nodes = []; |
| | | this.graphData.edges = []; |
| | | |
| | | if (res.pedigreeChartParentAllDetailDTO && res.pedigreeChartParentAllDetailDTO.one) { |
| | | if ( |
| | | res.pedigreeChartParentAllDetailDTO && |
| | | res.pedigreeChartParentAllDetailDTO.one |
| | | ) { |
| | | // 创建节点映射 |
| | | createNodeMap(res.pedigreeChartParentAllDetailDTO.one); |
| | | |
| | | // 处理所有节点 |
| | | const processAllNodes = (nodes) => { |
| | | nodes.forEach(node => { |
| | | const processedNode = processNode(node); |
| | | this.graphData.nodes.push(processedNode); |
| | | nodes.forEach((node) => { |
| | | if (Number(this.roleType) === 2 || node.codeStatus == 2 || (node.codeStatus == 1 && Number(this.roleType) === 3)) { |
| | | const processedNode = processNode(node); |
| | | this.graphData.nodes.push(processedNode); |
| | | |
| | | // 根据parentId创建边,直接使用原始id |
| | | if (node.parentId !== "0") { |
| | | this.graphData.edges.push({ |
| | | source: node.parentId, |
| | | target: node.id, |
| | | style: { |
| | | stroke: "rgba(4, 156, 154, 1)", |
| | | lineWidth: 1, |
| | | }, |
| | | }); |
| | | } |
| | | // 根据parentId创建边,直接使用原始id |
| | | if (node.parentId !== "0") { |
| | | this.graphData.edges.push({ |
| | | source: node.parentId, |
| | | target: node.id, |
| | | style: { |
| | | stroke: "rgba(4, 156, 154, 1)", |
| | | lineWidth: 1, |
| | | }, |
| | | }); |
| | | } |
| | | |
| | | if (node.children) { |
| | | processAllNodes(node.children); |
| | | if (node.children) { |
| | | processAllNodes(node.children); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | |
| | | strainCode: res.strainCode, |
| | | strainName: res.strainName, |
| | | }; |
| | | this.nodeTreeStatus = res.status |
| | | |
| | | this.projectData = res.tprojectTeamList |
| | | |
| | | // 更新图表 |
| | | this.updateGraphData(); |
| | | this.cacheData = null; |
| | | }); |
| | | }, |
| | | addNodeSign(value, type) { |
| | |
| | | // this.$refs.addSublevelForm.close() |
| | | this.confirmStorageDialogVisible = true; |
| | | }, |
| | | handleSubmit() { |
| | | // 传代计划数 审批 |
| | | sureApprovalCountSign(value) { |
| | | console.log("value", value); |
| | | confirmCount({ |
| | | id: value.id, |
| | | preserveSignature: value.preserveSignature, |
| | | }).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("审批传代计划数成功"); |
| | | this.$refs.approvalCount.closeDialog(); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | }, |
| | | handleSubmit(type) { |
| | | this.$refs.pedigreeForm.validate((valid) => { |
| | | if (valid) { |
| | | if (this.treeData.length === 0) { |
| | |
| | | } |
| | | |
| | | // 处理节点数据,将data字段中的数据提升到根级别 |
| | | const processNodeData = (node) => { |
| | | const processNodeData = (node, type) => { |
| | | console.log('node.codeStatus',node) |
| | | const processedNode = { |
| | | ...node, |
| | | ...node.data, |
| | | codeStatus: type == 2 ? '2' : node.data.codeStatus || type, |
| | | children: [], |
| | | }; |
| | | delete processedNode.data; |
| | |
| | | const buildTree = (nodes, edges) => { |
| | | // 创建节点映射,提升性能 |
| | | const nodeMap = new Map( |
| | | nodes.map((node) => [node.nodeId, processNodeData(node)]) |
| | | nodes.map((node) => [node.nodeId, processNodeData(node, type)]) |
| | | ); |
| | | |
| | | // 创建子节点ID集合,用于快速查找根节点 |
| | |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | strainCode: this.form.strainCode, |
| | | strainName: this.form.strainName, |
| | | |
| | | status: type, |
| | | }, |
| | | one: buildTree(this.graphData.nodes, this.graphData.edges), |
| | | }; |
| | | |
| | | console.log('这是提交数据', baseData) |
| | | if (this.$route.query.id) { |
| | | baseData.parent.id = this.$route.query.id; |
| | | |
| | | edit({ ...baseData }).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("编辑成功"); |
| | | this.$router.back(); |
| | | this.cacheData = null; // 👈 添加这一行 |
| | | this.$closeCurrentView('/strain/pedigree-vhart'); |
| | | } |
| | | }); |
| | | return |
| | | return; |
| | | } |
| | | add(baseData).then((res) => { |
| | | if (res.code == 200) { |
| | | this.$message.success("保存成功"); |
| | | this.$router.back(); |
| | | this.cacheData = null; |
| | | this.$closeCurrentView('/strain/pedigree-vhart'); |
| | | } |
| | | }); |
| | | } |
| | |
| | | // 实现存草稿逻辑 |
| | | }, |
| | | handleCancel() { |
| | | this.$router.back(); |
| | | this.$closeCurrentView('/strain/pedigree-vhart'); |
| | | }, |
| | | handleSignatureConfirm(signatureImage) { |
| | | this.confirmStorageDialogVisible = false; |
| | |
| | | // 处理提交逻辑 |
| | | }, |
| | | initGraph() { |
| | | const container = document.getElementById("mountNode"); |
| | | const container = this.$refs.mountNode; |
| | | if (!container) return; |
| | | const width = container.scrollWidth; |
| | | const height = container.scrollHeight || 600; |
| | | |
| | |
| | | if (cfg.label === "传代计划数") { |
| | | content = `${cfg.planCount || 0}`; |
| | | } else if (cfg.number) { |
| | | console.log('qweqweqweqw',cfg.data); |
| | | |
| | | console.log("qweqweqweqw", cfg.data); |
| | | |
| | | // 获取类型名称 |
| | | let typeName = "传代菌种"; |
| | | // if (cfg.data && cfg.data.strainType) { |
| | |
| | | // typeName = typeMap[cfg.data.strainType] || "接种菌种"; |
| | | // } |
| | | |
| | | if(cfg.data.parentId){ |
| | | typeName = '接代菌种' |
| | | if (cfg.data.parentId) { |
| | | typeName = "接代菌种"; |
| | | } |
| | | |
| | | content = `${typeName}编号:${cfg.number}`; |
| | |
| | | }); |
| | | |
| | | this.graph = new G6.Graph({ |
| | | container: "mountNode", |
| | | container, |
| | | width, |
| | | height, |
| | | fitView: true, |
| | |
| | | ...node, |
| | | id: node.nodeId, |
| | | level: 0, // 添加层级标记 |
| | | children: [] // 添加children数组 |
| | | children: [], // 添加children数组 |
| | | }); |
| | | }); |
| | | |
| | |
| | | })), |
| | | }; |
| | | |
| | | |
| | | // 更新图表数据 |
| | | this.graph.changeData(processedData); |
| | | |
| | |
| | | }, |
| | | handleResize() { |
| | | if (this.graph) { |
| | | const container = document.getElementById("mountNode"); |
| | | const container = this.$refs.mountNode; |
| | | if (!container) return; |
| | | const width = container.scrollWidth; |
| | | const height = container.scrollHeight || 600; |
| | | this.graph.changeSize(width, height); |
| | | } |
| | | }, |
| | | addNode() { |
| | | // 如果没有节点,新增祖代 |
| | | console.log("选择的节点", this.selectedNode); |
| | | if ( |
| | | this.selectedNode && |
| | | this.selectedNode.data && |
| | | this.selectedNode.data.auditStatus !== undefined && |
| | | this.selectedNode.data.auditStatus != 2 |
| | | ) { |
| | | this.$message.warning("该传代计划数未审核,请先审核"); |
| | | return; |
| | | } |
| | | |
| | | // 如果没有节点,新增母代 |
| | | if (this.graphData.nodes.length === 0) { |
| | | this.$refs.pedigreeForm.validate((valid) => { |
| | |
| | | strainCode: this.form.strainCode, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | formStatus: 'add' |
| | | formStatus: "add", |
| | | }); |
| | | } |
| | | }); |
| | | return; |
| | | } |
| | | // |
| | | if ( |
| | | !this.$route.query.id && |
| | | this.selectedNode && |
| | | this.selectedNode.label === "传代计划数" |
| | | ) { |
| | | this.$message.warning("一次只能添加一个传代"); |
| | | return; |
| | | } |
| | | |
| | |
| | | this.$refs.form.resetFields(); |
| | | }, |
| | | handleAddSublevel(value) { |
| | | if (value.formStatus == 'edit') { |
| | | updateChild(value).then((res) => { |
| | | console.log('11111111111111111', value) |
| | | if (value.formStatus == "edit") { |
| | | // let params = { ...value, id:value.parentId, codeStatus: '1' }; |
| | | // delete params.parentId |
| | | updateChild({ ...value, codeStatus: '1' }).then((res) => { |
| | | if (res.code === 200) { |
| | | this.$message.success("操作成功"); |
| | | this.$refs.addSublevelForm.closeDialog(); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | return |
| | | return; |
| | | } |
| | | if (this.$route.query.id) { |
| | | addProgenitor(value).then((res) => { |
| | | addProgenitor({ ...value, codeStatus: '1' }).then((res) => { |
| | | if (res.code === 200) { |
| | | this.$message.success("操作成功"); |
| | | this.$refs.addSublevelForm.closeDialog(); |
| | |
| | | strainCode1: this.form.strainCode, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | formStatus: "addCount", |
| | | }); |
| | | } else { |
| | | this.$refs.planForm.openInitData({ |
| | |
| | | strainCode: this.form.strainCode, |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | | formStatus: "addCount", |
| | | }); |
| | | } |
| | | }, |
| | | handleAddPlan(value) { |
| | | if (value.formStatus == 'edit') { |
| | | |
| | | updateChild(value).then((res) => { |
| | | console.log('2222222222222222222', value) |
| | | if (value.formStatus == "edit") { |
| | | let params = { ...value, id: value.parentId, codeStatus: '1' }; |
| | | delete params.parentId |
| | | updateChild({ ...params }).then((res) => { |
| | | if (res.code === 200) { |
| | | this.$message.success("操作成功"); |
| | | this.$refs.planForm.closeDialog(); |
| | |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | return |
| | | return; |
| | | } |
| | | if (this.$route.query.id) { |
| | | let params = { |
| | | parentId: value.id, |
| | | generationCount: value.generationCount, |
| | | vaccinateSignature: value.vaccinateSignature, |
| | | }; |
| | | addProgenitorChild(params).then((res) => { |
| | | if (res.code === 200) { |
| | | this.$message.success("操作成功"); |
| | | this.$refs.planForm.closeDialog(); |
| | | this.$refs.addSublevelPlan.closeDialog(); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | if (value.formStatus == "addCount") { |
| | | let params = { |
| | | parentId: value.id, |
| | | generationCount: value.generationCount, |
| | | vaccinateSignature: value.vaccinateSignature, |
| | | codeStatus: '1' |
| | | }; |
| | | addCount(params).then((res) => { |
| | | if (res.code === 200) { |
| | | this.$message.success("操作成功"); |
| | | this.$refs.planForm.closeDialog(); |
| | | this.$refs.addSublevelPlan.closeDialog(); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | } else { |
| | | let params = { |
| | | id: value.id, |
| | | generationCount: value.generationCount, |
| | | vaccinateSignature: value.vaccinateSignature, |
| | | codeStatus: '1' |
| | | }; |
| | | addProgenitorChild(params).then((res) => { |
| | | if (res.code === 200) { |
| | | this.$message.success("操作成功"); |
| | | this.$refs.planForm.closeDialog(); |
| | | this.$refs.addSublevelPlan.closeDialog(); |
| | | this.reloadData(); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | return; |
| | | } |
| | | const nodeModel = this.selectedNode; |
| | |
| | | form: { ...nodeModel.data }, |
| | | }); |
| | | } else if (nodeModel.label === "传代计划数") { |
| | | return |
| | | return; |
| | | const nodeIndex = this.graphData.nodes.findIndex( |
| | | (n) => n.nodeId === nodeModel.nodeId |
| | | ); |
| | | if (this.graphData.nodes[nodeIndex - 1].label === "子代") { |
| | | |
| | | this.$refs.addSublevelPlan.openInitData({ |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainCode1: this.form.strainCode, |
| | |
| | | status: "detail", |
| | | }); |
| | | } else { |
| | | |
| | | this.$refs.planForm.openInitData({ |
| | | strainSourceStart: this.form.strainSourceStart, |
| | | strainSourceEnd: this.form.strainSourceEnd, |
| | |
| | | .title { |
| | | font-size: 18px; |
| | | } |
| | | |
| | | |
| | | .chart { |
| | | padding: 20px 38px; |
| | |
| | | flex-direction: column; |
| | | align-items: flex-start; |
| | | width: 100%; |
| | | } |
| | | } |
| | | |
| | | .header-title { |
| | | display: flex; |
| | | align-items: center; |
| | | flex-wrap: wrap; |
| | | gap: 13px; |
| | | |
| | | .header-title-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 13px; |
| | | |
| | | 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; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | #mountNode { |
| | | .mount-node { |
| | | flex: 1; |
| | | width: 100%; |
| | | min-height: 500px; |