From 10638dc89f1cd2a20c4035383a66192da5dfbccd Mon Sep 17 00:00:00 2001
From: 董国庆 <364620639@qq.com>
Date: 星期三, 17 十二月 2025 11:04:34 +0800
Subject: [PATCH] 修改文件图片回显

---
 culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue  |   30 +
 culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue   |   28 
 culture/vue.config.js                                                                     |    4 
 culture/src/views/system/user/components/add-edit.vue                                     |    4 
 culture/src/utils/request.js                                                              |   12 
 culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue |   27 +
 culture/src/views/pedigree-chart/add.vue                                                  |  318 +++++++++++---
 culture/src/components/AiEditor/index.vue                                                 |   70 +++
 culture/src/utils/baseurl.js                                                              |    6 
 culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue      |   28 +
 culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue                         |   31 +
 culture/src/views/pedigree-chart/addProgenitor.vue                                        |  314 ++++++++++---
 culture/src/views/pedigree-chart/service.js                                               |   11 
 culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue                       |   36 +
 culture/src/views/pedigree-chart/progenitorComponents/approvalCount.vue                   |  313 ++++++++++++++
 culture/src/views/strainReportLibrary/reportLibraryOne/add.vue                            |   24 
 culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue                        |   24 
 culture/src/utils/utils.js                                                                |   27 
 18 files changed, 1,093 insertions(+), 214 deletions(-)

diff --git a/culture/src/components/AiEditor/index.vue b/culture/src/components/AiEditor/index.vue
index cf68171..1e5bafb 100644
--- a/culture/src/components/AiEditor/index.vue
+++ b/culture/src/components/AiEditor/index.vue
@@ -7,6 +7,7 @@
 <script>
 import { AiEditor } from "aieditor";
 import 'aieditor/dist/style.css'
+import { getAllocateIp } from '@/utils/utils'
 // import { customUploadRequest, getFullUrl } from '@/utils/utils'
 import apiConfig from '@/utils/baseurl'
 
@@ -78,6 +79,75 @@
     this.destroyEditor()
   },
   methods: {
+     // 去除内容中的IP地址,只保留相对路径
+     removeIpFromContent(content) {
+      if (!content || typeof content !== 'string') return content;
+      
+      // 获取当前IP地址
+      const currentIp = getAllocateIp();
+      
+      // 使用正则表达式匹配并替换所有包含当前IP的URL
+      const ipRegex = new RegExp(currentIp.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
+      return content.replace(ipRegex, '');
+    },
+    
+    // 为内容中的相对路径添加IP地址,并处理已包含IP的绝对路径
+    addIpToContent(content) {
+      if (!content || typeof content !== 'string') return content;
+      
+      // 获取当前IP地址
+      const currentIp = getAllocateIp();
+      
+      // 匹配所有src、href、poster属性
+      const pathRegex = /(src|href|poster)="([^"]+)"/g;
+      
+      return content.replace(pathRegex, (match, attr, path) => {
+        // 如果路径是相对路径(不以http开头),则添加当前IP地址
+        if (!path.startsWith('http')) {
+          // 检查路径是否已经以/images/开头,避免重复添加
+          if (path.startsWith('/images/')) {
+            // 如果currentIp已经以/images/结尾,则去掉路径开头的/
+            if (currentIp.endsWith('/images/')) {
+              return `${attr}="${currentIp}${path.substring(1)}"`;
+            } else {
+              return `${attr}="${currentIp}${path}"`;
+            }
+          } else {
+            return `${attr}="${currentIp}${path}"`;
+          }
+        }
+        
+        // 如果路径已经包含当前IP地址,直接返回
+        if (path.startsWith(currentIp)) {
+          return match;
+        }
+        
+        // 如果路径是绝对路径,提取路径部分并替换为当前IP地址
+        // 匹配形如 http://192.168.1.100:8080/xxx 的路径
+        const absolutePathRegex = /^https?:\/\/[^\/]+(\/.*)$/;
+        const matchResult = path.match(absolutePathRegex);
+        
+        if (matchResult) {
+          // 提取路径部分,替换为当前IP地址
+          let pathPart = matchResult[1];
+          
+          // 如果currentIp已经以/images/结尾,且pathPart以/images/开头,则去掉pathPart开头的/images/
+          if (currentIp.endsWith('/images/') && pathPart.startsWith('/images/')) {
+            pathPart = pathPart.substring(7); // 去掉开头的 '/images/'
+            // 如果pathPart以/开头,则去掉开头的/
+            if (pathPart.startsWith('/')) {
+              pathPart = pathPart.substring(1);
+            }
+          }
+          
+          return `${attr}="${currentIp}${pathPart}"`;
+        }
+        
+        // 其他情况(如外部链接)保持不变
+
+        return match;
+      });
+    },
     initEditor() {
       const options = {
         element: this.$refs.editorRef,
diff --git a/culture/src/utils/baseurl.js b/culture/src/utils/baseurl.js
index fa72e83..e2d3b80 100644
--- a/culture/src/utils/baseurl.js
+++ b/culture/src/utils/baseurl.js
@@ -7,9 +7,9 @@
     },
     // 生产环境
     production: {
-        baseURL: "http://221.182.45.100:8081",
-        imgUrl: "http://221.182.45.100:8081/open/file/upload",
-        showImgUrl:'http://221.182.45.100:9998/'
+        baseURL: "/culture",
+        imgUrl: "/culture/open/file/upload",
+        showImgUrl:'http://127.0.0.1:11223/images/'
     },
 };
 
