From 49cdc0884a9a4381cd968cffff65e2a332bc675a Mon Sep 17 00:00:00 2001
From: liding <756868258@qq.com>
Date: 星期六, 24 十月 2026 21:05:29 +0800
Subject: [PATCH] feat(cnas-search): 1.标准查新模块  2.印章使用记录

---
 outputs/standard-search-new/标准查新导入模板.xlsx                                        |    0 
 src/views/structural/sealManage/usageLedger/index.vue                            |   44 +--
 public/import-templates/标准查新导入模板.xlsx                                            |    0 
 src/views/business/reportPreparation/index.vue                                   |    5 
 src/views/CNAS/process/method/standardNoveltyRetrieval/index.vue                 |  205 +++++++--------
 src/utils/reportDocxLayout.js                                                    |   36 ++
 src/api/cnas/process/method/standardNoveltyRetrieval.js                          |   15 
 .env.staging                                                                     |    2 
 .env.development                                                                 |    2 
 vite/plugins/index.js                                                            |    3 
 src/utils/loadSuperDoc.js                                                        |    3 
 src/views/CNAS/process/method/standardNoveltyRetrieval/options.js                |   36 ++
 src/views/CNAS/process/method/standardNoveltyRetrieval/component/EditFormDia.vue |  118 +++++---
 src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue  |   95 +++++--
 .env.production                                                                  |    2 
 src/components/Onlyoffice/onlyoffice.vue                                         |  185 ++++++++++---
 src/components/ReportWordEditor/index.vue                                        |    2 
 17 files changed, 479 insertions(+), 274 deletions(-)

diff --git a/.env.development b/.env.development
index 4c4455e..435c7ee 100644
--- a/.env.development
+++ b/.env.development
@@ -10,7 +10,7 @@
 # 鏂囦欢璁块棶涓庢櫘閫氭帴鍙g粺涓�璧版湰鍦板紑鍙戜唬鐞�
 VITE_APP_BASE_URL = '/dev-api'
 
-# OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛堥瑙� pdf 鐢紝娌℃湁 http:// 鍓嶇紑浼氬綋鎴愮浉瀵硅矾寰勶級
+# OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛圵ord 绛夋枃妗g殑鍦ㄧ嚎棰勮涓庣紪杈戯紱PDF 浣跨敤娴忚鍣ㄥ師鐢熼瑙堬級
 VITE_APP_ONLYOFFICE_API = 'http://192.168.21.53:9001'
 
 # 鏄惁鍦ㄦ墦鍖呮椂寮�鍚帇缂╋紝鏀寔 gzip 鍜� brotli
diff --git a/.env.production b/.env.production
index 4168280..190570e 100644
--- a/.env.production
+++ b/.env.production
@@ -10,7 +10,7 @@
 # 鐢熶骇鐜ip+绔彛
 VITE_APP_BASE_URL = 'http://192.168.21.53:8001/lims'
 
-# OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛堥瑙� pdf 鐢紝娌℃湁 http:// 鍓嶇紑浼氬綋鎴愮浉瀵硅矾寰勶級
+# OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛圵ord 绛夋枃妗g殑鍦ㄧ嚎棰勮涓庣紪杈戯紱PDF 浣跨敤娴忚鍣ㄥ師鐢熼瑙堬級
 VITE_APP_ONLYOFFICE_API = 'http://192.168.21.53:9001'
 
 # 鏄惁鍦ㄦ墦鍖呮椂寮�鍚帇缂╋紝鏀寔 gzip 鍜� brotli
diff --git a/.env.staging b/.env.staging
index 854fc1b..b3a15eb 100644
--- a/.env.staging
+++ b/.env.staging
@@ -10,7 +10,7 @@
 # 娴嬭瘯鐜ip+绔彛
 VITE_APP_BASE_URL = '/stage-api'
 
-# OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛堥瑙� pdf 鐢紝娌℃湁 http:// 鍓嶇紑浼氬綋鎴愮浉瀵硅矾寰勶級
+# OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛圵ord 绛夋枃妗g殑鍦ㄧ嚎棰勮涓庣紪杈戯紱PDF 浣跨敤娴忚鍣ㄥ師鐢熼瑙堬級
 VITE_APP_ONLYOFFICE_API = 'http://192.168.21.53:9001'
 
 # 鏄惁鍦ㄦ墦鍖呮椂寮�鍚帇缂╋紝鏀寔 gzip 鍜� brotli
diff --git "a/outputs/standard-search-new/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" "b/outputs/standard-search-new/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
new file mode 100644
index 0000000..1e9a5bd
--- /dev/null
+++ "b/outputs/standard-search-new/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
Binary files differ
diff --git "a/public/import-templates/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx" "b/public/import-templates/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
index 4d545ee..00f55c5 100644
--- "a/public/import-templates/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
+++ "b/public/import-templates/\346\240\207\345\207\206\346\237\245\346\226\260\345\257\274\345\205\245\346\250\241\346\235\277.xlsx"
Binary files differ
diff --git a/src/api/cnas/process/method/standardNoveltyRetrieval.js b/src/api/cnas/process/method/standardNoveltyRetrieval.js
index cec5582..3df73a0 100644
--- a/src/api/cnas/process/method/standardNoveltyRetrieval.js
+++ b/src/api/cnas/process/method/standardNoveltyRetrieval.js
@@ -19,10 +19,19 @@
   });
 }
 
