From 0db8c9b94a9ac655549d5eba5c2a6c92ac386c06 Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期四, 08 十月 2026 11:20:56 +0800
Subject: [PATCH] 提交最新代码

---
 culture/src/views/strainReportLibrary/reportLibraryOneTWO/index.vue                         |    4 
 culture/src/views/system/role/edit.vue                                                      |    8 
 culture/src/views/projectList/editProject.vue                                               |    2 
 culture/src/views/strain-library/breeding-record/add.vue                                    |  175 +-
 culture/src/views/strain-library/breeding-record/index.vue                                  |    4 
 culture/src/views/strainReportLibrary/reportLibraryOneFour/index.vue                        |    4 
 culture/src/views/projectList/addProject.vue                                                |    4 
 culture/src/views/strain-library/validation/primitive-cell/DetailConditionDialog.vue        |  346 +++--
 culture/src/components/SignatureCanvas.vue                                                  |   13 
 culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue   |   21 
 culture/src/router/index.js                                                                 |   43 
 culture/src/views/strain-library/validation/primitive-cell/index.vue                        |    4 
 culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue        |   22 
 culture/src/utils/view-tabs.js                                                              |   67 +
 culture/src/views/strainReportLibrary/reportLibraryOne/add.vue                              |   78 -
 laboratory/src/views/dataManagement/suspendExperiment/components/editDialog.vue             |  130 ++
 culture/src/views/strain-library/validation/primitive-cell/confirm-detail.vue               |   54 
 culture/src/views/strain-library/strain-library-manage/add.vue                              |    2 
 laboratory/src/views/dataManagement/SampleDeliveryRecord/deliveryRecord.vue                 |   11 
 laboratory/src/views/dataManagement/schemeManagement/stop-experiment.vue                    |    9 
 culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue                          |   76 -
 culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue    |   21 
 culture/src/views/strain-library/main-cell-library/add.vue                                  |    2 
 culture/src/store/index.js                                                                  |   10 
 laboratory/src/views/dataManagement/sampleSubmissionList/submission.vue                     |    8 
 culture/src/views/pedigree-chart/add.vue                                                    |  174 ++
 laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue                   |   13 
 culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue                           |   83 -
 laboratory/LICENSE                                                                          |   20 
 culture/src/views/pedigree-chart/addProgenitor.vue                                          |  171 ++
 culture/src/views/pedigree-chart/index.vue                                                  |   14 
 culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue                         |   75 -
 culture/src/views/strainReportLibrary/reportLibraryOneThree/index.vue                       |    4 
 culture/src/views/system/role/add.vue                                                       |    8 
 culture/src/main.js                                                                         |   10 
 culture/src/views/strain-library/breeding-record/SlantRecordDialog.vue                      |   63 
 culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue     |   19 
 culture/vue.config.js                                                                       |    6 
 laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue                        |   80 +
 culture/src/views/strain-library/validation/chief-cell/DetailConditionDialog.vue            |  339 +++--
 culture/src/views/strain-library/validation/primitive-cell/primitive-cell-detail-dialog.vue |  271 +++-
 laboratory/src/views/dataManagement/sampleRecordList/changeRecord.vue                       |   10 
 culture/src/views/strain-library/validation/primitive-cell/add.vue                          |   54 
 culture/src/layouts/components/AppContent.vue                                               |   44 
 culture/src/views/strain-library/validation/chief-cell/confirm-detail.vue                   |   33 
 culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue     |  272 +++-
 culture/src/utils/baseurl.js                                                                |    7 
 culture/src/views/strain-library/production-cell-library/add.vue                            |    2 
 culture/src/layouts/components/HeaderNav.vue                                                |   29 
 laboratory/src/utils/request.js                                                             |    3 
 culture/src/views/strainReportLibrary/reportLibraryOne/index.vue                            |    4 
 culture/src/views/strain-library/production-cell-grandson/add.vue                           |    2 
 culture/src/views/strain-library/validation/chief-cell/index.vue                            |    6 
 culture/src/views/strain-library/validation/chief-cell/add.vue                              |   54 
 laboratory/vue.config.js                                                                    |    4 
 culture/src/utils/utils.js                                                                  |   86 +
 56 files changed, 2,004 insertions(+), 1,074 deletions(-)

diff --git a/culture/src/components/SignatureCanvas.vue b/culture/src/components/SignatureCanvas.vue
index 46bb6e3..11b773a 100644
--- a/culture/src/components/SignatureCanvas.vue
+++ b/culture/src/components/SignatureCanvas.vue
@@ -16,7 +16,7 @@
 </template>
 
 <script>