diff --git a/culture/src/utils/request.js b/culture/src/utils/request.js
index b965926..37d6026 100644
--- a/culture/src/utils/request.js
+++ b/culture/src/utils/request.js
@@ -57,13 +57,13 @@
         if (res.data && res.data.data) {
           // 这里假设使用decryptBySM4进行解密
           res.data.data = decryptBySM4(res.data.data);
+          console.log('加密',res.data.data)
         }
       } catch (e) {
         console.error('数据解密失败:', e);
       }
     }
 
-    console.log('rewdsada', res);
 
     if (res.data.code == 500) {
       Message({
@@ -73,6 +73,16 @@
       })
       return
     }
+    if (res.data  &&res.data.code == 401) {
+      Message({
+        message: res.data.msg || '登录已过期,请重新登录',
+        type: 'warning',
+        duration: 2000
+      })
+      sessionStorage.clear();
+      window.location.replace('/');
+      return
+    }
 
     if (res.data && res.data.data &&res.data.data.code == 401) {
       Message({
diff --git a/culture/src/utils/utils.js b/culture/src/utils/utils.js
index 88ec0ff..8953dde 100644
--- a/culture/src/utils/utils.js
+++ b/culture/src/utils/utils.js
@@ -25,8 +25,6 @@
 
   axios.post(uploadUrl, formData, { headers: uploadHeaders })
     .then(res => {
-      console.log('qweqweqweqw/////',res);
-      
       try {
         onSuccess(res.data);
       } catch (e) {
@@ -41,13 +39,11 @@
       }
     });
 };
-
 export function getFullUrl(url) {
-  if (!url) return '';
+  if (!url) return "";
   if (/^https?:\/\//.test(url)) return url;
-  return apiConfig.showImgUrl + url;
+  return getAllocateIp() + url;
 }
-
 /**
  * 通用文件下载方法
  * @param {string} url 文件的下载地址(支持相对和绝对路径)
@@ -58,7 +54,6 @@
   if (!url) return;
   // 处理相对路径
   const fullUrl = getFullUrl(url);
-  console.log('fullUrl fullUrl',fullUrl)
   const a = document.createElement('a');
   a.href = fullUrl;
   if (name) {
@@ -80,4 +75,20 @@
   if (!url) return;
   const fullUrl = getFullUrl(url);
   window.open(fullUrl, '_blank');
-}
\ No newline at end of file
+}
+/**
+ * 判断文件是否为图片
+ * @param {string} url 文件URL
+ * @returns {boolean} 是否为图片文件
+ */
+export function isImageFile(url) {
+  if (!url) return false;
+  const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg'];
+  const lowerUrl = url.toLowerCase();
+  return imageExtensions.some(ext => lowerUrl.includes(ext));
+}
+
+export function getAllocateIp() {
+  const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
+  return userInfo.allocateIp ? 'http://'+userInfo.allocateIp +':11222/images/' : apiConfig.showImgUrl;
+}
diff --git a/culture/src/views/pedigree-chart/add.vue b/culture/src/views/pedigree-chart/add.vue
index 2c15984..5b8ceb8 100644
--- a/culture/src/views/pedigree-chart/add.vue
+++ b/culture/src/views/pedigree-chart/add.vue
@@ -7,27 +7,44 @@
             <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">
@@ -40,7 +57,7 @@
             </template>
           </el-table-column>
           <el-table-column label="菌种入库时间/菌种废弃时间" prop="storageTime" />
-          <el-table-column v-if="roleType == 3" label="操作">
+          <el-table-column v-if="roleType == 2" label="操作">
             <template #default="{ row }">
               <el-button type="text" @click="handleConfirm(row)">确认入库</el-button>
             </template>
@@ -51,22 +68,25 @@
         <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="roleType == 3 || roleType == 1" class="el-icon-plus" @click="addNode">
               新增</el-button>
 
-            <el-button type="primary" v-if="$route.query.type != 1" @click="setGenerationPlan">设置传代计划数</el-button>
+            <el-button type="primary" v-if="roleType == 3 || roleType == 1"
+              @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="roleType == 1 || roleType == 3">编辑</el-button>
+            <el-button type="primary" @click="handleDelete" v-if="roleType == 1 || roleType == 3">删除</el-button>
           </div>
         </div>
 
         <div class="strain-flow-chart">
           <div id="mountNode"></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="roleType == 1 || roleType == 3">
+          <el-button type="primary" @click="handleSubmit('1')" style="width: 150px">保存</el-button>
+          <el-button type="primary" @click="handleSubmit('2')" style="width: 150px; margin-left: 20px">提交</el-button>
+        </div>
       </div>
       <div class="end-btn">
         <!-- <el-button @click="handleDraft">存草稿</el-button>
@@ -83,6 +103,9 @@
     <!-- 菌种工程师 -->
     <ConfirmStorageDialog name="菌种保藏人签字" text="是否确认该项菌种信息入库" :visible.sync="storageVisible"
       @confirm="handleSignatureConfirm1" />
+
+    <!-- 传代数审批 -->
+    <ApprovalCount ref="approvalCount" @addNodeSign="sureApprovalCountSign" />
   </div>
 </template>
 
@@ -93,9 +116,11 @@
 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,
@@ -103,6 +128,8 @@
   deleteNode,
   updateChild,
   edit,
+  confirmCount,
+  pageListCountDetail
 } from "./service";
 export default {
   name: "AddPedigree",
@@ -112,6 +139,7 @@
     AddSublevelForm,
     AddSublevelPlan,
     ConfirmStorageDialog,
+    ApprovalCount,
   },
   data() {
     return {
@@ -163,7 +191,22 @@
       storageVisible: 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.已提交
+      queryForm: {
+        pageSize: 10,
+        pageNum: 1,
+      },
+      newTotal: 0,
+      newCurrent: 1,
+      newSize: 10,
+      newTableData: [],
+      newQueryForm: {
+        pageSize: 10,
+        pageNum: 1,
+      },
     };
   },
   computed: {
@@ -184,7 +227,6 @@
     this.initEvents();
   },
   created() {
-
     if (this.$route.query.id) {
       this.reloadData();
     }
@@ -198,6 +240,15 @@
       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;
 
@@ -229,7 +280,7 @@
             strainSourceEnd: this.form.strainSourceEnd,
             confirmTime: this.form.confirmTime,
             parentId: nodeModel.id,
-            formStatus: "edit",
+            formStatus: "editCount",
           });
         } else {
           this.$refs.planForm.openInitData({
@@ -238,7 +289,7 @@
             strainCode1: this.form.strainCode,
             strainName1: this.form.strainName,
             ...nodeModel.data,
-            formStatus: "edit",
+            formStatus: "editCount",
           });
         }
       }