-// 鏌ヨ鐢辨爣鍑嗙淮鎶よ嚜鍔ㄥ綊妗g殑璁板綍
-export function pageAutoArchived(query) {
+// 鏌ヨ鏌愪釜鏍囧噯鐨勫巻娆℃煡鏂拌褰�
+export function listSearchNewHistory(query) {
   return request({
-    url: "/processMethodSearchNew/pageAutoArchived",
+    url: "/processMethodSearchNew/listSearchNewHistory",
+    method: "get",
+    params: query,
+  });
+}
+
+// 鍒嗛〉鏌ヨ鍏ㄩ儴鏌ユ柊璁板綍锛屽寘鍚凡搴熸鍜岃鏂扮増鏇夸唬鐨勬爣鍑�
+export function pageSearchNewHistory(query) {
+  return request({
+    url: "/processMethodSearchNew/pageSearchNewHistory",
     method: "get",
     params: query,
   });
diff --git a/src/components/Onlyoffice/onlyoffice.vue b/src/components/Onlyoffice/onlyoffice.vue
index 00db4a5..eb69148 100644
--- a/src/components/Onlyoffice/onlyoffice.vue
+++ b/src/components/Onlyoffice/onlyoffice.vue
@@ -8,13 +8,39 @@
       class="native-pdf-preview"
       title="PDF棰勮"
     ></iframe>
-    <div v-else id="vabOnlyOffice"></div>
+    <template v-else>
+      <div :id="editorId"></div>
+      <div v-if="editorWarning" class="editor-warning">{{ editorWarning }}</div>
+      <div v-if="editorState !== 'ready'" class="editor-status">
+        <template v-if="editorState === 'failed'">
+          <p>{{ editorError }}</p>
+          <el-button type="primary" @click="setEditor(option)">閲嶆柊鍔犺浇</el-button>
+        </template>
+        <span v-else>姝e湪杩炴帴鏂囨。鏈嶅姟骞跺姞杞芥姤鍛�...</span>
+      </div>
+    </template>
   </div>
 </template>
 
 <script>
 // OnlyOffice 鏂囨。鏈嶅姟鍦板潃锛屾寜鐜閰嶇疆锛涜剼鏈湪鐪熸闇�瑕侀瑙堟椂鎵嶅姞杞�
 const OFFICE_API_BASE = import.meta.env.VITE_APP_ONLYOFFICE_API || "http://192.168.21.53:9001";
+
+function normalizeOptions(source = {}) {
+  return {
+    url: source.url || "",
+    isEdit: source.isEdit === true || source.isEdit === "true",
+    fileType: source.fileType || "",
+    title: source.title || "",
+    lang: source.lang || "zh-CN",
+    isPrint: source.isPrint !== false,
+    user: { id: source.user_id, name: source.user_name },
+    editUrl: source.editUrl || "",
+    key: source.key || "",
+    model: source.model,
+    token: source.token
+  };
+}
 
 // 澶氫釜椤甸潰鍏辩敤缂栬緫鍣紝api.js 鍙姞杞戒竴娆�
 let docsApiPromise = null;
@@ -26,14 +52,23 @@
     docsApiPromise = new Promise((resolve, reject) => {
       const script = document.createElement("script");
       script.src = OFFICE_API_BASE.replace(/\/$/, "") + "/web-apps/apps/api/documents/api.js";
+      const timeout = window.setTimeout(() => {
+        script.remove();
+        reject(new Error("OnlyOffice 鏂囨。鏈嶅姟杩炴帴瓒呮椂"));
+      }, 15000);
       script.onload = () => {
+        window.clearTimeout(timeout);
         if (window.DocsAPI) {
           resolve(window.DocsAPI);
         } else {
           reject(new Error("api.js 鍔犺浇瀹屾垚浣嗘湭娉ㄥ唽 DocsAPI"));
         }
       };
-      script.onerror = () => reject(new Error("OnlyOffice 鏂囨。鏈嶅姟鑴氭湰鍔犺浇澶辫触锛�" + script.src));
+      script.onerror = () => {
+        window.clearTimeout(timeout);
+        script.remove();
+        reject(new Error("OnlyOffice 鏂囨。鏈嶅姟鑴氭湰鍔犺浇澶辫触"));
+      };
       document.head.appendChild(script);
     });
     // 鍔犺浇澶辫触鍚庡厑璁镐笅娆¢噸璇�
@@ -47,21 +82,18 @@
 export default {
   name: "VabOnlyOffice",
   props: ['options'],
+  emits: ['ready', 'error'],
   data() {
     return {
+      editorId: `onlyoffice-${this._uid || Math.random().toString(36).slice(2)}`,
       doctype: "",
       docEditor: null,
-      //鍙傝�僾abOnlyOffice缁勪欢鍙傛暟閰嶇疆
-      option: {
-        url: "",
-        isEdit: false,
-        fileType: "",
-        title: "",
-        lang: "zh-CN",
-        isPrint: true,
-        user: {},
-        editUrl: ""
-      }
+      editorGeneration: 0,
+      editorState: 'loading',
+      editorError: '',
+      editorWarning: '',
+      readyTimer: null,
+      option: normalizeOptions(this.options || this.$route.query)
     };
   },
   computed: {
@@ -69,41 +101,24 @@
       return this.isPdfFile(this.option);
     }
   },
-  created() {
-    if(this.options){
-      const option = this.options
-      this.option.url = option.url
-      this.option.isEdit = option.isEdit === "true" ? true : false
-      this.option.fileType = option.fileType
-      this.option.title = option.title
-      this.option.lang = option.lang
-      this.option.isPrint = option.isPrint
-      this.option.user.id = option.user_id
-      this.option.user.name = option.user_name
-      this.option.editUrl = option.editUrl
-    }else{
-      const option = this.$route.query
-      this.option.url = option.url
-      this.option.isEdit = option.isEdit === "true" ? true : false
-      this.option.fileType = option.fileType
-      this.option.title = option.title
-      this.option.lang = option.lang
-      this.option.isPrint = option.isPrint
-      this.option.user.id = option.user_id
-      this.option.user.name = option.user_name
-      this.option.editUrl = option.editUrl
-    }
-  },
   beforeUnmount() {
+    this.editorGeneration++;
+    window.clearTimeout(this.readyTimer);
     this.destroyEditor();
   },
   watch: {
-    option: {
-      handler: function(n) {
-        this.setEditor(n);
-        this.doctype = this.getFileType(n.fileType);
+    options: {
+      handler(newOptions) {
+        this.option = normalizeOptions(newOptions || this.$route.query);
+        this.setEditor(this.option);
       },
       deep: true
+    },
+    '$route.query'(query) {
+      if (!this.options) {
+        this.option = normalizeOptions(query);
+        this.setEditor(this.option);
+      }
     }
   },
   mounted() {
@@ -114,19 +129,32 @@
   methods: {
     destroyEditor() {
       if (this.docEditor !== null) {
-        this.docEditor.destroyEditor();
+        try {
+          this.docEditor.destroyEditor();
+        } catch (error) {
+          console.error('閿�姣� OnlyOffice 缂栬緫鍣ㄥけ璐�', error);
+        }
         this.docEditor = null;
       }
     },
     async setEditor(option) {
+      const generation = ++this.editorGeneration;
+      window.clearTimeout(this.readyTimer);
       this.destroyEditor();
       // PDF 浣跨敤娴忚鍣ㄥ師鐢熼瑙堬紱鍏朵粬鏂囨。鎵嶅垵濮嬪寲 OnlyOffice銆�
       if (!option || !option.url || this.isPdfFile(option)) {
         return;
       }
+      this.editorState = 'loading';
+      this.editorError = '';
+      this.editorWarning = '';
       // 绛夊緟 v-else 涓殑 OnlyOffice 瀹瑰櫒瀹屾垚娓叉煋銆�
       await this.$nextTick();
       this.doctype = this.getFileType(option.fileType);
+      if (!this.doctype) {
+        this.failEditor('鎶ュ憡鏂囦欢鏍煎紡涓嶅彈鏀寔', generation);
+        return;
+      }
       let config = {
         document: {
           //鍚庣紑
@@ -149,6 +177,7 @@
           //瀹氬埗
           customization: {
             autosave: true, //鏄惁鑷姩淇濆瓨
+            forcesave: true, //鐐瑰嚮淇濆瓨鏃剁珛鍗冲洖璋冧笟鍔℃湇鍔�
             chat: true,
             comments: false,
             help: false,
@@ -164,20 +193,54 @@
         },
         width: "100%",
         height: "100%",
-        token: option.token || ""
+        token: option.token || "",
+        events: {
+          onDocumentReady: () => {
+            if (generation === this.editorGeneration) {
+              window.clearTimeout(this.readyTimer);
+              this.editorState = 'ready';
+              this.$emit('ready');
+            }
+          },
+          onError: (event) => {
+            const detail = event && event.data && (event.data.errorDescription || event.data.errorCode);
+            this.failEditor(detail ? `鎶ュ憡鍔犺浇澶辫触锛�${detail}` : '鎶ュ憡鍔犺浇澶辫触锛岃妫�鏌ユ枃妗f湇鍔�', generation);
+          }
+        }
       };
 
       try {
         await loadDocsApi();
       } catch (error) {
         console.error(error);
-        this.$message.error("鏂囨。鏈嶅姟鏆傛椂涓嶅彲鐢紝鏃犳硶棰勮");
+        this.failEditor(error.message || '鏂囨。鏈嶅姟鏆傛椂涓嶅彲鐢�', generation);
         return;
       }
-      if (this._isDestroyed) {
+      if (generation !== this.editorGeneration || !this.$el?.isConnected) {
         return;
       }
-      this.docEditor = new window.DocsAPI.DocEditor("vabOnlyOffice", config);
+      try {
+        this.readyTimer = window.setTimeout(() => {
+          this.failEditor('鎶ュ憡鍔犺浇瓒呮椂锛岃妫�鏌ユ枃妗f湇鍔′笌鎶ュ憡鍦板潃', generation);
+        }, 30000);
+        this.docEditor = new window.DocsAPI.DocEditor(this.editorId, config);
+      } catch (error) {
+        window.clearTimeout(this.readyTimer);
+        console.error(error);
+        this.failEditor('鏂囨。缂栬緫鍣ㄥ垵濮嬪寲澶辫触锛岃閲嶈瘯', generation);
+      }
+    },
+    failEditor(message, generation) {
+      if (generation !== this.editorGeneration) return;
+      window.clearTimeout(this.readyTimer);
+      if (this.editorState === 'ready') {
+        this.editorWarning = String(message);
+        this.$emit('error', this.editorWarning);
+        return;
+      }
+      this.editorError = String(message);
+      this.editorState = 'failed';
+      this.$emit('error', this.editorError);
     },
     isPdfFile(option) {
       if (!option) {
@@ -253,10 +316,36 @@
 <style scoped>
 .document-preview,
 .native-pdf-preview,
-#vabOnlyOffice {
+.document-preview > div {
   width: 100%;
   height: 100%;
 }
+.document-preview {
+  position: relative;
+}
+.editor-status {
+  position: absolute;
+  inset: 0;
+  z-index: 2;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  gap: 12px;
+  background: #fff;
+  color: #606266;
+}
+.editor-warning {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  z-index: 2;
+  height: auto !important;
+  padding: 8px 12px;
+  background: #fff3e0;
+  color: #a35d00;
+}
 .native-pdf-preview {
   display: block;
   border: 0;
diff --git a/src/components/ReportWordEditor/index.vue b/src/components/ReportWordEditor/index.vue
index 58d2010..c84b0ef 100644
--- a/src/components/ReportWordEditor/index.vue
+++ b/src/components/ReportWordEditor/index.vue
@@ -25,6 +25,7 @@
 import { ElMessage } from 'element-plus'
 import { normalizeReportDocxForEditor } from '@/utils/reportDocxLayout'
 import { loadSuperDoc } from '@/utils/loadSuperDoc'
+import documentWorkerUrl from 'virtual:superdoc-http-worker-url'
 import { superdocToolbarZh } from '@/utils/superdocToolbarZh'
 import 'superdoc/style.css'
 
@@ -114,6 +115,7 @@
       }),
       documentMode: 'editing',
       role: 'editor',
+      workerUrls: { document: documentWorkerUrl },
       telemetry: { enabled: false },
       ui: { toolbar: { container: toolbar.value, strings: superdocToolbarZh }, ruler: true, comments: false },
       onReady: async ({ superdoc }) => {
diff --git a/src/utils/loadSuperDoc.js b/src/utils/loadSuperDoc.js
index a01ee88..49b6c94 100644
--- a/src/utils/loadSuperDoc.js
+++ b/src/utils/loadSuperDoc.js
@@ -1,8 +1,11 @@
+import { installCryptoRandomUUID } from './cryptoRandomUUID'
+
 let modulePromise
 
 // 瀹℃牳寮�濮嬫椂棰勫姞杞斤紱缂栬緫鍣ㄥ鐢ㄥ悓涓�娆″姞杞斤紝澶辫触鍚庝粛鍏佽閲嶈瘯銆�
 export function loadSuperDoc() {
   if (!modulePromise) {
+    installCryptoRandomUUID()
     modulePromise = import('superdoc').catch(error => {
       modulePromise = null
       throw error
diff --git a/src/utils/reportDocxLayout.js b/src/utils/reportDocxLayout.js
index 98ad551..ff2ae3f 100644
--- a/src/utils/reportDocxLayout.js
+++ b/src/utils/reportDocxLayout.js
@@ -4,6 +4,41 @@
 const floatingPositionPattern = /<w:tblpPr\b[^>]*\/>/
 const tableIndentPattern = /<w:tblInd\b[^>]*\/>/
 const runFontsPattern = /<w:rFonts\b[^>]*\/>/g
+const tableRowPattern = /<w:tr(?:\s[^>]*)?>[\s\S]*?<\/w:tr>/g
+const tableCellPattern = /<w:tc(?:\s[^>]*)?>[\s\S]*?<\/w:tc>/g
+
+function fitCoverCustomer(xml) {
+  let changed = false
+  const normalized = xml.replace(tableRowPattern, row => {
+    if (changed) return row
+    const cells = [...row.matchAll(tableCellPattern)]
+    if (cells.length !== 2) return row
+    const cellText = cell => [...cell.matchAll(/<w:t(?:\s[^>]*)?>([\s\S]*?)<\/w:t>/g)]
+      .map(match => match[1]).join('')
+    if (cellText(cells[0][0]).replace(/[\s:锛歖/g, '') !== '濮旀墭鍗曚綅') return row
+
+    const valueCell = cells[1][0]
+    const customer = cellText(valueCell)
+    const widthTag = valueCell.match(/<w:tcW\b[^>]*>/)?.[0]
+    const widthTwips = Number(widthTag?.match(/\bw:w="(\d+)"/)?.[1])
+    const fontHalfPoints = Number(valueCell.match(/<w:sz\b[^>]*\bw:val="(\d+)"/)?.[1])
+    if (!customer || customer.includes('{{') || !widthTwips || fontHalfPoints !== 32) return row
+
+    // 灏侀潰涓嬪垝绾挎槸鍗曞厓鏍煎簳杈规銆�16 纾呯殑闀垮崟浣嶅悕绉板垰濂藉崰婊″垪瀹芥椂锛�
+    // PDF 鎺掔増鍣ㄥ彲鑳藉皢娈佃惤缁撴潫绗︽尋鍒扮浜岃锛屽鑷磋〃鏍艰鍜屼笅鍒掔嚎涓嬬Щ銆�
+    const units = [...customer].reduce((sum, char) => sum +
+      (/\s/.test(char) ? 0.35 : char.codePointAt(0) > 0x2e80 ? 1 : 0.6), 0)
+    const availablePoints = widthTwips / 20 - 10
+    if (units * fontHalfPoints / 2 <= availablePoints) return row
+    const fittedHalfPoints = Math.max(24, Math.floor(availablePoints / units * 2))
+    const fittedCell = valueCell.replace(/<w:sz(?:Cs)?\b[^>]*\/>/g, tag =>
+      tag.replace(/\bw:val="32"/, `w:val="${fittedHalfPoints}"`))
+    if (fittedCell === valueCell) return row
+    changed = true
+    return row.replace(valueCell, fittedCell)
+  })
+  return changed ? normalized : null
+}
 
 function alignReportHeader(xml, reportCode) {
   // 鏃ф楠屾姤鍛婃妸椤电爜鏀惧湪娴姩鏂囨湰妗嗕腑锛汼uperDoc 閲嶆柊鍒嗛〉鏃朵細涓㈠け Word 鐨勬í鍚戦敋鐐广��
@@ -138,6 +173,7 @@
   const themeXml = themePart ? await themePart.async('string') : ''
   const themeFonts = { major: chineseThemeFont(themeXml, 'major'), minor: chineseThemeFont(themeXml, 'minor') }
   let normalizedXml = alignResultTable(documentXml) || documentXml
+  normalizedXml = fitCoverCustomer(normalizedXml) || normalizedXml
   normalizedXml = materializeChineseThemeFonts(normalizedXml, themeFonts) || normalizedXml
   let changed = normalizedXml !== documentXml
   if (changed) zip.file('word/document.xml', normalizedXml)
diff --git a/src/views/CNAS/process/method/standardNoveltyRetrieval/component/EditFormDia.vue b/src/views/CNAS/process/method/standardNoveltyRetrieval/component/EditFormDia.vue
index 591109d..279ddb8 100644
--- a/src/views/CNAS/process/method/standardNoveltyRetrieval/component/EditFormDia.vue
+++ b/src/views/CNAS/process/method/standardNoveltyRetrieval/component/EditFormDia.vue
@@ -1,75 +1,63 @@
 <template>
   <div>
-    <el-dialog v-model="formDia" title="缂栬緫" width="80%" @close="closeDia">
+    <el-dialog v-model="formDia" title="鏂板鏌ユ柊" width="820px" @close="closeDia">
       <el-form ref="form" :model="form" :rules="formRules" label-width="auto">
         <el-col :span="8">
           <el-form-item label="鏍囧噯鍚嶇О锛�" prop="methodName">
-            <el-input v-model="form.methodName" size="small"></el-input>
+            <el-input v-model="form.methodName" size="small" disabled></el-input>
           </el-form-item>
         </el-col>
         <el-col :span="8">
           <el-form-item label="鏍囧噯鍙凤細" prop="standardNo">
-            <el-input v-model="form.standardNo" size="small"></el-input>
+            <el-input v-model="form.standardNo" size="small" disabled></el-input>
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="鏂囦欢缂栧彿锛�" prop="fileNo">
-            <el-input v-model="form.fileNo" size="small"></el-input>
+          <el-form-item label="鏌ユ柊鏃ユ湡锛�" prop="searchNewTime">
+            <el-date-picker v-model="form.searchNewTime" type="date" value-format="YYYY-MM-DD"
+                            format="YYYY-MM-DD" placeholder="璇烽�夋嫨鏃ユ湡" size="small"
+                            style="width: 100%;" @change="refreshDefaultNextSearchDate"></el-date-picker>
           </el-form-item>
         </el-col>
         <el-col :span="8">
-          <el-form-item label="鏌ユ柊鏃堕棿锛�" prop="searchNewTime">
-            <el-date-picker v-model="form.searchNewTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
-                            format="YYYY-MM-DD HH:mm:ss" placeholder="璇烽�夋嫨" size="small"
-                            style="width: 100%;"></el-date-picker>
+          <el-form-item label="涓嬫鏌ユ柊鏃ユ湡锛�">
+            <el-input v-if="isSearchRetired" model-value="涓嶉�傜敤" size="small" disabled />
+            <el-date-picker v-else v-model="form.nextSearchDate" type="date" value-format="YYYY-MM-DD"
+                            format="YYYY-MM-DD" placeholder="榛樿涓変釜鏈堝悗锛屽彲淇敼" size="small"
+                            style="width: 100%;" />
           </el-form-item>
         </el-col>
         <el-col :span="8">
           <el-form-item label="鏌ユ柊浜猴細">
-            <el-input :model-value="form.searchNewUserName" size="small" disabled></el-input>
+            <el-input :model-value="currentUserName" size="small" disabled></el-input>
           </el-form-item>
         </el-col>
         <el-col :span="8">
           <el-form-item label="鏌ユ柊缁撴灉锛�" prop="searchNewResult">
-            <el-input v-model="form.searchNewResult" size="small"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="鏄惁鏄柊鏍囧噯锛�">
-            <el-tag type="success">鏄�</el-tag>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="鏌ユ柊璁板綍鏉ユ簮锛�" prop="searchNewSource">
-            <el-radio-group v-model="form.searchNewSource">
-              <el-radio :value="0">鏍囧噯缃�</el-radio>
-              <el-radio :value="1">濮旀墭鎯呮姤</el-radio>
-              <el-radio :value="2">鏍囧噯鏁�</el-radio>
-              <el-radio :value="3">鍏朵粬</el-radio>
-            </el-radio-group>
-          </el-form-item>
-        </el-col>
-        <el-col v-if="form.searchNewSource === 3" :span="8">
-          <el-form-item label="鏉ユ簮缃戝潃/缃戠珯鍚嶇О锛�" prop="searchNewWebsite"
-                        :rules="[{required: true, message: '璇峰~鍐欏叿浣撶綉鍧�鎴栫綉绔欏悕绉�', trigger: 'blur'}]">
-            <el-input v-model="form.searchNewWebsite" size="small"></el-input>
-          </el-form-item>
-        </el-col>
-        <el-col :span="8">
-          <el-form-item label="澶囨敞锛�" prop="remark">
-            <el-select v-model="form.remark"
-                       clearable size="small">
-              <el-option :value="0" label="浣滃簾"></el-option>
-              <el-option :value="1" label="鏇挎崲"></el-option>
+            <el-select v-model="form.searchNewResult" placeholder="璇烽�夋嫨" style="width: 100%"
+                       @change="handleSearchResultChange">
+              <el-option v-for="item in searchResultOptions" :key="item" :label="item" :value="item" />
             </el-select>
           </el-form-item>
         </el-col>
-        <el-col v-if="form.isNewStandard == 1" :span="8">
+        <el-col :span="24">
+          <el-form-item label="鏌ユ柊璁板綍鏉ユ簮锛�" prop="searchNewSource">
+            <el-radio-group v-model="form.searchNewSource">
+              <el-radio v-for="item in searchSourceOptions" :key="item.value" :value="item.value">{{ item.label }}</el-radio>
+            </el-radio-group>
+          </el-form-item>
+        </el-col>
+        <el-col v-if="form.searchNewSource === 3" :span="24">
+          <el-form-item label="鍏朵粬鏉ユ簮鍚嶇О锛�" prop="searchNewWebsite">
+            <el-input v-model="form.searchNewWebsite" size="small" placeholder="閫夊~锛屾棤闇�濉啓缃戝潃"></el-input>
+          </el-form-item>
+        </el-col>
+        <el-col v-if="form.searchNewResult === '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬'" :span="12">
           <el-form-item label="鏂版爣鍑嗗悕绉帮細" prop="newMethodName">
             <el-input v-model="form.newMethodName" size="small"></el-input>
           </el-form-item>
         </el-col>
-        <el-col v-if="form.isNewStandard == 1" :span="8">
+        <el-col v-if="form.searchNewResult === '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬'" :span="12">
           <el-form-item label="鏂版爣鍑嗗彿锛�" prop="newStandardNo">
             <el-input v-model="form.newStandardNo" size="small"></el-input>
           </el-form-item>
@@ -87,6 +75,8 @@
 import {
   updateMethodSearchNew
 } from '@/api/cnas/process/method/standardNoveltyRetrieval'
+import useUserStore from '@/store/modules/user'
+import { calculateNextSearchDate, isSearchRetired, searchResultOptions, searchSourceOptions } from '../options'
 
 export default {
   name: 'FormDialog',
@@ -96,6 +86,8 @@
     // 杩欓噷瀛樻斁鏁版嵁
     return {
       formDia: false,
+      searchResultOptions,
+      searchSourceOptions,
       form: {
         methodName: '',
         standardNo: '',
@@ -103,18 +95,20 @@
         newMethodName: '',
         newStandardNo: '',
         searchNewTime: '',
+        nextSearchDate: '',
         searchNewResult: '',
         searchNewUserName: '',
         searchNewWebsite: '',
         searchNewSource: '',
-        remark: '',
         fileNo: '',
       },
       formRules: {
         methodName: [{required: true, message: '璇峰~鍐欐爣鍑嗗悕绉�',trigger: 'blur'}],
         standardNo: [{required: true, message: '璇峰~鍐欐爣鍑嗗彿',trigger: 'blur'}],
-        newMethodName: [{required: false, message: '璇峰~鍐欐柊鏍囧噯鍚嶇О',trigger: 'blur'}],
-        newStandardNo: [{required: false, message: '璇峰~鍐欐柊鏍囧噯鍙�',trigger: 'blur'}],
+        newMethodName: [{required: true, message: '璇峰~鍐欐柊鏍囧噯鍚嶇О',trigger: 'blur'}],
+        newStandardNo: [{required: true, message: '璇峰~鍐欐柊鏍囧噯鍙�',trigger: 'blur'}],
+        searchNewTime: [{required: true, message: '璇烽�夋嫨鏌ユ柊鏃ユ湡',trigger: 'change'}],
+        searchNewResult: [{required: true, message: '璇烽�夋嫨鏌ユ柊缁撴灉',trigger: 'change'}],
         searchNewSource: [{required: true, message: '璇烽�夋嫨鏌ユ柊璁板綍鏉ユ簮',trigger: 'change'}],
         fileNo: [{required: true, message: '璇峰~鍐欐枃浠跺彿',trigger: 'blur'}],
       },
@@ -122,11 +116,40 @@
       info: {},
     };
   },
+  computed: {
+    isSearchRetired() {
+      return isSearchRetired(this.form.searchNewResult)
+    },
+    currentUserName() {
+      const user = useUserStore()
+      return user.nickName || user.name || user.userName
+    }
+  },
   // 鏂规硶闆嗗悎
   methods: {
     openDia(row) {
       this.formDia = true
-      this.form = {...row, isNewStandard: 1}
+      this.form = {
+        ...row,
+        searchNewTime: '',
+        nextSearchDate: '',
+        searchNewResult: '',
+        searchNewSource: null,
+        searchNewWebsite: '',
+        newMethodName: '',
+        newStandardNo: ''
+      }
+    },
+    refreshDefaultNextSearchDate() {
+      this.form.nextSearchDate = this.isSearchRetired ? null
+        : calculateNextSearchDate(this.form.searchNewTime)
+    },
+    handleSearchResultChange() {
+      if (this.isSearchRetired) {
+        this.form.nextSearchDate = null
+      } else if (!this.form.nextSearchDate) {
+        this.refreshDefaultNextSearchDate()
+      }
     },
     handleEdit() {
       this.$refs['form'].validate((valid) => {
@@ -134,13 +157,14 @@
           this.editLoad = true
           const processMethodSearchNews = this.HaveJson(this.form)
           delete processMethodSearchNews.createTime
+          processMethodSearchNews.searchNewTime = `${processMethodSearchNews.searchNewTime} 00:00:00`
           if (processMethodSearchNews.searchNewSource !== 3) {
             processMethodSearchNews.searchNewWebsite = null
           }
           updateMethodSearchNew(processMethodSearchNews).then(res => {
             this.editLoad = false
             if (res.code === 200){
-              this.$message.success('鎿嶄綔鎴愬姛')
+              this.$message.success('鏌ユ柊璁板綍宸蹭繚瀛�')
               this.closeDia()
             }
           }).catch(err => {
diff --git a/src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue b/src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue
index 784cd5f..5f666ba 100644
--- a/src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue
+++ b/src/views/CNAS/process/method/standardNoveltyRetrieval/component/FormDialog.vue
@@ -14,20 +14,33 @@
             </div>
             <el-row :gutter="20">
               <el-col :span="12">
-                <el-form-item :prop="`taskRel.${index}.newMethodName`" :rules="{required: true, message: '璇峰~鍐欐爣鍑嗗悕绉�',trigger: 'blur',}" label="鏂版爣鍑嗗悕绉帮細">
-                  <el-input v-model="items.newMethodName" size="small"></el-input>
+                <el-form-item :prop="`taskRel.${index}.methodName`" :rules="{required: true, message: '璇峰~鍐欐爣鍑嗗悕绉�',trigger: 'blur',}" label="鏍囧噯鍚嶇О锛�">
+                  <el-input v-model="items.methodName" size="small"></el-input>
                 </el-form-item>
               </el-col>
               <el-col :span="12">
-                <el-form-item :prop="`taskRel.${index}.newStandardNo`" :rules="{required: true,message: '璇峰~鍐欐爣鍑嗗彿',trigger: 'blur',}" label="鏂版爣鍑嗗彿锛�">
-                  <el-input v-model="items.newStandardNo" size="small"></el-input>
+                <el-form-item :prop="`taskRel.${index}.standardNo`" :rules="{required: true,message: '璇峰~鍐欐爣鍑嗗彿',trigger: 'blur',}" label="鏍囧噯鍙凤細">
+                  <el-input v-model="items.standardNo" size="small"></el-input>
                 </el-form-item>
               </el-col>
               <el-col :span="12">
-                <el-form-item :prop="`taskRel.${index}.searchNewTime`" label="鏌ユ柊鏃堕棿锛�">
-                  <el-date-picker v-model="items.searchNewTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss"
-                                  format="YYYY-MM-DD HH:mm:ss" placeholder="璇烽�夋嫨" size="small"
-                                  style="width: 100%;"></el-date-picker>
+                <el-form-item :prop="`taskRel.${index}.fileNo`" :rules="{required: true,message: '璇峰~鍐欐枃浠剁紪鍙�',trigger: 'blur',}" label="鏂囦欢缂栧彿锛�">
+                  <el-input v-model="items.fileNo" size="small"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item :prop="`taskRel.${index}.searchNewTime`" :rules="{required: true,message: '璇烽�夋嫨鏌ユ柊鏃ユ湡',trigger: 'change',}" label="鏌ユ柊鏃ユ湡锛�">
+                  <el-date-picker v-model="items.searchNewTime" type="date" value-format="YYYY-MM-DD"
+                                  format="YYYY-MM-DD" placeholder="璇烽�夋嫨鏃ユ湡" size="small"
+                                  style="width: 100%;" @change="refreshDefaultNextSearchDate(items)"></el-date-picker>
+                </el-form-item>
+              </el-col>
+              <el-col :span="12">
+                <el-form-item label="涓嬫鏌ユ柊鏃ユ湡锛�">
+                  <el-input v-if="isSearchRetired(items.searchNewResult)" model-value="涓嶉�傜敤" size="small" disabled />
+                  <el-date-picker v-else v-model="items.nextSearchDate" type="date" value-format="YYYY-MM-DD"
+                                  format="YYYY-MM-DD" placeholder="榛樿涓変釜鏈堝悗锛屽彲淇敼" size="small"
+                                  style="width: 100%;" />
                 </el-form-item>
               </el-col>
               <el-col :span="12">
@@ -35,34 +48,35 @@
                   <el-input :model-value="currentUserName" size="small" disabled></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="24">
-                <el-form-item :prop="`taskRel.${index}.searchNewResult`" label="鏌ユ柊缁撴灉锛�">
-                  <el-input v-model="items.searchNewResult" type="textarea" :rows="2" size="small"></el-input>
+              <el-col :span="12">
+                <el-form-item :prop="`taskRel.${index}.searchNewResult`" :rules="{required: true,message: '璇烽�夋嫨鏌ユ柊缁撴灉',trigger: 'change',}" label="鏌ユ柊缁撴灉锛�">
+                  <el-select v-model="items.searchNewResult" placeholder="璇烽�夋嫨" style="width: 100%"
+                             @change="handleSearchResultChange(items)">
+                    <el-option v-for="result in searchResultOptions" :key="result" :label="result" :value="result" />
+                  </el-select>
                 </el-form-item>
               </el-col>
               <el-col :span="24">
                 <el-form-item :prop="`taskRel.${index}.searchNewSource`" :rules="{required: true,message: '璇烽�夋嫨鏌ユ柊璁板綍鏉ユ簮',trigger: 'change',}" label="鏌ユ柊璁板綍鏉ユ簮锛�">
                   <el-radio-group v-model="items.searchNewSource">
-                    <el-radio :value="0">鏍囧噯缃�</el-radio>
-                    <el-radio :value="1">濮旀墭鎯呮姤</el-radio>
-                    <el-radio :value="2">鏍囧噯鏁�</el-radio>
-                    <el-radio :value="3">鍏朵粬</el-radio>
+                    <el-radio v-for="source in searchSourceOptions" :key="source.value" :value="source.value">{{ source.label }}</el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
               <el-col v-if="items.searchNewSource === 3" :span="24">
                 <el-form-item :prop="`taskRel.${index}.searchNewWebsite`"
-                              :rules="{required: true, message: '璇峰~鍐欏叿浣撶綉鍧�鎴栫綉绔欏悕绉�', trigger: 'blur'}"
-                              label="鏉ユ簮缃戝潃/缃戠珯鍚嶇О锛�">
-                  <el-input v-model="items.searchNewWebsite" size="small" placeholder="璇疯緭鍏ュ叿浣撶綉鍧�鎴栫綉绔欏悕绉�"></el-input>
+                              label="鍏朵粬鏉ユ簮鍚嶇О锛�">
+                  <el-input v-model="items.searchNewWebsite" size="small" placeholder="閫夊~锛屾棤闇�濉啓缃戝潃"></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="12">
-                <el-form-item :prop="`taskRel.${index}.remark`" :rules="{required: false,message: '璇烽�夋嫨澶囨敞',trigger: 'change',}" label="澶囨敞锛�">
-                  <el-select v-model="items.remark" clearable size="small" style="width: 100%;">
-                    <el-option :value="0" label="浣滃簾"></el-option>
-                    <el-option :value="1" label="鏇挎崲"></el-option>
-                  </el-select>
+              <el-col v-if="items.searchNewResult === '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬'" :span="12">
+                <el-form-item :prop="`taskRel.${index}.newMethodName`" :rules="{required: true,message: '璇峰~鍐欐柊鏍囧噯鍚嶇О',trigger: 'blur',}" label="鏂版爣鍑嗗悕绉帮細">
+                  <el-input v-model="items.newMethodName" size="small"></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col v-if="items.searchNewResult === '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬'" :span="12">
+                <el-form-item :prop="`taskRel.${index}.newStandardNo`" :rules="{required: true,message: '璇峰~鍐欐柊鏍囧噯鍙�',trigger: 'blur',}" label="鏂版爣鍑嗗彿锛�">
+                  <el-input v-model="items.newStandardNo" size="small"></el-input>
                 </el-form-item>
               </el-col>
             </el-row>
@@ -83,6 +97,7 @@
 <script>
 import { addMethodSearchNew } from '@/api/cnas/process/method/standardNoveltyRetrieval'
 import useUserStore from '@/store/modules/user'
+import { calculateNextSearchDate, isSearchRetired, searchResultOptions, searchSourceOptions } from '../options'
 
 export default {
   name: 'FormDialog',
@@ -92,16 +107,21 @@
     // 杩欓噷瀛樻斁鏁版嵁
     return {
       formDia: false,
+      searchResultOptions,
+      searchSourceOptions,
       form: {
         taskRel: [
           {
-            newMethodName: '',
-            newStandardNo: '',
+            methodName: '',
+            standardNo: '',
+            fileNo: '',
             searchNewTime: '',
+            nextSearchDate: '',
             searchNewResult: '',
             searchNewWebsite: '',
             searchNewSource: '',
-            remark: '',
+            newMethodName: '',
+            newStandardNo: '',
           }
         ]
       },
@@ -118,12 +138,26 @@
   },
   // 鏂规硶闆嗗悎
   methods: {
+    isSearchRetired,
     openDia (row) {
       this.formDia = true
     },
     // 娣诲姞涓�鏉�
     addBtn() {
-      this.form.taskRel.push({ newMethodName: '', newStandardNo:'', searchNewTime: '', searchNewResult: '', searchNewWebsite: '', searchNewSource: '', remark: ''});
+      this.form.taskRel.push({ methodName: '', standardNo: '', fileNo: '', searchNewTime: '',
+        nextSearchDate: '', searchNewResult: '', searchNewWebsite: '', searchNewSource: '',
+        newMethodName: '', newStandardNo: '' });
+    },
+    refreshDefaultNextSearchDate(item) {
+      item.nextSearchDate = isSearchRetired(item.searchNewResult) ? null
+        : calculateNextSearchDate(item.searchNewTime)
+    },
+    handleSearchResultChange(item) {
+      if (isSearchRetired(item.searchNewResult)) {
+        item.nextSearchDate = null
+      } else if (!item.nextSearchDate) {
+        this.refreshDefaultNextSearchDate(item)
+      }
     },
     // 鍒犻櫎涓�鏉�
     deleteHeaderRow (index) {
@@ -135,7 +169,10 @@
           this.editLoad = true
           const records = this.form.taskRel.map(item => ({
             ...item,
-            searchNewWebsite: item.searchNewSource === 3 ? item.searchNewWebsite : null
+            searchNewTime: `${item.searchNewTime} 00:00:00`,
+            searchNewWebsite: item.searchNewSource === 3 ? item.searchNewWebsite : null,
+            newMethodName: item.searchNewResult === '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬' ? item.newMethodName : null,
+            newStandardNo: item.searchNewResult === '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬' ? item.newStandardNo : null
           }))
           addMethodSearchNew(records).then(res => {
             this.editLoad = false
diff --git a/src/views/CNAS/process/method/standardNoveltyRetrieval/index.vue b/src/views/CNAS/process/method/standardNoveltyRetrieval/index.vue
index 8ea5d96..03a091b 100644
--- a/src/views/CNAS/process/method/standardNoveltyRetrieval/index.vue
+++ b/src/views/CNAS/process/method/standardNoveltyRetrieval/index.vue
@@ -13,6 +13,7 @@
         </div>
       </div>
       <div style="line-height: 30px;">
+        <el-button size="small" @click="openAllHistory">鏌ユ柊璁板綍</el-button>
         <el-button size="small" type="primary" style="margin-left: 10px;"
                    @click="$refs.importDialog.open()">瀵煎叆</el-button>
         <el-button size="small" style="margin-left: 10px;" type="primary" @click="openFormDia">鏂� 澧�</el-button>
@@ -26,6 +27,36 @@
       </div>
       <FormDialog v-if="formDialog" ref="formDialog" @closeDia="closeDia"></FormDialog>
       <EditFormDia v-if="editFormDialog" ref="editFormDialog" @closeEditDia="closeEditDia"></EditFormDia>
+      <el-dialog v-model="historyDialog" :title="`${historyStandard} 路 鏌ユ柊璁板綍`" width="960px">
+        <div v-if="historyScopeId === null" style="display: flex; gap: 8px; margin-bottom: 12px;">
+          <el-input v-model="historySearchNo" clearable placeholder="鎸夋爣鍑嗗彿鏌ヨ" style="width: 260px"
+                    @keyup.enter="searchAllHistory" />
+          <el-button type="primary" @click="searchAllHistory">鏌ヨ</el-button>
+        </div>
+        <el-table v-loading="historyLoading" :data="historyRecords" border>
+          <el-table-column prop="methodName" label="鏍囧噯鍚嶇О" min-width="160" />
+          <el-table-column prop="standardNo" label="鏍囧噯鍙�" min-width="135" />
+          <el-table-column prop="fileNo" label="鏂囦欢缂栧彿" min-width="120" />
+          <el-table-column prop="searchNewDate" label="鏌ユ柊鏃ユ湡" width="115" />
+          <el-table-column prop="nextSearchDate" label="涓嬫鏌ユ柊鏃ユ湡" width="125" />
+          <el-table-column prop="searchNewResult" label="鏌ユ柊缁撴灉" width="190" />
+          <el-table-column label="鏌ユ柊鏉ユ簮" min-width="210">
+            <template #default="scope">
+              {{ displaySearchSource(scope.row.searchNewSource) }}
+              <span v-if="scope.row.searchNewWebsite">锛坽{ scope.row.searchNewWebsite }}锛�</span>
+            </template>
+          </el-table-column>
+          <el-table-column prop="searchNewUserName" label="鏌ユ柊浜�" width="110" />
+          <el-table-column prop="newMethodName" label="鏂扮増鏍囧噯鍚嶇О" min-width="150" />
+          <el-table-column prop="newStandardNo" label="鏂扮増鏍囧噯鍙�" min-width="135" />
+          <el-table-column prop="createTime" label="鎻愪氦鏃堕棿" width="165" />
+        </el-table>
+        <el-empty v-if="!historyLoading && historyRecords.length === 0" description="鏆傛棤鏌ユ柊璁板綍" />
+        <el-pagination v-if="historyScopeId === null" v-model:current-page="historyPage.current"
+                       v-model:page-size="historyPage.size" :total="historyPage.total"
+                       layout="total, prev, pager, next" style="margin-top: 12px; justify-content: flex-end;"
+                       @current-change="loadHistory" />
+      </el-dialog>
       <import-dialog
         ref="importDialog"
         title="瀵煎叆鏍囧噯鏌ユ柊"
@@ -35,9 +66,9 @@
         template-name="鏍囧噯鏌ユ柊瀵煎叆妯℃澘.xlsx"
         :tips="[
           '琛ㄥご涓轰袱琛岋紝璇蜂粠绗� 3 琛屽紑濮嬪~鍐欐暟鎹�',
-          '鏍囧噯鍚嶇О銆佹爣鍑嗗彿璇峰~鍐欑幇琛屾爣鍑嗙殑鍚嶇О鍜岀紪鍙�',
-          '鏌ユ柊鏉ユ簮鎸夆�滄爣鍑嗙綉 鈫� 濮旀墭鎯呮姤鎵� 鈫� 鏍囧噯涔﹀簵 鈫� 鍏朵粬鈥濈殑椤哄簭鍙栫涓�涓潪绌洪」',
-          '澶囨敞鍒楀彧鑳藉~鍐欌�滄浛鎹⑩�濇垨鈥滀綔搴熲�濓紝鐣欑┖琛ㄧず鏃犲娉�'
+          '鏍囧噯鍚嶇О銆佹爣鍑嗗彿璇峰~鍐欐湰娆℃煡鏂扮殑鏍囧噯淇℃伅',
+          '鏌ユ柊鏃ユ湡鏍煎紡涓� YYYY-MM-DD锛屾煡鏂扮粨鏋滃~鍐欑幇琛屾湁鏁堛�佸凡淇/鏈夋柊鐗堟湰鏇夸唬銆佸簾姝紙鏃犳浛浠o級鎴栧嵆灏嗗疄鏂�',
+          '鍏釜鏌ユ柊鏉ユ簮鍒椾腑鍙兘濉啓涓�涓紝濉啓鈥溾垰鈥濊〃绀洪�変腑'
         ]"
         @success="searchList"
       />
@@ -50,8 +81,10 @@
 import ImportDialog from '@/components/ImportDialog/index.vue'
 import FormDialog from './component/FormDialog.vue';
 import EditFormDia from './component/EditFormDia.vue';
+import { displayDate, displaySearchSource } from './options'
 import {
-  delMethodSearchNew,
+  listSearchNewHistory,
+  pageSearchNewHistory,
   pageMethodSearchNew
 } from '@/api/cnas/process/method/standardNoveltyRetrieval'
 
@@ -67,6 +100,13 @@
   data() {
     // 杩欓噷瀛樻斁鏁版嵁
     return {
+      historyDialog: false,
+      historyLoading: false,
+      historyRecords: [],
+      historyStandard: '',
+      historyScopeId: null,
+      historySearchNo: '',
+      historyPage: { current: 1, size: 10, total: 0 },
       searchForm: {
         standardNo: ''
       },
@@ -87,48 +127,15 @@
           minWidth: '100'
         },
         {
-          dataType: 'tag',
-          label: '鏄惁鏄柊鏍囧噯',
-          prop: 'isNewStandard',
-          minWidth: '100',
-          formatData: (params) => {
-            if (params == 0) {
-              return '鍚�';
-            } else if (params == 1) {
-              return '鏄�';
-            } else {
-              return null
-            }
-          },
-          formatType: (params) => {
-            if (params == 0) {
-              return 'danger';
-            } else if (params == 1) {
-              return 'success';
-            } else {
-              return null
-            }
-          }
-        },
-        {
-          label: '鏂版爣鍑嗗悕绉�',
-          prop: 'newMethodName',
-          minWidth: '100'
-        },
-        {
-          label: '鏂版爣鍑嗗彿',
-          prop: 'newStandardNo',
-          minWidth: '100'
-        },
-        {
-          label: '鏌ユ柊鏃堕棿',
+          label: '鏈�杩戞煡鏂版棩鏈�',
           prop: 'searchNewTime',
-          minWidth: '150'
+          minWidth: '125',
+          formatData: displayDate
         },
         {
           label: '鏌ユ柊缁撴灉',
           prop: 'searchNewResult',
-          minWidth: '140'
+          minWidth: '190'
         },
         {
           label: '鏌ユ柊浜�',
@@ -136,65 +143,20 @@
           minWidth: '100'
         },
         {
-          dataType: 'tag',
           label: '鏌ユ柊璁板綍鏉ユ簮',
           prop: 'searchNewSource',
-          minWidth: '100',
-          formatData: (params) => {
-            if (params == 0) {
-              return '鏍囧噯缃�';
-            } else if (params == 1) {
-              return '濮旀墭鎯呮姤';
-            } else if (params == 2) {
-              return '鏍囧噯鏁�';
-            } else if (params == 3) {
-              return '鍏朵粬';
-            } else {
-              return null
-            }
-          },
-          formatType: (params) => {
-            if (params == 0) {
-              return 'success';
-            } else if (params == 1) {
-              return 'danger';
-            } else if (params == 2) {
-              return 'warning';
-            } else if (params == 3) {
-              return 'info';
-            } else {
-              return null
-            }
-          }
+          minWidth: '180',
+          formatData: displaySearchSource
         },
         {
-          label: '鏉ユ簮缃戝潃/缃戠珯鍚嶇О',
+          label: '鍏朵粬鏉ユ簮鍚嶇О',
           prop: 'searchNewWebsite',
           minWidth: '150'
         },
+        { label: '涓嬫鏌ユ柊鏃ユ湡', prop: 'nextSearchDate', minWidth: '125', formatData: displayDate },
         {
-          dataType: 'tag',
-          label: '澶囨敞',
-          prop: 'remark',
-          minWidth: '100',
-          formatData: (params) => {
-            if (params == 0) {
-              return '浣滃簾';
-            } else if (params == 1) {
-              return '鏇挎崲';
-            } else {
-              return null
-            }
-          },
-          formatType: (params) => {
-            if (params == 0) {
-              return 'danger';
-            } else if (params == 1) {
-              return 'success';
-            } else {
-              return null
-            }
-          }
+          dataType: 'tag', label: '鏌ユ柊鐘舵��', prop: 'searchDueStatus', minWidth: '100',
+          formatType: value => value === '宸查�炬湡' ? 'danger' : value === '浠婃棩鍒版湡' ? 'warning' : 'success'
         },
         {
           dataType: 'action',
@@ -202,17 +164,17 @@
           label: '鎿嶄綔',
           operation: [
             {
-              name: '缂栬緫',
+              name: '鏌ユ柊',
               type: 'text',
               clickFun: (row) => {
                 this.openEditFormDia(row);
               },
             },
             {
-              name: '鍒犻櫎',
+              name: '鏈爣鍑嗚褰�',
               type: 'text',
               clickFun: (row) => {
-                this.handleDelete(row);
+                this.openHistory(row);
               },
             },
           ]
@@ -234,6 +196,43 @@
   },
   // 鏂规硶闆嗗悎
   methods: {
+    displaySearchSource,
+    openAllHistory() {
+      this.historyStandard = '鍏ㄩ儴鏍囧噯'
+      this.historyScopeId = null
+      this.historySearchNo = ''
+      this.historyPage.current = 1
+      this.historyRecords = []
+      this.historyDialog = true
+      this.loadHistory()
+    },
+    searchAllHistory() {
+      this.historyPage.current = 1
+      this.loadHistory()
+    },
+    openHistory(row) {
+      this.historyStandard = row.standardNo || row.methodName
+      this.historyScopeId = row.methodSearchNewId
+      this.historyRecords = []
+      this.historyDialog = true
+      this.loadHistory()
+    },
+    loadHistory() {
+      this.historyLoading = true
+      const request = this.historyScopeId === null
+        ? pageSearchNewHistory({ standardNo: this.historySearchNo,
+            current: this.historyPage.current, size: this.historyPage.size })
+        : listSearchNewHistory({ methodSearchNewId: this.historyScopeId })
+      request.then(res => {
+        if (res.code !== 200) return
+        if (this.historyScopeId === null) {
+          this.historyRecords = res.data?.records || []
+          this.historyPage.total = res.data?.total || 0
+        } else {
+          this.historyRecords = res.data || []
+        }
+      }).finally(() => { this.historyLoading = false })
+    },
     // 鏌ヨ鍒楄〃
     searchList() {
       this.tableLoading = true
@@ -278,24 +277,10 @@
       this.editFormDialog = false
       this.searchList()
     },
-    // 鍒犻櫎鏍囧噯鏌ユ柊璁板綍
-    handleDelete(row) {
-      this.$confirm('鏄惁鍒犻櫎璇ユ潯鏌ユ柊璁板綍?', '鎻愮ず', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      }).then(() => {
-        delMethodSearchNew({ methodSearchNewId: row.methodSearchNewId }).then(res => {
-          if (res.code !== 200) return
-          this.$message.success('鍒犻櫎鎴愬姛')
-          this.searchList()
-        })
-      }).catch(() => {
-      })
-    },
     // 鍒嗛〉
     pagination(page) {
       this.page.size = page.limit
+      this.page.current = page.page
       this.searchList();
     },
   },
diff --git a/src/views/CNAS/process/method/standardNoveltyRetrieval/options.js b/src/views/CNAS/process/method/standardNoveltyRetrieval/options.js
new file mode 100644
index 0000000..e6fc632
--- /dev/null
+++ b/src/views/CNAS/process/method/standardNoveltyRetrieval/options.js
@@ -0,0 +1,36 @@
+import dayjs from 'dayjs'
+
+export const searchResultOptions = ['鐜拌鏈夋晥', '宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬', '搴熸锛堟棤鏇夸唬锛�', '鍗冲皢瀹炴柦']
+
+export function isSearchRetired(searchNewResult) {
+  return ['宸蹭慨璁�/鏈夋柊鐗堟湰鏇夸唬', '搴熸锛堟棤鏇夸唬锛�'].includes(searchNewResult)
+}
+
+export function calculateNextSearchDate(searchNewTime) {
+  if (!searchNewTime) return ''
+  const date = dayjs(searchNewTime)
+  return date.isValid() ? date.add(3, 'month').format('YYYY-MM-DD') : ''
+}
+
+export const searchSourceOptions = [
+  { value: 4, label: '涓浗鏍囧噯鍖栧鍛樹細' },
+  { value: 5, label: '鍥藉甯傚満鐩戠潱绠$悊鎬诲眬' },
+  { value: 6, label: '鍏ㄥ浗鏍囧噯淇℃伅鍏叡鏈嶅姟骞冲彴' },
+  { value: 7, label: '鍥藉鏍囧噯鍏ㄦ枃鍏紑绯荤粺' },
+  { value: 8, label: '宸ユ爣缃�' },
+  { value: 3, label: '鍏朵粬' }
+]
+
+const legacySearchSources = {
+  0: '鏍囧噯缃戯紙鍘嗗彶鏉ユ簮锛�',
+  1: '濮旀墭鎯呮姤鎵�锛堝巻鍙叉潵婧愶級',
+  2: '鏍囧噯涔﹀簵锛堝巻鍙叉潵婧愶級'
+}
+
+export function displaySearchSource(value) {
+  return searchSourceOptions.find(item => item.value === value)?.label || legacySearchSources[value] || ''
+}
+
+export function displayDate(value) {
+  return value ? String(value).slice(0, 10) : ''
+}
diff --git a/src/views/business/reportPreparation/index.vue b/src/views/business/reportPreparation/index.vue
index 495f00f..c0669fc 100644
--- a/src/views/business/reportPreparation/index.vue
+++ b/src/views/business/reportPreparation/index.vue
@@ -165,7 +165,7 @@
       <div class="seal-select-block" v-loading="sealLoading">
         <div class="seal-select-title">
           <span>鎸変綅缃�夋嫨鍗扮珷</span>
-          <span class="seal-select-tip">鑷姩鍖归厤 MA绔� / 1鍙风珷 / 楠戠紳绔狅紝姣忛」鍙崟鐙皟鏁存垨娓呯┖</span>
+          <span class="seal-select-tip">鑷姩鍖归厤 MA绔� / 1鍙风珷 / 妫�楠屾娴嬬被鍗扮珷锛屾瘡椤瑰彲鍗曠嫭璋冩暣鎴栨竻绌�</span>
         </div>
         <div v-if="sealOptions.length" class="seal-position-grid">
           <div v-for="position in sealPositions" :key="position.key" class="seal-position-card">
@@ -1290,7 +1290,8 @@
         const reportSeal = this.sealOptions.find(item => item.name === '1鍙风珷')
           || this.sealOptions.find(item => !String(item.name).toUpperCase().includes('MA') && !String(item.name).includes('楠戠紳'))
           || this.sealOptions[0]
-        const seamSeal = this.sealOptions.find(item => String(item.name).includes('楠戠紳'))
+        const seamSeal = this.sealOptions.find(item => /妫�楠屾娴媩妫�娴嬫楠�/.test(String(item.name || '')))
+          || this.sealOptions.find(item => String(item.name).includes('楠戠紳'))
         this.selectedSealPositions = {
           maSealId: availableIds.includes(Number(row && row.maSealId))
             ? Number(row.maSealId) : (maSeal ? Number(maSeal.id) : null),
diff --git a/src/views/structural/sealManage/usageLedger/index.vue b/src/views/structural/sealManage/usageLedger/index.vue
index 665d47c..bbd2bf1 100644
--- a/src/views/structural/sealManage/usageLedger/index.vue
+++ b/src/views/structural/sealManage/usageLedger/index.vue
@@ -35,18 +35,10 @@
         v-hasPermi="['structural:sealUsageLedger:export']"
         type="primary"
         size="small"
-        :disabled="selection.length === 0 || exportLoading || submitLoading"
-        :loading="selectedExportLoading"
-        @click="exportSelected"
-      >鍕鹃�夊鍑�</el-button>
-      <el-button
-        v-hasPermi="['structural:sealUsageLedger:export']"
-        type="primary"
-        size="small"
         :disabled="exportLoading || submitLoading"
-        :loading="filteredExportLoading"
-        @click="exportFiltered"
-      >鎸夋潯浠跺鍑�</el-button>
+        :loading="exportLoading"
+        @click="exportLedger"
+      >瀵煎嚭</el-button>
     </div>
 
     <lims-table
@@ -125,8 +117,7 @@
       tableData: [],
       selection: [],
       tableLoading: false,
-      selectedExportLoading: false,
-      filteredExportLoading: false,
+      exportLoading: false,
       copiesDialogVisible: false,
       submitLoading: false,
       copiesForm: { id: null, reportCode: '', copies: 1, version: 0 },
@@ -144,11 +135,6 @@
         { label: '浠芥暟', prop: 'copies', dataType: 'slot', slot: 'copies', width: '120px' },
         { label: '鐢ㄥ嵃浜虹瀛�', prop: 'useUserName', width: '140px' }
       ]
-    }
-  },
-  computed: {
-    exportLoading() {
-      return this.selectedExportLoading || this.filteredExportLoading
     }
   },
   mounted() {
@@ -221,19 +207,15 @@
         })
       })
     },
-    exportSelected() {
-      if (!this.selection.length) {
-        this.$message.warning('璇烽�夋嫨瑕佸鍑虹殑璁板綍')
-        return
-      }
-      this.selectedExportLoading = true
-      this.downloadWord({ mode: 'selected', ids: this.selection.map(item => item.id) })
-        .finally(() => { this.selectedExportLoading = false })
-    },
-    exportFiltered() {
-      this.filteredExportLoading = true
-      this.downloadWord({ mode: 'filtered', query: this.buildQuery() })
-        .finally(() => { this.filteredExportLoading = false })
+    exportLedger() {
+      if (this.exportLoading || this.submitLoading) return
+      const payload = this.selection.length
+        ? { mode: 'selected', ids: this.selection.map(item => item.id) }
+        : { mode: 'filtered', query: this.buildQuery() }
+      this.exportLoading = true
+      this.downloadWord(payload)
+        .catch(() => {})
+        .finally(() => { this.exportLoading = false })
     },
     downloadWord(payload) {
       return exportSealUsageLedger(payload).then(async data => {
diff --git a/vite/plugins/index.js b/vite/plugins/index.js
index e12cea1..833d84f 100644
--- a/vite/plugins/index.js
+++ b/vite/plugins/index.js
@@ -4,9 +4,10 @@
 import createSvgIcon from './svg-icon'
 import createCompression from './compression'
 import createSetupExtend from './setup-extend'
+import superdocHttpWorker from './superdoc-http-worker.js'
 
 export default function createVitePlugins(viteEnv, isBuild = false) {
-  const vitePlugins = [vue()]
+  const vitePlugins = [vue(), superdocHttpWorker()]
   vitePlugins.push(createAutoImport())
   vitePlugins.push(createSetupExtend())
   vitePlugins.push(createSvgIcon(isBuild))

--
Gitblit v1.9.3