-import { customUploadRequest } from '@/utils/utils'
+import { customUploadRequest, getUploadedFilePath } from '@/utils/utils'
 import {editSignPicture} from './service'
 export default {
   name: 'SignatureCanvas',
@@ -208,10 +208,13 @@
       customUploadRequest({
         file,
         onSuccess: (res) => {
-          // 假设返回的图片路径为 res.url
-          const url = res.msg || res.data || res
-          editSignPicture({ signPicture: res.msg }).then(res => {
-            if (res.code == 200) {
+          const url = getUploadedFilePath(res)
+          if (!url) {
+            this.$message.error('上传接口未返回文件地址')
+            return
+          }
+          editSignPicture({ signPicture: url }).then(result => {
+            if (result.code == 200) {
               this.$message.success('签名成功');
               this.$emit('confirm', url);
             }
diff --git a/culture/src/layouts/components/AppContent.vue b/culture/src/layouts/components/AppContent.vue
index 62372dc..45abca8 100644
--- a/culture/src/layouts/components/AppContent.vue
+++ b/culture/src/layouts/components/AppContent.vue
@@ -1,8 +1,9 @@
 <template>
   <div @click="foldFun" style="height: 100%;">
-    <keep-alive :include="keepAliveList">
-      <router-view />
+    <keep-alive ref="keepAlive">
+      <router-view v-if="shouldCacheView" :key="routeCacheKey" />
     </keep-alive>
+    <router-view v-if="!shouldCacheView" :key="$route.fullPath" />
   </div>
 </template>
 
@@ -15,9 +16,46 @@
     }
   },
   computed: {
-    ...mapState(['keepAliveList'])
+    ...mapState(['tagList', 'cachePruneRequest']),
+    activeTag() {
+      return this.tagList.find(tag => {
+        const fullPath = tag.fullPath || this.$router.resolve({
+          path: tag.path,
+          query: tag.query || {}
+        }).route.fullPath
+        return fullPath === this.$route.fullPath
+      })
+    },
+    shouldCacheView() {
+      return Boolean(this.$route.meta.keepAlive || this.$route.meta.hide)
+    },
+    routeCacheKey() {
+      return this.activeTag && this.activeTag.cacheKey
+        ? this.activeTag.cacheKey
+        : (this.$route.query._view || this.$route.fullPath)
+    }
+  },
+  watch: {
+    cachePruneRequest(request) {
+      if (request && request.keys) {
+        request.keys.forEach(key => this.pruneCacheEntry(key))
+      }
+    }
   },
   methods: {
+    pruneCacheEntry(key) {
+      const keepAlive = this.$refs.keepAlive
+      if (!keepAlive || !keepAlive.cache || !keepAlive.keys) return
+
+      const cached = keepAlive.cache[key]
+      if (cached && cached.componentInstance) {
+        cached.componentInstance.$destroy()
+      }
+      keepAlive.cache[key] = null
+
+      const index = keepAlive.keys.indexOf(key)
+      if (index > -1) keepAlive.keys.splice(index, 1)
+    },
     foldFun() {
       if (window.innerWidth < 1000) {
         this.$store.commit('SET_ISFOLD', true)
diff --git a/culture/src/layouts/components/HeaderNav.vue b/culture/src/layouts/components/HeaderNav.vue
index 0c66d87..1deaf24 100644
--- a/culture/src/layouts/components/HeaderNav.vue
+++ b/culture/src/layouts/components/HeaderNav.vue
@@ -12,8 +12,8 @@
         <i @click="clickFold" class="el-icon-s-fold"></i>
         <!-- 标签列表 -->
         <div class="tag-list-container" @wheel.prevent="handleWheel">
-          <div class="tag-list" v-for="tag in tagList" :key="tag.name">
-            <div @click="goTag(tag)" :class="{ 'activeTag': tag.path === $route.path }">
+          <div class="tag-list" v-for="tag in tagList" :key="tag.cacheKey || tag.fullPath || tag.path">
+            <div @click="goTag(tag)" :class="{ 'activeTag': getTagFullPath(tag) === $route.fullPath }">
               {{ tag.meta.title }}
             </div>
             <i @click="closeTag(tag)" v-if="tagList.length > 1" class="el-icon-close"></i>
@@ -35,6 +35,7 @@
 
 <script>
 import { mapState } from 'vuex'
+import { closeRouteView, getTagFullPath } from '@/utils/view-tabs'
 export default {
   data() {
     return {
@@ -72,22 +73,22 @@
     },
     // 关闭标签
     closeTag(tag) {
-      this.$store.commit('SET_TAGLIST', this.tagList.filter(item => item.path !== tag.path))
-      // 判断是否是当前标签
-      if (tag.path === this.$route.path) {
-        // if (this.tagList.length > 1) {
-        this.$router.push(this.tagList[this.tagList.length - 1].path)
-        // } else {
-        //   // this.$router.push('/welcome')
-        // }
-      }
+      closeRouteView({
+        router: this.$router,
+        store: this.$store,
+        route: this.$route,
+        tag
+      })
     },
     // 跳转标签
     goTag(tag) {
-      this.$router.push({
+      this.$router.push(tag.fullPath || {
         path: tag.path,
-        query: tag.query
+        query: tag.query || {}
       })
+    },
+    getTagFullPath(tag) {
+      return getTagFullPath(this.$router, tag)
     },
     handleWheel(e) {
       if (this.scrollTimer) {
@@ -259,4 +260,4 @@
     }
   }
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/culture/src/main.js b/culture/src/main.js
index 33131c1..7d28ab3 100644
--- a/culture/src/main.js
+++ b/culture/src/main.js
@@ -21,6 +21,7 @@
 import './assets/tailwind.css'
 import './styles/element-variables.less'
 import { fetchEncryptionKey } from './utils/encryption'
+import { closeRouteView } from './utils/view-tabs'
 
 Vue.config.productionTip = false;
 Vue.use(ElementUI, { size: 'small' })
@@ -72,6 +73,15 @@
   return height
 }
 
+Vue.prototype.$closeCurrentView = function (fallback) {
+  return closeRouteView({
+    router: this.$router,
+    store: this.$store,
+    route: this.$route,
+    fallback
+  })
+}
+
 // 获取加密密钥
 // fetchEncryptionKey()
 
diff --git a/culture/src/router/index.js b/culture/src/router/index.js
index d5365ce..10022be 100644
--- a/culture/src/router/index.js
+++ b/culture/src/router/index.js
@@ -732,6 +732,18 @@
   routes,
 });
 
+let tagCacheSequence = 0;
+const createTagCacheKey = (fullPath) => `${fullPath}::${Date.now()}-${tagCacheSequence++}`;
+const getTagFullPath = (tag) => tag.fullPath || router.resolve({
+  path: tag.path,
+  query: tag.query || {},
+}).route.fullPath;
+const getViewIdentity = (path, query = {}) => {
+  const businessQuery = { ...query };
+  delete businessQuery._view;
+  return router.resolve({ path, query: businessQuery }).route.fullPath;
+};
+
 // 前置路由拦截器
 router.beforeEach((to, from, next) => {
   // 设置当前页签名称
@@ -780,18 +792,47 @@
       }
   }
 
+  // Hidden business pages are independent tab instances. An existing tab keeps
+  // its _view; entering from a list again creates a clean component instance.
+  const isIndependentView = Boolean(to.meta.hide && !to.meta.oneself);
+  if (isIndependentView && !to.query._view) {
+    const viewIdentity = getViewIdentity(to.path, to.query);
+    const tagList = JSON.parse(sessionStorage.getItem("tagList") || "[]");
+    const staleTags = tagList.filter((tag) =>
+      getViewIdentity(tag.path, tag.query) === viewIdentity
+    );
+
+    if (staleTags.length) {
+      const staleKeys = staleTags.map((tag) => tag.cacheKey || getTagFullPath(tag));
+      const remainingTags = tagList.filter((tag) =>
+        getViewIdentity(tag.path, tag.query) !== viewIdentity
+      );
+      store.commit("SET_TAGLIST", remainingTags);
+      store.commit("PRUNE_VIEW_CACHE", staleKeys);
+    }
+
+    next({
+      path: to.path,
+      query: { ...to.query, _view: `${Date.now()}-${tagCacheSequence++}` },
+      replace: true,
+    });
+    return;
+  }
+
   // 设置标签列表
   if (!to.meta.hide || !to.meta.oneself) {
     let tagList = JSON.parse(sessionStorage.getItem("tagList") || "[]");
     // 判断是否存在
-    let isExist = tagList.some((item) => item.path === to.path);
+    let isExist = tagList.some((item) => getTagFullPath(item) === to.fullPath);
     if (!isExist) {
       // 只保存必要的信息
       const tagInfo = {
         path: to.path,
+        fullPath: to.fullPath,
         name: to.name,
         meta: to.meta,
         query: to.query,
+        cacheKey: createTagCacheKey(to.fullPath),
       };
       tagList.push(tagInfo);
       sessionStorage.setItem("tagList", JSON.stringify(tagList));
diff --git a/culture/src/store/index.js b/culture/src/store/index.js
index 07bb9ce..51771f8 100644
--- a/culture/src/store/index.js
+++ b/culture/src/store/index.js
@@ -2,11 +2,14 @@
 import Vuex from 'vuex'
 Vue.use(Vuex)
 
+let cachePruneSequence = 0
+
 const store = new Vuex.Store({
   state: {
     menus: sessionStorage.getItem('menuList') ? JSON.parse(sessionStorage.getItem('menuList')) : [],
     keepAliveList: sessionStorage.getItem('keepAliveList') ? JSON.parse(sessionStorage.getItem('keepAliveList')) : [],//缓存页面
     tagList: sessionStorage.getItem('tagList') ? JSON.parse(sessionStorage.getItem('tagList')) : [],//标签列表
+    cachePruneRequest: null,
     isFold: false,//是否折叠
     assay: [
       '检验方法正确',
@@ -48,6 +51,13 @@
       state.tagList = data;
       sessionStorage.setItem('tagList', JSON.stringify(data));
     },
+    PRUNE_VIEW_CACHE(state, data) {
+      const keys = (Array.isArray(data) ? data : [data]).filter(Boolean)
+      state.cachePruneRequest = {
+        id: ++cachePruneSequence,
+        keys
+      }
+    },
     SET_ISFOLD(state, data) {
       state.isFold = data;
     },
diff --git a/culture/src/utils/baseurl.js b/culture/src/utils/baseurl.js
index d1b6e8d..2608d69 100644
--- a/culture/src/utils/baseurl.js
+++ b/culture/src/utils/baseurl.js
@@ -1,3 +1,8 @@
+function getProductionFileUrl() {
+    if (typeof window === 'undefined') return '/images/';
+    return `${window.location.protocol}//${window.location.hostname}:11223/images/`;
+}
+
 const apiConfig = {
     // 开发环境
     development: {
@@ -9,7 +14,7 @@
     production: {
         baseURL: "/culture",
         imgUrl: "/culture/open/file/upload",
-        showImgUrl:'http://127.0.0.1:11223/images/'
+        showImgUrl: getProductionFileUrl()
     },
 };
 
diff --git a/culture/src/utils/utils.js b/culture/src/utils/utils.js
index 2bd2900..5e1f7fd 100644
--- a/culture/src/utils/utils.js
+++ b/culture/src/utils/utils.js
@@ -39,32 +39,81 @@
       }
     });
 };
-// export function getFullUrl(url) {
-//   if (!url) return "";
-//   if (/^https?:\/\//.test(url)) return url;
-//   return getAllocateIp() + url;
-// }
 
-export function getFullUrl(url) {
-  const origin = window.location.origin;
-  console.log('图片:', url);
+export function getUploadedFilePath(response) {
+  const payload = response && response.data && typeof response.data === 'object'
+    ? response.data
+    : response;
 
-  if (!url) return "";
-  if (/^https?:\/\//.test(url)) return url;
+  if (typeof payload === 'string') return payload.trim();
+  if (!payload || typeof payload !== 'object') return '';
 
-  console.log(origin.replace('8087','11223') + '/images/' + url);
-
-  return origin.replace('8087','11223') + '/images/' + url; //todo 具体端口以线上为准
-  // return getAllocateIp() + url;
+  const nestedPath = payload.data && typeof payload.data === 'object'
+    ? getUploadedFilePath(payload.data)
+    : '';
+  const candidates = [nestedPath, payload.data, payload.url, payload.fileUrl, payload.path, payload.msg];
+  const successMessages = ['操作成功', '上传成功', 'success', 'ok'];
+  return candidates.find(value => {
+    return typeof value === 'string'
+      && value.trim()
+      && !successMessages.includes(value.trim().toLowerCase());
+  }) || '';
 }
 
+export function normalizeFileList(value) {
+  let files = value;
+  if (typeof files === 'string') {
+    const text = files.trim();
+    if (!text) return [];
+    try {
+      files = JSON.parse(text);
+    } catch (e) {
+      files = [text];
+    }
+  }
+  if (!Array.isArray(files)) files = files ? [files] : [];
+
+  return files.map((file, index) => {
+    const source = typeof file === 'string' ? { url: file } : (file || {});
+    const url = source.url || source.fileUrl || source.path || source.filePath || '';
+    const fallbackName = String(url).split(/[\\/]/).pop() || `附件${index + 1}`;
+    return {
+      ...source,
+      name: source.name || source.fileName || fallbackName,
+      url,
+      uid: source.uid || source.id || `legacy-file-${index}-${url}`
+    };
+  }).filter(file => file.url);
+}
+
+export function getFullUrl(url) {
+  if (!url) return "";
+  const value = String(url).trim().replace(/\\/g, '/');
+  if (/^(data|blob):/.test(value)) return value;
+
+  const isAbsoluteUrl = /^(https?:)?\/\//.test(value);
+  if (isAbsoluteUrl && !/^(https?:)?\/\/(localhost|127\.0\.0\.1)(:\d+)?\//i.test(value)) {
+    return value;
+  }
+
+  const base = getAllocateIp().replace(/\/+$/, '') + '/';
+  let path = value;
+  if (isAbsoluteUrl) {
+    const parsedUrl = new URL(value, window.location.origin);
+    path = `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;
+  }
+  path = path.replace(/^\/+/, '');
+  if (/\/images\/$/.test(base) && path.startsWith('images/')) {
+    path = path.slice('images/'.length);
+  }
+  return base + path;
+}
 /**
  * 通用文件下载方法
  * @param {string} url 文件的下载地址(支持相对和绝对路径)
  * @param {string} name 下载保存的文件名(可选)
  */
 export function downloadFileByUrl(url, name) {
-  console.log('22222222222222222222',url)
   if (!url) return;
   // 处理相对路径
   const fullUrl = getFullUrl(url);
@@ -104,6 +153,9 @@
 
 export function getAllocateIp() {
   const userInfo = JSON.parse(sessionStorage.getItem("userInfo") || "{}");
-  // return  apiConfig.showImgUrl
-  return userInfo.allocateIp ? 'http://'+userInfo.allocateIp +':11223/images/' : apiConfig.showImgUrl;
+  const allocateIp = String(userInfo.allocateIp || '').trim();
+  const isLoopback = /^(localhost|127\.0\.0\.1)$/i.test(allocateIp);
+  return allocateIp && !isLoopback
+    ? `http://${allocateIp}:11223/images/`
+    : apiConfig.showImgUrl;
 }
diff --git a/culture/src/utils/view-tabs.js b/culture/src/utils/view-tabs.js
new file mode 100644
index 0000000..d7eea97
--- /dev/null
+++ b/culture/src/utils/view-tabs.js
@@ -0,0 +1,67 @@
+export function getTagFullPath(router, tag) {
+  if (tag.fullPath) return tag.fullPath
+  return router.resolve({
+    path: tag.path,
+    query: tag.query || {}
+  }).route.fullPath
+}
+
+function getNavigationTarget(router, remainingTags, fallback) {
+  if (fallback) {
+    const fallbackRoute = router.resolve(fallback).route
+    const matchingTag = remainingTags.slice().reverse().find((tag) => {
+      return router.resolve(getTagFullPath(router, tag)).route.path === fallbackRoute.path
+    })
+    return matchingTag ? getTagFullPath(router, matchingTag) : fallback
+  }
+
+  const target = remainingTags[remainingTags.length - 1]
+  return target ? getTagFullPath(router, target) : null
+}
+
+export function closeRouteView({ router, store, route, tag, fallback }) {
+  const currentRoute = route || router.currentRoute
+  const targetTag = tag || store.state.tagList.find((item) => {
+    return getTagFullPath(router, item) === currentRoute.fullPath
+  })
+  const targetFullPath = targetTag
+    ? getTagFullPath(router, targetTag)
+    : currentRoute.fullPath
+  const remainingTags = store.state.tagList.filter((item) => {
+    return getTagFullPath(router, item) !== targetFullPath
+  })
+  const isActive = targetFullPath === router.currentRoute.fullPath
+  const pruneKey = targetTag && targetTag.cacheKey
+    ? targetTag.cacheKey
+    : targetFullPath
+
+  const removeTagAndPrune = () => {
+    const latestTags = store.state.tagList.filter((item) => {
+      return getTagFullPath(router, item) !== targetFullPath
+    })
+    store.commit('SET_TAGLIST', latestTags)
+    store.commit('PRUNE_VIEW_CACHE', pruneKey)
+  }
+
+  if (!isActive) {
+    removeTagAndPrune()
+    return Promise.resolve()
+  }
+
+  const navigationTarget = getNavigationTarget(router, remainingTags, fallback)
+  if (!navigationTarget) {
+    removeTagAndPrune()
+    return Promise.resolve()
+  }
+
+  return Promise.resolve(router.push(navigationTarget)).then(
+    (result) => {
+      removeTagAndPrune()
+      return result
+    },
+    (error) => {
+      removeTagAndPrune()
+      throw error
+    }
+  )
+}
diff --git a/culture/src/views/pedigree-chart/add.vue b/culture/src/views/pedigree-chart/add.vue
index 0b4be92..42bf693 100644
--- a/culture/src/views/pedigree-chart/add.vue
+++ b/culture/src/views/pedigree-chart/add.vue
@@ -86,22 +86,22 @@
         <div class="header">
           <div class="title">菌种传代生产谱系图</div>
           <div class="option-btn">
-            <el-button type="primary" v-if="roleType == 3 || roleType == 1" class="el-icon-plus" @click="addNode" :disabled="editBoolean">
+            <el-button type="primary" v-if="!isReadOnly && (roleType == 3 || roleType == 1)" class="el-icon-plus" @click="addNode" :disabled="editBoolean">
               新增</el-button>
 
-            <el-button type="primary" v-if="roleType == 3 || roleType == 1"
+            <el-button type="primary" v-if="!isReadOnly && (roleType == 3 || roleType == 1)"
               @click="setGenerationPlan" :disabled="editBoolean">设置传代计划数</el-button>
             <el-button type="primary" @click="showDetail">详情</el-button>
-            <el-button type="primary" @click="handleEdit" v-if="roleType == 1 || roleType == 3" :disabled="editBoolean">编辑</el-button>
-            <el-button type="primary" @click="handleDelete" v-if="roleType == 1 || roleType == 3" :disabled="editBoolean">删除</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>
         <!-- v-if="!$route.query.id || (roleType == 1 && $route.query.id)" -->
-        <div v-if="roleType == 1 || roleType == 3">
+        <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>
@@ -112,20 +112,20 @@
       </div>
     </el-form>
 
-    <ParentForm ref="parentForm" @addNodeSign="addNodeSign" />
-    <PlanForm ref="planForm" @addNodeSign="addNodeSign" />
-    <AddSublevelForm ref="addSublevelForm" @addNodeSign="addNodeSign" />
-    <AddSublevelPlan ref="addSublevelPlan" @addNodeSign="addNodeSign" />
-    <ConfirmStorageDialog name="接种操作人签字" :visible.sync="confirmStorageDialogVisible"
+    <ParentForm :key="pageInstanceKey" ref="parentForm" @addNodeSign="addNodeSign" />
+    <PlanForm :key="pageInstanceKey" ref="planForm" @addNodeSign="addNodeSign" />
+    <AddSublevelForm :key="pageInstanceKey" ref="addSublevelForm" @addNodeSign="addNodeSign" />
+    <AddSublevelPlan :key="pageInstanceKey" ref="addSublevelPlan" @addNodeSign="addNodeSign" />
+    <ConfirmStorageDialog :key="`signature-${pageInstanceKey}`" name="接种操作人签字" :visible.sync="confirmStorageDialogVisible"
       @confirm="handleSignatureConfirm" />
     <!-- 菌种工程师 -->
-    <ConfirmStorageDialog name="菌种保藏人签字" text="是否确认该项菌种信息入库" :visible.sync="storageVisible"
+    <ConfirmStorageDialog :key="`storage-${pageInstanceKey}`" name="菌种保藏人签字" text="是否确认该项菌种信息入库" :visible.sync="storageVisible"
       @confirm="handleSignatureConfirm1" />
 
     <!-- 传代数审批 -->
-    <ApprovalCount ref="approvalCount" @addNodeSign="sureApprovalCountSign" />
+    <ApprovalCount :key="`approval-${pageInstanceKey}`" ref="approvalCount" @addNodeSign="sureApprovalCountSign" />
 
-    <chooseProject @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
+    <chooseProject :key="`project-${pageInstanceKey}`" @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
   </div>
 </template>
 
@@ -212,6 +212,9 @@
       nodeType: "", //1母代 2计划数 3子孙代
       tableData: [],
       cacheData: null,  // 👈 添加这一行
+      activeRouteKey: "",
+      graphLoadId: 0,
+      pageInstanceKey: 0,
       confirmStorageDialogVisible: false,
       storageVisible: false,
       editBoolean: false,
@@ -232,6 +235,9 @@
     };
   },
   computed: {
+    isReadOnly() {
+      return this.$route.path.includes('detail') || this.$route.query.mode === 'detail';
+    },
     canAddNode() {
       // 如果没有节点,可以新增母代
       if (this.graphData.nodes.length === 0) {
@@ -245,8 +251,7 @@
     },
   },
   mounted() {
-    this.initGraph();
-    this.initEvents();
+    this.resetMountNode();
   },
   deactivated() {
     // 缓存数据
@@ -261,11 +266,12 @@
       newTotal: this.newTotal,
       projectData: JSON.parse(JSON.stringify(this.projectData)),
       treeData: JSON.parse(JSON.stringify(this.treeData)),
-      nodeTreeStatus: this.nodeTreeStatus
+      nodeTreeStatus: this.nodeTreeStatus,
+      routeKey: this.activeRouteKey
     };
   },
   activated() {
-    if (this.cacheData) {
+    if (this.cacheData && this.cacheData.routeKey === this.$route.fullPath) {
       // 恢复数据
       this.form = JSON.parse(JSON.stringify(this.cacheData.form));
       this.graphData = JSON.parse(JSON.stringify(this.cacheData.graphData));
@@ -280,13 +286,17 @@
       this.nodeTreeStatus = this.cacheData.nodeTreeStatus || 1;
 
       // 更新图表
+      this.resetMountNode();
       if (this.graphData.nodes.length > 0) {
         this.updateGraphData();
       }
       return;
     }
+    this.cacheData = null;
     if (this.$route.query.id) {
       this.reloadData();
+    } else {
+      this.resetPageState();
     }
     if (this.$route.query.status !== undefined && this.$route.query.status != 1 && this.roleType != 1){
       this.editBoolean = true
@@ -298,22 +308,108 @@
     '$route': {
       immediate: true,
       handler(to) {
+        if (!["AddPedigree", "DetailPedigree"].includes(to.name)) {
+          return;
+        }
         console.log('变动');
+        const routeKey = to.fullPath;
+        const routeChanged = this.activeRouteKey && this.activeRouteKey !== routeKey;
+        this.activeRouteKey = routeKey;
+        if (routeChanged || !to.query.id) {
+          this.cacheData = null;
+          this.resetPageState();
+        }
         if (to.query.id) {
           this.reloadData();
         }
 
-        this.editBoolean =
-            this.roleType != 1 &&
-            to.query.status != 1;
+        this.editBoolean = this.shouldDisableEditing(to.query);
       }
     }
   },
   beforeDestroy() {
-    this.graph?.destroy();
-    window.removeEventListener("resize", this.handleResize);
+    this.destroyGraph();
   },
   methods: {
+    shouldDisableEditing(query = this.$route.query) {
+      const status = query && query.status;
+      return Number(this.roleType) !== 1
+          && status !== undefined
+          && status !== null
+          && status !== ""
+          && Number(status) !== 1;
+    },
+    destroyGraph() {
+      window.removeEventListener("resize", this.handleResize);
+      if (this.graph && !this.graph.get("destroyed")) {
+        this.graph.destroy();
+      }
+      this.graph = null;
+
+      const container = this.$refs.mountNode;
+      if (container) {
+        while (container.firstChild) {
+          container.removeChild(container.firstChild);
+        }
+      }
+    },
+    resetMountNode() {
+      this.destroyGraph();
+      if (!this.$refs.mountNode) return;
+      this.initGraph();
+      this.initEvents();
+    },
+    resetPageState() {
+      this.pageInstanceKey += 1;
+      this.form = {
+        strainSourceStart: "",
+        strainSourceEnd: "",
+        cellBank: "",
+        strainCode: "",
+        strainName: "",
+        remarks: "",
+      };
+      this.projectData = [];
+      this.tableData = [];
+      this.newTableData = [];
+      this.total = 0;
+      this.current = 1;
+      this.size = 10;
+      this.newTotal = 0;
+      this.newCurrent = 1;
+      this.newSize = 10;
+      this.queryForm = { pageSize: 10, pageNum: 1 };
+      this.newQueryForm = { pageSize: 10, pageNum: 1 };
+      this.showChoose = false;
+      this.dialogVisible = false;
+      this.confirmStorageDialogVisible = false;
+      this.storageVisible = false;
+      this.nodeData = {};
+      this.nodeType = "";
+      this.isAddingNode = false;
+      this.showDiscarded = false;
+      this.nodeTreeStatus = 1;
+      this.editBoolean = this.shouldDisableEditing();
+      this.resetGraphData();
+      this.$nextTick(() => {
+        this.$refs.pedigreeForm && this.$refs.pedigreeForm.clearValidate();
+      });
+    },
+    resetGraphData() {
+      this.graphLoadId += 1;
+      this.graphData = {
+        nodes: [],
+        edges: [],
+      };
+      this.treeData = [];
+      this.selectedNode = null;
+      this.nodeCount = 0;
+
+      if (this.graph) {
+        this.graph.changeData({ nodes: [], edges: [] });
+        this.graph.render();
+      }
+    },
     getProjectData(data) {
       this.projectData = [data]; // 将选中的项目组数据存储到数组中
       this.showChoose = false;
@@ -357,13 +453,15 @@
         );
         if (this.graphData.nodes[nodeIndex - 1].label === "子代") {
           this.$refs.addSublevelPlan.openInitData({
+            ...nodeModel.data,
             strainSourceStart: this.form.strainSourceStart,
             strainCode1: this.form.strainCode,
             strainName1: this.form.strainName,
             strainSourceEnd: this.form.strainSourceEnd,
             confirmTime: this.form.confirmTime,
             parentId: nodeModel.id,
-            formStatus: "editCount",
+            generationCount: nodeModel.data.generationCount || nodeModel.planCount,
+            formStatus: "edit",
           });
         } else {
           this.$refs.planForm.openInitData({
@@ -372,7 +470,8 @@
             strainCode1: this.form.strainCode,
             strainName1: this.form.strainName,
             ...nodeModel.data,
-            formStatus: "editCount",
+            generationCount: nodeModel.data.generationCount || nodeModel.planCount,
+            formStatus: "edit",
           });
         }
       }
@@ -551,12 +650,19 @@
       }
     },
     reloadData() {
+      this.resetPageState();
+      this.resetMountNode();
+      const graphLoadId = this.graphLoadId;
+      const routeKey = this.$route.fullPath;
       this.getList();
       this.getNewList()
       if (!this.$route.query.id) {
         return
       }
       getDetail({ id: this.$route.query.id }).then((res) => {
+        if (graphLoadId !== this.graphLoadId || routeKey !== this.$route.fullPath) {
+          return;
+        }
         const nodeMap = new Map();
         const calculateLevel = (node) => {
           if (node.parentId === "0") return 0;
@@ -628,7 +734,7 @@
           // 处理所有节点
           const processAllNodes = (nodes) => {
             nodes.forEach((node) => {
-              if (node.codeStatus == 2 || (node.codeStatus == 1 && this.roleType == 3)) {
+              if (Number(this.roleType) === 2 || node.codeStatus == 2 || (node.codeStatus == 1 && Number(this.roleType) === 3)) {
                 const processedNode = processNode(node);
                 this.graphData.nodes.push(processedNode);
 
@@ -757,7 +863,7 @@
               if (res.code == 200) {
                 this.$message.success("编辑成功");
                 this.cacheData = null;  // 👈 添加这一行
-                this.$router.back();
+                this.$closeCurrentView('/strain/pedigree-vhart');
               }
             });
             return;
@@ -766,7 +872,7 @@
             if (res.code == 200) {
               this.$message.success("保存成功");
               this.cacheData = null;
-              this.$router.back();
+              this.$closeCurrentView('/strain/pedigree-vhart');
             }
           });
         }
@@ -776,7 +882,7 @@
       // 实现存草稿逻辑
     },
     handleCancel() {
-      this.$router.back();
+      this.$closeCurrentView('/strain/pedigree-vhart');
     },
     handleSignatureConfirm(signatureImage) {
       this.confirmStorageDialogVisible = false;
@@ -803,7 +909,8 @@
       // 处理提交逻辑
     },
     initGraph() {
-      const container = document.getElementById("mountNode");
+      const container = this.$refs.mountNode;
+      if (!container) return;
       const width = container.scrollWidth;
       const height = container.scrollHeight || 600;
 
@@ -942,7 +1049,7 @@
       });
 
       this.graph = new G6.Graph({
-        container: "mountNode",
+        container,
         width,
         height,
         fitView: true,
@@ -1219,7 +1326,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);
@@ -1825,7 +1933,7 @@
     }
   }
 
-  #mountNode {
+  .mount-node {
     flex: 1;
     width: 100%;
     min-height: 500px;
diff --git a/culture/src/views/pedigree-chart/addProgenitor.vue b/culture/src/views/pedigree-chart/addProgenitor.vue
index d079324..c1a9b26 100644
--- a/culture/src/views/pedigree-chart/addProgenitor.vue
+++ b/culture/src/views/pedigree-chart/addProgenitor.vue
@@ -69,38 +69,38 @@
         <div class="header">
           <div class="title">菌种传代生产谱系图</div>
           <div class="option-btn">
-            <el-button type="primary" class="el-icon-plus" @click="addNode" :disabled="editBoolean" v-if="roleType == 3 || roleType == 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="roleType == 3 || roleType == 1" :disabled="editBoolean"
+            <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 || roleType == 3" :disabled="editBoolean">编辑</el-button>
-            <el-button type="primary" @click="handleDelete" v-if="roleType == 1 || roleType == 3" :disabled="editBoolean">删除</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>
-        <div v-if="roleType == 1 || roleType == 3">
+        <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 ref="approvalCount" @addNodeSign="sureApprovalCountSign" />
-    <chooseProject @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
+    <ApprovalCount :key="`approval-${pageInstanceKey}`" ref="approvalCount" @addNodeSign="sureApprovalCountSign" />
+    <chooseProject :key="`project-${pageInstanceKey}`" @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
   </div>
 </template>
 
@@ -195,9 +195,15 @@
         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) {
@@ -214,36 +220,108 @@
     '$route': {
       immediate: true,
       handler(to) {
+        if (!["AddProgenitor", "DetailProgenitor"].includes(to.name)) {
+          return;
+        }
         console.log('变动');
-        if (to.query.id) {
+        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.roleType != 1 &&
-            to.query.status != 1;
+        this.editBoolean = this.shouldDisableEditing(to.query);
       }
     }
   },
-  created() {
-    if (this.$route.query.status !== undefined && this.$route.query.status != 1 && this.roleType != 1){
-      this.editBoolean = true
-    }else {
-      this.editBoolean = false
-    }
+  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;
@@ -479,12 +557,22 @@
       }
     },
     async reloadData() {
+      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;
         // 设置基础表单数据
@@ -496,7 +584,7 @@
         // 递归处理节点数据,构建树形结构
         function processNode(node, parentType = null) {
           // label 逻辑与新增时保持一致
-         let roleType= JSON.parse(sessionStorage.getItem("userInfo")).roleType || 1
+         let roleType= Number(JSON.parse(sessionStorage.getItem("userInfo")).roleType || 1)
             let label = "";
             if (node.type === 2) {
               label = "传代计划数";
@@ -526,12 +614,9 @@
             }
 
             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))
+                .filter((child) => roleType === 2 || child.codeStatus == 2 || (child.codeStatus == 1 && roleType === 3))
                 .map((child) => processNode(child, node.type));
             }
             return processedNode;
@@ -641,7 +726,7 @@
             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;
@@ -649,7 +734,7 @@
           add(baseData).then((res) => {
             if (res.code == 200) {
               this.$message.success("保存成功");
-              this.$router.back();
+              this.$closeCurrentView('/strain/pedigree-vhart');
             }
           });
         }
@@ -659,7 +744,7 @@
       // 实现存草稿逻辑
     },
     handleCancel() {
-      this.$router.back();
+      this.$closeCurrentView('/strain/pedigree-vhart');
     },
     handleSignatureConfirm(signatureImage) {
       this.confirmStorageDialogVisible = false;
@@ -1204,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;
 
@@ -1336,7 +1422,7 @@
       });
 
       this.graph = new G6.Graph({
-        container: "mountNode",
+        container,
         width,
         height,
         fitView: true,
@@ -1600,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);
@@ -1757,7 +1844,7 @@
     }
   }
 
-  #mountNode {
+  .mount-node {
     flex: 1;
     width: 100%;
     min-height: 500px;
diff --git a/culture/src/views/pedigree-chart/index.vue b/culture/src/views/pedigree-chart/index.vue
index f8fabc3..6cbcc7b 100644
--- a/culture/src/views/pedigree-chart/index.vue
+++ b/culture/src/views/pedigree-chart/index.vue
@@ -81,7 +81,9 @@
         <el-table-column label="操作" width="250">
           <template slot-scope="scope">
             <el-button style="margin-right: 10px" type="text" @click="handleDetail(scope.row)">详情</el-button>
-            <el-button style="margin-right: 10px" type="text" v-if="Number(roleType) == 1" @click="handleDetail(scope.row)">编辑</el-button>
+            <el-button style="margin-right: 10px" type="text"
+              v-if="canEdit(scope.row)"
+              @click="handleEdit(scope.row)">编辑</el-button>
             <!-- 菌种超级管理员 -->
             <el-button type="text" v-if="Number(roleType) == 1" @click="handleDelete(scope.row)">删除</el-button>
           </template>
@@ -113,6 +115,7 @@
       tableData: [],
       total: 0,
       roleType: JSON.parse(sessionStorage.getItem('userInfo')).roleType || 1,  // 1.超级管理员 2.审批人 3.工程师 4.实验员
+      currentUserName: JSON.parse(sessionStorage.getItem('userInfo')).nickName || '',
       // 模拟数据
       mockListData: [],
       mockDraftData: [],
@@ -221,7 +224,14 @@
       // 实现撤销审批逻辑
     },
     handleEdit(row) {
-      // 实现编辑逻辑
+      const path = row.generationType == 1 ? '/strain/add-pedigree' : '/strain/add-progenitor';
+      this.$router.push({ path, query: { id: row.id, mode: 'edit', status: row.status } });
+    },
+    canEdit(row) {
+      if (Number(this.roleType) === 1) return true;
+      return Number(this.roleType) === 3
+        && Number(row.status) === 1
+        && row.createBy === this.currentUserName;
     },
     handleDelete(row) {
       // 实现删除逻辑
diff --git a/culture/src/views/projectList/addProject.vue b/culture/src/views/projectList/addProject.vue
index 64e6d42..b0bddcd 100644
--- a/culture/src/views/projectList/addProject.vue
+++ b/culture/src/views/projectList/addProject.vue
@@ -99,7 +99,7 @@
                         if (res.code == 200) {
                             this.$message.success('添加成功');
                             this.resetForm(); // 添加成功后重置表单
-                            this.$router.back(); // 跳转到上一个页面
+                            this.$closeCurrentView('/projectList/list');
                         }
                     }).catch(() => {
                         this.loading = false; // 失败时也关闭 loading
@@ -308,4 +308,4 @@
         width: 220px;
     }
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/culture/src/views/projectList/editProject.vue b/culture/src/views/projectList/editProject.vue
index 13fae1d..1a7817b 100644
--- a/culture/src/views/projectList/editProject.vue
+++ b/culture/src/views/projectList/editProject.vue
@@ -96,7 +96,7 @@
                     editProject(data).then(res => {
                         if (res.code == 200) {
                             this.$message.success('添加成功')
-                            this.$router.push({ name: 'ProjectList' })
+                            this.$closeCurrentView('/projectList/list')
                         }
                     })
                 }
diff --git a/culture/src/views/strain-library/breeding-record/SlantRecordDialog.vue b/culture/src/views/strain-library/breeding-record/SlantRecordDialog.vue
index 37a23b6..a2194f6 100644
--- a/culture/src/views/strain-library/breeding-record/SlantRecordDialog.vue
+++ b/culture/src/views/strain-library/breeding-record/SlantRecordDialog.vue
@@ -1,15 +1,15 @@
 <template>
-  <el-dialog :visible.sync="visible" :title="editData ? '编辑培养皿观察记录' : '新增培养皿观察记录'" width="80%" @close="handleClose">
+  <el-dialog :visible.sync="visible" :title="readOnly ? '培养皿观察记录详情' : editData ? '编辑培养皿观察记录' : '新增培养皿观察记录'" width="80%" @close="handleClose">
     <el-form :model="form" :rules="rules" ref="formRef" label-width="120px" label-position="top">
       <el-row :gutter="24">
         <el-col :span="12">
           <el-form-item label="分离菌落编号" prop="separateColonyCode">
-            <el-input :disabled="roleType!=4" v-model="form.separateColonyCode" placeholder="请输入分离菌落编号" />
+            <el-input :disabled="!editable" v-model="form.separateColonyCode" placeholder="请输入分离菌落编号" />
           </el-form-item>
         </el-col>
         <el-col :span="12">
           <el-form-item label="形状强壮度排名" prop="strength">
-            <el-input :disabled="roleType!=4" v-model="form.strength" placeholder="请输入形状强壮度排名" />
+            <el-input :disabled="!editable" v-model="form.strength" placeholder="请输入形状强壮度排名" />
           </el-form-item>
         </el-col>
       </el-row>
@@ -22,7 +22,7 @@
       </el-table-column>
       <el-table-column prop="desc" label="形态记录">
         <template #default="{ row }">
-          <el-input class="el-input-full" style="width: 100%;" :disabled="roleType!=4" v-model="row.desc" placeholder="请输入形态记录"
+          <el-input class="el-input-full" style="width: 100%;" :disabled="!editable" v-model="row.desc" placeholder="请输入形态记录"
             @blur="handleDescBlur(row)" />
         </template>
       </el-table-column>
@@ -36,7 +36,7 @@
             :http-request="options => rowHandleUpload(options, row)"
             :before-upload="file => rowBeforeUpload(file, row)"
             :show-file-list="false"
-            :disabled="roleType!=4 || row.uploading"
+            :disabled="!editable || row.uploading"
             accept="image/*"
             :auto-upload="true"
           >
@@ -48,17 +48,17 @@
                 @click.stop="handlePreview(row, img)"
               >
                 <el-image
-                  :src="img.url"
-                  :preview-src-list="row.images.map(i => i.url)"
+                  :src="getFullUrl(img.url)"
+                  :preview-src-list="row.images.map(i => getFullUrl(i.url))"
                   :initial-index="idx"
                   fit="cover"
                   style="width: 100%; height: 100%;"
                   @click.stop.native="handlePreview(row, img)"
                 />
-                <i class="el-icon-delete" v-if="roleType==4" @click.stop="rowHandleRemove(row, img, row.images.filter(f => f !== img))"></i>
+                <i class="el-icon-delete" v-if="editable" @click.stop="rowHandleRemove(row, img, row.images.filter(f => f !== img))"></i>
               </div>
               <div
-                v-if="roleType==4"
+                v-if="editable"
                 class="upload-thumb upload-btn"
                 @click.stop="triggerUpload(row.index)"
               >
@@ -74,7 +74,7 @@
         </template>
       </el-table-column>
     </el-table>
-    <div style="text-align: center;" v-if="roleType==4">
+    <div style="text-align: center;" v-if="editable">
       <el-button type="primary" @click="handleOk" :disabled="hasUploading">保存</el-button>
     </div>
   </el-dialog>
@@ -82,11 +82,15 @@
 
 <script>
 import moment from 'moment'
-import { customUploadRequest, getFullUrl } from '@/utils/utils'
+import { customUploadRequest, getFullUrl, getUploadedFilePath, normalizeFileList } from '@/utils/utils'
 export default {
   name: 'SlantRecordDialog',
   props: {
     visible: Boolean,
+    readOnly: {
+      type: Boolean,
+      default: false
+    },
     editData: {
       type: Object,
       default: null
@@ -132,7 +136,8 @@
                 index: index + 1,
                 desc: record.desc || '',
                 time: record.time || this.getNowTime(),
-                images: record.images || []
+                images: this.normalizeImages(record.images),
+                uploading: false
               }))
               while (this.tableData.length < 10) {
                 this.tableData.push({
@@ -203,6 +208,7 @@
       }
     },
     handleOk() {
+      if (!this.editable) return
       this.$refs.formRef.validate(valid => {
         if (!valid) return
 
@@ -235,8 +241,15 @@
       this.$emit('update:visible', false)
     },
     rowBeforeUpload(file, row) {
-      // 可做校验,暂时直接允许
-      return true;
+      if (!file.type || !file.type.startsWith('image/')) {
+        this.$message.error('只能上传图片文件')
+        return false
+      }
+      if (file.size > 10 * 1024 * 1024) {
+        this.$message.error('图片大小不能超过 10MB')
+        return false
+      }
+      return true
     },
     rowHandleUpload(options, row) {
       row.uploading = true;
@@ -244,10 +257,11 @@
       customUploadRequest({
         file,
         onSuccess: (res) => {
-          if (res.code === 200) {
+          const uploadedPath = getUploadedFilePath(res)
+          if (uploadedPath) {
             const fileObj = {
-              name: file.name + new Date().getTime(),
-              url: getFullUrl(res.msg || res.data || ''),
+              name: file.name,
+              url: uploadedPath,
               uid: new Date().getTime()
             };
             if (!Array.isArray(row.images)) this.$set(row, 'images', []);
@@ -256,8 +270,8 @@
             this.$message.success('文件上传成功');
             onSuccess(res);
           } else {
-            this.$message.error(res.msg || '文件上传失败');
-            onError(res);
+            this.$message.error(res && res.msg ? res.msg : '上传接口未返回文件地址');
+            onError(new Error('missing uploaded file path'));
           }
           row.uploading = false;
         },
@@ -277,21 +291,28 @@
       this.previewVisible = true
     },
     handleDescBlur(row) {
-      console.log(row)
-      if (row.desc) {
+      if (this.editable && row.desc) {
         row.time = this.getNowTime()
         this.$forceUpdate()
       }
     },
     triggerUpload(index) {
+      if (!this.editable) return
       const uploadRef = this.$refs['uploadRef' + index];
       if (uploadRef && uploadRef.$el) {
         const input = uploadRef.$el.querySelector('input[type=file]');
         if (input) input.click();
       }
+    },
+    getFullUrl,
+    normalizeImages(images) {
+      return normalizeFileList(images)
     }
   },
   computed: {
+    editable() {
+      return [1, 4].includes(Number(this.roleType)) && !this.readOnly
+    },
     hasUploading() {
       return this.tableData.some(row => row.uploading)
     }
diff --git a/culture/src/views/strain-library/breeding-record/add.vue b/culture/src/views/strain-library/breeding-record/add.vue
index 9c66f5e..f473d51 100644
--- a/culture/src/views/strain-library/breeding-record/add.vue
+++ b/culture/src/views/strain-library/breeding-record/add.vue
@@ -6,7 +6,7 @@
           <img src="@/assets/public/headercard.png" />
           <div>所属项目组</div>
         </div>
-        <div class="header-title-right">
+        <div class="header-title-right" v-if="!isReadOnly">
           <el-button @click="showChoose = true" class="el-icon-circle-plus-outline" type="primary">
             选择项目组</el-button>
         </div>
@@ -40,19 +40,19 @@
         <el-row v-if="activeTab === 'strain'" :gutter="10">
           <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
             <el-form-item label="菌株编号" prop="strainCode">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.strainCode" class="w-380"
+              <el-input :disabled="isReadOnly" v-model="form.strainCode" class="w-380"
                 placeholder="请输入菌株编号" />
             </el-form-item>
           </el-col>
           <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
             <el-form-item label="菌株名称" prop="strainName">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.strainName" class="w-380"
+              <el-input :disabled="isReadOnly" v-model="form.strainName" class="w-380"
                 placeholder="请输入菌株名称" />
             </el-form-item>
           </el-col>
           <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
             <el-form-item label="培养基配方" prop="formula">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.formula" class="w-380"
+              <el-input :disabled="isReadOnly" v-model="form.formula" class="w-380"
                 placeholder="请输入培养基配方" />
             </el-form-item>
           </el-col>
@@ -61,18 +61,18 @@
         <el-row v-if="activeTab === 'material'" :gutter="10">
           <el-col :span="24">
             <el-form-item label="来源物资、时间及批号" prop="sourceMaterialTimeBatchNumber">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.sourceMaterialTimeBatchNumber"
+              <el-input :disabled="isReadOnly" v-model="form.sourceMaterialTimeBatchNumber"
                 placeholder="请输入物资编号" />
             </el-form-item>
           </el-col>
           <el-col :span="24">
             <el-form-item label="培养基配方" prop="formula">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.formula" placeholder="请输入培养基配方" />
+              <el-input :disabled="isReadOnly" v-model="form.formula" placeholder="请输入培养基配方" />
             </el-form-item>
           </el-col>
           <el-col :span="24">
             <el-form-item label="分离菌落编号" prop="separateColonyNumber">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.separateColonyNumber"
+              <el-input :disabled="isReadOnly" v-model="form.separateColonyNumber"
                 placeholder="请输入分离菌落编号" />
             </el-form-item>
           </el-col>
@@ -86,19 +86,19 @@
         <el-row :gutter="10">
           <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
             <el-form-item label="培养基" prop="cultureMedium">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.cultureMedium" class="w-380"
+              <el-input :disabled="isReadOnly" v-model="form.cultureMedium" class="w-380"
                 placeholder="请输入培养基" />
             </el-form-item>
           </el-col>
           <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
             <el-form-item label="培养温度" prop="temperature">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.temperature" class="w-380"
+              <el-input :disabled="isReadOnly" v-model="form.temperature" class="w-380"
                 placeholder="请输入培养温度" />
             </el-form-item>
           </el-col>
           <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
             <el-form-item label="需氧类型" prop="aerobicType">
-              <el-select :disabled="!!$route.query.isDetail" v-model="form.aerobicType" class="w-380"
+              <el-select :disabled="isReadOnly" v-model="form.aerobicType" class="w-380"
                 placeholder="请选择需氧类型">
                 <el-option label="专性需氧" :value="1"></el-option>
                 <el-option label="专性厌氧" :value="2"></el-option>
@@ -109,7 +109,7 @@
           </el-col>
           <el-col :xs="24" :sm="12" :md="12" :lg="6" :xl="6">
             <el-form-item label="培养时间" prop="cultureTime">
-              <el-input :disabled="!!$route.query.isDetail" v-model="form.cultureTime" class="w-380"
+              <el-input :disabled="isReadOnly" v-model="form.cultureTime" class="w-380"
                 placeholder="请输入培养时间" />
               <!-- <el-date-picker v-model="form.cultureTime" class="w-380" placeholder="请选择培养时间" type="date" value-format="yyyy-MM-dd" /> -->
             </el-form-item>
@@ -121,7 +121,7 @@
             <div>一、培养皿分离记录</div>
           </div>
           <div class="header-title-right">
-            <el-button @click="handleAddSeparation" v-if="!$route.query.isDetail && [1, 4].includes(roleType)"
+            <el-button @click="handleAddSeparation" v-if="canEditRecord"
               class="el-icon-circle-plus-outline" type="primary">
               新增培养皿分离记录</el-button>
           </div>
@@ -139,12 +139,12 @@
             </template>
           </el-table-column>
           <el-table-column prop="createTime" label="操作时间" />
-          <el-table-column prop="address" label="操作">
-            <template slot-scope="scope" v-if="[1, 4].includes(roleType)">
+          <el-table-column prop="address" label="操作" v-if="canEditRecord">
+            <template slot-scope="scope">
               <el-button type="text" @click="handleEditSeparation(scope.row, scope.$index)"
-                v-if="!$route.query.isDetail">编辑</el-button>
+                v-if="canEditRecord">编辑</el-button>
               <el-button type="text" @click="handleDeleteSeparation(scope.$index)"
-                v-if="!$route.query.isDetail">删除</el-button>
+                v-if="canEditRecord">删除</el-button>
             </template>
           </el-table-column>
         </Table>
@@ -154,7 +154,7 @@
             <div>二、培养皿生物学形态观察记录</div>
           </div>
           <div class="header-title-right">
-            <el-button @click="handleAddObservation" v-if="!$route.query.isDetail && [1, 4].includes(roleType)"
+            <el-button @click="handleAddObservation" v-if="canEditRecord"
               class="el-icon-circle-plus-outline" type="primary">
               新增观察记录</el-button>
           </div>
@@ -169,7 +169,7 @@
               <!-- <el-button type="text" @click="handleEditObservation(scope.row)" v-if="!$route.query.isDetail">编辑</el-button> -->
               <el-button type="text" @click="handleEditObservation(scope.row)">形态记录</el-button>
               <el-button type="text" @click="handleDeleteObservation(scope.$index)"
-                v-if="!$route.query.isDetail && [1, 4].includes(roleType)">删除</el-button>
+                v-if="canEditRecord">删除</el-button>
             </template>
           </el-table-column>
         </Table>
@@ -179,7 +179,7 @@
             <div>三、接种斜面记录</div>
           </div>
           <div class="header-title-right">
-            <el-button @click="handleAddInoculation" v-if="!$route.query.isDetail && [1, 4].includes(roleType)"
+            <el-button @click="handleAddInoculation" v-if="canEditRecord"
               class="el-icon-circle-plus-outline" type="primary">
               新增斜面记录</el-button>
           </div>
@@ -215,15 +215,14 @@
             </template>
           </el-table-column>
           <el-table-column prop="preserveTime" label="入库保藏/废弃时间" />
-          <el-table-column label="操作"
-            v-if="[1, 3].includes(roleType) && $route.query.isDetail || ([4].includes(roleType))">
+          <el-table-column label="操作" v-if="canEditRecord || canEngineerConfirm">
             <template slot-scope="scope">
               <el-button type="text" @click="handleEditInoculation(scope.row, scope.$index)"
-                v-if="!$route.query.isDetail && [1, 4].includes(roleType)">编辑</el-button>
+                v-if="canEditRecord">编辑</el-button>
               <el-button type="text" @click="handleConfirmStorageClick(scope.row, scope.$index)"
-                v-if="$route.query.isDetail && [3].includes(roleType) && !scope.row.preserveSignature">确认入库</el-button>
+                v-if="canEngineerConfirm && !scope.row.preserveSignature">确认入库</el-button>
               <el-button type="text" @click="handleDeleteInoculation(scope.$index)"
-                v-if="!scope.row.preserveSignature && [4].includes(roleType)">删除</el-button>
+                v-if="canEditRecord && !scope.row.preserveSignature">删除</el-button>
             </template>
           </el-table-column>
         </Table>
@@ -233,7 +232,7 @@
             <div>四、菌种保藏记录</div>
           </div>
           <div class="header-title-right">
-            <el-button @click="handleAddPreserve" v-if="!$route.query.isDetail && [1, 4].includes(roleType)"
+            <el-button @click="handleAddPreserve" v-if="canEditRecord"
               class="el-icon-circle-plus-outline" type="primary">
               新增菌种保藏记录</el-button>
           </div>
@@ -259,22 +258,21 @@
             </template>
           </el-table-column>
           <el-table-column prop="preserveTime" label="保藏时间" />
-          <el-table-column label="操作"
-            v-if="[1, 3].includes(roleType) && $route.query.isDetail || ([4].includes(roleType))">
+          <el-table-column label="操作" v-if="canEditRecord || canEngineerConfirm">
             <template slot-scope="scope">
               <el-button type="text" @click="handleEditPreserve(scope.row, scope.$index)"
-                v-if="!$route.query.isDetail && [1, 4].includes(roleType)">编辑</el-button>
+                v-if="canEditRecord">编辑</el-button>
               <el-button type="text" @click="handleConfirmPreserve(scope.row, scope.$index)"
-                v-if="$route.query.isDetail && [3].includes(roleType) && !scope.row.preserveSignature">确认入库</el-button>
+                v-if="canEngineerConfirm && !scope.row.preserveSignature">确认入库</el-button>
               <el-button type="text" @click="handleDeletePreserve(scope.$index)"
-                v-if="!scope.row.preserveSignature && [4].includes(roleType)">删除</el-button>
+                v-if="canEditRecord && !scope.row.preserveSignature">删除</el-button>
             </template>
           </el-table-column>
         </Table>
         <!-- 弹窗组件 -->
         <SeparationRecordDialog :visible.sync="showSeparationDialog" :editData="editSeparationData"
           @confirm="handleSeparationConfirm" @close="resetSeparationEdit" />
-        <SlantRecordDialog :visible.sync="showObservationDialog" :editData="editObservationData"
+        <SlantRecordDialog :visible.sync="showObservationDialog" :editData="editObservationData" :read-only="isReadOnly"
           @ok="handleObservationConfirm" />
         <InoculationSlopeRecordDialog :visible.sync="showInoculationDialog" :editData="editInoculationData"
           @save="handleInoculationConfirm" />
@@ -284,8 +282,7 @@
           @confirm="handleConfirmStorage" />
         <ConfirmPreserveDialog :visible.sync="showConfirmPreserveDialog" :editData="editPreserveData"
           @confirm="handleConfirmPreserveSubmit" />
-        <div class="end-btn" style="margin-top: 20px;"
-          v-if="($route.query.isDetail && [4, 3].includes(roleType)) || !$route.query.isDetail && [1, 3, 4].includes(roleType)">
+        <div class="end-btn" style="margin-top: 20px;" v-if="canEditRecord">
           <el-button type="primary" v-if="[1, 4].includes(roleType)" @click="handleSubmit(1)">提交</el-button>
           <el-button v-if="[1, 4].includes(roleType)" type="primary" @click="handleSubmit(3)">同步给保藏人</el-button>
           <el-button v-if="!$route.query.isDetail && roleType != 1" type="default" @click="handleSubmit(2)">存草稿</el-button>
@@ -293,7 +290,7 @@
       </el-form>
     </Card>
 
-    <chooseProject @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
+    <chooseProject v-if="!isReadOnly" @submit="getProjectData" :show="showChoose" @close="showChoose = false"></chooseProject>
   </div>
 </template>
 <script>
@@ -401,6 +398,17 @@
     };
   },
   computed: {
+    isReadOnly() {
+      return Boolean(this.$route.query.isDetail) || Number(this.form.status) === 1
+    },
+    canEditRecord() {
+      return !this.isReadOnly && [1, 4].includes(this.roleType)
+    },
+    canEngineerConfirm() {
+      return Boolean(this.$route.query.isDetail)
+        && this.roleType === 3
+        && Number(this.form.status) === 2
+    },
     totalInoculationCount() {
       // 只统计入库(保存)
       return this.form.vaccinationSlopes
@@ -455,25 +463,32 @@
       }
     },
     ChangeTab(tab) {
-      if (!this.$route.query.id) {
-        this.activeTab = tab
-      }
+      if (this.isReadOnly) return
+      this.activeTab = tab
+      this.form.preserveSource = tab === 'strain' ? 1 : 2
     },
     async getDetail() {
-      const res = await detail({ id: this.$route.query.id })
+      const response = await detail({ id: this.$route.query.id })
+      const res = response.data || response
       if (res.preserveSource == 1) {
         this.activeTab = 'strain'
       } else {
         this.activeTab = 'material'
       }
-      res.vaccinationSlopes = res.vaccinationSlopes.map(item => {
+      res.vaccinationSlopes = (res.vaccinationSlopes || []).map(item => {
         return {
           ...item,
           handleType: item.handleType === 1 ? '保存' : '废弃'
         }
       })
-      this.form = res
-      this.projectData = res.tprojectTeamList;
+      this.form = {
+        ...this.form,
+        ...res,
+        observationOfPetriDishes: res.observationOfPetriDishes || [],
+        separationOfCultureDishesList: res.separationOfCultureDishesList || [],
+        culturePreservations: res.culturePreservations || []
+      }
+      this.projectData = res.tprojectTeamList || [];
     },
     handleSeparationConfirm(data) {
       if (this.editSeparationIndex !== null) {
@@ -535,63 +550,45 @@
       this.editPreserveData = null;
     },
     handleSubmit(type) {
-      if (this.activeTab === 'material') {
-        this.form.preserveSource = 2
-      } else {
-        this.form.preserveSource = 1
+      if (this.isReadOnly) return
+      if (type === 1) {
+        if (!this.form.id || Number(this.form.status) !== 2) {
+          this.$message.warning('请先同步给保藏人并完成入库确认')
+          return
+        }
+        const hasUnconfirmedSlope = this.form.vaccinationSlopes.some(item => !item.preserveId && !item.preserveSignature)
+        const hasUnconfirmedPreservation = this.form.culturePreservations.some(item => !item.preserveId && !item.preserveSignature)
+        if (hasUnconfirmedSlope || hasUnconfirmedPreservation) {
+          this.$message.warning('存在未确认的接种斜面或菌种保藏记录,不能提交')
+          return
+        }
       }
-
-      if (type == 1) {
-        this.form.status = 1
-      } else if (type == 3) {
-        this.form.status = 2
-      } else {
-        this.form.status = 3
-      }
-
       this.$refs.form.validate(async (valid) => {
         if (!valid) return;
         try {
-          if (this.form.vaccinationSlopes.length > 0) {
-            let arr = this.form.vaccinationSlopes
-            this.form.vaccinationSlopes = arr.map(item => {
-              return {
-                ...item,
-                handleType: item.handleType === '保存' ? 1 : 2,
-              }
-            })
+          const status = type === 1 ? 1 : type === 3 ? 2 : 3
+          const payload = {
+            ...this.form,
+            preserveSource: this.activeTab === 'material' ? 2 : 1,
+            status,
+            isDraft: status === 2 ? this.form.isDraft : 0,
+            vaccinationSlopes: (this.form.vaccinationSlopes || []).map(item => ({
+              ...item,
+              handleType: item.handleType === '保存' || item.handleType === 1 ? 1 : 2
+            }))
           }
-          console.log(this.form, this.form.isDraft);
-
-          if (this.form.id && (this.form.isDraft == 0 || this.form.isDraft == null || this.form.isDraft == 1)) {
-
-            if (this.form.status != 2) {
-              this.form.isDraft == 0
-            }
-
-            edit(this.form).then(res => {
-              if (res.code === 200) {
-                this.$message.success('编辑成功');
-                this.cacheForm = null
-                this.$router.back();
-              } else {
-                this.$message.error('编辑失败');
-              }
-            })
+          const request = payload.id ? edit(payload) : add(payload)
+          const res = await request
+          if (res.code === 200) {
+            this.$message.success(payload.id ? '编辑成功' : '添加成功')
+            this.cacheForm = null
+            this.$closeCurrentView('/strain/breeding-record')
           } else {
-            add(this.form).then(res => {
-              if (res.code === 200) {
-                this.$message.success('添加成功');
-                this.cacheForm = null
-                this.$router.back();
-              } else {
-                this.$message.error('添加失败');
-              }
-            });
+            this.$message.error(res.msg || (payload.id ? '编辑失败' : '添加失败'))
           }
 
         } catch (e) {
-          this.$message.error('添加失败');
+          this.$message.error(this.form.id ? '编辑失败' : '添加失败');
         }
       });
     },
diff --git a/culture/src/views/strain-library/breeding-record/index.vue b/culture/src/views/strain-library/breeding-record/index.vue
index edf59a4..280fd38 100644
--- a/culture/src/views/strain-library/breeding-record/index.vue
+++ b/culture/src/views/strain-library/breeding-record/index.vue
@@ -89,14 +89,14 @@
         <el-table-column prop="createTime" label="创建时间"></el-table-column>
         <el-table-column prop="status" label="状态">
           <template slot-scope="scope">
-            {{ scope.row.status === 1 ? '已提交' : scope.row.status === 2 ? '已同步' :'草稿' }}
+            {{ scope.row.status === 1 ? '已提交' : scope.row.status === 2 ? '已同步/未提交' :'草稿' }}
           </template>
         </el-table-column>
         <el-table-column label="操作" width="250">
           <template slot-scope="scope">
             <el-button  style="margin-right: 10px" type="text" @click="handleDetail(scope.row)">详情</el-button>
             <el-button  style="margin-right: 10px" type="text" @click="handleEdit(scope.row)"
-              v-if="([1,4].includes(roleType) && scope.row.status != 1)">编辑</el-button>
+              v-if="[1, 4].includes(roleType) && scope.row.status != 1">编辑</el-button>
             <el-button type="text" @click="handleDelete(scope.row)"
               v-if="[1].includes(roleType) || ([1, 4].includes(roleType) && currentType != 'list')">删除</el-button>
           </template>
diff --git a/culture/src/views/strain-library/main-cell-library/add.vue b/culture/src/views/strain-library/main-cell-library/add.vue
index af099ab..8a399a7 100644
--- a/culture/src/views/strain-library/main-cell-library/add.vue
+++ b/culture/src/views/strain-library/main-cell-library/add.vue
@@ -366,7 +366,7 @@
         this.cacheForm = null
         this.displayStrainSeq = null
         this.signatureVisible = false;
-        this.$router.push({ path: '/strain-library/main-cell-library' });
+        this.$closeCurrentView('/strain-library/main-cell-library');
         this.$message.success('操作成功');
       } catch (error) {
         this.$message.error('操作失败');
diff --git a/culture/src/views/strain-library/production-cell-grandson/add.vue b/culture/src/views/strain-library/production-cell-grandson/add.vue
index 2ad11fe..9568c8a 100644
--- a/culture/src/views/strain-library/production-cell-grandson/add.vue
+++ b/culture/src/views/strain-library/production-cell-grandson/add.vue
@@ -369,7 +369,7 @@
               this.displayStrainSeq = null
 
                 this.signatureVisible = false;
-                this.$router.push({ path: '/strain-library/production-cell-grandson' });
+                this.$closeCurrentView('/strain-library/production-cell-grandson');
                 this.$message.success('操作成功');
             } catch (error) {
                 this.$message.error('操作失败');
diff --git a/culture/src/views/strain-library/production-cell-library/add.vue b/culture/src/views/strain-library/production-cell-library/add.vue
index 71af3f5..a6df7aa 100644
--- a/culture/src/views/strain-library/production-cell-library/add.vue
+++ b/culture/src/views/strain-library/production-cell-library/add.vue
@@ -370,7 +370,7 @@
               this.displayStrainSeq = null
 
                 this.signatureVisible = false;
-                this.$router.push({ path: '/strain-library/production-cell-library' });
+                this.$closeCurrentView('/strain-library/production-cell-library');
                 this.$message.success('操作成功');
             } catch (error) {
                 this.$message.error('操作失败');
diff --git a/culture/src/views/strain-library/strain-library-manage/add.vue b/culture/src/views/strain-library/strain-library-manage/add.vue
index e59cce3..08d64ae 100644
--- a/culture/src/views/strain-library/strain-library-manage/add.vue
+++ b/culture/src/views/strain-library/strain-library-manage/add.vue
@@ -402,7 +402,7 @@
         this.cacheForm = null
         this.displayStrainSeq = null
         this.signatureVisible = false;
-        this.$router.push({ path: '/strain-library/strain-library-manage' });
+        this.$closeCurrentView('/strain-library/strain-library-manage');
         this.$message.success('操作成功');
       } catch (error) {
         this.$message.error('操作失败');
diff --git a/culture/src/views/strain-library/validation/chief-cell/DetailConditionDialog.vue b/culture/src/views/strain-library/validation/chief-cell/DetailConditionDialog.vue
index 803e2be..c430dbf 100644
--- a/culture/src/views/strain-library/validation/chief-cell/DetailConditionDialog.vue
+++ b/culture/src/views/strain-library/validation/chief-cell/DetailConditionDialog.vue
@@ -1,59 +1,52 @@
 <template>
-  <el-dialog :close-on-click-modal="false" :visible.sync="visible" width="80%" @open="handleOpen" @close="handleClose">
-    <!-- 项目组名称 - 新增 -->
-    <div class="project-header">
-      <span class="project-label">项目组:</span>
-      <span class="project-name">{{ detail.projectName }}</span>
+  <el-dialog :close-on-click-modal="false" :visible.sync="visible"
+    width="88%" top="5vh" custom-class="validation-detail-dialog" @open="handleOpen" @close="handleClose">
+    <div class="validation-overview">
+      <div class="stacked-field">
+        <span class="field-label">菌种来源</span>
+        <div class="value-box multiline-box source-box">{{ detail.strainSource || '-' }}</div>
+      </div>
+      <div class="project-header">
+        <span class="project-label">项目组:</span>
+        <span class="project-name">{{ detail.projectName || '-' }}</span>
+      </div>
+      <div class="detail-panel">
+      <div class="single-field-row">
+        <div class="inline-field code-field">
+          <span class="field-label">鉴别菌株编号</span>
+          <div class="value-box compact-box">{{ detail.identifyingStrainCode || '-' }}</div>
+        </div>
+      </div>
+      <div class="stacked-field name-field">
+        <span class="field-label">鉴别菌株名称</span>
+        <div class="value-box multiline-box">{{ detail.identifyingStrainName || '-' }}</div>
+      </div>
+      <div class="paired-fields">
+        <div class="inline-field">
+          <span class="field-label">验证实验编号</span>
+          <div class="value-box compact-box">{{ detail.validationExperimentCode || '-' }}</div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">实验时间</span>
+          <div class="value-box compact-box">{{ detail.experimentTime | formatDate }}</div>
+        </div>
+      </div>
+      <div class="paired-fields signature-row">
+        <div class="inline-field">
+          <span class="field-label">菌种实验员签字</span>
+          <div class="signature-area">
+            <el-image v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)"
+              :preview-src-list="[getFullUrl(detail.handleSignature)]" fit="contain" alt="菌种实验员签字" />
+            <span v-else class="waiting-text">暂无签名</span>
+          </div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">签字时间</span>
+          <div class="value-box compact-box">{{ detail.handleTime || '-' }}</div>
+        </div>
+      </div>
+      </div>
     </div>
-    <el-card class="top-card">
-      <el-row :gutter="24" class="top-info-row">
-        <el-col :span="6" class="info-col">
-          <div class="info-item source-item">
-            <span class="label">菌种来源:</span>
-            <el-tooltip
-              :content="detail.strainSource || '暂无数据'"
-              placement="top"
-              :disabled="!detail.strainSource || detail.strainSource.length < 30"
-              popper-class="source-tooltip"
-              effect="dark"
-          >
-            <span class="source-text">{{ detail.strainSource || '暂无数据' }}</span>
-          </el-tooltip>
-          </div>
-          <div class="info-item">
-            <span class="label">鉴别菌株编号:</span>{{ detail.identifyingStrainCode }}
-          </div>
-          <div class="info-item">
-            <span class="label">鉴别菌株名称:</span>{{ detail.identifyingStrainName }}
-          </div>
-        </el-col>
-        <el-col :span="6" class="info-col">
-          <div class="info-item">
-            <span class="label">验证实验编号:</span>{{ detail.validationExperimentCode }}
-          </div>
-          <div class="info-item">
-            <span class="label">实验时间:</span>{{ detail.experimentTime | formatDate }}
-          </div>
-          <div class="info-item"></div>
-        </el-col>
-        <el-col :span="6" class="info-col">
-          <div class="info-item sign-label">
-            <span class="label">菌种实验员签字</span>
-          </div>
-          <div class="info-item signature-item">
-            <div class="signature-area">
-              <el-image style="width: 120px;" v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)" :preview-src-list="[getFullUrl(detail.handleSignature)]" alt="签字" />
-              <span v-else class="waiting-text">暂无签名</span>
-            </div>
-          </div>
-        </el-col>
-        <el-col :span="6" class="info-col">
-          <div class="info-item">
-            <span class="label">签字时间:</span>{{ detail.handleTime }}
-          </div>
-        </el-col>
-      </el-row>
-    </el-card>
     <div class="section-card" style="margin-top: 24px">
       <el-form ref="form" label-width="100px" :model="detail" label-position="top">
         <el-form-item label="实验结论" prop="result">
@@ -149,7 +142,7 @@
       if(date){
         return moment(date).format('YYYY-MM-DD')
       }else{
-        return ''
+        return '-'
       }
     },
   },
@@ -205,141 +198,170 @@
 </script>
 
 <style scoped lang="less">
-.el-dialog__body {
-  padding-bottom: 0;
+::v-deep(.validation-detail-dialog) {
+  max-width: 1320px;
 }
 
+.validation-overview {
+  color: #303133;
+  font-size: 15px;
+}
 
-/* 项目组名称样式 - 新增 */
+.field-label {
+  display: block;
+  margin-bottom: 8px;
+  color: #606266;
+  font-weight: 600;
+  line-height: 22px;
+  white-space: nowrap;
+}
+
+.value-box {
+  min-width: 0;
+  padding: 8px 12px;
+  color: #303133;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  box-sizing: border-box;
+  line-height: 22px;
+  word-break: break-word;
+  overflow-wrap: anywhere;
+}
+
+.multiline-box {
+  min-height: 72px;
+  white-space: pre-wrap;
+}
+
+.source-box {
+  min-height: 68px;
+}
+
+.validation-overview > .stacked-field {
+  margin: 0 32px;
+}
+
+.validation-overview > .stacked-field .field-label {
+  padding-left: 112px;
+}
+
 .project-header {
   display: flex;
   align-items: center;
   justify-content: center;
-  padding: 12px 20px;
-  margin-bottom: 16px;
-  background: linear-gradient(135deg, #f0f7ff 0%, #e8f4fd 100%);
-  border: 1px solid #b3d8f0;
-  border-radius: 8px;
+  min-height: 52px;
+  padding: 10px 20px;
+  margin: 16px 0;
+  background: #f0f8fb;
+  border: 1px solid #b9dfe6;
+  border-radius: 6px;
+  box-sizing: border-box;
 
   .project-label {
+    margin: 0 8px 0 0;
+    color: #4d5965;
     font-size: 16px;
-    font-weight: 600;
-    color: #2c3e50;
-    margin-right: 8px;
   }
 
   .project-name {
+    color: #1890ff;
     font-size: 18px;
     font-weight: 700;
-    color: #1890ff;
-    letter-spacing: 1px;
+    word-break: break-word;
   }
 }
 
-.top-card {
-  margin-bottom: 0;
-  background: rgba(239, 239, 239, 1);
-  border-radius: 16px;
-}
-
-.top-info-row {
-  display: flex;
-  flex-wrap: wrap;
-  align-items: stretch;
-  // gap: 16px; // 如需列间距可取消注释
-}
-
-.info-col {
-  display: flex;
-  flex-direction: column;
-  flex: 1 1 220px;
-  min-width: 220px;
+.detail-panel {
+  padding: 24px 40px 28px;
+  background: #f3f4f6;
+  border: 1px solid #e2e6eb;
+  border-radius: 6px;
   box-sizing: border-box;
-  // margin-bottom: 16px; // 如需换行后下方留空可取消注释
 }
 
-.info-item {
+.single-field-row {
   display: flex;
-  font-size: 15px;
-  line-height: 45px;
+  padding-left: 42px;
 }
 
-.label {
-  color: #666;
-  font-weight: 500;
-  flex-shrink: 0;
-}
-
-
-// 或者直接覆盖所有 .el-tooltip__popper
-/deep/ .source-tooltip {
-  max-width: 320px !important;
-  min-width: 120px !important;
-  word-break: break-word;
-  line-height: 1.6;
-  padding: 10px 14px;
-  font-size: 13px;
-}
-
-.source-item {
-  flex: 1;
+.inline-field {
+  display: grid;
+  grid-template-columns: 150px minmax(0, 1fr);
+  column-gap: 12px;
+  align-items: center;
   min-width: 0;
 
-  .source-text {
-    flex: 1;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    color: #303133;
-    cursor: pointer;
-    padding: 0 4px;
-
-    &:hover {
-      color: #409EFF;
-    }
+  .field-label {
+    margin-bottom: 0;
   }
 }
 
-.sign-col {
+.code-field {
+  width: 100%;
+  max-width: 416px;
+  grid-template-columns: 160px minmax(0, 1fr);
+}
+
+.compact-box {
+  display: flex;
   align-items: center;
-  text-align: center;
+  min-height: 40px;
 }
 
-.sign-label {
-  justify-content: center;
+.name-field {
+  margin-top: 22px;
 }
 
-.signature-item {
-  justify-content: center;
+.name-field .field-label {
+  padding-left: 42px;
+}
+
+.paired-fields {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+  gap: 72px;
+  margin-top: 22px;
+  padding: 0 32px;
+}
+
+.time-field {
+  grid-template-columns: 100px minmax(0, 1fr);
+}
+
+.paired-fields .compact-box,
+.paired-fields .signature-area {
+  width: 100%;
+  max-width: 265px;
+}
+
+.signature-row {
+  align-items: start;
+}
+
+.signature-row .signature-area {
+  max-width: 260px;
 }
 
 .signature-area {
-  min-height: 80px;
-  min-width: 120px;
-  background: #f5f7fa;
+  width: 100%;
+  height: 72px;
+  background: #fff;
   border: 1px solid #dcdfe6;
   border-radius: 4px;
   display: flex;
   align-items: center;
   justify-content: center;
-  margin-top: 8px;
+  overflow: hidden;
 }
 
-.signature-area img {
-  max-width: 100%;
-  max-height: 100%;
-  display: block;
+.signature-area .el-image {
+  width: 100%;
+  height: 100%;
 }
 
 .waiting-text {
   color: #909399;
-  font-size: 14px;
-}
-
-.sign-time {
-  justify-content: center;
-  text-align: center;
-  color: #666;
   font-size: 14px;
 }
 
@@ -364,8 +386,37 @@
 }
 
 @media (max-width: 900px) {
-  .info-col {
-    height: auto;
+  .detail-panel {
+    padding: 20px;
+  }
+
+  .paired-fields {
+    grid-template-columns: 1fr;
+    gap: 16px;
+    padding: 0;
+  }
+}
+
+@media (max-width: 600px) {
+  .inline-field {
+    display: block;
+  }
+
+  .inline-field .field-label {
+    margin-bottom: 8px;
+  }
+
+  .single-field-row {
+    padding-left: 0;
+  }
+
+  .name-field .field-label,
+  .validation-overview > .stacked-field .field-label {
+    padding-left: 0;
+  }
+
+  .validation-overview > .stacked-field {
+    margin: 0;
   }
 }
 </style>
diff --git a/culture/src/views/strain-library/validation/chief-cell/add.vue b/culture/src/views/strain-library/validation/chief-cell/add.vue
index 9ea09e8..4df9dad 100644
--- a/culture/src/views/strain-library/validation/chief-cell/add.vue
+++ b/culture/src/views/strain-library/validation/chief-cell/add.vue
@@ -26,8 +26,8 @@
       </Table>
         <el-form :model="form" :rules="rules" ref="strainForm" label-position="top" class="strain-form">
             <div class="form-row">
-                <el-form-item label="菌种来源" prop="strainSource">
-                    <el-input type="textarea" style="width:790px;" v-model="form.strainSource" placeholder="请输入" :rows="3"></el-input>
+                <el-form-item label="菌种来源" prop="strainSource" class="full-width">
+                    <el-input type="textarea" v-model="form.strainSource" placeholder="请输入" :rows="3"></el-input>
                 </el-form-item>
             </div>
             <div class="form-row three-columns">
@@ -44,12 +44,12 @@
                     <el-input v-model="form.validationExperimentCode" placeholder="请输入"></el-input>
                 </el-form-item>
                 <el-form-item label="实验时间" prop="experimentTime">
-                    <el-date-picker :prefix-icon="' '" style="width: 290px;" v-model="form.experimentTime" type="date"
+                    <el-date-picker :prefix-icon="' '" style="width: 100%;" v-model="form.experimentTime" type="date"
                         placeholder="请选择实验时间"></el-date-picker>
                 </el-form-item>
                 <div class="form-item-placeholder"></div>
             </div>
-            <div class="end-btn" style="margin-top: 400px">
+            <div class="end-btn form-actions">
                 <el-button type="primary" @click="handleSubmit">提交</el-button>
                 <el-button @click="handleDraft" v-if="roleType != 1">存草稿</el-button>
             </div>
@@ -106,17 +106,12 @@
     activated() {
       if (this.cacheForm) {
         this.form = this.cacheForm;
+        return;
       }
 
-        if (this.$route.query.id && this.cacheForm) {
-            detail({ id: this.$route.query.id }).then(res => {
-                if (res) {
-                    // 这里根据实际接口返回字段做适配
-                    this.form = res
-                  this.projectData = res.tprojectTeamList
-                }
-            })
-        }
+      if (this.$route.query.id) {
+        this.loadDetailData();
+      }
     },
   deactivated() {
     this.cacheForm = JSON.parse(JSON.stringify(this.form));
@@ -149,33 +144,38 @@
                     // 编辑
                     edit({ ...submitData, id }).then(() => {
                       this.cacheForm = null
-                        this.$router.back();
+                        this.$closeCurrentView('/strain/validation/chief-cell');
                     });
                 } else {
                     // 新增
                     add(submitData).then(() => {
                       this.cacheForm = null
-                        this.$router.back();
+                        this.$closeCurrentView('/strain/validation/chief-cell');
                     });
                 }
             } else {
                 // 存草稿
                 add(submitData).then(() => {
                   this.cacheForm = null
-                    this.$router.back();
+                    this.$closeCurrentView('/strain/validation/chief-cell');
                 });
             }
         },
-        mounted() {
+        async loadDetailData() {
             const id = this.$route.query.id || this.$route.params.id;
-            if (id) {
-                // 编辑或详情回显
-                detail({ id }).then(res => {
-                    if (res && res.data) {
-                        // 这里根据实际接口返回字段做适配
-                        Object.assign(this.form, res.data);
-                    }
-                });
+            try {
+                const res = await detail({ id });
+                if (!res || !res.id) {
+                    throw new Error('未获取到验证资料详情');
+                }
+                this.form = { ...this.form, ...res };
+                this.projectData = Array.isArray(res.tprojectTeamList) ? res.tprojectTeamList : [];
+            } catch (error) {
+                console.error('获取母代菌种库验证资料失败:', error);
+                const message = error instanceof Error && error.message
+                    ? error.message
+                    : '获取编辑数据失败,请返回列表后重试';
+                this.$message.error(message);
             }
         }
     }
@@ -227,6 +227,10 @@
     }
 }
 
+.form-actions {
+    margin-top: 48px;
+}
+
 .strain-form {
     padding: 0 40px;
 
diff --git a/culture/src/views/strain-library/validation/chief-cell/confirm-detail.vue b/culture/src/views/strain-library/validation/chief-cell/confirm-detail.vue
index b4f95fd..ff3a6f1 100644
--- a/culture/src/views/strain-library/validation/chief-cell/confirm-detail.vue
+++ b/culture/src/views/strain-library/validation/chief-cell/confirm-detail.vue
@@ -2,8 +2,7 @@
   <Card class="confirm-detail-page">
     <el-card class="top-card">
       <el-row :gutter="24" class="top-info-row">
-        <el-col :span="8" class="info-col">
-<!--          <div class="info-item"><span class="label">菌种来源:</span>{{ detail.strainSource }}</div>-->
+        <el-col :span="24" class="info-col source-col">
           <div class="info-item source-item">
             <span class="label">菌种来源:</span>
             <el-tooltip
@@ -16,6 +15,8 @@
               <span class="source-text">{{ detail.strainSource || '暂无数据' }}</span>
             </el-tooltip>
           </div>
+        </el-col>
+        <el-col :span="8" class="info-col">
           <div class="info-item"><span class="label">鉴别菌株编号:</span>{{ detail.identifyingStrainCode }}</div>
           <div class="info-item"><span class="label">鉴别菌株名称:</span>{{ detail.identifyingStrainName }}</div>
         </el-col>
@@ -33,7 +34,7 @@
             </div>
           </div>
         </el-col>
-        <el-col :span="6" class="info-col">
+        <el-col :span="8" class="info-col">
           <div class="info-item">
             <span class="label">签字时间:</span>{{ detail.handleTime }}
           </div>
@@ -176,10 +177,17 @@
     },
     getDetail() {
       detail({id: this.$route.query.id}).then(res => {
+        const data = res.data || res
+        const purpose = Array.isArray(data.purpose)
+          ? data.purpose
+          : String(data.purpose || '').split(',').filter(Boolean).map(Number)
         this.detail = {
-          ...res,
-          handleSignature: res.handleSignature || '', // 处理签名为空的情况
-          purpose: res.purpose || [] // 处理 purpose 为空的情况
+          ...data,
+          handleSignature: data.handleSignature || '',
+          purpose
+        }
+        if (Array.isArray(data.list) && data.list.length) {
+          this.tableData = data.list.map(item => ({ ...item }))
         }
       })
     },
@@ -205,14 +213,17 @@
     handleSave() {
       this.$refs.form.validate((valid) => {
         if (valid) {
-          this.detail.list = this.tableData || []
-          this.detail.purpose = this.detail.purpose.join(',')
-          this.detail.isDraft = 0
-          confirm({...this.detail}).then(res => {
+          const payload = {
+            ...this.detail,
+            list: this.tableData || [],
+            purpose: (this.detail.purpose || []).join(','),
+            isDraft: 0
+          }
+          confirm(payload).then(res => {
             if (res.code == 200) {
               this.$message.success('保存成功');
               this.cacheForm = null
-              this.$router.back()
+              this.$closeCurrentView('/strain/validation/chief-cell')
             } else {
               this.$message.error(res.msg);
             }
diff --git a/culture/src/views/strain-library/validation/chief-cell/index.vue b/culture/src/views/strain-library/validation/chief-cell/index.vue
index 8fe3210..3bfe613 100644
--- a/culture/src/views/strain-library/validation/chief-cell/index.vue
+++ b/culture/src/views/strain-library/validation/chief-cell/index.vue
@@ -88,7 +88,7 @@
           <template #default="{ row }">
             <el-button type="text" v-if="row.status == 1 && roleType == 3"
               style="margin-right: 10px;"
-              @click="$router.push('/strain/validation/confirm-detail?id=' + row.id)">确认</el-button>
+              @click="$router.push('/strain/validation/confirm-detail-chief?id=' + row.id)">确认</el-button>
             <el-button type="text" style="margin-right: 10px;" v-if="roleType == 4"
               @click="handleDetail(row)">详情</el-button>
             <el-button type="text" style="margin-right: 10px;" v-if="roleType != 4"
@@ -224,6 +224,10 @@
       // Implement batch add logic
     },
     handleEdit(row) {
+      if (Number(this.roleType) === 1) {
+        this.$router.push({ path: "/strain/validation/confirm-detail-chief", query: { id: row.id, mode: 'edit' } });
+        return;
+      }
       this.$router.push({
         path: "/strain/validation/edit-chief-cell",
         query: {
diff --git a/culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue b/culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue
index c60dfaa..07a0c9c 100644
--- a/culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue
+++ b/culture/src/views/strain-library/validation/chief-cell/primitive-cell-detail-dialog.vue
@@ -1,65 +1,58 @@
 <template>
   <el-dialog
     :visible.sync="visible"
-    title="母代菌种库验证资料详情"
-    width="650px"
+    width="88%"
+    top="6vh"
+    custom-class="validation-simple-detail-dialog"
     :close-on-click-modal="false"
     @close="handleClose"
   >
-    <el-form label-width="120px" label-position="top" class="detail-form">
-      <el-row :gutter="24">
-        <el-col :span="12">
-          <el-form-item label="项目组名称">
-            <el-input v-model="detail.projectName" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-        <el-row :gutter="24">
-            <el-col :span="12">
-            <el-form-item label="菌种来源">
-                <el-input type="textarea" rows="6" v-model="detail.strainSource" disabled placeholder="请输入" />
-            </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row :gutter="24">
-        <el-col :span="12">
-          <el-form-item label="菌种编号">
-            <el-input v-model="detail.identifyingStrainCode" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="菌种名称">
-            <el-input v-model="detail.identifyingStrainName" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="验证实验编号">
-            <el-input v-model="detail.validationExperimentCode" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="实验时间">
-            <el-input v-model="detail.experimentTime" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-
-      </el-row>
-      <el-row :gutter="24">
-        <el-col :span="12">
-          <el-form-item label="菌种实验员签字">
-            <div class="signature-area">
-              <el-image style="width: 120px;" v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)" :preview-src-list="[getFullUrl(detail.handleSignature)]" alt="签字" />
-              <span v-else class="waiting-text">暂无签名</span>
-            </div>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="签字时间">
-            <el-input v-model="detail.handleTime" disabled />
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
+    <div class="validation-overview">
+      <div class="stacked-field">
+        <span class="field-label">菌种来源</span>
+        <div class="value-box multiline-box source-box">{{ detail.strainSource || '-' }}</div>
+      </div>
+      <div class="project-header">
+        <span class="project-label">项目组:</span>
+        <span class="project-name">{{ detail.projectName || '-' }}</span>
+      </div>
+      <div class="detail-panel">
+      <div class="single-field-row">
+        <div class="inline-field code-field">
+          <span class="field-label">鉴别菌株编号</span>
+          <div class="value-box compact-box">{{ detail.identifyingStrainCode || '-' }}</div>
+        </div>
+      </div>
+      <div class="stacked-field name-field">
+        <span class="field-label">鉴别菌株名称</span>
+        <div class="value-box multiline-box">{{ detail.identifyingStrainName || '-' }}</div>
+      </div>
+      <div class="paired-fields">
+        <div class="inline-field">
+          <span class="field-label">验证实验编号</span>
+          <div class="value-box compact-box">{{ detail.validationExperimentCode || '-' }}</div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">实验时间</span>
+          <div class="value-box compact-box">{{ detail.experimentTime || '-' }}</div>
+        </div>
+      </div>
+      <div class="paired-fields signature-row">
+        <div class="inline-field">
+          <span class="field-label">菌种实验员签字</span>
+          <div class="signature-area">
+            <el-image v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)"
+              :preview-src-list="[getFullUrl(detail.handleSignature)]" fit="contain" alt="菌种实验员签字" />
+            <span v-else class="waiting-text">暂无签名</span>
+          </div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">签字时间</span>
+          <div class="value-box compact-box">{{ detail.handleTime || '-' }}</div>
+        </div>
+      </div>
+      </div>
+    </div>
   </el-dialog>
 </template>
 
@@ -94,27 +87,174 @@
 }
 </script>
 
-<style scoped>
-.detail-form {
-  margin-top: 10px;
+<style scoped lang="less">
+::v-deep(.validation-simple-detail-dialog) {
+  max-width: 1320px;
+}
+
+.validation-overview {
+  color: #303133;
+  font-size: 15px;
+}
+.field-label {
+  display: block;
+  margin-bottom: 8px;
+  color: #606266;
+  font-weight: 600;
+  line-height: 22px;
+  white-space: nowrap;
+}
+.value-box {
+  min-width: 0;
+  padding: 8px 12px;
+  color: #303133;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  box-sizing: border-box;
+  line-height: 22px;
+  word-break: break-word;
+  overflow-wrap: anywhere;
+}
+.multiline-box {
+  min-height: 72px;
+  white-space: pre-wrap;
+}
+.source-box {
+  min-height: 68px;
+}
+.validation-overview > .stacked-field {
+  margin: 0 32px;
+}
+.validation-overview > .stacked-field .field-label {
+  padding-left: 112px;
+}
+.project-header {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-height: 52px;
+  padding: 10px 20px;
+  margin: 16px 0;
+  background: #f0f8fb;
+  border: 1px solid #b9dfe6;
+  border-radius: 6px;
+  box-sizing: border-box;
+}
+.project-label {
+  margin: 0 8px 0 0;
+  color: #4d5965;
+  font-size: 16px;
+}
+.project-name {
+  color: #1890ff;
+  font-size: 18px;
+  font-weight: 700;
+  word-break: break-word;
+}
+.detail-panel {
+  padding: 24px 40px 28px;
+  background: #f3f4f6;
+  border: 1px solid #e2e6eb;
+  border-radius: 6px;
+  box-sizing: border-box;
+}
+.single-field-row {
+  display: flex;
+  padding-left: 42px;
+}
+.inline-field {
+  display: grid;
+  grid-template-columns: 150px minmax(0, 1fr);
+  column-gap: 12px;
+  align-items: center;
+  min-width: 0;
+}
+.inline-field .field-label {
+  margin-bottom: 0;
+}
+.code-field {
+  width: 100%;
+  max-width: 416px;
+  grid-template-columns: 160px minmax(0, 1fr);
+}
+.compact-box {
+  display: flex;
+  align-items: center;
+  min-height: 40px;
+}
+.name-field {
+  margin-top: 22px;
+}
+.name-field .field-label {
+  padding-left: 42px;
+}
+.paired-fields {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+  gap: 72px;
+  margin-top: 22px;
+  padding: 0 32px;
+}
+.time-field {
+  grid-template-columns: 100px minmax(0, 1fr);
+}
+.paired-fields .compact-box,
+.paired-fields .signature-area {
+  width: 100%;
+  max-width: 265px;
+}
+.signature-row {
+  align-items: start;
+}
+.signature-row .signature-area {
+  max-width: 260px;
 }
 .signature-area {
-  min-height: 120px;
-  min-width: 240px;
-  background: #f5f7fa;
+  width: 100%;
+  height: 72px;
+  background: #fff;
   border: 1px solid #dcdfe6;
   border-radius: 4px;
   display: flex;
   align-items: center;
   justify-content: center;
+  overflow: hidden;
 }
-.signature-area img {
-  max-width: 100%;
-  max-height: 100%;
-  display: block;
+.signature-area .el-image {
+  width: 100%;
+  height: 100%;
 }
 .waiting-text {
   color: #909399;
   font-size: 14px;
 }
+@media (max-width: 900px) {
+  .detail-panel {
+    padding: 20px;
+  }
+  .paired-fields {
+    grid-template-columns: 1fr;
+    gap: 16px;
+    padding: 0;
+  }
+}
+@media (max-width: 600px) {
+  .inline-field {
+    display: block;
+  }
+  .inline-field .field-label {
+    margin-bottom: 8px;
+  }
+  .single-field-row {
+    padding-left: 0;
+  }
+  .name-field .field-label,
+  .validation-overview > .stacked-field .field-label {
+    padding-left: 0;
+  }
+  .validation-overview > .stacked-field {
+    margin: 0;
+  }
+}
 </style>
diff --git a/culture/src/views/strain-library/validation/primitive-cell/DetailConditionDialog.vue b/culture/src/views/strain-library/validation/primitive-cell/DetailConditionDialog.vue
index efa0a38..a641d82 100644
--- a/culture/src/views/strain-library/validation/primitive-cell/DetailConditionDialog.vue
+++ b/culture/src/views/strain-library/validation/primitive-cell/DetailConditionDialog.vue
@@ -1,59 +1,52 @@
 <template>
-  <el-dialog :close-on-click-modal="false" :visible.sync="visible" width="80%" @open="handleOpen" @close="handleClose">
-    <!-- 项目组名称 - 新增 -->
-    <div class="project-header">
-      <span class="project-label">项目组:</span>
-      <span class="project-name">{{ detail.projectName }}</span>
+  <el-dialog :close-on-click-modal="false" :visible.sync="visible"
+    width="88%" top="5vh" custom-class="validation-detail-dialog" @open="handleOpen" @close="handleClose">
+    <div class="validation-overview">
+      <div class="stacked-field">
+        <span class="field-label">菌种来源</span>
+        <div class="value-box multiline-box source-box">{{ detail.strainSource || '-' }}</div>
+      </div>
+      <div class="project-header">
+        <span class="project-label">项目组:</span>
+        <span class="project-name">{{ detail.projectName || '-' }}</span>
+      </div>
+      <div class="detail-panel">
+      <div class="single-field-row">
+        <div class="inline-field code-field">
+          <span class="field-label">鉴别菌株编号</span>
+          <div class="value-box compact-box">{{ detail.identifyingStrainCode || '-' }}</div>
+        </div>
+      </div>
+      <div class="stacked-field name-field">
+        <span class="field-label">鉴别菌株名称</span>
+        <div class="value-box multiline-box">{{ detail.identifyingStrainName || '-' }}</div>
+      </div>
+      <div class="paired-fields">
+        <div class="inline-field">
+          <span class="field-label">验证实验编号</span>
+          <div class="value-box compact-box">{{ detail.validationExperimentCode || '-' }}</div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">实验时间</span>
+          <div class="value-box compact-box">{{ detail.experimentTime | formatDate }}</div>
+        </div>
+      </div>
+      <div class="paired-fields signature-row">
+        <div class="inline-field">
+          <span class="field-label">菌种实验员签字</span>
+          <div class="signature-area">
+            <el-image v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)"
+              :preview-src-list="[getFullUrl(detail.handleSignature)]" fit="contain" alt="菌种实验员签字" />
+            <span v-else class="waiting-text">暂无签名</span>
+          </div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">签字时间</span>
+          <div class="value-box compact-box">{{ detail.handleTime || '-' }}</div>
+        </div>
+      </div>
+      </div>
     </div>
-    <el-card class="top-card">
-      <el-row :gutter="24" class="top-info-row">
-        <el-col :span="6" class="info-col">
-          <div class="info-item source-item">
-            <span class="label">菌种来源:</span>
-            <el-tooltip
-                :content="detail.strainSource || '暂无数据'"
-                placement="top"
-                :disabled="!detail.strainSource || detail.strainSource.length < 30"
-                popper-class="source-tooltip"
-                effect="dark"
-            >
-              <span class="source-text">{{ detail.strainSource || '暂无数据' }}</span>
-            </el-tooltip>
-          </div>
-          <div class="info-item">
-            <span class="label">鉴别菌株编号:</span>{{ detail.identifyingStrainCode }}
-          </div>
-          <div class="info-item">
-            <span class="label">鉴别菌株名称:</span>{{ detail.identifyingStrainName }}
-          </div>
-        </el-col>
-        <el-col :span="6" class="info-col">
-          <div class="info-item">
-            <span class="label">验证实验编号:</span>{{ detail.validationExperimentCode }}
-          </div>
-          <div class="info-item">
-            <span class="label">实验时间:</span>{{ detail.experimentTime | formatDate }}
-          </div>
-          <div class="info-item"></div>
-        </el-col>
-        <el-col :span="6" class="info-col">
-          <div class="info-item sign-label">
-            <span class="label">菌种实验员签字</span>
-          </div>
-          <div class="info-item signature-item">
-            <div class="signature-area">
-              <el-image style="width: 120px;" v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)" :preview-src-list="[getFullUrl(detail.handleSignature)]" alt="签字" />
-              <span v-else class="waiting-text">暂无签名</span>
-            </div>
-          </div>
-        </el-col>
-        <el-col :span="6" class="info-col">
-          <div class="info-item">
-            <span class="label">签字时间:</span>{{ detail.handleTime }}
-          </div>
-        </el-col>
-      </el-row>
-    </el-card>
     <div class="section-card" style="margin-top: 24px">
       <el-form ref="form" label-width="100px" :model="detail" label-position="top">
         <el-form-item label="实验结论" prop="result">
@@ -146,7 +139,7 @@
       if(date){
         return moment(date).format('YYYY-MM-DD')
       }else{
-        return ''
+        return '-'
       }
     },
   },
@@ -197,142 +190,170 @@
 </script>
 
 <style scoped lang="less">
-.el-dialog__body {
-  padding-bottom: 0;
+::v-deep(.validation-detail-dialog) {
+  max-width: 1320px;
 }
 
-/* 项目组名称样式 - 新增 */
+.validation-overview {
+  color: #303133;
+  font-size: 15px;
+}
+
+.field-label {
+  display: block;
+  margin-bottom: 8px;
+  color: #606266;
+  font-weight: 600;
+  line-height: 22px;
+  white-space: nowrap;
+}
+
+.value-box {
+  min-width: 0;
+  padding: 8px 12px;
+  color: #303133;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  box-sizing: border-box;
+  line-height: 22px;
+  word-break: break-word;
+  overflow-wrap: anywhere;
+}
+
+.multiline-box {
+  min-height: 72px;
+  white-space: pre-wrap;
+}
+
+.source-box {
+  min-height: 68px;
+}
+
+.validation-overview > .stacked-field {
+  margin: 0 32px;
+}
+
+.validation-overview > .stacked-field .field-label {
+  padding-left: 112px;
+}
+
 .project-header {
   display: flex;
   align-items: center;
   justify-content: center;
-  padding: 12px 20px;
-  margin-bottom: 16px;
-  background: linear-gradient(135deg, #f0f7ff 0%, #e8f4fd 100%);
-  border: 1px solid #b3d8f0;
-  border-radius: 8px;
+  min-height: 52px;
+  padding: 10px 20px;
+  margin: 16px 0;
+  background: #f0f8fb;
+  border: 1px solid #b9dfe6;
+  border-radius: 6px;
+  box-sizing: border-box;
 
   .project-label {
+    margin: 0 8px 0 0;
+    color: #4d5965;
     font-size: 16px;
-    font-weight: 600;
-    color: #2c3e50;
-    margin-right: 8px;
   }
 
   .project-name {
+    color: #1890ff;
     font-size: 18px;
     font-weight: 700;
-    color: #1890ff;
-    letter-spacing: 1px;
+    word-break: break-word;
   }
 }
 
-.top-card {
-  margin-bottom: 0;
-  min-height: 160px;
-  overflow-y: auto;
-  background: #e3e3e3;
-  border-radius: 16px;
-}
-
-.top-info-row {
-  display: flex;
-  flex-wrap: wrap;
-  align-items: stretch;
-}
-
-.info-col {
-  display: flex;
-  flex-direction: column;
-  flex: 1 1 220px;
-  min-width: 220px;
+.detail-panel {
+  padding: 24px 40px 28px;
+  background: #f3f4f6;
+  border: 1px solid #e2e6eb;
+  border-radius: 6px;
   box-sizing: border-box;
 }
 
-.info-item {
+.single-field-row {
   display: flex;
-  font-size: 15px;
-  line-height: 45px;
+  padding-left: 42px;
+}
+
+.inline-field {
+  display: grid;
+  grid-template-columns: 150px minmax(0, 1fr);
+  column-gap: 12px;
   align-items: center;
-  min-height: 45px;
-}
-
-.label {
-  color: #666;
-  font-weight: 500;
-  flex-shrink: 0;
-  white-space: nowrap;
-}
-
-.source-item {
-  flex: 1;
   min-width: 0;
 
-  .source-text {
-    flex: 1;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    color: #303133;
-    cursor: pointer;
-    padding: 0 4px;
-
-    &:hover {
-      color: #409EFF;
-    }
+  .field-label {
+    margin-bottom: 0;
   }
 }
 
-// 或者直接覆盖所有 .el-tooltip__popper
-/deep/ .source-tooltip {
-  max-width: 320px !important;
-  min-width: 120px !important;
-  word-break: break-word;
-  line-height: 1.6;
-  padding: 10px 14px;
-  font-size: 13px;
+.code-field {
+  width: 100%;
+  max-width: 416px;
+  grid-template-columns: 160px minmax(0, 1fr);
 }
 
-.sign-col {
+.compact-box {
+  display: flex;
   align-items: center;
-  text-align: center;
+  min-height: 40px;
 }
 
-.sign-label {
-  justify-content: center;
+.name-field {
+  margin-top: 22px;
 }
 
-.signature-item {
-  justify-content: center;
+.name-field .field-label {
+  padding-left: 42px;
+}
+
+.paired-fields {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+  gap: 72px;
+  margin-top: 22px;
+  padding: 0 32px;
+}
+
+.time-field {
+  grid-template-columns: 100px minmax(0, 1fr);
+}
+
+.paired-fields .compact-box,
+.paired-fields .signature-area {
+  width: 100%;
+  max-width: 265px;
+}
+
+.signature-row {
+  align-items: start;
+}
+
+.signature-row .signature-area {
+  max-width: 260px;
 }
 
 .signature-area {
-  min-height: 80px;
-  min-width: 120px;
-  background: #f5f7fa;
+  width: 100%;
+  height: 72px;
+  background: #fff;
   border: 1px solid #dcdfe6;
   border-radius: 4px;
   display: flex;
   align-items: center;
   justify-content: center;
-  margin-top: 8px;
+  overflow: hidden;
 }
 
-.signature-area img {
-  max-width: 100%;
-  max-height: 100%;
-  display: block;
+.signature-area .el-image {
+  width: 100%;
+  height: 100%;
 }
 
 .waiting-text {
   color: #909399;
-  font-size: 14px;
-}
-
-.sign-time {
-  justify-content: center;
-  text-align: center;
-  color: #666;
   font-size: 14px;
 }
 
@@ -356,17 +377,38 @@
   background-color: rgb(228, 248, 250) !important;
 }
 
-::v-deep(.source-tooltip) {
-  max-width: 320px !important;
-  word-break: break-word;
-  line-height: 1.6;
-  padding: 10px 14px;
-  font-size: 13px;
+@media (max-width: 900px) {
+  .detail-panel {
+    padding: 20px;
+  }
+
+  .paired-fields {
+    grid-template-columns: 1fr;
+    gap: 16px;
+    padding: 0;
+  }
 }
 
-@media (max-width: 900px) {
-  .info-col {
-    height: auto;
+@media (max-width: 600px) {
+  .inline-field {
+    display: block;
+  }
+
+  .inline-field .field-label {
+    margin-bottom: 8px;
+  }
+
+  .single-field-row {
+    padding-left: 0;
+  }
+
+  .name-field .field-label,
+  .validation-overview > .stacked-field .field-label {
+    padding-left: 0;
+  }
+
+  .validation-overview > .stacked-field {
+    margin: 0;
   }
 }
 </style>
diff --git a/culture/src/views/strain-library/validation/primitive-cell/add.vue b/culture/src/views/strain-library/validation/primitive-cell/add.vue
index d92ae07..13fda62 100644
--- a/culture/src/views/strain-library/validation/primitive-cell/add.vue
+++ b/culture/src/views/strain-library/validation/primitive-cell/add.vue
@@ -26,8 +26,8 @@
       </Table>
         <el-form :model="form" :rules="rules" ref="strainForm" label-position="top" class="strain-form">
             <div class="form-row">
-                <el-form-item label="菌种来源" prop="strainSource">
-                    <el-input type="textarea" style="width:790px;" v-model="form.strainSource" placeholder="请输入" :rows="3"></el-input>
+                <el-form-item label="菌种来源" prop="strainSource" class="full-width">
+                    <el-input type="textarea" v-model="form.strainSource" placeholder="请输入" :rows="3"></el-input>
                 </el-form-item>
             </div>
             <div class="form-row three-columns">
@@ -44,12 +44,12 @@
                     <el-input v-model="form.validationExperimentCode" placeholder="请输入"></el-input>
                 </el-form-item>
                 <el-form-item label="实验时间" prop="experimentTime">
-                    <el-date-picker :prefix-icon="' '" style="width: 290px;" v-model="form.experimentTime" type="date"
+                    <el-date-picker :prefix-icon="' '" style="width: 100%;" v-model="form.experimentTime" type="date"
                         placeholder="请选择实验时间"></el-date-picker>
                 </el-form-item>
                 <div class="form-item-placeholder"></div>
             </div>
-            <div class="end-btn" style="margin-top: 400px">
+            <div class="end-btn form-actions">
                 <el-button type="primary" @click="handleSubmit">提交</el-button>
                 <el-button @click="handleDraft" v-if="roleType != 1">存草稿</el-button>
             </div>
@@ -107,17 +107,12 @@
   activated() {
     if (this.cacheForm) {
       this.form = this.cacheForm;
+      return;
     }
 
-        if (this.$route.query.id && !this.cacheForm) {
-            detail({ id: this.$route.query.id }).then(res => {
-                if (res) {
-                    // 这里根据实际接口返回字段做适配
-                    this.form = res
-                    this.projectData = res.tprojectTeamList
-                }
-            })
-        }
+    if (this.$route.query.id) {
+      this.loadDetailData();
+    }
     },
   deactivated() {
     this.cacheForm = JSON.parse(JSON.stringify(this.form));
@@ -150,33 +145,38 @@
                     // 编辑
                     edit({ ...submitData, id }).then(() => {
                       this.cacheForm = null
-                        this.$router.back();
+                        this.$closeCurrentView('/strain/validation/primitive-cell');
                     });
                 } else {
                     // 新增
                     add(submitData).then(() => {
                       this.cacheForm = null
-                        this.$router.back();
+                        this.$closeCurrentView('/strain/validation/primitive-cell');
                     });
                 }
             } else {
                 // 存草稿
                 add(submitData).then(() => {
                   this.cacheForm = null
-                    this.$router.back();
+                    this.$closeCurrentView('/strain/validation/primitive-cell');
                 });
             }
         },
-        mounted() {
+        async loadDetailData() {
             const id = this.$route.query.id || this.$route.params.id;
-            if (id) {
-                // 编辑或详情回显
-                detail({ id }).then(res => {
-                    if (res && res.data) {
-                        // 这里根据实际接口返回字段做适配
-                        Object.assign(this.form, res.data);
-                    }
-                });
+            try {
+                const res = await detail({ id });
+                if (!res || !res.id) {
+                    throw new Error('未获取到验证资料详情');
+                }
+                this.form = { ...this.form, ...res };
+                this.projectData = Array.isArray(res.tprojectTeamList) ? res.tprojectTeamList : [];
+            } catch (error) {
+                console.error('获取祖代菌种库验证资料失败:', error);
+                const message = error instanceof Error && error.message
+                    ? error.message
+                    : '获取编辑数据失败,请返回列表后重试';
+                this.$message.error(message);
             }
         }
     }
@@ -228,6 +228,10 @@
     }
 }
 
+.form-actions {
+    margin-top: 48px;
+}
+
 .strain-form {
     padding: 0 40px;
 
diff --git a/culture/src/views/strain-library/validation/primitive-cell/confirm-detail.vue b/culture/src/views/strain-library/validation/primitive-cell/confirm-detail.vue
index 3fbebb7..06a82be 100644
--- a/culture/src/views/strain-library/validation/primitive-cell/confirm-detail.vue
+++ b/culture/src/views/strain-library/validation/primitive-cell/confirm-detail.vue
@@ -3,8 +3,7 @@
     <!-- 顶部信息卡片 - 优化排版 -->
     <el-card class="top-card" shadow="never">
       <el-row :gutter="24" class="top-info-row">
-        <!-- 左列:菌种来源 + 编号 + 名称 -->
-        <el-col :span="9" class="info-col">
+        <el-col :span="24" class="info-col source-col">
           <div class="info-item source-item">
             <span class="label">菌种来源:</span>
             <el-tooltip
@@ -17,6 +16,9 @@
               <span class="source-text">{{ detail.strainSource || '暂无数据' }}</span>
             </el-tooltip>
           </div>
+        </el-col>
+
+        <el-col :span="8" class="info-col">
           <div class="info-item">
             <span class="label">鉴别菌株编号:</span>
             <span class="value">{{ detail.identifyingStrainCode || '-' }}</span>
@@ -27,8 +29,7 @@
           </div>
         </el-col>
 
-        <!-- 中列:验证信息 -->
-        <el-col :span="7" class="info-col">
+        <el-col :span="8" class="info-col">
           <div class="info-item">
             <span class="label">验证实验编号:</span>
             <span class="value">{{ detail.validationExperimentCode || '-' }}</span>
@@ -43,7 +44,6 @@
           </div>
         </el-col>
 
-        <!-- 右列:签名 -->
         <el-col :span="8" class="info-col sign-col">
           <div class="sign-wrapper">
             <div class="sign-label-text">菌种实验员签字</div>
@@ -282,24 +282,26 @@
           .then(res => {
             console.log('详情数据返回:', res)
 
+            const data = res.data || res
+
             // 处理 purpose
             let purposeArray = []
-            if (res.purpose) {
-              if (typeof res.purpose === 'string') {
-                purposeArray = res.purpose.split(',').map(item => Number(item.trim())).filter(num => !isNaN(num))
-              } else if (Array.isArray(res.purpose)) {
-                purposeArray = res.purpose
+            if (data.purpose) {
+              if (typeof data.purpose === 'string') {
+                purposeArray = data.purpose.split(',').map(item => Number(item.trim())).filter(num => !isNaN(num))
+              } else if (Array.isArray(data.purpose)) {
+                purposeArray = data.purpose
               }
             }
 
             // 处理 tableData
-            const tableList = res.list && res.list.length > 0 ? res.list : this.initialTableData.map(item => ({ ...item }))
+            const tableList = data.list && data.list.length > 0 ? data.list : this.initialTableData.map(item => ({ ...item }))
 
             // 更新数据
             this.detail = {
-              ...res,
-              handleSignature: res.handleSignature || '',
-              purpose: purposeArray || []
+              ...data,
+              handleSignature: data.handleSignature || '',
+              purpose: purposeArray
             }
             this.tableData = tableList
 
@@ -344,15 +346,18 @@
     handleSave() {
       this.$refs.form.validate((valid) => {
         if (valid) {
-          this.detail.list = this.tableData || []
-          this.detail.purpose = this.detail.purpose.join(',')
-          this.detail.isDraft = 0
-          confirm({ ...this.detail }).then(res => {
+          const payload = {
+            ...this.detail,
+            list: this.tableData || [],
+            purpose: (this.detail.purpose || []).join(','),
+            isDraft: 0
+          }
+          confirm(payload).then(res => {
             if (res.code == 200) {
               this.$message.success('保存成功')
               this.cacheForm = null
               this.cacheFormtableData = null
-              this.$router.back()
+              this.$closeCurrentView('/strain/validation/primitive-cell')
             } else {
               this.$message.error(res.msg || '保存失败')
             }
@@ -367,15 +372,18 @@
     handleDraft() {
       this.$refs.form.validate((valid) => {
         if (valid) {
-          this.detail.list = this.tableData || []
-          this.detail.purpose = this.detail.purpose.join(',')
+          const payload = {
+            ...this.detail,
+            list: this.tableData || [],
+            purpose: (this.detail.purpose || []).join(',')
+          }
 
-          saveDraft({ ...this.detail }).then(res => {
+          saveDraft(payload).then(res => {
             if (res.code == 200) {
               this.$message.success('存稿成功')
               this.cacheForm = null
               this.cacheFormtableData = null
-              this.$router.back()
+              this.$closeCurrentView('/strain/validation/primitive-cell')
             } else {
               this.$message.error(res.msg || '存稿失败')
             }
diff --git a/culture/src/views/strain-library/validation/primitive-cell/index.vue b/culture/src/views/strain-library/validation/primitive-cell/index.vue
index 889a7a6..87c4cec 100644
--- a/culture/src/views/strain-library/validation/primitive-cell/index.vue
+++ b/culture/src/views/strain-library/validation/primitive-cell/index.vue
@@ -205,6 +205,10 @@
       // Implement batch add logic
     },
     handleEdit(row) {
+      if (Number(this.roleType) === 1) {
+        this.$router.push({ path: "/strain/validation/confirm-detail", query: { id: row.id, mode: 'edit' } });
+        return;
+      }
       this.$router.push({
         path: "/strain/validation/edit-primitive-cell",
         query: {
diff --git a/culture/src/views/strain-library/validation/primitive-cell/primitive-cell-detail-dialog.vue b/culture/src/views/strain-library/validation/primitive-cell/primitive-cell-detail-dialog.vue
index 2278ddb..4d3ac05 100644
--- a/culture/src/views/strain-library/validation/primitive-cell/primitive-cell-detail-dialog.vue
+++ b/culture/src/views/strain-library/validation/primitive-cell/primitive-cell-detail-dialog.vue
@@ -1,64 +1,58 @@
 <template>
   <el-dialog
     :visible.sync="visible"
-    title="祖代菌种库验证资料详情"
-    width="650px"
+    width="88%"
+    top="6vh"
+    custom-class="validation-simple-detail-dialog"
     :close-on-click-modal="false"
     @close="handleClose"
   >
-    <el-form label-width="120px" label-position="top" class="detail-form">
-      <el-row :gutter="24">
-        <el-col :span="12">
-          <el-form-item label="项目组名称">
-            <el-input v-model="detail.projectName" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-        <el-row :gutter="24">
-            <el-col :span="12">
-            <el-form-item label="菌种来源">
-                <el-input type="textarea" rows="6" v-model="detail.strainSource" disabled placeholder="请输入" />
-            </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row :gutter="24">
-        <el-col :span="12">
-          <el-form-item label="菌种编号">
-            <el-input v-model="detail.identifyingStrainCode" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="菌种名称">
-            <el-input v-model="detail.identifyingStrainName" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="验证实验编号">
-            <el-input v-model="detail.validationExperimentCode" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="实验时间">
-            <el-input v-model="detail.experimentTime" disabled placeholder="请输入" />
-          </el-form-item>
-        </el-col>
-      </el-row>
-      <el-row :gutter="24">
-        <el-col :span="12">
-          <el-form-item label="菌种实验员签字">
-            <div class="signature-area">
-              <el-image v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)" :preview-src-list="[getFullUrl(detail.handleSignature)]" alt="签字" />
-              <span v-else class="waiting-text">暂无签名</span>
-            </div>
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="签字时间">
-            <el-input v-model="detail.handleTime" disabled />
-          </el-form-item>
-        </el-col>
-      </el-row>
-    </el-form>
+    <div class="validation-overview">
+      <div class="stacked-field">
+        <span class="field-label">菌种来源</span>
+        <div class="value-box multiline-box source-box">{{ detail.strainSource || '-' }}</div>
+      </div>
+      <div class="project-header">
+        <span class="project-label">项目组:</span>
+        <span class="project-name">{{ detail.projectName || '-' }}</span>
+      </div>
+      <div class="detail-panel">
+      <div class="single-field-row">
+        <div class="inline-field code-field">
+          <span class="field-label">鉴别菌株编号</span>
+          <div class="value-box compact-box">{{ detail.identifyingStrainCode || '-' }}</div>
+        </div>
+      </div>
+      <div class="stacked-field name-field">
+        <span class="field-label">鉴别菌株名称</span>
+        <div class="value-box multiline-box">{{ detail.identifyingStrainName || '-' }}</div>
+      </div>
+      <div class="paired-fields">
+        <div class="inline-field">
+          <span class="field-label">验证实验编号</span>
+          <div class="value-box compact-box">{{ detail.validationExperimentCode || '-' }}</div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">实验时间</span>
+          <div class="value-box compact-box">{{ detail.experimentTime || '-' }}</div>
+        </div>
+      </div>
+      <div class="paired-fields signature-row">
+        <div class="inline-field">
+          <span class="field-label">菌种实验员签字</span>
+          <div class="signature-area">
+            <el-image v-if="detail.handleSignature" :src="getFullUrl(detail.handleSignature)"
+              :preview-src-list="[getFullUrl(detail.handleSignature)]" fit="contain" alt="菌种实验员签字" />
+            <span v-else class="waiting-text">暂无签名</span>
+          </div>
+        </div>
+        <div class="inline-field time-field">
+          <span class="field-label">签字时间</span>
+          <div class="value-box compact-box">{{ detail.handleTime || '-' }}</div>
+        </div>
+      </div>
+      </div>
+    </div>
   </el-dialog>
 </template>
 
@@ -93,27 +87,174 @@
 }
 </script>
 
-<style scoped>
-.detail-form {
-  margin-top: 10px;
+<style scoped lang="less">
+::v-deep(.validation-simple-detail-dialog) {
+  max-width: 1320px;
+}
+
+.validation-overview {
+  color: #303133;
+  font-size: 15px;
+}
+.field-label {
+  display: block;
+  margin-bottom: 8px;
+  color: #606266;
+  font-weight: 600;
+  line-height: 22px;
+  white-space: nowrap;
+}
+.value-box {
+  min-width: 0;
+  padding: 8px 12px;
+  color: #303133;
+  background: #fff;
+  border: 1px solid #dcdfe6;
+  border-radius: 4px;
+  box-sizing: border-box;
+  line-height: 22px;
+  word-break: break-word;
+  overflow-wrap: anywhere;
+}
+.multiline-box {
+  min-height: 72px;
+  white-space: pre-wrap;
+}
+.source-box {
+  min-height: 68px;
+}
+.validation-overview > .stacked-field {
+  margin: 0 32px;
+}
+.validation-overview > .stacked-field .field-label {
+  padding-left: 112px;
+}
+.project-header {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  min-height: 52px;
+  padding: 10px 20px;
+  margin: 16px 0;
+  background: #f0f8fb;
+  border: 1px solid #b9dfe6;
+  border-radius: 6px;
+  box-sizing: border-box;
+}
+.project-label {
+  margin: 0 8px 0 0;
+  color: #4d5965;
+  font-size: 16px;
+}
+.project-name {
+  color: #1890ff;
+  font-size: 18px;
+  font-weight: 700;
+  word-break: break-word;
+}
+.detail-panel {
+  padding: 24px 40px 28px;
+  background: #f3f4f6;
+  border: 1px solid #e2e6eb;
+  border-radius: 6px;
+  box-sizing: border-box;
+}
+.single-field-row {
+  display: flex;
+  padding-left: 42px;
+}
+.inline-field {
+  display: grid;
+  grid-template-columns: 150px minmax(0, 1fr);
+  column-gap: 12px;
+  align-items: center;
+  min-width: 0;
+}
+.inline-field .field-label {
+  margin-bottom: 0;
+}
+.code-field {
+  width: 100%;
+  max-width: 416px;
+  grid-template-columns: 160px minmax(0, 1fr);
+}
+.compact-box {
+  display: flex;
+  align-items: center;
+  min-height: 40px;
+}
+.name-field {
+  margin-top: 22px;
+}
+.name-field .field-label {
+  padding-left: 42px;
+}
+.paired-fields {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+  gap: 72px;
+  margin-top: 22px;
+  padding: 0 32px;
+}
+.time-field {
+  grid-template-columns: 100px minmax(0, 1fr);
+}
+.paired-fields .compact-box,
+.paired-fields .signature-area {
+  width: 100%;
+  max-width: 265px;
+}
+.signature-row {
+  align-items: start;
+}
+.signature-row .signature-area {
+  max-width: 260px;
 }
 .signature-area {
-  min-height: 120px;
-  min-width: 240px;
-  background: #f5f7fa;
+  width: 100%;
+  height: 72px;
+  background: #fff;
   border: 1px solid #dcdfe6;
   border-radius: 4px;
   display: flex;
   align-items: center;
   justify-content: center;
+  overflow: hidden;
 }
-.signature-area img {
-  max-width: 100%;
-  max-height: 100%;
-  display: block;
+.signature-area .el-image {
+  width: 100%;
+  height: 100%;
 }
 .waiting-text {
   color: #909399;
   font-size: 14px;
 }
+@media (max-width: 900px) {
+  .detail-panel {
+    padding: 20px;
+  }
+  .paired-fields {
+    grid-template-columns: 1fr;
+    gap: 16px;
+    padding: 0;
+  }
+}
+@media (max-width: 600px) {
+  .inline-field {
+    display: block;
+  }
+  .inline-field .field-label {
+    margin-bottom: 8px;
+  }
+  .single-field-row {
+    padding-left: 0;
+  }
+  .name-field .field-label,
+  .validation-overview > .stacked-field .field-label {
+    padding-left: 0;
+  }
+  .validation-overview > .stacked-field {
+    margin: 0;
+  }
+}
 </style>
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue
index c83f700..489bafb 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOne/add.vue
@@ -161,7 +161,7 @@
 <script>
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import { customUploadRequest, getFullUrl ,downloadFileByUrl,getAllocateIp,isImageFile} from "@/utils/utils";
+import { customUploadRequest, getFullUrl, downloadFileByUrl, getAllocateIp, getUploadedFilePath, isImageFile, normalizeFileList } from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import { add, getDetail, update } from './service'
 
@@ -255,6 +255,9 @@
     };
   },
   activated() {
+    if (!["/strainReportLibrary/add", "/strainReportLibrary/detail"].includes(this.$route.path)) {
+      return;
+    }
     if (this.cacheData) {
       // 恢复表单数据
       this.form = JSON.parse(JSON.stringify(this.cacheData.form));
@@ -285,41 +288,6 @@
         this.$nextTick(() => {
             window.scrollTo(0, 0);
         });
-
-        if (this.$route.query.id  && !this.cacheData) {
-            getDetail(this.$route.query.id).then(res => {
-                const data = res.data || res;
-
-                this.form = {
-                    ...this.form,
-                    ...data,
-                    processData: []
-                };
-
-                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])
-                    return item
-                })
-
-                this.selectedMember = [{
-                    nickName: data.experimentName,
-                    userId: data.experimentId
-                }]
-
-                this.projectData = data.projectTeam ?
-                    [{ ...data.projectTeam, staffName: data.projectTeam.staff || '' }] :
-                    [];
-
-                console.log('qwe45645664', this.tableData);
-
-
-
-            }).catch(err => {
-                this.$message.error('获取详情失败');
-            });
-        }
     },
     methods: {
       // 👇 添加这个方法
@@ -333,8 +301,8 @@
             processData: []
           };
 
-          let arr = data.evaluate.split(',')
-          this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
+          const arr = String(data.evaluate || '').split(',')
+          this.fileList = normalizeFileList(data.enclosureUrl)
           this.assessmentTable = this.assessmentTable.map((item, index) => {
             item.selectedScore = Number(arr[index])
             return item
@@ -366,11 +334,9 @@
                     // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
@@ -390,11 +356,12 @@
             customUploadRequest({
                 file,
                 onSuccess: (res) => {
-                    if (res.code === 200) {
+                    const uploadedPath = getUploadedFilePath(res)
+                    if (uploadedPath) {
                         const fileObj = {
                             id: new Date().getTime(),
                             reportId: this.$route.query.id ? this.$route.query.id : "",
-                            fileUrl: res.msg || res.data || "",
+                            fileUrl: uploadedPath,
                             reportType: 2, // 报告类型
                             fileName: file.name,
                             fileSize: file.size,
@@ -403,17 +370,15 @@
                         // 添加到文件列表显示
                         this.fileList.push({
                             name: file.name,
-                            url: getFullUrl(fileObj.fileUrl),
+                            url: fileObj.fileUrl,
                             uid: fileObj.id,
                         });
 
-                        // 添加到表单数据
-                        this.form.feasibilityReportFiles.push(fileObj);
                         this.$message.success("文件上传成功");
                         onSuccess(res);
                     }else {
-                      this.$message.error("文件上传失败");
-                      onError(res.msg);
+                      this.$message.error(res && res.msg ? res.msg : "上传接口未返回文件地址");
+                      onError(new Error('missing uploaded file path'));
                     }
                 },
                 onError: (err) => {
@@ -427,7 +392,6 @@
             const index = this.fileList.findIndex((item) => item.name === file.name);
             if (index !== -1) {
                 this.fileList.splice(index, 1);
-                this.form.feasibilityReportFiles.splice(index, 1);
             }
         },
         addData() {
@@ -460,7 +424,7 @@
                     isDraft: 0,
                     projectId: this.projectData[0].id,
                     experimentId: this.selectedMember[0].userId,
-                    enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                    enclosureUrl: JSON.stringify(this.fileList),
                     // reportCode: this.form.reportCode,
                     reportContent: this.$refs.materialEditor.getContent(),
                     reportName: this.form.reportName,
@@ -475,7 +439,7 @@
                         if (res.code == 200) {
                             this.$message.success('编辑成功');
                           this.cacheData = null;
-                          this.$router.back()
+                          this.$closeCurrentView('/strainReportLibrary/reportLibraryOne')
                         } else {
                             this.$message.error(res.msg || '编辑失败');
                             this.submitLoading = false;
@@ -489,7 +453,7 @@
                     if (res.code == 200) {
                         this.$message.success('发送成功');
                       this.cacheData = null;
-                      this.$router.push('/strainReportLibrary/reportLibraryOne');
+                      this.$closeCurrentView('/strainReportLibrary/reportLibraryOne');
                     } else {
                         this.$message.error(res.msg || '发送失败');
                         this.submitLoading = false;
@@ -511,7 +475,7 @@
                     isDraft: 1,
                     projectId: this.projectData[0].id,
                     experimentId: this.selectedMember[0].userId,
-                    enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                    enclosureUrl: JSON.stringify(this.fileList),
                     // reportCode: this.form.reportCode,
                     reportContent: this.$refs.materialEditor.getContent(),
                     reportName: this.form.reportName,
@@ -525,7 +489,8 @@
                         this.submitLoading = false;
                         if (res.code == 200) {
                             this.$message.success('编辑成功');
-                            this.$router.back()
+                            this.cacheData = null;
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryOne')
                         } else {
                             this.$message.error(res.msg || '编辑失败');
                             this.submitLoading = false;
@@ -537,7 +502,8 @@
                     this.submitLoading = false;
                     if (res.code == 200) {
                         this.$message.success('保存成功');
-                        this.$router.push('/strainReportLibrary/reportLibraryOne');
+                        this.cacheData = null;
+                        this.$closeCurrentView('/strainReportLibrary/reportLibraryOne');
                     } else {
                         this.$message.error(res.msg || '保存失败');
                         this.submitLoading = false;
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue
index 19c8c3a..aafe84d 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOne/components/approval/index.vue
@@ -1,7 +1,7 @@
 <template>
-    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false"
+    <el-dialog :title="dialogTitle" :visible.sync="visible" width="94%" @open="open" :close-on-click-modal="false"
         @close="handleClose">
-        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '50vh' : '40vh' }">
+        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '68vh' : '60vh' }">
             <!-- 左侧审批内容 -->
             <div class="approval-content">
                 <Card class="approval-content-card">
@@ -64,10 +64,8 @@
                                 </div>
                             </div>
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList" :disabled="roleType == 2" list-type="text"
-                                    :before-upload="beforeUpload" :on-preview="handlePreview">
-                                    <el-button size="small" type="primary" v-if="roleType != 2">点击上传</el-button>
-                                    <div slot="tip" class="el-upload__tip">支持 Word、Excel 和所有图片格式,禁止 PPT、PDF、CAJ</div>
+                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :on-preview="handlePreview">
+                                    <span v-if="!fileList.length">暂无附件</span>
                                 </el-upload>
                             </el-form-item>
 
@@ -160,7 +158,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
-import { getAllocateIp, downloadFileByUrl, isImageFile } from '@/utils/utils';
+import { getAllocateIp, getFullUrl, downloadFileByUrl, isImageFile, normalizeFileList } from '@/utils/utils';
 
 
 export default {
@@ -276,9 +274,9 @@
                     processData: []
                 };
 
-                let arr = data.evaluate.split(',')
+                const arr = String(data.evaluate || '').split(',')
 
-                this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
+                this.fileList = normalizeFileList(data.enclosureUrl)
 
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
@@ -433,11 +431,9 @@
                   // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOne/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOne/index.vue
index bae629c..726e5f5 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOne/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOne/index.vue
@@ -77,9 +77,9 @@
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status == 2 && [1, 2].includes(roleType)"
                             @click="handleEvaluate(row)">评定</el-button>
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status != 1 || roleType == 3" @click="viewDetail(row)">详情</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && (row.status == 4 || isDraft)"
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && (row.status == 4 || isDraft))"
                             @click="handleDetail(row)">编辑</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && isDraft" @click="handleDelete(row)">删除</el-button>
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && isDraft)" @click="handleDelete(row)">删除</el-button>
                         <el-button type="text"  v-if="row.status == 1 && roleType == 3&&!isDraft"
                             @click="handleRevoke(row)">撤销审批</el-button>
                     </template>
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOneFour/add.vue
index 27a4cb9..8bf64b0 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 ,downloadFileByUrl,getAllocateIp,isImageFile} from "@/utils/utils";
+import { customUploadRequest, getFullUrl, downloadFileByUrl, getAllocateIp, getUploadedFilePath, isImageFile, normalizeFileList } from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import { add, getDetail, update } from './service'
 
@@ -246,6 +246,9 @@
     },
   // 👇 添加这两个钩子
   activated() {
+    if (!["/strainReportLibrary/addFour", "/strainReportLibrary/detailFour"].includes(this.$route.path)) {
+      return;
+    }
     if (this.cacheData) {
       // 恢复表单数据
       this.form = JSON.parse(JSON.stringify(this.cacheData.form));
@@ -288,44 +291,6 @@
         this.$nextTick(() => {
             window.scrollTo(0, 0);
         });
-      if (this.$route.query.id && !this.cacheData) {
-            getDetail(this.$route.query.id).then(res => {
-                const data = res.data || res;
-                this.form = {
-                    ...this.form,
-                    ...data,
-                    processData: []
-                };
-
-              // 添加空值判断
-              let arr = [];
-              if (data.evaluate) {
-                arr = data.evaluate.split(',');
-              } else {
-                // 如果 evaluate 为空,使用默认值(根据你的 assessmentTable 长度)
-                arr = this.assessmentTable.map(() => 0);
-              }
-
-                this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
-                this.assessmentTable = this.assessmentTable.map((item, index) => {
-                  item.selectedScore = Number(arr[index] ?? 0);
-                    return item
-                })
-
-                this.selectedMember = [{
-                    nickName: data.experimentName,
-                    userId: data.experimentId
-                }]
-
-                this.projectData = data.projectTeam ?
-                    [{ ...data.projectTeam, staffName: data.projectTeam.staff || '' }] :
-                    [];
-
-
-            }).catch(err => {
-                this.$message.error('获取详情失败');
-            });
-        }
     },
     methods: {
       // 👇 添加这个方法
@@ -345,7 +310,7 @@
             arr = this.assessmentTable.map(() => 0);
           }
 
-          this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : []);
+          this.fileList = normalizeFileList(data.enclosureUrl);
 
           this.assessmentTable = this.assessmentTable.map((item, index) => {
             item.selectedScore = Number(arr[index] ?? 0);
@@ -378,11 +343,9 @@
                     // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
@@ -429,11 +392,12 @@
             customUploadRequest({
                 file,
                 onSuccess: (res) => {
-                    if (res.code === 200) {
+                    const uploadedPath = getUploadedFilePath(res)
+                    if (uploadedPath) {
                         const fileObj = {
                             id: new Date().getTime(),
                             reportId: this.$route.query.id ? this.$route.query.id : "",
-                            fileUrl: res.msg || res.data || "",
+                            fileUrl: uploadedPath,
                             reportType: 2, // 报告类型
                             fileName: file.name,
                             fileSize: file.size,
@@ -442,14 +406,15 @@
                         // 添加到文件列表显示
                         this.fileList.push({
                             name: file.name,
-                            url: getFullUrl(fileObj.fileUrl),
+                            url: fileObj.fileUrl,
                             uid: fileObj.id,
                         });
 
-                        // 添加到表单数据
-                        this.form.feasibilityReportFiles.push(fileObj);
                         this.$message.success("文件上传成功");
                         onSuccess(res);
+                    } else {
+                        this.$message.error(res && res.msg ? res.msg : "上传接口未返回文件地址");
+                        onError(new Error('missing uploaded file path'));
                     }
                 },
                 onError: (err) => {
@@ -463,7 +428,6 @@
             const index = this.fileList.findIndex((item) => item.name === file.name);
             if (index !== -1) {
                 this.fileList.splice(index, 1);
-                this.form.feasibilityReportFiles.splice(index, 1);
             }
         },
         async addData() {
@@ -496,7 +460,7 @@
                         isDraft: 0,
                         projectId: this.projectData[0].id,
                         // experimentId: this.selectedMember[0].userId,
-                        enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                        enclosureUrl: JSON.stringify(this.fileList),
                         // reportCode: this.form.reportCode,
                         reportContent: this.$refs.materialEditor.getContent(),
                         reportName: this.form.reportName,
@@ -511,7 +475,7 @@
                             if (res.code == 200) {
                                 this.$message.success('编辑成功');
                               this.cacheData = null;  // 👈 添加这一行
-                                this.$router.back()
+                                this.$closeCurrentView('/strainReportLibrary/reportLibraryFour')
                             }
                         }).catch(() => {
                             this.submitLoading = false;
@@ -523,7 +487,7 @@
                         if (res.code == 200) {
                             this.$message.success('发送成功');
                           this.cacheData = null;  // 👈 添加这一行
-                            this.$router.push('/strainReportLibrary/reportLibraryFour');
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryFour');
                         }
                     }).catch(() => {
                         this.submitLoading = false;
@@ -548,7 +512,7 @@
                             isDraft: 1,
                             projectId: this.projectData[0].id,
                             // experimentId: this.selectedMember[0].userId,
-                            enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                            enclosureUrl: JSON.stringify(this.fileList),
                             // reportCode: this.form.reportCode,
                             reportContent: this.$refs.materialEditor.getContent(),
                             reportName: this.form.reportName,
@@ -563,7 +527,7 @@
                                 if (res.code == 200) {
                                     this.$message.success('编辑成功');
                                   this.cacheData = null;  // 👈 添加这一行
-                                    this.$router.back()
+                                    this.$closeCurrentView('/strainReportLibrary/reportLibraryFour')
                                 }
                             }).catch(() => {
                                 this.submitLoading = false;
@@ -575,7 +539,7 @@
                             if (res.code == 200) {
                                 this.$message.success('保存成功');
                               this.cacheData = null;  // 👈 添加这一行
-                                this.$router.push('/strainReportLibrary/reportLibraryFour');
+                                this.$closeCurrentView('/strainReportLibrary/reportLibraryFour');
                             }
                         }).catch(() => {
                             this.draftLoading = false;
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue
index 87c46e8..e8b562a 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneFour/components/approval/index.vue
@@ -1,7 +1,7 @@
 <template>
-    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false"
+    <el-dialog :title="dialogTitle" :visible.sync="visible" width="94%" @open="open" :close-on-click-modal="false"
         @close="handleClose">
-        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '50vh' : '40vh' }">
+        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '68vh' : '60vh' }">
             <!-- 左侧审批内容 -->
             <div class="approval-content">
                 <Card class="approval-content-card">
@@ -58,9 +58,8 @@
                             </el-form-item>
 
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :before-upload="beforeUpload" :on-preview="handlePreview">
-                                    <el-button size="small" type="primary" v-if="roleType != 2">点击上传</el-button>
-                                    <div slot="tip" class="el-upload__tip">支持 Word、Excel 和所有图片格式,禁止 PPT、PDF、CAJ</div>
+                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :on-preview="handlePreview">
+                                    <span v-if="!fileList.length">暂无附件</span>
                                 </el-upload>
                             </el-form-item>
 
@@ -144,7 +143,7 @@
         </div>
         <div slot="footer" class="dialog-footer">
             <el-button @click="handleClose">{{ obj.isDetail ? '关闭' : '取 消' }}</el-button>
-            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
+            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">审核</el-button>
         </div>
     </el-dialog>
 </template>
@@ -153,7 +152,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
-import { getAllocateIp, downloadFileByUrl, isImageFile } from '@/utils/utils';
+import { getAllocateIp, getFullUrl, downloadFileByUrl, isImageFile, normalizeFileList } from '@/utils/utils';
 
 
 export default {
@@ -292,11 +291,9 @@
                     // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
@@ -319,7 +316,7 @@
                 };
 
                 let arr = (data.evaluate || '').split(',')
-                this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
+                this.fileList = normalizeFileList(data.enclosureUrl)
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
                     return item
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneFour/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneFour/index.vue
index 6d0a6df..fa9ac06 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneFour/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneFour/index.vue
@@ -76,9 +76,9 @@
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status == 2 && [1, 2].includes(roleType)"
                             @click="handleEvaluate(row)">评定</el-button>
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status != 1 || roleType == 3" @click="viewDetail(row)">详情</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && row.status == 4 || isDraft"
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && (row.status == 4 || isDraft))"
                             @click="handleDetail(row)">编辑</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && isDraft" @click="handleDelete(row)">删除</el-button>
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && isDraft)" @click="handleDelete(row)">删除</el-button>
                         <el-button type="text" v-if="row.status == 1 && roleType == 3&&!isDraft"
                             @click="handleRevoke(row)">撤销审批</el-button>
                     </template>
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue
index 1596c64..ef4830c 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/add.vue
@@ -159,7 +159,7 @@
 <script>
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import {customUploadRequest, downloadFileByUrl, getAllocateIp, getFullUrl, isImageFile} from "@/utils/utils";
+import { customUploadRequest, downloadFileByUrl, getAllocateIp, getFullUrl, getUploadedFilePath, isImageFile, normalizeFileList } from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import {add, getDetail, update} from './service'
 
@@ -244,6 +244,9 @@
     },
   // 👇 添加这两个钩子
   activated() {
+    if (!["/strainReportLibrary/addTwo", "/strainReportLibrary/detailTwo"].includes(this.$route.path)) {
+      return;
+    }
     if (this.cacheData) {
       // 恢复表单数据
       this.form = JSON.parse(JSON.stringify(this.cacheData.form));
@@ -285,45 +288,6 @@
         this.$nextTick(() => {
             window.scrollTo(0, 0);
         });
-      if (this.$route.query.id && !this.cacheData) {
-            getDetail(this.$route.query.id).then(res => {
-                const data = res.data || res;
-                this.form = {
-                    ...this.form,
-                    ...data,
-                    processData: []
-                };
-
-              // 添加空值判断
-              let arr = [];
-              if (data.evaluate) {
-                arr = data.evaluate.split(',');
-              } else {
-                // 如果 evaluate 为空,使用默认值(根据你的 assessmentTable 长度)
-                arr = this.assessmentTable.map(() => 0);
-              }
-
-                this.selectedMember = [{
-                    nickName: data.experimentName,
-                    userId: data.experimentId
-                }]
-                this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
-
-              this.assessmentTable = this.assessmentTable.map((item, index) => {
-                item.selectedScore = Number(arr[index] ?? 0);
-                return item;
-              });
-
-                this.projectData = data.projectTeam ?
-                    [{ ...data.projectTeam, staffName: data.projectTeam.staff || '' }] :
-                    [];
-
-
-            }).catch(err => {
-              console.log(err)
-                this.$message.error('获取详情失败');
-            });
-        }
     },
     methods: {
       // 👇 添加这个方法
@@ -348,7 +312,7 @@
             nickName: data.experimentName,
             userId: data.experimentId
           }];
-          this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : []);
+          this.fileList = normalizeFileList(data.enclosureUrl);
 
           this.assessmentTable = this.assessmentTable.map((item, index) => {
             item.selectedScore = Number(arr[index] ?? 0);
@@ -377,11 +341,9 @@
           // 图片文件:使用 window.open 预览
           if (file.url && file.url.startsWith('http')) {
             console.log('图片链接', file.url)
-            window.open(file.url, '_blank');
+            window.open(getFullUrl(file.url), '_blank');
           } else {
-            let newUrl = getAllocateIp() + file.url;
-            console.log('图片链接', newUrl)
-            window.open(newUrl, '_blank');
+            window.open(getFullUrl(file.url), '_blank');
           }
         } else {
           // 非图片文件:使用下载方式
@@ -427,11 +389,12 @@
             customUploadRequest({
                 file,
                 onSuccess: (res) => {
-                    if (res.code === 200) {
+                    const uploadedPath = getUploadedFilePath(res)
+                    if (uploadedPath) {
                         const fileObj = {
                             id: new Date().getTime(),
                             reportId: this.$route.query.id ? this.$route.query.id : "",
-                            fileUrl: res.msg || res.data || "",
+                            fileUrl: uploadedPath,
                             reportType: 2, // 报告类型
                             fileName: file.name,
                             fileSize: file.size,
@@ -440,14 +403,15 @@
                         // 添加到文件列表显示
                         this.fileList.push({
                             name: file.name,
-                            url: getFullUrl(fileObj.fileUrl),
+                            url: fileObj.fileUrl,
                             uid: fileObj.id,
                         });
 
-                        // 添加到表单数据
-                        this.form.feasibilityReportFiles.push(fileObj);
                         this.$message.success("文件上传成功");
                         onSuccess(res);
+                    } else {
+                        this.$message.error(res && res.msg ? res.msg : "上传接口未返回文件地址");
+                        onError(new Error('missing uploaded file path'));
                     }
                 },
                 onError: (err) => {
@@ -461,7 +425,6 @@
             const index = this.fileList.findIndex((item) => item.name === file.name);
             if (index !== -1) {
                 this.fileList.splice(index, 1);
-                this.form.feasibilityReportFiles.splice(index, 1);
             }
         },
 
@@ -497,7 +460,7 @@
                     isDraft: 0,
                     projectId: this.projectData[0].id,
                     // experimentId: this.selectedMember[0].userId,
-                    enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                    enclosureUrl: JSON.stringify(this.fileList),
                     // reportCode: this.form.reportCode,
                     reportContent: this.$refs.materialEditor.getContent(),
                     reportName: this.form.reportName,
@@ -512,8 +475,8 @@
                         this.loading = false;
                         if (res.code == 200) {
                             this.$message.success('编辑成功');
-                            this.$router.back()
-                          this.cacheData = null;
+                            this.cacheData = null;
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryTwo')
                         } else {
                             this.$message.error(res.message || '编辑失败');
                         }
@@ -528,8 +491,8 @@
                     this.loading = false;
                     if (res.code == 200) {
                         this.$message.success('发送成功');
-                        this.$router.back()
-                      this.cacheData = null;
+                        this.cacheData = null;
+                        this.$closeCurrentView('/strainReportLibrary/reportLibraryTwo')
                     } else {
                         this.$message.error(res.message || '发送失败');
                     }
@@ -557,7 +520,7 @@
                         isDraft: 1,
                         projectId: this.projectData[0].id,
                         // experimentId: this.selectedMember[0].userId,
-                        enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                        enclosureUrl: JSON.stringify(this.fileList),
                         // reportCode: this.form.reportCode,
                         reportContent: this.$refs.materialEditor.getContent(),
                         reportName: this.form.reportName,
@@ -571,7 +534,8 @@
                             this.loading = false;
                             if (res.code == 200) {
                                 this.$message.success('编辑成功');
-                                this.$router.back()
+                                this.cacheData = null;
+                                this.$closeCurrentView('/strainReportLibrary/reportLibraryTwo')
                             } else {
                                 this.$message.error(res.message || '编辑失败');
                             }
@@ -586,7 +550,8 @@
                         this.loading = false;
                         if (res.code == 200) {
                             this.$message.success('保存成功');
-                            this.$router.back()
+                            this.cacheData = null;
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryTwo')
                         } else {
                             this.$message.error(res.message || '保存失败');
                         }
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue
index 50bacef..b6547e2 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/components/approval/index.vue
@@ -1,7 +1,7 @@
 <template>
-    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false"
+    <el-dialog :title="dialogTitle" :visible.sync="visible" width="94%" @open="open" :close-on-click-modal="false"
         @close="handleClose">
-        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '50vh' : '40vh' }">
+        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '68vh' : '60vh' }">
             <!-- 左侧审批内容 -->
             <div class="approval-content">
                 <Card class="approval-content-card">
@@ -64,9 +64,8 @@
                                 </div>
                             </div>
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList" :disabled="roleType == 2" :before-upload="beforeUpload" :on-preview="handlePreview">
-                                    <el-button size="small" type="primary" v-if="roleType != 2">点击上传</el-button>
-                                    <div slot="tip" class="el-upload__tip">支持 Word、Excel 和所有图片格式,禁止 PPT、PDF、CAJ</div>
+                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :on-preview="handlePreview">
+                                    <span v-if="!fileList.length">暂无附件</span>
                                 </el-upload>
                             </el-form-item>
 
@@ -159,7 +158,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
-import { getAllocateIp, downloadFileByUrl, isImageFile } from '@/utils/utils';
+import { getAllocateIp, getFullUrl, downloadFileByUrl, isImageFile, normalizeFileList } from '@/utils/utils';
 
 
 export default {
@@ -297,11 +296,9 @@
                     // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
@@ -324,7 +321,7 @@
                 };
 
                 let arr = (data.evaluate || '').split(',')
-                this.fileList = data.enclosureUrl ? JSON.parse(data.enclosureUrl) : []
+                this.fileList = normalizeFileList(data.enclosureUrl)
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
                     return item
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/index.vue
index a788eba..ccf74d0 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneTWO/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneTWO/index.vue
@@ -76,9 +76,9 @@
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status == 2 && [1, 2].includes(roleType)"
                             @click="handleEvaluate(row)">评定</el-button>
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status != 1 || roleType == 3" @click="viewDetail(row)">详情</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && row.status == 4  || isDraft"
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && (row.status == 4 || isDraft))"
                             @click="handleDetail(row)">编辑</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && isDraft" @click="handleDelete(row)">删除</el-button>
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && isDraft)" @click="handleDelete(row)">删除</el-button>
                         <el-button type="text"  v-if="row.status == 1 && roleType == 3&&!isDraft"
                             @click="handleRevoke(row)">撤销审批</el-button>
                     </template>
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue b/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue
index 4e07538..6e53e37 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneThree/add.vue
@@ -158,7 +158,7 @@
 <script>
 import AiEditor from '@/components/AiEditor'
 import ChooseProject from '@/components/chooseProject/index.vue'
-import {customUploadRequest, downloadFileByUrl, getAllocateIp, getFullUrl, isImageFile} from "@/utils/utils";
+import { customUploadRequest, downloadFileByUrl, getAllocateIp, getFullUrl, getUploadedFilePath, isImageFile, normalizeFileList } from "@/utils/utils";
 import SelectMember from '@/components/SelectMember'
 import {add, getDetail, update} from './service'
 
@@ -244,6 +244,9 @@
     },
   // 👇 添加这两个钩子
   activated() {
+    if (!["/strainReportLibrary/addThree", "/strainReportLibrary/detailThree"].includes(this.$route.path)) {
+      return;
+    }
     if (this.cacheData) {
       // 恢复表单数据
       this.form = JSON.parse(JSON.stringify(this.cacheData.form));
@@ -285,43 +288,6 @@
         this.$nextTick(() => {
             window.scrollTo(0, 0);
         });
-      if (this.$route.query.id && !this.cacheData) {
-            getDetail(this.$route.query.id).then(res => {
-                const data = res.data || res;
-                this.form = {
-                    ...this.form,
-                    ...data,
-                    processData: []
-                };
-
-              // 添加空值判断
-              let arr = [];
-              if (data.evaluate) {
-                arr = data.evaluate.split(',');
-              } else {
-                // 如果 evaluate 为空,使用默认值(根据你的 assessmentTable 长度)
-                arr = this.assessmentTable.map(() => 0);
-              }
-
-                this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
-
-                this.assessmentTable = this.assessmentTable.map((item, index) => {
-                  item.selectedScore = Number(arr[index] ?? 0);
-                    return item
-                })
-                this.selectedMember = [{
-                    nickName: data.experimentName,
-                    userId: data.experimentId
-                }]
-                this.projectData = data.projectTeam ?
-                    [{ ...data.projectTeam, staffName: data.projectTeam.staff || '' }] :
-                    [];
-
-
-            }).catch(err => {
-                this.$message.error('获取详情失败');
-            });
-        }
     },
     methods: {
       // 👇 添加这个方法
@@ -341,7 +307,7 @@
             arr = this.assessmentTable.map(() => 0);
           }
 
-          this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : []);
+          this.fileList = normalizeFileList(data.enclosureUrl);
 
           this.assessmentTable = this.assessmentTable.map((item, index) => {
             item.selectedScore = Number(arr[index] ?? 0);
@@ -374,11 +340,9 @@
                     // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
@@ -424,11 +388,12 @@
             customUploadRequest({
                 file,
                 onSuccess: (res) => {
-                    if (res.code === 200) {
+                    const uploadedPath = getUploadedFilePath(res)
+                    if (uploadedPath) {
                         const fileObj = {
                             id: new Date().getTime(),
                             reportId: this.$route.query.id ? this.$route.query.id : "",
-                            fileUrl: res.msg || res.data || "",
+                            fileUrl: uploadedPath,
                             reportType: 2, // 报告类型
                             fileName: file.name,
                             fileSize: file.size,
@@ -437,14 +402,15 @@
                         // 添加到文件列表显示
                         this.fileList.push({
                             name: file.name,
-                            url: getFullUrl(fileObj.fileUrl),
+                            url: fileObj.fileUrl,
                             uid: fileObj.id,
                         });
 
-                        // 添加到表单数据
-                        this.form.feasibilityReportFiles.push(fileObj);
                         this.$message.success("文件上传成功");
                         onSuccess(res);
+                    } else {
+                        this.$message.error(res && res.msg ? res.msg : "上传接口未返回文件地址");
+                        onError(new Error('missing uploaded file path'));
                     }
                 },
                 onError: (err) => {
@@ -458,7 +424,6 @@
             const index = this.fileList.findIndex((item) => item.name === file.name);
             if (index !== -1) {
                 this.fileList.splice(index, 1);
-                this.form.feasibilityReportFiles.splice(index, 1);
             }
         },
         addData() {
@@ -492,7 +457,7 @@
                     isDraft: 0,
                     projectId: this.projectData[0].id,
                     // experimentId: this.selectedMember[0].userId,
-                    enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                    enclosureUrl: JSON.stringify(this.fileList),
                     // reportCode: this.form.reportCode,
                     reportContent: this.$refs.materialEditor.getContent(),
                     reportName: this.form.reportName,
@@ -508,7 +473,7 @@
                         if (res.code == 200) {
                           this.cacheData = null
                             this.$message.success('编辑成功');
-                            this.$router.back()
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryThree')
                         } else {
                             this.$message.error(res.msg || '编辑失败');
                         }
@@ -526,7 +491,7 @@
                         if (res.code == 200) {
                           this.cacheData = null
                             this.$message.success('编辑成功');
-                            this.$router.back()
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryThree')
                           this.cacheData = null;
                         }
                     }).catch(() => {
@@ -539,7 +504,7 @@
                     if (res.code == 200) {
                       this.cacheData = null
                         this.$message.success('发送成功');
-                        this.$router.push('/strainReportLibrary/reportLibraryThree');
+                        this.$closeCurrentView('/strainReportLibrary/reportLibraryThree');
                       this.cacheData = null;
                     } else {
                         this.$message.error(res.msg || '发送失败');
@@ -571,7 +536,7 @@
                         isDraft: 1,
                         projectId: this.projectData[0].id,
                         // experimentId: this.selectedMember[0].userId,
-                        enclosureUrl: this.fileList.length && JSON.stringify(this.fileList),
+                        enclosureUrl: JSON.stringify(this.fileList),
                         // reportCode: this.form.reportCode,
                         reportContent: this.$refs.materialEditor.getContent(),
                         reportName: this.form.reportName,
@@ -585,7 +550,7 @@
                       if (res.code == 200) {
                         this.cacheData = null
                             this.$message.success('保存成功');
-                            this.$router.back()
+                            this.$closeCurrentView('/strainReportLibrary/reportLibraryThree')
                         } else {
                           console.log('接口报错', res.msg);
                             this.$message.error(res.msg || '保存失败');
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue
index 694f448..61602e3 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneThree/components/approval/index.vue
@@ -1,7 +1,7 @@
 <template>
-    <el-dialog :title="dialogTitle" :visible.sync="visible" width="80%" @open="open" po :close-on-click-modal="false"
+    <el-dialog :title="dialogTitle" :visible.sync="visible" width="94%" @open="open" :close-on-click-modal="false"
         @close="handleClose">
-        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '50vh' : '40vh' }">
+        <div class="approval-dialog" :style="{ height: obj?.isDetail ? '68vh' : '60vh' }">
             <!-- 左侧审批内容 -->
             <div class="approval-content">
                 <Card class="approval-content-card">
@@ -64,9 +64,8 @@
                                 </div>
                             </div>
                             <el-form-item prop="name" style="margin-top: 38px">
-                                <el-upload action="#" :file-list="fileList" :disabled="roleType == 2" :before-upload="beforeUpload" :on-preview="handlePreview">
-                                    <el-button size="small" type="primary" v-if="roleType != 2">点击上传</el-button>
-                                    <div slot="tip" class="el-upload__tip">支持 Word、Excel 和所有图片格式,禁止 PPT、PDF、CAJ</div>
+                                <el-upload action="#" :file-list="fileList" disabled list-type="text" :on-preview="handlePreview">
+                                    <span v-if="!fileList.length">暂无附件</span>
                                 </el-upload>
                             </el-form-item>
 
@@ -150,7 +149,7 @@
         </div>
         <div slot="footer" class="dialog-footer">
             <el-button @click="handleClose">{{ obj.isDetail ? '关闭' : '取 消' }}</el-button>
-            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">通过</el-button>
+            <el-button type="primary" @click="handleApprove" v-if="!obj.isDetail">审核</el-button>
         </div>
     </el-dialog>
 </template>
@@ -159,7 +158,7 @@
 import ApprovalProcess from '@/components/approvalProcess'
 import AiEditor from '@/components/AiEditor'
 import { getDetail } from '../../service';
-import { customUploadRequest, getFullUrl, downloadFileByUrl, getAllocateIp, isImageFile } from "@/utils/utils";
+import { customUploadRequest, getFullUrl, downloadFileByUrl, getAllocateIp, isImageFile, normalizeFileList } from "@/utils/utils";
 
 export default {
     name: "ApprovalDialog",
@@ -272,7 +271,7 @@
                 };
 
                 let arr = (data.evaluate || '').split(',')
-                this.fileList = (data.enclosureUrl ? JSON.parse(data.enclosureUrl) : [])
+                this.fileList = normalizeFileList(data.enclosureUrl)
                 this.assessmentTable = this.assessmentTable.map((item, index) => {
                     item.selectedScore = Number(arr[index])
                     return item
@@ -397,11 +396,9 @@
                     // 图片文件:使用 window.open 预览
                     if (file.url && file.url.startsWith('http')) {
                         console.log('图片链接', file.url)
-                        window.open(file.url, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     } else {
-                        let newUrl = getAllocateIp() + file.url;
-                        console.log('图片链接', newUrl)
-                        window.open(newUrl, '_blank');
+                        window.open(getFullUrl(file.url), '_blank');
                     }
                 } else {
                     // 非图片文件:使用下载方式
diff --git a/culture/src/views/strainReportLibrary/reportLibraryOneThree/index.vue b/culture/src/views/strainReportLibrary/reportLibraryOneThree/index.vue
index 68e15d5..7bf0381 100644
--- a/culture/src/views/strainReportLibrary/reportLibraryOneThree/index.vue
+++ b/culture/src/views/strainReportLibrary/reportLibraryOneThree/index.vue
@@ -76,9 +76,9 @@
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status == 2 && [1, 2].includes(roleType)"
                             @click="handleEvaluate(row)">评定</el-button>
                         <el-button type="text" style="margin-right: 10px;" v-if="row.status != 1 || roleType == 3" @click="viewDetail(row)">详情</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && row.status == 4  || isDraft"
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && (row.status == 4 || isDraft))"
                             @click="handleDetail(row)">编辑</el-button>
-                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 3 && isDraft" @click="handleDelete(row)">删除</el-button>
+                        <el-button type="text" style="margin-right: 10px;" v-if="roleType == 1 || (roleType == 3 && isDraft)" @click="handleDelete(row)">删除</el-button>
                         <el-button type="text"  v-if="row.status == 1 && roleType == 3&&!isDraft"
                             @click="handleRevoke(row)">撤销审批</el-button>
                     </template>
diff --git a/culture/src/views/system/role/add.vue b/culture/src/views/system/role/add.vue
index 2bbc2d2..3f34001 100644
--- a/culture/src/views/system/role/add.vue
+++ b/culture/src/views/system/role/add.vue
@@ -83,7 +83,7 @@
     </div>
 
     <div class="btn_box">
-      <el-button @click="$router.go(-1)">返回</el-button>
+      <el-button @click="$closeCurrentView('/system/role')">返回</el-button>
       <el-button type="primary" @click="onSubmit">保存</el-button>
     </div>
   </Card>
@@ -158,7 +158,7 @@
             obj.roleId = this.$route.query.roleId
             edit(obj).then(() => {
               this.msgsuccess('保存成功')
-              this.$router.go(-1)
+              this.$closeCurrentView('/system/role')
             })
           } else {
             add(obj).then(() => {
@@ -168,7 +168,7 @@
                 remark: "",
               }
               this.menu = []
-              this.$router.go(-1)
+              this.$closeCurrentView('/system/role')
             })
           }
         }
@@ -400,4 +400,4 @@
     font-family: 'Source Han Sans CN Bold Bold';
   }
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/culture/src/views/system/role/edit.vue b/culture/src/views/system/role/edit.vue
index 0f6351c..dcfbff5 100644
--- a/culture/src/views/system/role/edit.vue
+++ b/culture/src/views/system/role/edit.vue
@@ -83,7 +83,7 @@
     </div>
 
     <div class="btn_box">
-      <el-button @click="$router.go(-1)">返回</el-button>
+      <el-button @click="$closeCurrentView('/system/role')">返回</el-button>
       <el-button type="primary" @click="onSubmit">保存</el-button>
     </div>
   </Card>
@@ -158,12 +158,12 @@
             obj.roleId = this.$route.query.roleId
             edit(obj).then(() => {
               this.msgsuccess('保存成功')
-              this.$router.go(-1)
+              this.$closeCurrentView('/system/role')
             })
           } else {
             add(obj).then(() => {
               this.msgsuccess('保存成功')
-              this.$router.go(-1)
+              this.$closeCurrentView('/system/role')
             })
           }
         }
@@ -395,4 +395,4 @@
     font-family: 'Source Han Sans CN Bold Bold';
   }
 }
-</style>
\ No newline at end of file
+</style>
diff --git a/culture/vue.config.js b/culture/vue.config.js
index 0ba7571..26abac1 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:8082",
+        target: "http://localhost:8082",
         secure: false, // 使用的是http协议则设置为false,https协议则设置为true
         changeOrigin: true, //开启代理
         pathRewrite: {
@@ -22,7 +22,7 @@
       "/": {
         // 设置以什么前缀开头的请求用来代理
         // target: "http://221.182.45.100:8081", //要访问的跨域的域名
-        target: "http://192.168.110.64:8082",
+        target: "http://localhost:8082",
         secure: false, // 使用的是http协议则设置为false,https协议则设置为true
         changeOrigin: true, //开启代理
         pathRewrite: {
@@ -32,7 +32,7 @@
       "/open": {
         // 设置以什么前缀开头的请求用来代理
         // target: "http://221.182.45.100:8081", //要访问的跨域的域名
-        target: "http://192.168.110.64:8082",
+        target: "http://localhost:8082",
         secure: false, // 使用的是http协议则设置为false,https协议则设置为true
         changeOrigin: true, //开启代理
         pathRewrite: {
diff --git a/laboratory/LICENSE b/laboratory/LICENSE
new file mode 100644
index 0000000..8564f29
--- /dev/null
+++ b/laboratory/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 RuoYi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/laboratory/src/utils/request.js b/laboratory/src/utils/request.js
index 44b806c..cf6a4ae 100644
--- a/laboratory/src/utils/request.js
+++ b/laboratory/src/utils/request.js
@@ -14,9 +14,6 @@
   config => {
     config['headers']['Authorization'] = `${sessionStorage.getItem('token')}`
 
-    // 🔥 关键修改:设置请求头的字符集为UTF-8
-    config['headers']['Content-Type'] = 'application/json;charset=UTF-8'
-
     // 判断是否需要加密(只对/api开头的请求进行加密)
     const needEncrypt = config.url.startsWith('/api');
 
diff --git a/laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue b/laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue
index 46cb5b7..1ba7055 100644
--- a/laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue
+++ b/laboratory/src/views/chemistQa/projectTesting/addDetectionReport.vue
@@ -1,4 +1,4 @@
-<template>
+<template>
     <div class="add-container" :loading="loading">
         <Card v-loading="loading">
             <div class="header-title" style="width: 100%;">
@@ -126,7 +126,9 @@
                     { required: true, message: '请选择检测项', trigger: 'change' }
                 ]
             },
-            queryForm: {}
+            queryForm: {},
+            loadedItemId: '', // 当前已加载记录关联的检测项id,用于keep-alive重新进入时判断是否变化
+            loadedReportId: '', // 当前已加载记录的id,用于keep-alive重新进入时判断是否变化
         }
     },
 
@@ -136,36 +138,62 @@
         this.form.commitPersonId = JSON.parse(sessionStorage.getItem('userInfo')).userId
         this.form.developDate = new Date().toISOString().split('T')[0];
 
-        // this.form.itemId = this.$route.query.itemId
-        if (this.$route.query.itemId) {
-            getDetail(this.$route.query.itemId).then(res => {
-                if (res) {
-                    let item = {
-                        teamName: res.projectTeamVO.teamName,
-                        teamId: res.teamId,
-                        remark: res.remark,
-
-                        itemName: res.itemName,
-                        itemCode: res.itemCode,
-                        createBy: res.createBy,
-                        createTime: res.createTime
-                    }
-                    this.form.itemId = this.$route.query.itemId
-                    this.form.teamId = this.$route.query.teamId
-
-                    this.tableData = [{ ...item }]
-                }
-            })
-        }
-        if (this.$route.query.id) {
-            this.getDetail()
-        }
+        this.loadRouteData();
+    },
+    activated() {
+        // 页面被 keep-alive 缓存,再次打开其他记录时重新加载,避免显示上一次的旧数据
+        this.loadRouteData();
     },
     computed: {
     ...mapState(["tagList", "isFold"]),
   },
 
     methods: {
+        loadRouteData() {
+            const routeItemId = this.$route.query.itemId || '';
+            const routeId = this.$route.query.id || '';
+            if (routeItemId === this.loadedItemId && routeId === this.loadedReportId) {
+                return;
+            }
+            this.loadedItemId = routeItemId;
+            this.loadedReportId = routeId;
+            // 重置开发人、日期等默认信息
+            this.form.developPerson = JSON.parse(sessionStorage.getItem('userInfo')).nickName;
+            this.form.developPersonName = JSON.parse(sessionStorage.getItem('userInfo')).nickName;
+            this.form.commitPersonId = JSON.parse(sessionStorage.getItem('userInfo')).userId
+            this.form.developDate = new Date().toISOString().split('T')[0];
+            // 重置表单与文件,防止显示上一次记录的数据
+            this.form.itemId = '';
+            this.form.teamId = '';
+            this.tableData = [];
+            this.fileList = [];
+            this.form.qaReportFiles = [];
+
+            // 此段逻辑从 mounted() 中抽出,路由参数变化时重新加载
+            if (this.$route.query.itemId) {
+                getDetail(this.$route.query.itemId).then(res => {
+                    if (res) {
+                        let item = {
+                            teamName: res.projectTeamVO.teamName,
+                            teamId: res.teamId,
+                            remark: res.remark,
+
+                            itemName: res.itemName,
+                            itemCode: res.itemCode,
+                            createBy: res.createBy,
+                            createTime: res.createTime
+                        }
+                        this.form.itemId = this.$route.query.itemId
+                        this.form.teamId = this.$route.query.teamId
+
+                        this.tableData = [{ ...item }]
+                    }
+                })
+            }
+            if (this.$route.query.id) {
+                this.getDetail()
+            }
+        },
         getDetail() {
             getDetailInfo({ id: this.$route.query.id }).then(res => {
                 if (res) {
diff --git a/laboratory/src/views/dataManagement/SampleDeliveryRecord/deliveryRecord.vue b/laboratory/src/views/dataManagement/SampleDeliveryRecord/deliveryRecord.vue
index b5e4da4..8e9151b 100644
--- a/laboratory/src/views/dataManagement/SampleDeliveryRecord/deliveryRecord.vue
+++ b/laboratory/src/views/dataManagement/SampleDeliveryRecord/deliveryRecord.vue
@@ -259,6 +259,7 @@
       showReceivedColumns: false,
       schedulingData: [],
       schedulingTotal: 0,
+      loadedId: null, // 当前已加载记录的id,用于 keep-alive 重新进入时判断是否需要重新拉取
       form: {
         sampleCode: "",
         id: "",
@@ -296,9 +297,19 @@
     const { id } = this.$route.query;
     if (id) {
       this.form.id = id;
+      this.loadedId = id;
       this.getDetailData(id);
     }
   },
+  activated() {
+    const routeId = this.$route.query.id;
+    // 页面被 keep-alive 缓存,再次打开其他记录时重新加载,避免显示上一次的旧数据
+    if (routeId && routeId !== this.loadedId) {
+      this.loadedId = routeId;
+      this.form.id = routeId;
+      this.getDetailData(routeId);
+    }
+  },
   methods: {
     async getDetailData(id) {
       try {
diff --git a/laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue b/laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue
index 41f094f..a343381 100644
--- a/laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue
+++ b/laboratory/src/views/dataManagement/confirmation-sheet/components/add.vue
@@ -1,4 +1,4 @@
-<template>
+<template>
   <Card>
     <div class="header-title-left">
       <img src="@/assets/public/headercard.png" />
@@ -99,6 +99,7 @@
       },
       selectedScheduling: null, // 添加选中的实验调度数据
       currentTestItem: null, // 当前编辑的检测项
+      sheetId: '', // 当前已加载确认单的id,用于keep-alive重新进入时判断是否需要重新拉取
       formData: {
         id: '', // 确认单ID
         dispatchId: '', // 实验调度ID
@@ -124,9 +125,19 @@
     // 判断是否是编辑模式
     const id = this.$route.query.id
     if (id) {
+      this.sheetId = id
       this.getDetailData(id)
     }
   },
+  activated() {
+    const routeId = this.$route.query.id
+    // 页面被 keep-alive 缓存,再次打开其他确认单时重新加载,避免显示上一次的旧数据
+    if (routeId && routeId !== this.sheetId) {
+      this.sheetId = routeId
+      this.getDetailData(routeId)
+    }
+    // 新增(无id)场景保留用户填写的数据
+  },
   // computed: {
   //   ...mapState(["tagList", "isFold"]),
   // },
diff --git a/laboratory/src/views/dataManagement/sampleRecordList/changeRecord.vue b/laboratory/src/views/dataManagement/sampleRecordList/changeRecord.vue
index 9e50e1d..d829286 100644
--- a/laboratory/src/views/dataManagement/sampleRecordList/changeRecord.vue
+++ b/laboratory/src/views/dataManagement/sampleRecordList/changeRecord.vue
@@ -175,6 +175,16 @@
       this.getDetailData();
     }
   },
+  activated() {
+    const routeId = this.$route.query.id;
+    const routeType = this.$route.query.type || 'add';
+    // 页面被 keep-alive 缓存,再次打开其他记录时重新加载,避免显示上一次的旧数据
+    if (routeId && (routeId !== this.id || routeType !== this.type)) {
+      this.id = routeId;
+      this.type = routeType;
+      this.getDetailData();
+    }
+  },
   computed: {
     ...mapState(["tagList", "isFold"]),
   },
diff --git a/laboratory/src/views/dataManagement/sampleSubmissionList/submission.vue b/laboratory/src/views/dataManagement/sampleSubmissionList/submission.vue
index 43c7b5e..e554e0b 100644
--- a/laboratory/src/views/dataManagement/sampleSubmissionList/submission.vue
+++ b/laboratory/src/views/dataManagement/sampleSubmissionList/submission.vue
@@ -290,6 +290,14 @@
       this.getDetailData();
     }
   },
+  activated() {
+    const routeId = this.$route.query.id;
+    // 页面被 keep-alive 缓存,再次打开其他记录时重新加载,避免显示上一次的旧数据
+    if (routeId && routeId !== this.id) {
+      this.id = routeId;
+      this.getDetailData();
+    }
+  },
   methods: {
     getFullUrl,
     async getDetailData() {
diff --git a/laboratory/src/views/dataManagement/schemeManagement/stop-experiment.vue b/laboratory/src/views/dataManagement/schemeManagement/stop-experiment.vue
index 1c7e77f..57641bc 100644
--- a/laboratory/src/views/dataManagement/schemeManagement/stop-experiment.vue
+++ b/laboratory/src/views/dataManagement/schemeManagement/stop-experiment.vue
@@ -144,6 +144,15 @@
       this.$message.error('参数错误,缺少实验ID')
     }
   },
+  activated() {
+    const routeId = this.$route.query.id
+    // 页面被 keep-alive 缓存,再次打开其他实验时重新加载,避免显示上一次的旧数据
+    if (routeId && routeId !== this.id) {
+      this.id = routeId
+      this.getExperimentDetail()
+      this.open()
+    }
+  },
   computed: {
     ...mapState(["tagList", "isFold"]),
   },
diff --git a/laboratory/src/views/dataManagement/suspendExperiment/components/editDialog.vue b/laboratory/src/views/dataManagement/suspendExperiment/components/editDialog.vue
new file mode 100644
index 0000000..d056bea
--- /dev/null
+++ b/laboratory/src/views/dataManagement/suspendExperiment/components/editDialog.vue
@@ -0,0 +1,130 @@
+<template>
+  <el-dialog
+      title="编辑中止申请"
+      :visible.sync="dialogVisible"
+      width="700px"
+      :close-on-click-modal="false"
+      @close="handleClose"
+  >
+    <el-form :model="form" :rules="rules" ref="formRef" label-width="140px">
+      <el-form-item label="项目课题方案名称" prop="projectName">
+        <el-input v-model="form.projectName" placeholder="请输入项目课题方案名称" disabled></el-input>
+      </el-form-item>
+<!--      <el-form-item label="实验编号" prop="experimentCode">-->
+<!--        <el-input v-model="form.experimentCode" placeholder="请输入实验编号" disabled></el-input>-->
+<!--      </el-form-item>-->
+      <el-form-item label="实验名称" prop="experimentName">
+        <el-input v-model="form.experimentName" placeholder="请输入实验名称" disabled></el-input>
+      </el-form-item>
+      <el-form-item label="中止原因" prop="stopReason">
+        <ai-editor
+            ref="purposeEditor"
+            :value="form.stopReason"
+            height="400px" placeholder="请输入文字"
+        ></ai-editor>
+      </el-form-item>
+    </el-form>
+    <div slot="footer" class="dialog-footer">
+      <el-button @click="handleClose">取 消</el-button>
+      <el-button type="primary" @click="handleSubmit" :loading="submitting">确 定</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import AiEditor from "@/components/AiEditor/index.vue";
+import {update} from "@/views/dataManagement/schemeManagement/service";
+
+export default {
+  name: "EditDialog",
+  components: {AiEditor},
+  props: {
+    visible: {
+      type: Boolean,
+      default: false,
+    },
+    data: {
+      type: Object,
+      default: () => ({}),
+    },
+  },
+  computed: {
+    dialogVisible: {
+      get() {
+        return this.visible;
+      },
+      set(val) {
+        this.$emit('update:visible', val);
+      }
+    },
+  },
+  watch: {
+    visible: {
+      handler(val) {
+        if (val && this.data) {
+          this.form = {
+            id: this.data.id || '',
+            projectName: this.data.projectName || '',
+            experimentCode: this.data.experimentCode || '',
+            experimentName: this.data.experimentName || '',
+            stopReason: this.data.stopReason || '',
+          };
+        }
+      },
+      immediate: true,
+    },
+  },
+  data() {
+    return {
+      form: {
+        id: '',
+        projectName: '',
+        experimentCode: '',
+        experimentName: '',
+        stopReason: '',
+      },
+      rules: {
+        stopReason: [
+          { required: true, message: '请输入中止原因', trigger: 'blur' }
+        ],
+      },
+      submitting: false,
+    };
+  },
+  methods: {
+    handleClose() {
+      this.$emit('update:visible', false);
+      this.$refs.formRef && this.$refs.formRef.resetFields();
+    },
+    async handleSubmit() {
+      console.log('this.form', this.form)
+      try {
+        await this.$refs.formRef.validate();
+        this.submitting = true;
+        await update(this.form);
+        this.$message.success('编辑成功');
+        this.$emit('success');
+        this.handleClose();
+      } catch (error) {
+        if (error !== 'cancel') {
+          this.$message.error('编辑失败');
+        }
+      } finally {
+        this.submitting = false;
+      }
+    },
+  },
+};
+</script>
+
+<style scoped lang="less">
+.dialog-footer {
+  display: flex;
+  justify-content: center;
+  gap: 20px;
+
+  .el-button {
+    width: 120px;
+  }
+}
+</style>
diff --git a/laboratory/vue.config.js b/laboratory/vue.config.js
index 9a6d28b..329008e 100644
--- a/laboratory/vue.config.js
+++ b/laboratory/vue.config.js
@@ -11,7 +11,7 @@
     proxy: {
       "/": {
         // 设置以什么前缀开头的请求用来代理
-        target: "http://192.168.110.188:11221", //要访问的跨域的域名
+        target: "http://192.168.1.2:11221", //要访问的跨域的域名
         secure: false, // 使用的是http协议则设置为false,https协议则设置为true
         changeOrigin: true, //开启代理
         pathRewrite: {
@@ -19,7 +19,7 @@
         },
       },
       "/": { // 设置以什么前缀开头的请求用来代理
-          target: "http://192.168.110.188:11221", //要访问的跨域的域名
+          target: "http://192.168.1.2:11221", //要访问的跨域的域名
           secure: false, // 使用的是http协议则设置为false,https协议则设置为true
           changeOrigin: true, //开启代理
           pathRewrite: {

--
Gitblit v1.7.1