@@ -247,6 +298,15 @@
       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: "确定",
@@ -311,10 +371,49 @@
         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("数据加载失败");
+      }
+    },
     reloadData() {
       this.getList();
+      this.getNewList()
       getDetail({ id: this.$route.query.id }).then((res) => {
-
         const nodeMap = new Map();
         const calculateLevel = (node) => {
           if (node.parentId === "0") return 0;
@@ -360,7 +459,14 @@
             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,
             },
           };
         };
@@ -369,30 +475,35 @@
         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 (node.codeStatus == 2 || (node.codeStatus == 1 && 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);
+                }
               }
             });
           };
@@ -407,7 +518,7 @@
           strainCode: res.strainCode,
           strainName: res.strainName,
         };
-
+        this.nodeTreeStatus = res.status
         // 更新图表
         this.updateGraphData();
       });
@@ -419,7 +530,21 @@
       // 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) {
@@ -428,10 +553,12 @@
           }
 
           // 处理节点数据,将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;
@@ -442,7 +569,7 @@
           const buildTree = (nodes, edges) => {
             // 创建节点映射,提升性能
             const nodeMap = new Map(
-              nodes.map((node) => [node.nodeId, processNodeData(node)])
+              nodes.map((node) => [node.nodeId, processNodeData(node, type)])
             );
 
             // 创建子节点ID集合,用于快速查找根节点
@@ -471,11 +598,11 @@
               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;
 
@@ -485,7 +612,7 @@
                 this.$router.back();
               }
             });
-            return
+            return;
           }
           add(baseData).then((res) => {
             if (res.code == 200) {
@@ -614,8 +741,8 @@
           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) {
@@ -627,8 +754,8 @@
             //   typeName = typeMap[cfg.data.strainType] || "接种菌种";
             // }
 
-            if(cfg.data.parentId){
-              typeName = '接代菌种'
+            if (cfg.data.parentId) {
+              typeName = "接代菌种";
             }
 
             content = `${typeName}编号:${cfg.number}`;
@@ -831,7 +958,7 @@
             ...node,
             id: node.nodeId,
             level: 0, // 添加层级标记
-            children: [] // 添加children数组
+            children: [], // 添加children数组
           });
         });
 
@@ -899,7 +1026,6 @@
         })),
       };
 
-
       // 更新图表数据
       this.graph.changeData(processedData);
 
@@ -951,6 +1077,18 @@
       }
     },
     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) => {
@@ -960,10 +1098,19 @@
               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;
       }
 
@@ -1043,18 +1190,21 @@
       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();
@@ -1193,6 +1343,7 @@
           strainCode1: this.form.strainCode,
           strainSourceStart: this.form.strainSourceStart,
           strainSourceEnd: this.form.strainSourceEnd,
