puzhibing
6 天以前 0db8c9b94a9ac655549d5eba5c2a6c92ac386c06
culture/src/views/pedigree-chart/addProgenitor.vue
@@ -1,21 +1,54 @@
<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">
          <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" :disabled="!!$route.query.id" placeholder="请输入"
              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" style="margin-top: 30px; display: block" v-if="roleType != 4">
        <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="保存/废弃">
@@ -23,8 +56,8 @@
              {{ row.status === 1 ? "保存" : "废弃" }}
            </template>
          </el-table-column>
          <el-table-column label="菌种入库时间/菌种废弃时间" prop="storageTime" />
          <el-table-column label="操作" v-if="roleType == 3">
          <el-table-column label="菌种入库时间/菌种废弃时间" prop="createTime" />
          <el-table-column label="操作" v-if="roleType == 2">
            <template #default="{ row }">
              <el-button type="text" @click="handleConfirm(row)">确认入库</el-button>
            </template>
@@ -36,31 +69,38 @@
        <div class="header">
          <div class="title">菌种传代生产谱系图</div>
          <div class="option-btn">
            <el-button type="primary" class="el-icon-plus" @click="addNode" v-if="$route.query.type != 1">
            <el-button type="primary" class="el-icon-plus" @click="addNode" :disabled="editBoolean" v-if="!isReadOnly && (roleType == 3 || roleType == 1)">
              <!-- v-if="$route.query.type != 1" -->
              新增</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)" :disabled="editBoolean"
              @click="setGenerationPlan">设置传代计划数</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 v-if="!$route.query.id || (roleType == 1 && $route.query.id)" type="primary" @click="handleSubmit"
          style="width: 150px">保存</el-button>
        <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>
    </el-form>
    <AddAncestor ref="addAncestor" @addNodeSign="addNodeSign" />
    <PlanForm ref="planForm" @addNodeSign="addNodeSign" />
    <AddSublevelForm ref="addSublevelForm" @addNodeSign="addNodeSign" />
    <ConfirmStorageDialog name="接种操作人签字" :visible.sync="confirmStorageDialogVisible"
    <AddAncestor :key="pageInstanceKey" ref="addAncestor" @addNodeSign="addNodeSign" />
    <PlanForm :key="pageInstanceKey" ref="planForm" @addNodeSign="addNodeSign" />
    <AddSublevelForm :key="pageInstanceKey" ref="addSublevelForm" @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>