+          formStatus: "addCount",
         });
       } else {
         this.$refs.planForm.openInitData({
@@ -1202,13 +1353,16 @@
           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();
@@ -1216,22 +1370,41 @@
             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;
@@ -1286,12 +1459,11 @@
           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,
@@ -1301,7 +1473,6 @@
             status: "detail",
           });
         } else {
-
           this.$refs.planForm.openInitData({
             strainSourceStart: this.form.strainSourceStart,
             strainSourceEnd: this.form.strainSourceEnd,
@@ -1332,7 +1503,6 @@
 .title {
   font-size: 18px;
 }
-
 
 .chart {
   padding: 20px 38px;
diff --git a/culture/src/views/pedigree-chart/addProgenitor.vue b/culture/src/views/pedigree-chart/addProgenitor.vue
index e9f56ce..e29d5a6 100644
--- a/culture/src/views/pedigree-chart/addProgenitor.vue
+++ b/culture/src/views/pedigree-chart/addProgenitor.vue
@@ -4,14 +4,29 @@
       <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">
@@ -24,7 +39,7 @@
             </template>
           </el-table-column>
           <el-table-column label="菌种入库时间/菌种废弃时间" prop="storageTime" />
-          <el-table-column label="操作" v-if="roleType == 3">
+          <el-table-column label="操作" v-if="roleType == 2">
             <template #default="{ row }">
               <el-button type="text" @click="handleConfirm(row)">确认入库</el-button>
             </template>
@@ -36,20 +51,24 @@
         <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" v-if="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="roleType == 3 || roleType == 1"
+              @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="roleType == 1 || roleType == 3">编辑</el-button>
+            <el-button type="primary" @click="handleDelete" v-if="roleType == 1 || roleType == 3">删除</el-button>
           </div>
         </div>
 
         <div class="strain-flow-chart">
           <div id="mountNode"></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="roleType == 1 || roleType == 3">
+          <el-button type="primary" @click="handleSubmit('1')" style="width: 150px">保存</el-button>
+          <el-button type="primary" @click="handleSubmit('2')" style="width: 150px; margin-left: 20px">提交</el-button>
+        </div>
       </div>
     </el-form>
 
@@ -61,6 +80,8 @@
     <!-- 菌种工程师 -->
     <ConfirmStorageDialog name="菌种保藏人签字" text="是否确认该项菌种信息入库" :visible.sync="storageVisible"
       @confirm="handleSignatureConfirm1" />
+    <!-- 传代数审批 -->
+    <ApprovalCount ref="approvalCount" @addNodeSign="sureApprovalCountSign" />
   </div>
 </template>
 
@@ -74,13 +95,17 @@
   add,
   getDetail,
   addProgenitorChild,
+  addCount,
   addProgenitor,
   pageListDetail,
+  pageListCountDetail,
   confirmStorage,
   deleteNode,
   updateChild,
-  edit
+  edit,
+  confirmCount,
 } from "./service";
+import ApprovalCount from "./progenitorComponents/approvalCount.vue";
 
 export default {
   name: "AddPedigree",
@@ -89,6 +114,7 @@
     AddAncestor,
     AddSublevelForm,
     ConfirmStorageDialog,
+    ApprovalCount,
   },
   data() {
     return {
@@ -133,8 +159,18 @@
       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,
+      },
     };
   },
   computed: {
@@ -165,8 +201,18 @@
   },
   methods: {
     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("确定删除该节点吗?", "提示", {
@@ -183,9 +229,19 @@
       });
     },
     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;
@@ -235,7 +291,6 @@
           current: this.current,
           size: this.size,
         });
-
         if (listRes.code === 200) {
           this.tableData = listRes.data.records;
           this.total = listRes.data.total;
@@ -249,9 +304,50 @@
         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.getNewList();
       getDetail({ id: this.$route.query.id }).then((res) => {
+        console.log("详情数据", res);
         const detailData = res.pedigreeChartParentAllDetailDTO;
         // 设置基础表单数据
         this.form = {
@@ -262,41 +358,45 @@
         // 递归处理节点数据,构建树形结构
         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= 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) {
+              // 根据子节点的 codeStatus 和 roleType 决定是否处理子节点
+              // codeStatus == 2: 处理
+              // codeStatus == 1 且 roleType == 3: 处理
+              // codeStatus == 1 且 roleType != 3: 不处理(过滤掉)
+              processedNode.children = node.children
+                .filter((child) => child.codeStatus == 2 || (child.codeStatus == 1 && roleType == 3))
+                .map((child) => processNode(child, node.type));
+            }
+            return processedNode;
         }
 
         // 构建完整的树形结构,添加空值校验
@@ -306,7 +406,8 @@
 
         // 在数据加载完成后重新渲染图表
         this.$nextTick(() => {
-          if (this.graph) {
+          console.log('this.graphData.nodes',this.graphData.nodes)
+          if (this.graph && this.graphData.nodes.length > 0) {
             // 转换树形数据为G6可用的格式
             const convertToG6Data = (nodes) => {
               const g6Nodes = [];
@@ -356,20 +457,35 @@
       this.nodeData = value;
       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,9 +493,11 @@
 
           // 获取基础表单数据
           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) => {
@@ -388,7 +506,7 @@
                 this.$router.back();
               }
             });
-            return
+            return;
           }
           add(baseData).then((res) => {
             if (res.code == 200) {
@@ -430,6 +548,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 +581,15 @@
             });
           }
         });
+        return;
+      }
+      //
+      if (
+        !this.$route.query.id &&
+        this.selectedNode &&
+        this.selectedNode.label === "传代计划数"
+      ) {
+        this.$message.warning("一次只能添加一个传代");
         return;
       }
 
@@ -502,8 +644,9 @@
       }
     },
     handleAddParent(value) {
+      console.log('value编辑 编辑修改', 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();
@@ -515,7 +658,7 @@
       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 +690,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 +702,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 +877,10 @@
       }
     },
     setGenerationPlan() {
+      if (this.newTableData.length != 0) {
+        this.$message.warning("有未审核的待确认传代计划数,请先审核");
+        return;
+      }
       if (!this.selectedNode) {
         this.$message.warning("请先选择节点");
         return;
@@ -766,22 +914,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;
       }
 
@@ -983,9 +1151,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] || "接种菌种";
             }
diff --git a/culture/src/views/pedigree-chart/progenitorComponents/approvalCount.vue b/culture/src/views/pedigree-chart/progenitorComponents/approvalCount.vue
new file mode 100644
index 0000000..ed74f7f
--- /dev/null
+++ b/culture/src/views/pedigree-chart/progenitorComponents/approvalCount.vue
@@ -0,0 +1,313 @@
+<template>
+  <!-- 设置传代计划数弹窗 -->
+  <div>
+    <el-dialog
+      title="确认祖代传代计划数"
+      :visible.sync="planDialogVisible"
+      width="40%"
+      :close-on-click-modal="false"
+    >
+      <el-form
+        :model="planForm"
+        :rules="planRules"
+        ref="planForm"
+        label-position="top"
+      >
+        <el-row :gutter="20">
+          <el-col :span="16">
+            <el-form-item label="菌株类型">
+              <div class="activeType">
+                {{
+                  ["原始祖代菌株SO", "分离菌落 CO", "祖代菌株 O"][
+                    planForm.strainType - 1
+                  ]
+                }}
+              </div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="20" v-if="planForm.strainType == '1'">
+            <el-form-item label="来源获得" prop="source">
+              <el-input
+                disabled
+                v-model="planForm.source"
+                placeholder="请输入"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10" v-else>
+            <el-form-item label="菌落编号" prop="colonyNumber">
+              <el-input
+                disabled
+                v-model="planForm.colonyNumber"
+                placeholder="请输入"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="菌种名称" prop="strainName">
+              <el-input
+                disabled
+                v-model="planForm.strainName"
+                placeholder="请输入"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="菌种编号" prop="strainCode">
+              <el-input
+                disabled
+                v-model="planForm.strainCode"
+                placeholder="请输入"
+              ></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="10">
+            <el-form-item label="保存/废弃">
+              <div class="active">保存</div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="10">
+            <el-form-item label="菌种入库时间">
+              <el-input disabled v-model="planForm.confirmTime"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="10">
+            <el-form-item label="传代计划数" prop="generationCount">
+              <el-input-number
+                disabled
+                v-model="planForm.generationCount"
+                :controls="false"
+                :min="1"
+                placeholder="请输入"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row :gutter="20">
+          <el-col :span="10">
+            <el-form-item label="菌种保藏人签字">
+              <div
+                class="signature-area"
+                :class="{ waiting: !planForm.vaccinateSignature }"
+              >
+                <template v-if="planForm.vaccinateSignature">
+                  <el-image
+                    :src="getFullUrl(planForm.vaccinateSignature)"
+                    :preview-src-list="[
+                      getFullUrl(planForm.vaccinateSignature),
+                    ]"
+                    alt="菌种保藏人签字"
+                  />
+                </template>
+                <template v-else>
+                  <span class="waiting-text">等待签字</span>
+                </template>
+              </div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="10">
+            <el-form-item label="菌种审批人签字" prop="preserveSignature">
+              <div
+                class="signature-area"
+                :class="{ waiting: !planForm.preserveSignature }"
+              >
+                <template v-if="planForm.preserveSignature">
+                  <el-image
+                    :src="getFullUrl(planForm.preserveSignature)"
+                    :preview-src-list="[getFullUrl(planForm.preserveSignature)]"
+                    alt="菌种审批人签字"
+                  />
+                </template>
+                <template v-else>
+                  <span class="waiting-text">等待签字</span>
+                </template>
+              </div>
+              <el-button
+                type="primary"
+                class="sign-btn"
+                @click="showApprovalSignature = true"
+                v-if="!planForm.preserveSignature"
+                >审批人签字</el-button
+              >
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div v-if="planForm.formStatus !== 'detail'" class="dialog-footer">
+        <el-button type="primary" @click="handleAddPlan">提交签字</el-button>
+      </div>
+    </el-dialog>
+    <signature-canvas
+      :visible.sync="showApprovalSignature"
+      @confirm="handleApprovalSignatureConfirm"
+    />
+  </div>
+</template>
+<script>
+import moment from "moment";
+import SignatureCanvas from "@/components/SignatureCanvas.vue";
+import { getFullUrl } from "@/utils/utils";
+import { queryDetail } from "../service";
+export default {
+  name: "ApprovalCount",
+  components: { SignatureCanvas },
+  props: {
+    formStatus: {
+      type: String,
+      default: "add",
+    },
+  },
+  data() {
+    return {
+      planDialogVisible: false,
+      planForm: {},
+      planRules: {
+        preserveSignature: [
+          { required: true, message: "请审批人签字", trigger: "change" },
+        ],
+      },
+      showApprovalSignature: false,
+    };
+  },
+  methods: {
+    getFullUrl(url) {
+      if (url) {
+        return getFullUrl(url);
+      }
+    },
+    openInitData(value) {
+      this.planForm = value;
+      queryDetail().then((res) => {
+        this.planForm.preserveSignature = res.signPicture;
+      });
+      if (value.confirmTime) {
+        this.planForm.confirmTime = moment(value.confirmTime).format(
+          "YYYY-MM-DD HH:mm:ss"
+        );
+      } else {
+        this.planForm.confirmTime = moment().format("YYYY-MM-DD HH:mm:ss");
+      }
+
+      this.openDialog();
+    },
+    openDialog() {
+      this.planDialogVisible = true;
+    },
+    closeDialog() {
+      this.planDialogVisible = false;
+    },
+    handleApprovalSignatureConfirm(dataUrl) {
+      this.planForm.preserveSignature = dataUrl;
+      this.showApprovalSignature = false;
+    },
+    handleAddPlan() {
+      this.$refs.planForm.validate((valid) => {
+        if (valid) {
+          // // 保存审批人签字到本地(如果有的话)
+          // if (this.planForm.preserveSignature) {
+          //     localStorage.setItem('approvalSignature_' + this.planForm.id, this.planForm.preserveSignature)
+          // }
+          // // 调用父组件方法
+          this.$emit('addNodeSign', {...this.planForm})
+          // // 关闭弹窗
+          // this.planDialogVisible = false
+          // // 清理本地签字数据
+          // localStorage.removeItem('approvalSignature_' + this.planForm.id)
+        }
+      });
+    },
+  },
+};
+</script>
+<style scoped lang="less">
+.dialog-footer {
+  margin-top: 39px;
+  display: flex;
+  justify-content: center;
+
+  .el-button--primary {
+    width: 150px;
+    height: 40px;
+    background: #049c9a;
+    border-radius: 4px;
+  }
+}
+
+::v-deep .el-input-number .el-input__inner {
+  text-align: left;
+}
+
+.el-input-number--small {
+  width: 100%;
+}
+
+.active {
+  font-family: "SourceHanSansCN-Medium";
+  color: #049c9a;
+  background: #ebfefd;
+  border-radius: 10px;
+  width: 178px;
+  line-height: 40px;
+  text-align: center;
+  font-weight: 500;
+  font-size: 16px;
+}
+
+.activeType {
+  width: 150px;
+  background: #ebfefd;
+  font-weight: 500;
+  color: #049c9a;
+  border-radius: 4px;
+  font-size: 16px;
+  line-height: 40px;
+  text-align: center;
+}
+
+.signature-area {
+  height: 100px;
+  width: 100%;
+  background: #f5f7fa;
+  border-radius: 4px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid #dcdfe6;
+  overflow: hidden;
+  padding: 0;
+  margin-bottom: 8px;
+}
+
+.signature-area.waiting {
+  border-style: dashed;
+  background: #fafafa;
+}
+
+.signature-area img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  display: block;
+}
+
+.waiting-text {
+  color: #909399;
+  font-size: 14px;
+}
+
+.sign-btn {
+  height: 32px;
+  border-radius: 4px;
+  font-size: 14px;
+  padding: 0 20px;
+  font-weight: 400;
+  margin-left: 12px;
+  width: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/culture/src/views/pedigree-chart/service.js b/culture/src/views/pedigree-chart/service.js
index db56ea8..e2e7da1 100644
--- a/culture/src/views/pedigree-chart/service.js
+++ b/culture/src/views/pedigree-chart/service.js
@@ -28,6 +28,9 @@
 // 新增计划数
 export const addProgenitorChild = (params) => {
   return axios.post('/api/t-pedigree-chart/updateCount', { ...params })
+}// 新增计划数
+export const addCount = (params) => {
+  return axios.post('/api/t-pedigree-chart/addCount', { ...params })
 }
 
 // 祖代-母代新增菌种传代项
@@ -38,6 +41,10 @@
 // 谱系图-获取谱系图详情待入库菌种分页列表
 export const pageListDetail = (params) => {
   return axios.post('/api/t-pedigree-chart/pageListDetail', { ...params })
+}
+// 谱系图-2.0获取谱系图详情待确认传代计划数分页列表
+export const pageListCountDetail = (params) => {
+  return axios.post('/api/t-pedigree-chart/pageListCountDetail', { ...params })
 }
 
 // 谱系图-菌种工程师确认入库
@@ -63,4 +70,8 @@
 // 获取用户详情
 export const queryDetail = (data) => {
   return axios.get('/system/user/queryDetail',)
+}
+// 谱系图-2.0审批人确认传代计划数
+export const confirmCount = (data) => {
+  return axios.post('/api/t-pedigree-chart/confirmCount', { ...data })
 }
\ No newline at end of file
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue
index 1a50dde..772bb67 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue
@@ -162,7 +162,7 @@
 import { Card } from 'element-ui';
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import { customUploadRequest, getFullUrl } from "@/utils/utils";
+import { customUploadRequest, getFullUrl ,downloadFileByUrl,getAllocateIp,isImageFile} from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import { add, getDetail, update } from './service'
 
@@ -285,10 +285,24 @@
     },
     methods: {
         handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
             }
         },
         // 上传前校验
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue
index 8eff015..f8683f3 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue
@@ -64,7 +64,8 @@
                                 </div>
                             </div>
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :on-preview="handlePreview">
+                                <el-upload action="#" :file-list="fileList" disabled list-type="text"
+                                    :on-preview="handlePreview">
                                     <el-button size="small" type="primary">点击上传</el-button>
                                     <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                                 </el-upload>