@@ -74,24 +114,33 @@
  add,
  getDetail,
  addProgenitorChild,
  addCount,
  addProgenitor,
  pageListDetail,
  pageListCountDetail,
  confirmStorage,
  deleteNode,
  updateChild,
  edit
  edit,
  confirmCount,
} from "./service";
import ApprovalCount from "./progenitorComponents/approvalCount.vue";
import ChooseProject from "@/components/chooseProject/index.vue";
export default {
  name: "AddPedigree",
  components: {
    ChooseProject,
    PlanForm,
    AddAncestor,
    AddSublevelForm,
    ConfirmStorageDialog,
    ApprovalCount,
  },
  data() {
    return {
      showChoose: false,
      projectData: [], // 存储选中的项目组数据
      queryForm: {
        pageSize: 10,
        pageNum: 1,
@@ -129,15 +178,32 @@
      tableData: [],
      confirmStorageDialogVisible: false,
      storageVisible: false,
      editBoolean: false,//编辑控制
      total: 0,
      current: 1,
      size: 10,
      comfirmId: "",
      roleType: Number(JSON.parse(sessionStorage.getItem('userInfo')).roleType || 1),  // 1.超级管理员 2.审批人 3.工程师 4.实验员
      roleType: Number(
        JSON.parse(sessionStorage.getItem("userInfo")).roleType || 1
      ), // 1.超级管理员 2.审批人 3.工程师 4.实验员
      // 2.0
      newTotal: 0,
      newCurrent: 1,
      newSize: 10,
      newTableData: [],
      newQueryForm: {
        pageSize: 10,
        pageNum: 1,
      },
      activeRouteKey: "",
      graphLoadId: 0,
      pageInstanceKey: 0,
    };
  },
  computed: {
    isReadOnly() {
      return this.$route.path.includes('detail') || this.$route.query.mode === 'detail';
    },
    canAddNode() {
      // 如果没有节点,可以新增母代
      if (this.graphData.nodes.length === 0) {
@@ -150,48 +216,251 @@
      return false;
    },
  },
  created() {
  watch: {
    '$route': {
      immediate: true,
      handler(to) {
        if (!["AddProgenitor", "DetailProgenitor"].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.resetPageState();
        }
        if (this.graph && to.query.id) {
          this.reloadData();
        }
        this.editBoolean = this.shouldDisableEditing(to.query);
      }
    }
  },
  mounted() {
    this.resetMountNode();
    if (this.$route.query.id) {
      this.reloadData();
    }
  },
  mounted() {
    this.initGraph();
    this.initEvents();
  },
  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 = {
        strainCode: "",
        strainName: "",
        generationType: "2",
      };
      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.editBoolean = this.shouldDisableEditing();
      this.resetGraphData();
      this.$nextTick(() => {
        this.$refs.pedigreeForm && this.$refs.pedigreeForm.clearValidate();
      });
    },
    resetGraphData() {
      this.graphLoadId += 1;
      this.graphData = {
        nodes: [],
        edges: [],
      };
      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;
    },
    handleDelete() {
      console.log('handleDelete selectedNode', this.selectedNode)
      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;
      }
      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.id);
          this.$message.success("删除成功");
        } else {
          // 编辑模式:调用后端删除接口
          deleteNode({ id: this.selectedNode.id }).then((res) => {
            if (res.code == 200) {
              this.$message.success("删除成功");
              this.reloadData();
            }
          });
        }
      });
    },
    // 前端删除节点方法
    deleteNodeFromGraph(nodeId) {
      // 递归删除节点
      const deleteNodeRecursive = (nodes, targetId) => {
        for (let i = 0; i < nodes.length; i++) {
          if (nodes[i].id === targetId) {
            // 找到目标节点,直接删除
            nodes.splice(i, 1);
            return true;
          }
          // 在子节点中查找
          if (nodes[i].children && nodes[i].children.length > 0) {
            if (deleteNodeRecursive(nodes[i].children, targetId)) {
              // 如果删除的是传代计划数的子节点(母代),需要更新计划数的当前数量
              if (nodes[i].label === '传代计划数') {
                nodes[i].currentCount = nodes[i].children.length;
              }
              return true;
            }
          }
        }
        return false;
      };
      // 执行删除
      const deleted = deleteNodeRecursive(this.graphData.nodes, nodeId);
      if (deleted) {
        // 清空选中节点
        this.selectedNode = null;
        // 转换树形数据为G6可用的格式
        const convertToG6Data = (nodes) => {
          const g6Nodes = [];
          const g6Edges = [];
          const processNode = (node, parentId = null) => {
            g6Nodes.push({
              id: node.id,
              label: node.label,
              number: node.number,
              data: node.data,
              isDiscarded: node.isDiscarded,
              style: node.style,
              planCount: node.planCount,
              currentCount: node.currentCount,
            });
            if (parentId) {
              g6Edges.push({
                source: parentId,
                target: node.id,
                style: {
                  stroke: "rgba(4, 156, 154, 1)",
                  lineWidth: 1,
                },
              });
            }
            if (node.children && node.children.length > 0) {
              node.children.forEach((child) => processNode(child, node.id));
            }
          };
          nodes.forEach((node) => processNode(node));
          return { nodes: g6Nodes, edges: g6Edges };
        };
        // 更新图表
        const g6Data = convertToG6Data(this.graphData.nodes);
        this.graph.changeData(g6Data);
        this.graph.render();
        this.graph.fitView();
      }
    },
    handleEdit() {
      console.log('handleEdit selectedNode', this.selectedNode)
      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 (nodeModel.label === "祖代") {
        this.$refs.addAncestor.openInitData({
          id: nodeModel.id,
          ...nodeModel.data,
          formStatus: "edit",
        });
@@ -235,7 +504,6 @@
          current: this.current,
          size: this.size,
        });
        if (listRes.code === 200) {
          this.tableData = listRes.data.records;
          this.total = listRes.data.total;
@@ -249,9 +517,63 @@
        this.$message.error("数据加载失败");
      }
    },
    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("数据加载失败");
      }
    },
    async reloadData() {
      this.getList();
      this.resetPageState();
      this.resetMountNode();
      const graphLoadId = this.graphLoadId;
      const routeKey = this.$route.fullPath;
      await this.getList();
      await this.getNewList();
      if (graphLoadId !== this.graphLoadId || routeKey !== this.$route.fullPath) {
        return;
      }
      if (!this.$route.query.id) {
        return
      }
      getDetail({ id: this.$route.query.id }).then((res) => {
        if (graphLoadId !== this.graphLoadId || routeKey !== this.$route.fullPath) {
          return;
        }
        this.projectData = res.tprojectTeamList
        const detailData = res.pedigreeChartParentAllDetailDTO;
        // 设置基础表单数据
        this.form = {
@@ -262,41 +584,42 @@
        // 递归处理节点数据,构建树形结构
        function processNode(node, parentType = null) {
          // label 逻辑与新增时保持一致
          let label = "";
          if (node.type === 2) {
            label = "传代计划数";
          } else if (parentType === 2) {
            label = "母代";
          } else {
            label = "祖代";
          }
          const processedNode = {
            id: node.id,
            label,
            number: node.strainCode,
            data: node,
            isDiscarded: node.status === 1,
            style: {
              fill: node.status === 1 ? "#00B5AA" : "#999",
              opacity: node.status === 1 ? 0.6 : 0.3,
            },
            children: [],
          };
         let roleType= Number(JSON.parse(sessionStorage.getItem("userInfo")).roleType || 1)
            let label = "";
            if (node.type === 2) {
              label = "传代计划数";
            } else if (parentType === 2) {
              label = "母代";
            } else {
              label = "祖代";
            }
            const processedNode = {
              id: node.id,
              label,
              number: node.strainCode,
              data: node,
              isDiscarded: node.status === 1,
              style: {
                fill: node.status === 1 ? "#00B5AA" : "#999",
                opacity: node.status === 1 ? 0.6 : 0.3,
              },
              children: [],
            };
          if (node.type === 2) {
            processedNode.planCount = node.generationCount;
            processedNode.currentCount = node.children
              ? node.children.length
              : 0;
          }
            if (node.type === 2) {
              processedNode.planCount = node.generationCount;
              processedNode.currentCount = node.children
                ? node.children.length
                : 0;
            }
          if (node.children && node.children.length > 0) {
            processedNode.children = node.children.map((child) =>
              processNode(child, node.type)
            );
          }
          return processedNode;
            if (node.children && node.children.length > 0) {
              // 审批人需要查看完整谱系,包括仍处于保存状态的节点。
              processedNode.children = node.children
                .filter((child) => roleType === 2 || child.codeStatus == 2 || (child.codeStatus == 1 && roleType === 3))
                .map((child) => processNode(child, node.type));
            }
            return processedNode;
        }
        // 构建完整的树形结构,添加空值校验
@@ -306,45 +629,9 @@
        // 在数据加载完成后重新渲染图表
        this.$nextTick(() => {
          if (this.graph) {
            // 转换树形数据为G6可用的格式
            const convertToG6Data = (nodes) => {
              const g6Nodes = [];
              const g6Edges = [];
              const processNode = (node, parentId = null) => {
                g6Nodes.push({
                  id: node.id,
                  label: node.label,
                  number: node.number,
                  data: node.data,
                  isDiscarded: node.isDiscarded,
                  style: node.style,
                  planCount: node.planCount,
                  currentCount: node.currentCount,
                });
                if (parentId) {
                  g6Edges.push({
                    source: parentId,
                    target: node.id,
                    style: {
                      stroke: "rgba(4, 156, 154, 1)",
                      lineWidth: 1,
                    },
                  });
                }
                if (node.children && node.children.length > 0) {
                  node.children.forEach((child) => processNode(child, node.id));
                }
              };
              nodes.forEach((node) => processNode(node));
              return { nodes: g6Nodes, edges: g6Edges };
            };
            const g6Data = convertToG6Data(this.graphData.nodes);
          console.log('this.graphData.nodes',this.graphData.nodes)
          if (this.graph && this.graphData.nodes.length > 0) {
            const g6Data = this.convertToG6Data(this.graphData.nodes);
            this.graph.changeData(g6Data);
            this.graph.render();
            this.graph.fitView();
@@ -352,24 +639,76 @@
        });
      });
    },
    // 转换树形数据为G6可用的格式
    convertToG6Data(nodes) {
      const g6Nodes = [];
      const g6Edges = [];
      const processNode = (node, parentId = null) => {
        g6Nodes.push({
          id: node.id,
          label: node.label,
          number: node.number,
          data: node.data,
          isDiscarded: node.isDiscarded,
          style: node.style,
          planCount: node.planCount,
          currentCount: node.currentCount,
        });
        if (parentId) {
          g6Edges.push({
            source: parentId,
            target: node.id,
            style: {
              stroke: "rgba(4, 156, 154, 1)",
              lineWidth: 1,
            },
          });
        }
        if (node.children && node.children.length > 0) {
          node.children.forEach((child) => processNode(child, node.id));
        }
      };
      nodes.forEach((node) => processNode(node));
      return { nodes: g6Nodes, edges: g6Edges };
    },
    addNodeSign(value, type) {
      this.nodeData = value;
      //todo 同步画布数据 nodeData.strainType
      this.nodeType = type;
      // this.$refs.addAncestor.closeDialog()
      this.$refs.addSublevelForm.closeDialog()
      this.$refs.addSublevelForm.closeDialog();
      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) {
          // 递归处理节点数据,将data对象的内容提取到上一级并删除data属性
          const processNodeData = (nodes) => {
          const processNodeData = (nodes, type) => {
            return nodes.map((node) => {
              const { data, children, ...rest } = node;
              const processedNode = {
                ...rest,
                ...data, // 将data对象的内容展开到当前节点
                children: children ? processNodeData(children) : [],
                codeStatus: type == 2 ? '2' : data.codeStatus || type,
                children: children ? processNodeData(children, type) : [],
              };
              return processedNode;
            });
@@ -377,23 +716,25 @@
          // 获取基础表单数据
          let baseData = {
            parent: { ...this.form },
            one: processNodeData(this.graphData.nodes),
            parent: { ...this.form, status: type },
            one: processNodeData(this.graphData.nodes, type),
          };
          console.log("baseData baseData", baseData);
          // return
          if (this.$route.query.id) {
            baseData.parent.id = this.$route.query.id;
            edit({ ...baseData, id: this.$route.query.id }).then((res) => {
              if (res.code == 200) {
                this.$message.success("编辑成功");
                this.$router.back();
                this.$closeCurrentView('/strain/pedigree-vhart');
              }
            });
            return
            return;
          }
          add(baseData).then((res) => {
            if (res.code == 200) {
              this.$message.success("保存成功");
              this.$router.back();
              this.$closeCurrentView('/strain/pedigree-vhart');
            }
          });
        }
@@ -403,7 +744,7 @@
      // 实现存草稿逻辑
    },
    handleCancel() {
      this.$router.back();
      this.$closeCurrentView('/strain/pedigree-vhart');
    },
    handleSignatureConfirm(signatureImage) {
      this.confirmStorageDialogVisible = false;
@@ -430,6 +771,21 @@
    },
    addNode() {
      // 如果没有节点,新增祖代
      console.log("选择的节点", this.selectedNode);
      // if (this.selectedNode && this.selectedNode.data && this.selectedNode.data.auditStatus && this.selectedNode.data.auditStatus != 2) {
      //   this.$message.warning("该传代计划数未审核,请先审核");
      //   return;
      // }
      if (
        this.selectedNode &&
        this.selectedNode.data &&
        this.selectedNode.data.auditStatus !== null &&
        this.selectedNode.data.auditStatus != 2
      ) {
        this.$message.warning("该传代计划数未审核,请先审核");
        return;
      }
      if (this.graphData.nodes.length === 0) {
        this.$refs.pedigreeForm.validate((valid) => {
          if (valid) {
@@ -448,6 +804,15 @@
            });
          }
        });
        return;
      }
      //
      if (
        !this.$route.query.id &&
        this.selectedNode &&
        this.selectedNode.label === "传代计划数"
      ) {
        this.$message.warning("一次只能添加一个传代");
        return;
      }
@@ -502,20 +867,27 @@
      }
    },
    handleAddParent(value) {
      console.log('handleAddParent 编辑修改', value);
      if (value.formStatus == "edit") {
        updateChild(value).then((res) => {
        updateChild({ ...value, codeStatus: '1' }).then((res) => {
          if (res.code == 200) {
            this.$message.success("操作成功");
            this.$refs.addAncestor.closeDialog();
            this.reloadData();
            // this.reloadData();
            // 1. 如果是编辑模式(前端编辑),先删除旧节点
            if (this.selectedNode) {
              // 删除旧节点
              this.deleteNodeFromGraph(this.selectedNode.id);
            }
          }
        });
        return;
        // return;
      }
      if (this.$route.query.id) {
        value.pedigreeChartId = this.$route.query.id;
        value.parentId = "0";
        addProgenitor(value).then((res) => {
        addProgenitor({ ...value, codeStatus: '1' }).then((res) => {
          if (res.code == 200) {
            this.$message.success("操作成功");
            this.$refs.addAncestor.closeDialog();
@@ -547,8 +919,9 @@
      this.$refs.form.resetFields();
    },
    handleAddSublevel(value) {
      console.log('222222222222 编辑编辑', value)
      if (value.formStatus == "edit") {
        updateChild(value).then((res) => {
        updateChild({ ...value, codeStatus: '1' }).then((res) => {
          if (res.code == 200) {
            this.$message.success("操作成功");
            this.$refs.addSublevelForm.closeDialog();
@@ -558,7 +931,7 @@
        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();
@@ -733,6 +1106,10 @@
      }
    },
    setGenerationPlan() {
      if (this.newTableData.length != 0) {
        this.$message.warning("有未审核的待确认传代计划数,请先审核");
        return;
      }
      if (!this.selectedNode) {
        this.$message.warning("请先选择节点");
        return;
@@ -766,22 +1143,42 @@
      this.$refs.planForm.openInitData({
        ...nodeModel.data,
        label: nodeModel.label,
        formStatus: "add",
      });
    },
    handleAddPlan(value) {
      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.reloadData();
          }
        });
        console.log('value', value)
        if (value.formStatus == "add") {
          let params = {
            parentId: value.id,
            generationCount: value.generationCount,
            vaccinateSignature: value.vaccinateSignature,
          };
          addCount({ ...params, codeStatus: '1' }).then((res) => {
            if (res.code === 200) {
              this.$message.success("操作成功");
              this.$refs.planForm.closeDialog();
              this.reloadData();
            }
          });
        } else {
          let params = {
            id: value.id,
            generationCount: value.generationCount,
            vaccinateSignature: value.vaccinateSignature,
          };
          addProgenitorChild({ ...params, codeStatus: '1' }).then((res) => {
            if (res.code === 200) {
              this.$message.success("操作成功");
              this.$refs.planForm.closeDialog();
              this.reloadData();
            }
          });
        }
        return;
      }
@@ -892,7 +1289,8 @@
      }
    },
    initGraph() {
      const container = document.getElementById("mountNode");
      const container = this.$refs.mountNode;
      if (!container) return;
      const width = container.scrollWidth;
      const height = container.scrollHeight || 600;
@@ -983,9 +1381,9 @@
            let typeName = "接种菌种";
            if (cfg.data && cfg.data.strainType) {
              const typeMap = {
                "1": "原始祖代菌株SO",
                "2": "分离菌落 CO",
                "3": "祖代菌株 O",
                1: "原始祖代菌株SO",
                2: "分离菌落 CO",
                3: "祖代菌株 O",
              };
              typeName = typeMap[cfg.data.strainType] || "接种菌种";
            }
@@ -1024,7 +1422,7 @@
      });
      this.graph = new G6.Graph({
        container: "mountNode",
        container,
        width,
        height,
        fitView: true,
@@ -1166,11 +1564,11 @@
        evt.preventDefault(); // 阻止默认触摸行为
        const node = evt.item;
        const nodeModel = node.getModel();
        // 如果节点已废弃,不允许任何操作
        if (!nodeModel.isDiscarded) {
          this.$message.warning("该节点已废弃,不能进行操作");
          return;
        }
        // 如果节点已废弃,不允许任何操作    放开
        // if (!nodeModel.isDiscarded) {
        //   this.$message.warning("该节点已废弃,不能进行操作");
        //   return;
        // }
        // 更新选中节点
        this.selectedNode = nodeModel;
        // 更新节点选中状态
@@ -1288,7 +1686,8 @@
    },
    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);
@@ -1354,6 +1753,40 @@
  }
}
.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;
      }
    }
  }
}
.strain-form {
  width: 100%;
@@ -1411,7 +1844,7 @@
    }
  }
  #mountNode {
  .mount-node {
    flex: 1;
    width: 100%;
    min-height: 500px;