@@ -159,6 +160,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
+import { getAllocateIp, downloadFileByUrl, isImageFile } from '@/utils/utils';
 
 
 export default {
@@ -203,7 +205,7 @@
                 auditPersonName: "",
                 auditTime: ""
             },
-            fileList:[],
+            fileList: [],
             assessmentTable: [
                 {
                     category: '1.该分题的菌种专业知识',
@@ -392,10 +394,24 @@
             this.getList()
         },
         handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
             }
         },
     },
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue
index 51c27be..c01c40a 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue
@@ -160,7 +160,7 @@
 import { Card } from 'element-ui';
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import { customUploadRequest, getFullUrl } from "@/utils/utils";
+import { customUploadRequest, getFullUrl ,downloadFileByUrl,getAllocateIp,isImageFile} from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import { add, getDetail, update } from './service'
 
@@ -281,10 +281,24 @@
     },
     methods: {
         handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
             }
         },
 
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue
index f348780..f612516 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue
@@ -58,7 +58,8 @@
                             </el-form-item>
 
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :on-preview="handlePreview">
+                                <el-upload action="#" :file-list="fileList" disabled list-type="text"
+                                    :on-preview="handlePreview">
                                     <el-button size="small" type="primary">点击上传</el-button>
                                     <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                                 </el-upload>
@@ -153,6 +154,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
+import { getAllocateIp, downloadFileByUrl, isImageFile } from '@/utils/utils';
 
 
 export default {
@@ -197,7 +199,7 @@
                 auditPersonName: "",
                 auditTime: ""
             },
-            fileList:[],
+            fileList: [],
             assessmentTable: [
                 {
                     category: '1.该分题的菌种专业知识',
@@ -252,10 +254,24 @@
     },
     methods: {
         handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
             }
         },
         open() {
@@ -272,7 +288,7 @@
                     processData: []
                 };
 
-                let arr = (data.evaluate||'').split(',')
+                let arr = (data.evaluate || '').split(',')
                 this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue
index f968364..ea8de38 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue
@@ -160,7 +160,7 @@
 import { Card } from 'element-ui';
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import { customUploadRequest, getFullUrl } from "@/utils/utils";
+import { customUploadRequest, getFullUrl ,downloadFileByUrl,getAllocateIp,isImageFile} from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import { add, getDetail, update } from './service'
 
@@ -277,14 +277,27 @@
             });
         }
     },
-    methods: {
-        handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
-            }
-        },
+    methods: {handlePreview(file) {
+      if (file && file.url) {
+        // 判断是否为图片文件
+        const isImage = isImageFile(file.url);
+        
+        if (isImage) {
+          // 图片文件:使用 window.open 预览
+          if (file.url && file.url.startsWith(getAllocateIp())) {
+            console.log('图片链接', file.url)
+            window.open(file.url, '_blank');
+          } else {
+            let newUrl = getAllocateIp() + file.url;
+            console.log('图片链接', newUrl)
+            window.open(newUrl, '_blank');
+          }
+        } else {
+          // 非图片文件:使用下载方式
+          downloadFileByUrl(file.url, file.name);
+        }
+      }
+    },
         // 上传前校验
         beforeUpload(file) {
             return true;
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue
index 6f0fdee..a24f458 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue
@@ -64,8 +64,7 @@
                                 </div>
                             </div>
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList"
-                                    :on-preview="handlePreview">
+                                <el-upload action="#" :file-list="fileList" :on-preview="handlePreview">
                                     <el-button size="small" type="primary">点击上传</el-button>
                                     <div slot="tip" class="el-upload__tip">支持任意格式文件上传</div>
                                 </el-upload>
@@ -160,6 +159,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
+import { getAllocateIp, downloadFileByUrl, isImageFile } from '@/utils/utils';
 
 
 export default {
@@ -258,10 +258,24 @@
     },
     methods: {
         handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
             }
         },
         open() {
@@ -278,7 +292,7 @@
                     processData: []
                 };
 
-                let arr = (data.evaluate||'').split(',')
+                let arr = (data.evaluate || '').split(',')
                 this.fileList = data.enclosureUrl ? JSON.parse(data.enclosureUrl) : []
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue
index a2160fb..3ae3e32 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue
@@ -160,7 +160,7 @@
 import { Card } from 'element-ui';
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import { customUploadRequest, getFullUrl } from "@/utils/utils";
+import { customUploadRequest, getFullUrl, downloadFileByUrl, getAllocateIp, isImageFile } from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import { add, getDetail, update } from './service'
 
@@ -280,10 +280,24 @@
     },
     methods: {
         handlePreview(file) {
-            if (file.url) {
-                window.open(file.url, '_blank');
-            } else {
-                this.$message.warning('无可预览地址');
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
             }
         },
         // 上传前校验
@@ -357,11 +371,11 @@
                     this.sendLoading = false;
                     return;
                 }
-                    // if (!this.selectedMember || !this.selectedMember[0]) {
-                    //     this.$message.warning('请选择菌种实验员');
-                    //     this.sendLoading = false;
-                    //     return;
-                    // }
+                // if (!this.selectedMember || !this.selectedMember[0]) {
+                //     this.$message.warning('请选择菌种实验员');
+                //     this.sendLoading = false;
+                //     return;
+                // }
                 const params = {
                     isDraft: 0,
                     projectId: this.projectData[0].id,
@@ -431,7 +445,7 @@
                 })
 
                 try {
-                     
+
                     const params = {
                         isDraft: 1,
                         projectId: this.projectData[0].id,
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue
index 335df7f..2ca3968 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue
@@ -56,7 +56,7 @@
                                 <ai-editor :readOnly="true" :value="form.reportContent" 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" />
@@ -159,7 +159,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
-
+import { customUploadRequest, getFullUrl, downloadFileByUrl, getAllocateIp, isImageFile } from "@/utils/utils";
 
 export default {
     name: "ApprovalDialog",
@@ -270,7 +270,7 @@
                     processData: []
                 };
 
-                let arr = (data.evaluate||'').split(',')
+                let arr = (data.evaluate || '').split(',')
                 this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
@@ -357,6 +357,27 @@
             }
             return [1, 1];
         },
+        handlePreview(file) {
+            if (file && file.url) {
+                // 判断是否为图片文件
+                const isImage = isImageFile(file.url);
+
+                if (isImage) {
+                    // 图片文件:使用 window.open 预览
+                    if (file.url && file.url.startsWith(getAllocateIp())) {
+                        console.log('图片链接', file.url)
+                        window.open(file.url, '_blank');
+                    } else {
+                        let newUrl = getAllocateIp() + file.url;
+                        console.log('图片链接', newUrl)
+                        window.open(newUrl, '_blank');
+                    }
+                } else {
+                    // 非图片文件:使用下载方式
+                    downloadFileByUrl(file.url, file.name);
+                }
+            }
+        },
         getTableSummary(param) {
             const { columns } = param;
             const sums = [];
diff --git a/culture/src/views/system/user/components/add-edit.vue b/culture/src/views/system/user/components/add-edit.vue
index 21f0eca..5260ea7 100644
--- a/culture/src/views/system/user/components/add-edit.vue
+++ b/culture/src/views/system/user/components/add-edit.vue
@@ -23,6 +23,9 @@
         <el-form-item label="启动状态" prop="status">
           <el-switch v-model="form.status"></el-switch>
         </el-form-item>
+        <el-form-item label="IP地址" prop="allocateIp">
+          <el-input v-model="form.allocateIp" placeholder="请输入" style="width: 50%"></el-input>
+        </el-form-item>
         <el-form-item label="备注" prop="remark">
           <el-input type="textarea" v-model="form.remark" placeholder="请输入" style="width: 50%"></el-input>
         </el-form-item>
@@ -83,6 +86,7 @@
         roleId: [{ required: true, message: '请选择角色', trigger: 'change' }],
         userName: [{ required: true, message: '请输入登陆账号', trigger: 'blur' }],
         status: [{ required: true, message: '请选择启动状态', trigger: 'blur' }],
+        allocateIp: [{ required: true, message: '请输入IP地址', trigger: 'blur' }],
       },
     }
   },
diff --git a/culture/vue.config.js b/culture/vue.config.js
index 1209754..5d4788c 100644
--- a/culture/vue.config.js
+++ b/culture/vue.config.js
@@ -12,7 +12,7 @@
       "/api": {
         // 设置以什么前缀开头的请求用来代理
         // target: "http://221.182.45.100:8081", //要访问的跨域的域名
-        target: "http://192.168.110.64:8081",
+        target: "http://192.168.110.64:8082",
         secure: false, // 使用的是http协议则设置为false,https协议则设置为true
         changOrigin: true, //开启代理
         pathRewrite: {
@@ -22,7 +22,7 @@
       "/": {
         // 设置以什么前缀开头的请求用来代理
         // target: "http://221.182.45.100:8081", //要访问的跨域的域名
-        target: "http://192.168.110.64:8081",
+        target: "http://192.168.110.64:8082",
         secure: false, // 使用的是http协议则设置为false,https协议则设置为true
         changOrigin: true, //开启代理
         pathRewrite: {

--
Gitblit v1.7.1