From 4afb944c92aed7287cc4691fc9019f3b9faea1c0 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期二, 03 十一月 2026 16:04:37 +0800
Subject: [PATCH] 增加对pdf预览支持,统计分析对时间范围的限定要求

---
 src/views/project/travelexpenseapply/edit.vue                      |   10 
 src/components/AttachmentPreviewPane/index.vue                     |  172 +++
 src/views/project/statistics/caseStatistics/index.vue              |    5 
 src/views/project/donorcharge/donorchargedetail/index.vue          |   10 
 src/views/project/statistics/applyStatistics/index.vue             |    5 
 src/views/project/travelexpensecheck/index.vue                     |   15 
 src/views/project/fund/performancedetails/index.vue                |  198 +--
 src/views/project/fund/applyDetail0/index.vue                      |  102 +-
 src/utils/filePreview.js                                           |   18 
 src/views/project/statistics/performanceStaristics/index.vue       |    5 
 src/views/project/fund/officeExpenseApply/index.vue                |   10 
 src/views/project/tallage/computingBill/index.vue                  |   98 +-
 src/views/project/travelexpenseapply/index.vue                     |   10 
 src/views/project/donationdetails/index.vue                        |   34 
 src/views/project/statistics/casePanorama/index.vue                |    5 
 src/views/project/fund/medicalCostApply/index.vue                  |   24 
 src/views/project/travelexpenseapply/travelexpensedetail/index.vue | 1165 +++++-------------------
 src/views/project/statistics/chargeStatistics/index.vue            |    4 
 src/views/project/fundcheck/officeExpenseCheck/index.vue           |   15 
 src/views/project/fund/applyDetail/index.vue                       |  178 +--
 src/views/project/fund/expertFeeApply/index.vue                    |   10 
 src/views/project/fund/ethicalExpertFeeApply/index.vue             |   10 
 src/main.js                                                        |   48 +
 src/views/project/fundcheck/medicalCostCheck/index.vue             |   15 
 src/assets/styles/pdf-resize-dialog.scss                           |  109 ++
 src/App.vue                                                        |    4 
 src/utils/fileNameCheck.js                                         |   20 
 src/views/project/unitCost/particulars/index.vue                   |   35 
 src/components/FilePreview/index.vue                               |  465 +++++++++
 29 files changed, 1,481 insertions(+), 1,318 deletions(-)

diff --git a/src/App.vue b/src/App.vue
index 0d50caa..336ec19 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -3,12 +3,16 @@
     <keep-alive>
     <router-view />
     </keep-alive>
+    <file-preview ref="filePreview" />
   </div>
 </template>
 
 <script>
+import FilePreview from "@/components/FilePreview/index.vue";
+
 export default  {
   name:  'App',
+  components: { FilePreview },
     metaInfo() {
         return {
             title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
diff --git a/src/assets/styles/pdf-resize-dialog.scss b/src/assets/styles/pdf-resize-dialog.scss
new file mode 100644
index 0000000..ec4db39
--- /dev/null
+++ b/src/assets/styles/pdf-resize-dialog.scss
@@ -0,0 +1,109 @@
+/* 绁ㄦ嵁/闄勪欢棰勮寮圭獥锛氬彲鎷栨嫿鍙充笅瑙掓敼鍙樺ぇ灏忥紝鍐呭鍖洪殢寮圭獥楂樺害鑷�傚簲 */
+.pdf-resize-dialog {
+  width: 80vw !important;
+  height: 82vh !important;
+  min-width: 720px;
+  min-height: 480px;
+  max-width: 96vw;
+  max-height: 94vh;
+  overflow: auto;
+  resize: both;
+  display: flex;
+  flex-direction: column;
+}
+
+.pdf-resize-dialog .el-dialog__header,
+.pdf-resize-dialog .el-dialog__footer {
+  flex: 0 0 auto;
+}
+
+.pdf-resize-dialog .el-dialog__body {
+  flex: 1 1 auto;
+  min-height: 0;
+  overflow: auto;
+  padding: 10px 20px;
+}
+
+.pdf-resize-dialog .pdfimg {
+  height: 600px;
+  min-height: 520px;
+}
+
+.pdf-resize-dialog .pdfimg .box-pdf {
+  height: 100%;
+  overflow: auto;
+}
+
+.pdf-resize-dialog .pdfimgmin {
+  min-height: 520px;
+}
+
+.pdf-resize-dialog .pdfimgmin .el-image,
+.pdf-resize-dialog .pdfimgmin .el-image__inner,
+.pdf-resize-dialog .pdfimgmin img {
+  max-height: 100%;
+}
+
+.pdf-resize-dialog.is-fullscreen,
+.pdf-resize-dialog.pdf-fullscreen {
+  width: 100vw !important;
+  height: 100vh !important;
+  max-width: 100vw !important;
+  max-height: 100vh !important;
+  margin: 0 !important;
+  top: 0 !important;
+  left: 0 !important;
+  resize: none;
+}
+
+.pdf-fullscreen-btn {
+  float: right;
+  margin-right: 28px;
+}
+
+.file-preview-dialog.is-fullscreen {
+  width: 100vw !important;
+  height: 100vh !important;
+  max-width: 100vw !important;
+  max-height: 100vh !important;
+  margin: 0 !important;
+  top: 0 !important;
+  left: 0 !important;
+  resize: none;
+}
+
+/* 鍏ㄥ眬 PDF/鍥剧墖棰勮寮圭獥涔熸敮鎸佹嫋鎷芥敼鍙樺ぇ灏� */
+.file-preview-dialog {
+  width: 80vw !important;
+  height: 82vh !important;
+  min-width: 720px;
+  min-height: 480px;
+  max-width: 96vw;
+  max-height: 94vh;
+  overflow: auto;
+  resize: both;
+  display: flex;
+  flex-direction: column;
+}
+
+.file-preview-dialog .el-dialog__header,
+.file-preview-dialog .el-dialog__footer {
+  flex: 0 0 auto;
+}
+
+.file-preview-dialog .el-dialog__body {
+  flex: 1 1 auto;
+  min-height: 0;
+  overflow: auto;
+  padding: 10px 20px;
+}
+
+.file-preview-dialog .file-preview {
+  height: 70vh;
+  min-height: 420px;
+}
+
+.file-preview-dialog .file-preview__pdf,
+.file-preview-dialog .file-preview__list {
+  height: 100%;
+}
diff --git a/src/components/AttachmentPreviewPane/index.vue b/src/components/AttachmentPreviewPane/index.vue
new file mode 100644
index 0000000..d832651
--- /dev/null
+++ b/src/components/AttachmentPreviewPane/index.vue
@@ -0,0 +1,172 @@
+<template>
+  <div class="attachment-preview-pane">
+    <div v-if="!file" class="attachment-preview-pane__tip">
+      璇烽�夋嫨宸︿晶鏂囦欢棰勮
+    </div>
+    <template v-else>
+      <div v-if="fileType === 'image'" class="attachment-preview-pane__toolbar">
+        <el-button-group>
+          <el-button
+            size="mini"
+            icon="el-icon-zoom-out"
+            title="缂╁皬"
+            @click="zoom(-0.2)"
+          />
+          <el-button size="mini" class="attachment-preview-pane__scale">
+            {{ Math.round(scale * 100) }}%
+          </el-button>
+          <el-button
+            size="mini"
+            icon="el-icon-zoom-in"
+            title="鏀惧ぇ"
+            @click="zoom(0.2)"
+          />
+        </el-button-group>
+        <el-button-group>
+          <el-button
+            size="mini"
+            icon="el-icon-refresh-left"
+            title="鍚戝乏鏃嬭浆"
+            @click="rotate(-90)"
+          />
+          <el-button
+            size="mini"
+            icon="el-icon-refresh-right"
+            title="鍚戝彸鏃嬭浆"
+            @click="rotate(90)"
+          />
+        </el-button-group>
+        <el-button size="mini" icon="el-icon-refresh" @click="reset"
+          >閲嶇疆</el-button
+        >
+      </div>
+
+      <div v-if="fileType === 'image'" class="attachment-preview-pane__wrap">
+        <img
+          :src="file.url"
+          class="attachment-preview-pane__image"
+          :style="{
+            transform: 'scale(' + scale + ') rotate(' + deg + 'deg)'
+          }"
+          alt="鍥剧墖棰勮"
+        />
+      </div>
+      <iframe
+        v-else-if="fileType === 'pdf'"
+        :src="file.url"
+        class="attachment-preview-pane__pdf"
+        title="PDF棰勮"
+      />
+      <div v-else class="attachment-preview-pane__tip">
+        璇ユ枃浠剁被鍨嬫殏涓嶆敮鎸侀瑙堬紝璇蜂笅杞藉悗鏌ョ湅
+      </div>
+    </template>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "AttachmentPreviewPane",
+  props: {
+    file: {
+      type: Object,
+      default: null
+    }
+  },
+  data() {
+    return {
+      scale: 1,
+      deg: 0
+    };
+  },
+  computed: {
+    fileType() {
+      if (!this.file) {
+        return "other";
+      }
+      if (this.file.type) {
+        return this.file.type;
+      }
+      const ext = String(this.file.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (ext === "pdf") {
+        return "pdf";
+      }
+      if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        return "image";
+      }
+      return "other";
+    }
+  },
+  watch: {
+    file() {
+      this.reset();
+    }
+  },
+  methods: {
+    zoom(delta) {
+      const next = Math.round((this.scale + delta) * 100) / 100;
+      this.scale = Math.min(5, Math.max(0.2, next));
+    },
+    rotate(deg) {
+      this.deg += deg;
+    },
+    reset() {
+      this.scale = 1;
+      this.deg = 0;
+    }
+  }
+};
+</script>
+
+<style scoped>
+.attachment-preview-pane {
+  width: 100%;
+  height: 100%;
+  min-height: 420px;
+  display: flex;
+  flex-direction: column;
+  align-items: stretch;
+  justify-content: flex-start;
+}
+.attachment-preview-pane__toolbar {
+  flex: 0 0 auto;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  padding: 4px 0 10px;
+}
+.attachment-preview-pane__scale {
+  min-width: 64px;
+  cursor: default;
+}
+.attachment-preview-pane__wrap {
+  flex: 1 1 auto;
+  min-height: 0;
+  overflow: auto;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.attachment-preview-pane__image {
+  max-width: 100%;
+  max-height: 100%;
+  transition: transform 0.2s ease;
+  transform-origin: center center;
+}
+.attachment-preview-pane__pdf {
+  flex: 1 1 auto;
+  width: 100%;
+  min-height: 420px;
+  border: 0;
+}
+.attachment-preview-pane__tip {
+  color: #909399;
+  font-size: 14px;
+  text-align: center;
+  padding: 20px;
+}
+</style>
diff --git a/src/components/FilePreview/index.vue b/src/components/FilePreview/index.vue
new file mode 100644
index 0000000..e80dc0e
--- /dev/null
+++ b/src/components/FilePreview/index.vue
@@ -0,0 +1,465 @@
+<template>
+  <el-dialog
+    :visible.sync="visible"
+    width="80%"
+    top="5vh"
+    append-to-body
+    :close-on-click-modal="false"
+    :destroy-on-close="false"
+    :fullscreen="fullscreen"
+    custom-class="file-preview-dialog"
+    @closed="handleClosed"
+  >
+    <div slot="title" class="file-preview-title">
+      <span>{{ currentFile ? currentFile.name : "鏂囦欢棰勮" }}</span>
+      <el-button
+        class="file-preview-fullscreen-btn"
+        size="mini"
+        :icon="fullscreen ? 'el-icon-close' : 'el-icon-full-screen'"
+        @click="fullscreen = !fullscreen"
+        >{{ fullscreen ? "杩樺師" : "鍏ㄥ睆" }}</el-button
+      >
+    </div>
+
+    <div v-loading="loading" class="file-preview">
+      <div class="file-preview__list">
+        <el-table
+          :data="previewFiles"
+          highlight-current-row
+          size="mini"
+          height="70vh"
+          @row-click="handleSelect"
+        >
+          <el-table-column prop="name" label="鏂囦欢" show-overflow-tooltip />
+        </el-table>
+      </div>
+
+      <div class="file-preview__body">
+        <template v-if="currentFile">
+          <div v-if="currentFile.error && !currentFile.previewUrl" class="file-preview__tip">
+            鏂囦欢鍔犺浇澶辫触锛歿{ currentFile.error }}
+          </div>
+          <iframe
+            v-else-if="currentFile.type === 'pdf'"
+            :src="currentFile.previewUrl"
+            class="file-preview__pdf"
+            title="PDF棰勮"
+          />
+          <div
+            v-else-if="currentFile.type === 'image'"
+            class="file-preview__image-pane"
+          >
+            <div class="file-preview__toolbar">
+              <el-button-group>
+                <el-button
+                  size="mini"
+                  icon="el-icon-zoom-out"
+                  title="缂╁皬"
+                  @click="zoomImage(-0.2)"
+                />
+                <el-button size="mini" class="file-preview__scale">
+                  {{ Math.round(imageScale * 100) }}%
+                </el-button>
+                <el-button
+                  size="mini"
+                  icon="el-icon-zoom-in"
+                  title="鏀惧ぇ"
+                  @click="zoomImage(0.2)"
+                />
+              </el-button-group>
+              <el-button-group>
+                <el-button
+                  size="mini"
+                  icon="el-icon-refresh-left"
+                  title="鍚戝乏鏃嬭浆"
+                  @click="rotateImage(-90)"
+                />
+                <el-button
+                  size="mini"
+                  icon="el-icon-refresh-right"
+                  title="鍚戝彸鏃嬭浆"
+                  @click="rotateImage(90)"
+                />
+              </el-button-group>
+              <el-button
+                size="mini"
+                icon="el-icon-refresh"
+                @click="resetImage"
+                >閲嶇疆</el-button
+              >
+            </div>
+            <div class="file-preview__image-wrap">
+              <img
+                :src="currentFile.previewUrl"
+                class="file-preview__image"
+                :style="{
+                  transform:
+                    'scale(' + imageScale + ') rotate(' + imageRotate + 'deg)'
+                }"
+                alt="鍥剧墖棰勮"
+              />
+            </div>
+          </div>
+          <div v-else class="file-preview__tip">
+            璇ユ枃浠剁被鍨嬫殏涓嶆敮鎸侀瑙堬紝璇蜂笅杞藉悗鏌ョ湅
+          </div>
+        </template>
+        <div v-else class="file-preview__tip">鏆傛棤鍙瑙堟枃浠�</div>
+      </div>
+    </div>
+
+    <span slot="footer" class="dialog-footer">
+      <span class="file-preview-pager">
+        <el-button
+          v-if="currentIndex > 0"
+          size="mini"
+          icon="el-icon-arrow-left"
+          @click="prevFile"
+          >涓婁竴寮�</el-button
+        >
+        <span class="file-preview-pager__text">
+          {{ previewFiles.length ? currentIndex + 1 : 0 }} /
+          {{ previewFiles.length }}
+        </span>
+        <el-button
+          v-if="currentIndex < previewFiles.length - 1"
+          size="mini"
+          @click="nextFile"
+          >涓嬩竴寮�<i class="el-icon-arrow-right el-icon--right"></i
+        ></el-button>
+      </span>
+      <el-button
+        v-if="currentFile && currentFile.type === 'pdf' && currentFile.previewUrl"
+        icon="el-icon-top-right"
+        @click="openInNewWindow"
+        >鏂扮獥鍙f墦寮�</el-button
+      >
+      <el-button type="primary" icon="el-icon-download" @click="handleDownload"
+        >涓嬭浇</el-button
+      >
+      <el-button @click="visible = false">鍏抽棴</el-button>
+    </span>
+  </el-dialog>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+const IMAGE_EXT = ["jpg", "jpeg", "png", "gif", "bmp", "webp"];
+
+export default {
+  name: "FilePreview",
+  data() {
+    return {
+      visible: false,
+      loading: false,
+      fileList: [],
+      previewFiles: [],
+      currentIndex: 0,
+      imageScale: 1,
+      imageRotate: 0,
+      fullscreen: false
+    };
+  },
+  computed: {
+    currentFile() {
+      return this.previewFiles[this.currentIndex] || null;
+    }
+  },
+  methods: {
+    /**
+     * 鎵撳紑棰勮
+     * files: [{ name, url }] 鎴栧崟涓� { name, url }
+     * index: 榛樿閫変腑涓嬫爣
+     */
+    open(files, index = 0) {
+      this.revokeUrls();
+      this.resetImage();
+      this.fullscreen = true;
+      this.fileList = Array.isArray(files) ? files : files ? [files] : [];
+      this.currentIndex = Math.max(0, Number(index) || 0);
+      this.previewFiles = [];
+      this.visible = true;
+      this.loadFiles();
+    },
+    async loadFiles() {
+      if (!this.fileList.length) {
+        this.loading = false;
+        return;
+      }
+      this.loading = true;
+      const token = getToken();
+      const result = await Promise.all(
+        this.fileList.map((file, idx) => this.loadOne(file, idx, token))
+      );
+      if (!this.visible) {
+        result.forEach(item => {
+          if (item.owned && item.previewUrl) URL.revokeObjectURL(item.previewUrl);
+        });
+        return;
+      }
+      this.previewFiles = result;
+      if (this.currentIndex >= this.previewFiles.length) {
+        this.currentIndex = 0;
+      }
+      this.loading = false;
+    },
+    async loadOne(file, idx, token) {
+      const name = file.name || "鏈懡鍚嶆枃浠�";
+      const type = this.getFileType(name);
+      const item = {
+        name,
+        type,
+        rawUrl: file.url,
+        previewUrl: "",
+        owned: false,
+        error: ""
+      };
+
+      // 鍏朵粬绫诲瀷涓嶅姞杞介瑙堬紝淇濈暀涓嬭浇鍦板潃鍗冲彲
+      if (type === "other") {
+        return item;
+      }
+
+      try {
+        const url = this.resolveUrl(file.url);
+        let previewUrl = url;
+
+        // blob/data URL 宸茬粡鏄湰鍦拌祫婧愶紝鏃犻渶鍐嶆璇锋眰
+        if (!/^(blob:|data:)/i.test(url)) {
+          const headers = token ? { Authorization: "Bearer " + token } : {};
+          const response = await fetch(url, { headers, cache: "no-store" });
+          if (!response.ok) {
+            throw new Error("HTTP " + response.status);
+          }
+          const blob = await response.blob();
+          if (type === "pdf") {
+            await this.assertPdf(blob);
+          } else if (type === "image" && blob.type && !/^image\//i.test(blob.type)) {
+            throw new Error("鏂囦欢鍐呭涓嶆槸鏈夋晥鍥剧墖锛屽彲鑳借繑鍥炰簡鎺ュ彛鎻愮ず淇℃伅");
+          }
+          const typedBlob =
+            type === "pdf"
+              ? new Blob([blob], { type: "application/pdf" })
+              : blob;
+          previewUrl = URL.createObjectURL(typedBlob);
+          item.owned = true;
+        } else if (type === "pdf" && /^blob:/i.test(url)) {
+          // 璋冪敤鏂逛紶鍏ョ殑 PDF blob 鍙兘娌℃湁姝g‘鐨� MIME锛岄噸鏂板寘瑁�
+          const response = await fetch(url);
+          const blob = await response.blob();
+          await this.assertPdf(blob);
+          previewUrl = URL.createObjectURL(
+            new Blob([blob], { type: "application/pdf" })
+          );
+          item.owned = true;
+        } else if (type === "image" && /^blob:/i.test(url)) {
+          // 鏍¢獙璋冪敤鏂逛紶鍏ョ殑鍥剧墖 blob锛岄伩鍏嶆妸 JSON 閿欒鍝嶅簲褰撳浘鐗囨樉绀�
+          const response = await fetch(url);
+          const blob = await response.blob();
+          if (blob.type && !/^image\//i.test(blob.type)) {
+            throw new Error("鏂囦欢鍐呭涓嶆槸鏈夋晥鍥剧墖锛屽彲鑳借繑鍥炰簡鎺ュ彛鎻愮ず淇℃伅");
+          }
+          previewUrl = URL.createObjectURL(blob);
+          item.owned = true;
+        }
+
+        item.previewUrl = previewUrl;
+      } catch (e) {
+        item.error = e && e.message ? e.message : "鍔犺浇澶辫触";
+        // 鍐呭闈炴硶鏃朵笉瑕侀��鍥炲師鍦板潃锛屽惁鍒欐祻瑙堝櫒鍙細鍐嶆鏄剧ず绌虹櫧/鈥滄湭鑳藉姞杞解��
+        item.previewUrl =
+          type === "pdf" || /涓嶆槸鏈夋晥/.test(item.error)
+            ? ""
+            : this.resolveUrl(file.url);
+      }
+      return item;
+    },
+    async assertPdf(blob) {
+      const head = await blob.slice(0, 5).text();
+      if (head !== "%PDF-") {
+        throw new Error(
+          "鏂囦欢鍐呭涓嶆槸鏈夋晥 PDF锛屽彲鑳芥槸鐧诲綍澶辨晥鎴栨枃浠跺湴鍧�閿欒锛堣繑鍥炰簡鎺ュ彛鎻愮ず淇℃伅锛�"
+        );
+      }
+    },
+    resolveUrl(url) {
+      if (!url) {
+        return "";
+      }
+      if (/^(blob:|data:|https?:)/i.test(url)) {
+        return url;
+      }
+      return (process.env.VUE_APP_BASE_API || "") + url;
+    },
+    getFileType(name) {
+      const ext = String(name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (ext === "pdf") {
+        return "pdf";
+      }
+      if (IMAGE_EXT.indexOf(ext) > -1) {
+        return "image";
+      }
+      return "other";
+    },
+    handleSelect(row) {
+      const index = this.previewFiles.indexOf(row);
+      if (index > -1) {
+        this.currentIndex = index;
+        this.resetImage();
+      }
+    },
+    prevFile() {
+      if (this.currentIndex > 0) {
+        this.currentIndex -= 1;
+        this.resetImage();
+      }
+    },
+    nextFile() {
+      if (this.currentIndex < this.previewFiles.length - 1) {
+        this.currentIndex += 1;
+        this.resetImage();
+      }
+    },
+    zoomImage(delta) {
+      const next = Math.round((this.imageScale + delta) * 100) / 100;
+      this.imageScale = Math.min(5, Math.max(0.2, next));
+    },
+    rotateImage(deg) {
+      this.imageRotate += deg;
+    },
+    resetImage() {
+      this.imageScale = 1;
+      this.imageRotate = 0;
+    },
+    handleDownload() {
+      const file = this.currentFile;
+      if (!file) {
+        return;
+      }
+      const href = file.previewUrl || this.resolveUrl(file.rawUrl);
+      if (!href) {
+        return;
+      }
+      const a = document.createElement("a");
+      a.href = href;
+      a.download = file.name;
+      document.body.appendChild(a);
+      a.click();
+      document.body.removeChild(a);
+    },
+    openInNewWindow() {
+      if (this.currentFile && this.currentFile.previewUrl) {
+        window.open(this.currentFile.previewUrl, "_blank");
+      }
+    },
+    handleClosed() {
+      this.revokeUrls();
+      this.previewFiles = [];
+      this.fileList = [];
+      this.currentIndex = 0;
+      this.resetImage();
+      this.fullscreen = false;
+    },
+    revokeUrls() {
+      this.previewFiles.forEach(item => {
+        if (item.owned && item.previewUrl && /^blob:/i.test(item.previewUrl)) {
+          URL.revokeObjectURL(item.previewUrl);
+        }
+      });
+    }
+  },
+  beforeDestroy() {
+    this.revokeUrls();
+  }
+};
+</script>
+
+<style scoped>
+.file-preview-title {
+  font-weight: 600;
+  font-size: 15px;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding-right: 30px;
+}
+.file-preview-fullscreen-btn {
+  margin-left: 12px;
+}
+.file-preview-pager {
+  float: left;
+  display: inline-flex;
+  align-items: center;
+  gap: 8px;
+}
+.file-preview-pager__text {
+  color: #606266;
+  font-size: 12px;
+}
+.file-preview {
+  display: flex;
+  height: 70vh;
+  min-height: 420px;
+}
+.file-preview__list {
+  width: 240px;
+  flex: 0 0 240px;
+  border-right: 1px solid #ebeef5;
+  padding-right: 10px;
+  overflow: hidden;
+}
+.file-preview__body {
+  flex: 1;
+  min-width: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  overflow: auto;
+}
+.file-preview__pdf {
+  width: 100%;
+  height: 70vh;
+  border: 0;
+}
+.file-preview__image {
+  max-width: 100%;
+  max-height: 100%;
+  transition: transform 0.2s ease;
+  transform-origin: center center;
+}
+.file-preview__image-pane {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  min-height: 0;
+}
+.file-preview__toolbar {
+  flex: 0 0 auto;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  padding: 4px 0 10px;
+}
+.file-preview__scale {
+  min-width: 64px;
+  cursor: default;
+}
+.file-preview__image-wrap {
+  flex: 1 1 auto;
+  min-height: 0;
+  overflow: auto;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.file-preview__tip {
+  color: #909399;
+  font-size: 14px;
+}
+</style>
diff --git a/src/main.js b/src/main.js
index 6ecaa60..11ed65b 100644
--- a/src/main.js
+++ b/src/main.js
@@ -18,7 +18,9 @@
 // 杩愯鏃朵富棰樺眰 + 缁勪欢榛樿澶栬锛氬繀椤绘櫄浜� element-ui 涓� ruoyi.scss锛屽惁鍒欒鐩栦笉鐢熸晥
 import '@/assets/styles/theme-runtime.scss'
 import '@/assets/styles/element-override.scss'
+import '@/assets/styles/pdf-resize-dialog.scss'
 import App from './App'
+import FilePreview from '@/components/FilePreview/index.vue'
 import store from './store'
 import router from './router'
 import directive from './directive' //directive
@@ -43,6 +45,7 @@
 import FileUpload from "@/components/FileUpload"
 // 鍥剧墖涓婁紶缁勪欢
 import ImageUpload from "@/components/ImageUpload"
+import AttachmentPreviewPane from "@/components/AttachmentPreviewPane/index.vue"
 // 瀛楀吀鏍囩缁勪欢
 import DictTag from '@/components/DictTag'
 // 澶撮儴鏍囩缁勪欢
@@ -90,6 +93,30 @@
 Vue.component('Editor', Editor)
 Vue.component('FileUpload', FileUpload)
 Vue.component('ImageUpload', ImageUpload)
+Vue.component('AttachmentPreviewPane', AttachmentPreviewPane)
+
+// 闄勪欢鍐呭祵棰勮锛氭墍鏈夋姤閿�椤靛叡鐢�
+Vue.mixin({
+  data() {
+    return {
+      embeddedFile: null,
+      pdfFullscreen: false
+    }
+  },
+  methods: {
+    openEmbeddedPreview(item) {
+      if (!item) return
+      const ext = String(item.name || '').toLowerCase().split('.').pop()
+      const type = ext === 'pdf'
+        ? 'pdf'
+        : ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)
+          ? 'image'
+          : 'other'
+      this.embeddedFile = { name: item.name, url: item.url, type }
+      this.pdfVisible = true
+    }
+  }
+})
 
 Vue.use(directive)
 Vue.use(plugins)
@@ -116,9 +143,28 @@
 
 Vue.config.productionTip = false
 
-new Vue({
+// 鍓嶇鏋勫缓鏍囪瘑锛氱敤浜庣‘璁ゆ祻瑙堝櫒瀹為檯鍔犺浇鐨勬槸鍝竴鐗堜唬鐮�
+window.__APP_BUILD__ = '2026-11-03-PDF-PREVIEW-15'
+
+const app = new Vue({
   el: '#app',
   router,
   store,
   render: h => h(App)
 })
+
+// 鏂囦欢棰勮锛欰pp 鍐呮寕杞界殑鍏ㄥ眬缁勪欢锛岄伩鍏嶅湪搴旂敤澶栨墜宸� $mount
+let fallbackPreview = null
+Vue.prototype.$previewFile = (files, index = 0) => {
+  if (app.$refs.filePreview) {
+    app.$refs.filePreview.open(files, index)
+    return
+  }
+  // 鍏滃簳锛欰pp 鍐呯粍浠跺皻鏈寕杞芥椂锛屼粛淇濊瘉鏈夐瑙堝叆鍙�
+  if (!fallbackPreview) {
+    const FilePreviewCtor = Vue.extend(FilePreview)
+    fallbackPreview = new FilePreviewCtor().$mount()
+    document.body.appendChild(fallbackPreview.$el)
+  }
+  fallbackPreview.open(files, index)
+}
diff --git a/src/utils/fileNameCheck.js b/src/utils/fileNameCheck.js
index 2554490..719f952 100644
--- a/src/utils/fileNameCheck.js
+++ b/src/utils/fileNameCheck.js
@@ -1,11 +1,12 @@
 /**
- * 鎶ラ攢鍗曢檮浠舵枃浠跺悕瑙勮寖鏍¢獙锛�2026-10-15锛�
+ * 鎶ラ攢鍗曢檮浠舵枃浠跺悕瑙勮寖鏍¢獙锛�2026-11-03 璋冩暣锛�
  *
- * 涓氬姟鍙e緞锛堜笟鍔℃柟纭锛夛細
- *   1. 蹇呴』鍖呭惈涓枃锛堣嚦灏� 1 涓眽瀛楋級鈥斺��"涓烘柟渚挎煡楠岄檮浠讹紝璇风敤涓枃瑙勮寖鍛藉悕闄勪欢锛�"
- *   2. 鍘绘帀鎵╁睍鍚嶅悗鐨勪富骞诧紝鎸夊瓧绗︽暟璁$畻涓嶈兘瓒呰繃 20 涓瓧鈥斺��"涓烘柟渚挎煡楠岄檮浠讹紝闄勪欢鍚嶅瓧闀垮害涓嶈兘瓒呰繃20涓瓧锛�"
+ * 涓氬姟鍙e緞锛�
+ *   1. 鍏佽鏂囦欢鍚嶄笉鍚腑鏂囷紱鍚腑鏂�/绾嫳鏂�/鏁板瓧鍧囧彲
+ *   2. 鍘绘帀鎵╁睍鍚嶅悗鐨勪富骞诧紝鎸夊瓧绗︽暟璁$畻涓嶈兘瓒呰繃 20 涓瓧
  *   3. 涓嶈兘鍖呭惈绌烘牸鍙� / \ : * ? " < > | # % 绛夌壒娈婂瓧绗�
  *   4. 鍚屼竴鏄庣粏琛屽唴涓嶈兘閲嶅悕锛堟瘮杈冩椂蹇界暐鎵╁睍鍚嶅ぇ灏忓啓涓庨灏剧┖鏍硷級
+ *   5. 鍙牎楠屾柊涓婁紶/鏂颁繚瀛樼殑闄勪欢锛涘巻鍙查檮浠剁敱鍚庣鎸� existingNames 鏀捐
  *
  * 浣跨敤鍦烘櫙锛�
  *   - 涓婁紶鎴愬姛鍥炶皟锛氫笉鍚堟牸 鈫� 寮规彁绀轰笖涓嶅姞鍏ュ垪琛紱
@@ -16,13 +17,10 @@
 /** 涓诲共锛堝幓鎵╁睍鍚嶏級鏈�澶у瓧绗︽暟 */
 export const MAX_MAIN_LENGTH = 20;
 
-/** 姹夊瓧 */
-const RE_CHINESE = /[\u4e00-\u9fa5]/;
-
 /** 闈炴硶瀛楃锛氱┖鏍硷紙鍚悇绫荤┖鐧斤級+ / \ : * ? " < > | # % */
 const RE_ILLEGAL = /[\s/\\:*?"<>|#%]/;
 
-export const MSG_NO_CHINESE = "涓烘柟渚挎煡楠岄檮浠讹紝璇风敤涓枃瑙勮寖鍛藉悕闄勪欢锛�";
+export const MSG_EMPTY_NAME = "涓烘柟渚挎煡楠岄檮浠讹紝闄勪欢鍚嶄笉鑳戒负绌猴紒";
 export const MSG_TOO_LONG = "涓烘柟渚挎煡楠岄檮浠讹紝闄勪欢鍚嶅瓧闀垮害涓嶈兘瓒呰繃20涓瓧锛�";
 export const MSG_ILLEGAL = '涓烘柟渚挎煡楠岄檮浠讹紝闄勪欢鍚嶄笉鑳藉寘鍚┖鏍煎強 / \\ : * ? " < > | # % 绛夌壒娈婂瓧绗︼紒';
 export const MSG_DUPLICATE = "涓烘柟渚挎煡楠岄檮浠讹紝鍚屼竴琛屽唴涓嶈兘鏈夐噸鍚嶇殑闄勪欢锛�";
@@ -46,15 +44,13 @@
 export function checkFileName(fileName) {
   const name = (fileName || "").trim();
   if (!name) {
-    return { ok: false, msg: MSG_NO_CHINESE, main: "" };
+    return { ok: false, msg: MSG_EMPTY_NAME, main: "" };
   }
   if (RE_ILLEGAL.test(name)) {
     return { ok: false, msg: MSG_ILLEGAL, main: mainName(name) };
   }
   const main = mainName(name);
-  if (!RE_CHINESE.test(main)) {
-    return { ok: false, msg: MSG_NO_CHINESE, main };
-  }
+  // 涓嶅啀寮哄埗瑕佹眰涓枃锛涘惈涓枃銆佺函鑻辨枃銆佹暟瀛楀潎鍙�
   // 鎸夊瓧绗︽暟璁★紙鐢ㄦ墿灞曡繍绠楃鎸夌爜鐐硅鏁帮紝涓枃/瀛楁瘝/鏁板瓧/鍏ㄨ鍚勮 1锛�
   if ([...main].length > MAX_MAIN_LENGTH) {
     return { ok: false, msg: MSG_TOO_LONG, main };
diff --git a/src/utils/filePreview.js b/src/utils/filePreview.js
new file mode 100644
index 0000000..83ae08b
--- /dev/null
+++ b/src/utils/filePreview.js
@@ -0,0 +1,18 @@
+import Vue from "vue";
+import FilePreview from "@/components/FilePreview/index.vue";
+
+let instance = null;
+
+/**
+ * 鍏ㄥ眬鏂囦欢棰勮锛氬浘鐗囥�丳DF
+ * @param {Array|Object} files [{ name, url }] 鎴栧崟涓� { name, url }
+ * @param {Number} index 榛樿閫変腑涓嬫爣
+ */
+export default function previewFile(files, index = 0) {
+  if (!instance) {
+    const FilePreviewCtor = Vue.extend(FilePreview);
+    instance = new FilePreviewCtor().$mount();
+    document.body.appendChild(instance.$el);
+  }
+  instance.open(files, index);
+}
diff --git a/src/views/project/donationdetails/index.vue b/src/views/project/donationdetails/index.vue
index 00d7057..50b2afe 100644
--- a/src/views/project/donationdetails/index.vue
+++ b/src/views/project/donationdetails/index.vue
@@ -2511,6 +2511,7 @@
       :title="pdftitle"
       :visible.sync="pdfVisible"
       width="68%"
+      custom-class="pdf-resize-dialog"
     >
       <!-- <el-tabs style="margin-top: 20px;" v-model="activeName" type="card">
         <el-tab-pane :label="activetele" name="1"> </el-tab-pane>
@@ -4282,14 +4283,8 @@
     },
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
 
     // 鑾峰彇闄勪欢鏁版嵁骞跺垎绫讳簩绾у垪
@@ -4337,7 +4332,7 @@
       const config = {
         headers: { Authorization: "Bearer " + this.ICDtoken }
       };
-      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+      const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
       console.log(this.Networkheader);
       //鑾峰彇绁ㄦ嵁淇℃伅浣嶇疆
       if (response.code == 200) {
@@ -4398,7 +4393,7 @@
       this.pdfVisible = true;
       if (this.annexfilesList.length) {
         this.annexfilesList.forEach((value, indexson) => {
-          const pdfimg = this.Networkheader + "/prod-api" + value.annexurl;
+          const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.annexurl;
           fetch(pdfimg, config)
             .then(response => response.blob())
             .then(blob => {
@@ -4433,18 +4428,13 @@
       console.log(item, "鐐瑰嚮鏂囦欢鎷縤tem");
       this.pdftitle =
         "鍏�" + this.donatelist.length + "椤癸紝褰撳墠閫変腑" + item.annexname;
-      let name = item.annexname.split(".");
-      if (name[1] == "pdf") {
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-      } else if (name[1] == "jpg" || "png") {
-        this.previewpdf = true;
-        if (item.annexurl) {
-          this.pdfimg = item.annexurl;
-        } else {
-          this.pdfimg = "";
-        }
+      const ext = String(item.annexname || "pdf").toLowerCase().split(".").pop();
+      if (ext === "pdf") {
+        this.$previewFile([{ name: item.annexname, url: item.annexurl }]);
+        return;
+      } else if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([{ name: item.annexname, url: item.annexurl }]);
+        return;
       } else {
         this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
         this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
diff --git a/src/views/project/donorcharge/donorchargedetail/index.vue b/src/views/project/donorcharge/donorchargedetail/index.vue
index e4b94c7..693ecbb 100644
--- a/src/views/project/donorcharge/donorchargedetail/index.vue
+++ b/src/views/project/donorcharge/donorchargedetail/index.vue
@@ -472,14 +472,8 @@
     handleUploadError() {},
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
     // 鍙戠エ鍒囨崲
     handleClick(tab, event) {
diff --git a/src/views/project/fund/applyDetail/index.vue b/src/views/project/fund/applyDetail/index.vue
index b4b6494..715f80a 100644
--- a/src/views/project/fund/applyDetail/index.vue
+++ b/src/views/project/fund/applyDetail/index.vue
@@ -516,7 +516,24 @@
       </span>
     </el-dialog>
     <el-dialog v-dialogDrags :modal="false" :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible"
-      width="60%">
+      :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false">
+      <template slot="title">
+        <span>{{ pdftitle }}</span>
+        <el-button class="pdf-fullscreen-btn" size="mini"
+          :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'"
+          @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "杩樺師" : "鍏ㄥ睆" }}</el-button>
+      </template>
+      <el-alert
+        :title="
+          activeName == 'invoice'
+            ? '褰撳墠姝e湪鎿嶄綔锛氬彂绁ㄦ枃浠讹紙璇风‘璁ょエ鎹睘浜庡彂绁級'
+            : '褰撳墠姝e湪鎿嶄綔锛氭櫘閫氶檮浠讹紙璇峰嬁鍦ㄦ涓婁紶鍙戠エ锛�'
+        "
+        :type="activeName == 'invoice' ? 'success' : 'warning'"
+        :closable="false"
+        show-icon
+        style="margin-bottom: 10px;"
+      />
       <div style="margin-bottom: 10px;">
         <el-table :data="tableDatatop" style="width: 100%">
           <el-table-column v-if="businessType == 4" prop="price" align="center" label="鍗曚环">
@@ -601,18 +618,7 @@
               </div>
             </div>
 
-            <div v-if="this.previewpdf && pdfimgsrcList.length" class="pdfimgmin">
-              <!-- <img :src="pdfimg" /> -->
-              <el-image ref="imagePreview" style="width: 95%; height: 90%" :src="pdfimg"
-                @click="handleImageClick(initialIndex)">
-                <!-- <div slot="error" class="image-slot">
-                <i class="el-icon-picture-outline"></i>
-              </div> -->
-              </el-image>
-              <custom-image-viewer :url-list="pdfimgsrcList" :initial-index="currentIndex" :visible="viewerVisible"
-                @update:visible="viewerVisible = $event" @close="handleViewerClose" />
-            </div>
-            <div v-else class="pdfimgmins">{{ hintitle }}</div>
+            <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" />
           </div>
         </el-tab-pane>
         <el-tab-pane label="鍙戠エ鏂囦欢" name="invoice">
@@ -653,19 +659,7 @@
               </div>
             </div>
 
-            <div v-if="this.previewpdf && invoicepdfimgsrcList.length" class="pdfimgmin">
-              <!-- <img :src="pdfimg" /> -->
-              <el-image style="width: 95%; height: 90%" :src="invoicepdfimg"
-                @click="invoicehandleImageClick(initialIndex)">
-                <!-- <div slot="error" class="image-slot">
-                <i class="el-icon-picture-outline"></i>
-              </div> -->
-              </el-image>
-              <custom-image-viewer :url-list="invoicepdfimgsrcList" :initial-index="invoicecurrentIndex"
-                :visible="invoiceviewerVisible" @update:visible="invoiceviewerVisible = $event"
-                @close="invoicehandleViewerClose" />
-            </div>
-            <div v-else class="pdfimgmins">{{ hintitle }}</div>
+            <attachment-preview-pane :file="invoiceEmbeddedFile" style="flex: 1; min-width: 0;" />
           </div>
         </el-tab-pane>
       </el-tabs>
@@ -1121,7 +1115,7 @@
       invoicepdfimg: "",
       invoicepdfimgsrcList: [],
       invoDatatop: [],
-      activeName: "common", //鏂囦欢绫诲瀷
+      activeName: "invoice", //鏂囦欢绫诲瀷锛氶粯璁ゅ彂绁ㄦ枃浠�
       //涓婁紶闄勪欢璺緞
       uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload",
       ICDtoken: getToken(),
@@ -1132,6 +1126,7 @@
       //绁ㄦ嵁鏂囦欢
       pdftitle: "",
       pdfimg: "",
+      invoiceEmbeddedFile: null,
       pdfimgsrcList: [],
       currentIndex: 0, // 鍒濆绱㈠紩
       invoicecurrentIndex: 0, // 鍒濆绱㈠紩
@@ -1234,14 +1229,8 @@
     },
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
     /** 閫氳繃鍙傛暟鑾峰彇涓氬姟绫诲瀷 */
     getroute() {
@@ -2975,7 +2964,7 @@
 
     /**
      * 2026-10-15锛氫笂浼犳椂鏍¢獙闄勪欢鏂囦欢鍚嶏紙涓氬姟瑕佹眰锛氫笉鍚堟牸绔嬪嵆鎻愮ず涓斾笉鍔犲叆鍒楄〃锛夈��
-     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細蹇呴』鍚腑鏂� / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
+     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細涓嶅己鍒跺惈涓枃 / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
      * 涓嶅惈绌烘牸鍙� / \ : * ? " < > | # % 绛夌壒娈婂瓧绗︺��
      */
     checkUploadFileName(file) {
@@ -3014,27 +3003,27 @@
       const config = {
         headers: { Authorization: "Bearer " + this.ICDtoken }
       };
-      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+      const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
       //鑾峰彇绁ㄦ嵁淇℃伅浣嶇疆
       if (this.activeName == "common") {
         if (response.code == 200) {
           this.previewpdf = true;
 
-          fetch(pdfimg, config)
-            .then(response => response.blob())
-            .then(blob => {
-              // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-              this.pdfimg = URL.createObjectURL(blob);
-              this.pdfimgsrcList.push(URL.createObjectURL(blob));
-              this.fileListto.push({
-                name: file.name,
-                url: URL.createObjectURL(blob)
-              });
-            })
-            .catch(error => {
-              console.error("Error loading image", error);
-              return;
-            });
+          // 鏂颁笂浼犳枃浠剁洿鎺ヤ娇鐢ㄦ祻瑙堝櫒鏈湴 File锛岄伩鍏嶆湇鍔$鏂囦欢鍦板潃/Token
+          // 寮傚父鏃舵妸 JSON 閿欒鍝嶅簲褰撴垚鍥剧墖鎴� PDF 棰勮銆�
+          const localBlob = file.raw;
+          const localUrl = URL.createObjectURL(localBlob);
+          this.pdfimg = localUrl;
+          this.embeddedFile = {
+            name: file.name,
+            url: localUrl,
+            type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+          };
+          this.pdfimgsrcList.push(localUrl);
+          this.fileListto.push({
+            name: file.name,
+            url: localUrl
+          });
 
           this.$modal.msgSuccess(response.msg);
 
@@ -3053,21 +3042,19 @@
       } else {
         if (response.code == 200) {
           this.previewpdf = true;
-          fetch(pdfimg, config)
-            .then(response => response.blob())
-            .then(blob => {
-              // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-              this.invoicepdfimg = URL.createObjectURL(blob);
-              this.invoicepdfimgsrcList.push(URL.createObjectURL(blob));
-              this.invoicefileListto.push({
-                name: file.name,
-                url: URL.createObjectURL(blob)
-              });
-            })
-            .catch(error => {
-              console.error("Error loading image", error);
-              return;
-            });
+          const localBlob = file.raw;
+          const localUrl = URL.createObjectURL(localBlob);
+          this.invoicepdfimg = localUrl;
+          this.invoiceEmbeddedFile = {
+            name: file.name,
+            url: localUrl,
+            type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+          };
+          this.invoicepdfimgsrcList.push(localUrl);
+          this.invoicefileListto.push({
+            name: file.name,
+            url: localUrl
+          });
 
           this.$modal.msgSuccess(response.msg);
 
@@ -3103,7 +3090,7 @@
 
       if (this.rbDetails[index].annexfilesList) {
         // this.rbDetails[index].annexfilesList.forEach((value, indexson) => {
-        //   const pdfimg = this.Networkheader + "/prod-api" + value.url;
+        //   const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
         //   fetch(pdfimg, config)
         //     .then(response => response.blob())
         //     .then(blob => {
@@ -3125,7 +3112,7 @@
 
         const fetchPromises = this.rbDetails[index].annexfilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -3158,7 +3145,7 @@
       if (this.rbDetails[index].invoicefilesList) {
         const fetchPromises = this.rbDetails[index].invoicefilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -3201,50 +3188,17 @@
       console.log(this.rbDetails[index].annexfilesList, "annexfilesList");
     },
 
-    // 鐐瑰嚮宸蹭笂浼犳枃浠�
+    // 璐圭敤鎶ラ攢锛氶檮浠剁粺涓�浣跨敤鐙珛 FilePreview锛堝綍鍏ャ�佸鎵广�佽鎯呬竴鑷达級
     downFile(item) {
-      if (this.activeName == "common") {
-        this.pdftitle =
-          "鍏�" + this.pdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-        let name = item.name.split(".");
-        if (name[1] == "pdf") {
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        } else if (name[1] == "jpg" || "png") {
-          console.log(item, "灞曠ず");
-          this.previewpdf = true;
-          if (item.url) {
-            this.pdfimg = item.url;
-          } else {
-            this.pdfimg = "";
-          }
-        } else {
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-        }
-      } else {
-        this.pdftitle =
-          "鍏�" + this.invoicepdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-        let name = item.name.split(".");
-        if (name[1] == "pdf") {
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        } else if (name[1] == "jpg" || "png") {
-          this.previewpdf = true;
-          if (item.url) {
-            this.invoicepdfimg = item.url;
-          } else {
-            this.invoicepdfimg = "";
-          }
-        } else {
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-        }
+      const source =
+        this.activeName == "common" ? this.fileListto : this.invoicefileListto;
+      let list = (source || []).map(f => ({ name: f.name, url: f.url }));
+      let index = list.findIndex(f => f.url === item.url);
+      if (index < 0 && item && item.url) {
+        list = [{ name: item.name, url: item.url }];
+        index = 0;
       }
+      this.$previewFile(list, index > -1 ? index : 0);
     },
     getIndexInArray(arr, obj) {
       return arr.indexOf(obj);
diff --git a/src/views/project/fund/applyDetail0/index.vue b/src/views/project/fund/applyDetail0/index.vue
index 90a2988..f770dec 100644
--- a/src/views/project/fund/applyDetail0/index.vue
+++ b/src/views/project/fund/applyDetail0/index.vue
@@ -1034,8 +1034,21 @@
       :close-on-click-modal="false"
       :title="pdftitle"
       :visible.sync="pdfVisible"
+      :fullscreen="pdfFullscreen"
       width="60%"
+      custom-class="pdf-resize-dialog"
+      @closed="pdfFullscreen = false"
     >
+      <template slot="title">
+        <span>{{ pdftitle }}</span>
+        <el-button
+          class="pdf-fullscreen-btn"
+          size="mini"
+          :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'"
+          @click="pdfFullscreen = !pdfFullscreen"
+          >{{ pdfFullscreen ? "杩樺師" : "鍏ㄥ睆" }}</el-button
+        >
+      </template>
       <div class="pdfimg">
         <div class="box-pdf">
           <div>
@@ -1125,16 +1138,7 @@
           </div> -->
         </div>
 
-        <div v-if="this.previewpdf" class="pdfimgmin">
-          <!-- <img :src="pdfimg" /> -->
-          <el-image
-            style="width: 95%; height: 90%"
-            :src="pdfimg"
-            :preview-src-list="pdfimgsrcList"
-          >
-          </el-image>
-        </div>
-        <div v-else class="pdfimgmins">{{ hintitle }}</div>
+        <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" />
       </div>
     </el-dialog>
     <el-dialog title="鎻愮ず" :visible.sync="Savereminder" width="30%">
@@ -1552,15 +1556,8 @@
     },
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-        // console.log(this.Networkheader);
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
     /** 閫氳繃鍙傛暟鑾峰彇涓氬姟绫诲瀷 */
     getroute() {
@@ -3011,7 +3008,7 @@
     // },
     /**
      * 2026-10-15锛氫笂浼犳椂鏍¢獙闄勪欢鏂囦欢鍚嶏紙涓氬姟瑕佹眰锛氫笉鍚堟牸绔嬪嵆鎻愮ず涓斾笉鍔犲叆鍒楄〃锛夈��
-     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細蹇呴』鍚腑鏂� / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
+     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細涓嶅己鍒跺惈涓枃 / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
      * 涓嶅惈绌烘牸鍙� / \ : * ? " < > | # % 绛夌壒娈婂瓧绗︺��
      */
     checkUploadFileName(file) {
@@ -3056,9 +3053,15 @@
         this.fileListto.push({ name: file.name, url: response.fileName });
         // this.fileListto.push({ name: file.name, url: response.url });
         this.pdfimgsrcList.push(
-          this.Networkheader + "/prod-api" + response.fileName
+          this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName
         );
-        this.pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+        this.pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
+        const localUrl = URL.createObjectURL(file.raw);
+        this.embeddedFile = {
+          name: file.name,
+          url: localUrl,
+          type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+        };
 
         this.rbDetails[this.atpresent].annexfilesList = this.fileListto;
       } else {
@@ -3073,11 +3076,11 @@
       if (this.rbDetails[index].annexfilesList) {
         this.previewpdf = true;
         this.fileListto = this.rbDetails[index].annexfilesList;
-        this.pdfimg = this.Networkheader + "/prod-api" + this.fileListto[0].url;
+        this.pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + this.fileListto[0].url;
         // this.pdfimg = this.fileListto[0].url;
         this.pdfimgsrcList = [];
         this.fileListto.forEach(item => {
-          this.pdfimgsrcList.push(this.Networkheader + "/prod-api" + item.url);
+          this.pdfimgsrcList.push(this.Networkheader + process.env.VUE_APP_BASE_API + item.url);
         });
         console.log(this.pdfimgsrcList);
         console.log(this.pdfimg);
@@ -3088,34 +3091,31 @@
       }
     },
 
-    // 鐐瑰嚮宸蹭笂浼犳枃浠�
+    // 鐐瑰嚮宸蹭笂浼犳枃浠讹細鍦ㄩ檮浠跺脊绐楀彸渚у唴宓岄瑙�
     downFile(item) {
-      console.log(item);
-      this.pdftitle = item.name;
-      let name = item.name.split(".");
-      if (name[1] == "pdf") {
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-      } else if (name[1] == "jpg" || "png") {
-        this.previewpdf = true;
-        if (item.url) {
-          this.pdfimg = this.Networkheader + "/prod-api" + item.url;
-
-          // if (!this.pdfimgsrcList.includes(this.pdfimg)) {
-          //   this.pdfimgsrcList.push(this.pdfimg);
-          //   console.log("鍔犲叆");
-          // }
-          console.log(this.pdfimg);
-          console.log(this.pdfimgsrcList, "imglist");
-        } else {
-          this.pdfimg = this.Networkheader + "/prod-api" + item.url;
-        }
-      } else {
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
+      if (this.operationType == "detail") {
+        const list = (this.fileListto || []).map(f => ({
+          name: f.name,
+          url: f.url
+        }));
+        const index = list.findIndex(f => f.url === item.url);
+        this.$previewFile(list, index > -1 ? index : 0);
+        return;
       }
+      const ext = String(item.name || "").toLowerCase().split(".").pop();
+      const isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext);
+      if (ext !== "pdf" && !isImage) {
+        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
+        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
+        return;
+      }
+      this.embeddedFile = {
+        name: item.name,
+        url: item.url,
+        type: ext === "pdf" ? "pdf" : "image"
+      };
+      this.pdftitle = item.name;
+      this.pdfVisible = true;
     },
     getIndexInArray(arr, obj) {
       return arr.indexOf(obj);
@@ -3126,7 +3126,7 @@
       console.log(row);
       const indexlist = this.getIndexInArray(
         this.pdfimgsrcList,
-        this.Networkheader + "/prod-api" + row.url
+        this.Networkheader + process.env.VUE_APP_BASE_API + row.url
       );
       console.log(indexlist);
       this.pdfimgsrcList.splice(indexlist, 1);
diff --git a/src/views/project/fund/ethicalExpertFeeApply/index.vue b/src/views/project/fund/ethicalExpertFeeApply/index.vue
index c6a74c6..6e6576e 100644
--- a/src/views/project/fund/ethicalExpertFeeApply/index.vue
+++ b/src/views/project/fund/ethicalExpertFeeApply/index.vue
@@ -2064,8 +2064,16 @@
       }
     },
 
-    // 涓嬭浇鏂囦欢
+    // 棰勮/涓嬭浇鏂囦欢
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/fund/expertFeeApply/index.vue b/src/views/project/fund/expertFeeApply/index.vue
index 0cd2053..1c0e30f 100644
--- a/src/views/project/fund/expertFeeApply/index.vue
+++ b/src/views/project/fund/expertFeeApply/index.vue
@@ -2661,8 +2661,16 @@
     //鏂囦欢涓婁紶
     handleUploadError() {},
 
-    /** 涓嬭浇鏂囦欢鎸夐挳鎿嶄綔 */
+    /** 棰勮/涓嬭浇鏂囦欢 */
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/fund/medicalCostApply/index.vue b/src/views/project/fund/medicalCostApply/index.vue
index dc2a2e0..05f74d4 100644
--- a/src/views/project/fund/medicalCostApply/index.vue
+++ b/src/views/project/fund/medicalCostApply/index.vue
@@ -1366,18 +1366,18 @@
     // 鐐瑰嚮宸蹭笂浼犳枃浠�
     downFile(item) {
       this.pdftitle = item.name;
-      let name = item.name.split(".");
-      if (name[1] == "pdf") {
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-      } else if (name[1] == "jpg" || "png") {
-        this.previewpdf = true;
-        if (item.url) {
-          this.pdfimg = item.url;
-        } else {
-          this.pdfimg = item.response.url;
-        }
+      const ext = String(item.name || "pdf").toLowerCase().split(".").pop();
+      if (ext === "pdf") {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
+      } else if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([
+          {
+            name: item.name,
+            url: item.url || (item.response && item.response.url)
+          }
+        ]);
+        return;
       } else {
         this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
         this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
diff --git a/src/views/project/fund/officeExpenseApply/index.vue b/src/views/project/fund/officeExpenseApply/index.vue
index dc6fc04..507427d 100644
--- a/src/views/project/fund/officeExpenseApply/index.vue
+++ b/src/views/project/fund/officeExpenseApply/index.vue
@@ -1936,8 +1936,16 @@
         console.log(response.msg);
       }
     },
-    // 涓嬭浇鏂囦欢
+    // 棰勮/涓嬭浇鏂囦欢
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/fund/performancedetails/index.vue b/src/views/project/fund/performancedetails/index.vue
index bbddd00..14e574c 100644
--- a/src/views/project/fund/performancedetails/index.vue
+++ b/src/views/project/fund/performancedetails/index.vue
@@ -596,8 +596,28 @@
       :close-on-click-modal="false"
       :title="pdftitle"
       :visible.sync="pdfVisible"
+      :fullscreen="pdfFullscreen"
       width="60%"
+      custom-class="pdf-resize-dialog"
+      @closed="pdfFullscreen = false"
     >
+      <template slot="title">
+        <span>{{ pdftitle }}</span>
+        <el-button class="pdf-fullscreen-btn" size="mini"
+          :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'"
+          @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "杩樺師" : "鍏ㄥ睆" }}</el-button>
+      </template>
+      <el-alert
+        :title="
+          activeName == 2
+            ? '褰撳墠姝e湪鎿嶄綔锛氬彂绁ㄦ枃浠讹紙璇风‘璁ょエ鎹睘浜庡彂绁級'
+            : '褰撳墠姝e湪鎿嶄綔锛氭櫘閫氶檮浠讹紙璇峰嬁鍦ㄦ涓婁紶鍙戠エ锛�'
+        "
+        :type="activeName == 2 ? 'success' : 'warning'"
+        :closable="false"
+        show-icon
+        style="margin-bottom: 10px;"
+      />
       <div style="margin-bottom: 10px;">
         <el-table :data="tableDatatop" style="width: 100%">
           <el-table-column
@@ -724,24 +744,7 @@
               </div>
             </div>
 
-            <div
-              v-if="this.previewpdf && pdfimgsrcList.length"
-              class="pdfimgmin"
-            >
-              <el-image
-                style="width: 95%; height: 90%"
-                :src="pdfimg"
-                @click="handleImageClick(0)"
-              />
-              <custom-image-viewer
-                :url-list="pdfimgsrcList"
-                :initial-index="currentIndex"
-                :visible="viewerVisible"
-                @update:visible="viewerVisible = $event"
-                @close="handleViewerClose"
-              />
-            </div>
-            <div v-else class="pdfimgmins">{{ hintitle }}</div>
+            <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" />
           </div>
         </el-tab-pane>
         <el-tab-pane label="鍙戠エ鏂囦欢" :name="2">
@@ -829,24 +832,7 @@
               </div>
             </div>
 
-            <div
-              v-if="this.previewpdf && invoicepdfimgsrcList.length"
-              class="pdfimgmin"
-            >
-              <el-image
-                style="width: 95%; height: 90%"
-                :src="invoicepdfimg"
-                @click="invoiceHandleImageClick(0)"
-              />
-              <custom-image-viewer
-                :url-list="invoicepdfimgsrcList"
-                :initial-index="invoiceCurrentIndex"
-                :visible="invoiceViewerVisible"
-                @update:visible="invoiceViewerVisible = $event"
-                @close="invoiceHandleViewerClose"
-              />
-            </div>
-            <div v-else class="pdfimgmins">{{ hintitle }}</div>
+            <attachment-preview-pane :file="invoiceEmbeddedFile" style="flex: 1; min-width: 0;" />
           </div>
         </el-tab-pane>
       </el-tabs>
@@ -1261,7 +1247,7 @@
       invoicefileListto: [],
       invoicepdfimg: "",
       invoicepdfimgsrcList: [],
-      activeName: 1, //鏂囦欢绫诲瀷
+      activeName: 2, //鏂囦欢绫诲瀷锛氶粯璁ゅ彂绁ㄦ枃浠�
       //涓婁紶闄勪欢璺緞
       uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload",
       //鏂囦欢涓婁紶token
@@ -1271,6 +1257,7 @@
       //绁ㄦ嵁鏂囦欢
       pdftitle: "",
       pdfimg: "",
+      invoiceEmbeddedFile: null,
       pdfimgsrcList: [],
       pdfVisible: false,
       previewpdf: false,
@@ -2826,18 +2813,12 @@
     },
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
     /**
      * 2026-10-15锛氫笂浼犳椂鏍¢獙闄勪欢鏂囦欢鍚嶏紙涓氬姟瑕佹眰锛氫笉鍚堟牸绔嬪嵆鎻愮ず涓斾笉鍔犲叆鍒楄〃锛夈��
-     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細蹇呴』鍚腑鏂� / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
+     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細涓嶅己鍒跺惈涓枃 / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
      * 涓嶅惈绌烘牸鍙� / \ : * ? " < > | # % 绛夌壒娈婂瓧绗︺��
      */
     checkUploadFileName(file) {
@@ -2876,27 +2857,23 @@
       const config = {
         headers: { Authorization: "Bearer " + this.ICDtoken }
       };
-      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+      const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
       //鑾峰彇绁ㄦ嵁淇℃伅浣嶇疆
       if (this.activeName == 1) {
         if (response.code == 200) {
           this.previewpdf = true;
-
-          fetch(pdfimg, config)
-            .then(response => response.blob())
-            .then(blob => {
-              // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-              this.pdfimg = URL.createObjectURL(blob);
-              this.pdfimgsrcList.push(URL.createObjectURL(blob));
-              this.fileListto.push({
-                name: file.name,
-                url: URL.createObjectURL(blob)
-              });
-            })
-            .catch(error => {
-              console.error("Error loading image", error);
-              return;
-            });
+          const localUrl = URL.createObjectURL(file.raw);
+          this.pdfimg = localUrl;
+          this.embeddedFile = {
+            name: file.name,
+            url: localUrl,
+            type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+          };
+          this.pdfimgsrcList.push(localUrl);
+          this.fileListto.push({
+            name: file.name,
+            url: localUrl
+          });
 
           this.$modal.msgSuccess(response.msg);
 
@@ -2915,21 +2892,18 @@
       } else {
         if (response.code == 200) {
           this.previewpdf = true;
-          fetch(pdfimg, config)
-            .then(response => response.blob())
-            .then(blob => {
-              // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-              this.invoicepdfimg = URL.createObjectURL(blob);
-              this.invoicepdfimgsrcList.push(URL.createObjectURL(blob));
-              this.invoicefileListto.push({
-                name: file.name,
-                url: URL.createObjectURL(blob)
-              });
-            })
-            .catch(error => {
-              console.error("Error loading image", error);
-              return;
-            });
+          const localUrl = URL.createObjectURL(file.raw);
+          this.invoicepdfimg = localUrl;
+          this.invoiceEmbeddedFile = {
+            name: file.name,
+            url: localUrl,
+            type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+          };
+          this.invoicepdfimgsrcList.push(localUrl);
+          this.invoicefileListto.push({
+            name: file.name,
+            url: localUrl
+          });
 
           this.$modal.msgSuccess(response.msg);
 
@@ -2966,7 +2940,7 @@
       if (this.rbDetails[index].annexfilesList) {
         const fetchPromises = this.rbDetails[index].annexfilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -2999,7 +2973,7 @@
       if (this.rbDetails[index].invoicefilesList) {
         const fetchPromises = this.rbDetails[index].invoicefilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -3033,7 +3007,7 @@
         this.pdftitle = "";
       }
 
-      if (this.activeName == "common") {
+      if (this.activeName == 1) {
         this.pdftitle = "鍏�" + this.pdfimgsrcList.length + "椤�";
       } else {
         this.pdftitle = "鍏�" + this.invoicepdfimgsrcList.length + "椤�";
@@ -3042,50 +3016,38 @@
       console.log(this.rbDetails[index].annexfilesList, "annexfilesList");
     },
 
-    // 鐐瑰嚮宸蹭笂浼犳枃浠�
+    // 鐐瑰嚮宸蹭笂浼犳枃浠讹細鍦ㄩ檮浠跺脊绐楀彸渚у唴宓岄瑙�
     downFile(item) {
+      if (this.operationType == "detail") {
+        const source =
+          this.activeName == 1 ? this.fileListto : this.invoicefileListto;
+        const list = (source || []).map(f => ({ name: f.name, url: f.url }));
+        const index = list.findIndex(f => f.url === item.url);
+        this.$previewFile(list, index > -1 ? index : 0);
+        return;
+      }
+      const ext = String(item.name || "").toLowerCase().split(".").pop();
+      const isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext);
+      if (ext !== "pdf" && !isImage) {
+        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
+        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
+        return;
+      }
+      const file = {
+        name: item.name,
+        url: item.url,
+        type: ext === "pdf" ? "pdf" : "image"
+      };
       if (this.activeName == 1) {
+        this.embeddedFile = file;
         this.pdftitle =
           "鍏�" + this.pdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-        let name = item.name.split(".");
-        if (name[1] == "pdf") {
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        } else if (name[1] == "jpg" || "png") {
-          console.log(item, "灞曠ず");
-          this.previewpdf = true;
-          if (item.url) {
-            this.pdfimg = item.url;
-          } else {
-            this.pdfimg = "";
-          }
-        } else {
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-        }
       } else {
+        this.invoiceEmbeddedFile = file;
         this.pdftitle =
           "鍏�" + this.invoicepdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-        let name = item.name.split(".");
-        if (name[1] == "pdf") {
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        } else if (name[1] == "jpg" || "png") {
-          this.previewpdf = true;
-          if (item.url) {
-            this.invoicepdfimg = item.url;
-          } else {
-            this.invoicepdfimg = "";
-          }
-        } else {
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-        }
       }
+      this.pdfVisible = true;
     },
     getIndexInArray(arr, obj) {
       return arr.indexOf(obj);
@@ -3173,7 +3135,7 @@
     },
     Downloadfile(row) {
       console.log(row);
-      window.location.href = this.Networkheader + "/prod-api" + row.url;
+      window.location.href = this.Networkheader + process.env.VUE_APP_BASE_API + row.url;
     },
     //琛ㄦ牸鍚堣
     getSummaries(param) {
diff --git a/src/views/project/fundcheck/medicalCostCheck/index.vue b/src/views/project/fundcheck/medicalCostCheck/index.vue
index 415efc9..25819e0 100644
--- a/src/views/project/fundcheck/medicalCostCheck/index.vue
+++ b/src/views/project/fundcheck/medicalCostCheck/index.vue
@@ -1760,8 +1760,21 @@
         console.log(response.msg);
       }
     },
-    // 涓嬭浇鏂囦欢
+    // 棰勮/涓嬭浇鏂囦欢
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        const list = (this.fileList || []).map(f => ({
+          name: f.name,
+          url: f.url
+        }));
+        const index = list.findIndex(f => f.url === item.url);
+        this.$previewFile(list, index > -1 ? index : 0);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/fundcheck/officeExpenseCheck/index.vue b/src/views/project/fundcheck/officeExpenseCheck/index.vue
index 68a8220..fdfd72b 100644
--- a/src/views/project/fundcheck/officeExpenseCheck/index.vue
+++ b/src/views/project/fundcheck/officeExpenseCheck/index.vue
@@ -1765,8 +1765,21 @@
         console.log(response.msg);
       }
     },
-    // 涓嬭浇鏂囦欢
+    // 棰勮/涓嬭浇鏂囦欢
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        const list = (this.fileList || []).map(f => ({
+          name: f.name,
+          url: f.url
+        }));
+        const index = list.findIndex(f => f.url === item.url);
+        this.$previewFile(list, index > -1 ? index : 0);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/statistics/applyStatistics/index.vue b/src/views/project/statistics/applyStatistics/index.vue
index a534727..55d4462 100644
--- a/src/views/project/statistics/applyStatistics/index.vue
+++ b/src/views/project/statistics/applyStatistics/index.vue
@@ -338,6 +338,10 @@
 
     /** 鏌ヨ鎹愮尞鍩虹鍒楄〃 */
     getList() {
+      if (!this.selecttime || this.selecttime.length !== 2) {
+        this.$modal.msgWarning("璇烽�夋嫨鏃堕棿鑼冨洿鍚庡啀鏌ヨ");
+        return;
+      }
       listbxiaostatistics(this.queryParams).then(res => {
         this.total = res.total;
         this.jxidata = res.rows;
@@ -503,7 +507,6 @@
   //鐢熷懡鍛ㄦ湡 - 鍒涘缓瀹屾垚锛堝彲浠ヨ闂綋鍓峵his瀹炰緥锛�
   created() {
     //鑾峰彇鍒楄〃
-    this.getList();
     this.listDept();
     this.getUserList();
   }
diff --git a/src/views/project/statistics/casePanorama/index.vue b/src/views/project/statistics/casePanorama/index.vue
index 6f0e584..4fe50f4 100644
--- a/src/views/project/statistics/casePanorama/index.vue
+++ b/src/views/project/statistics/casePanorama/index.vue
@@ -210,11 +210,14 @@
   },
   created() {
     this.getDeptOptions();
-    this.getList();
   },
   methods: {
     /** 鏌ヨ妗堜緥鍏ㄦ櫙 */
     getList() {
+      if (!this.dateRange || this.dateRange.length !== 2) {
+        this.$modal.msgWarning("璇烽�夋嫨鏃堕棿鑼冨洿鍚庡啀鏌ヨ");
+        return;
+      }
       this.loading = true;
       listCasePanorama(this.queryParams)
         .then(res => {
diff --git a/src/views/project/statistics/caseStatistics/index.vue b/src/views/project/statistics/caseStatistics/index.vue
index c2a3f02..0991122 100644
--- a/src/views/project/statistics/caseStatistics/index.vue
+++ b/src/views/project/statistics/caseStatistics/index.vue
@@ -340,6 +340,10 @@
 
     /** 鏌ヨ鎹愮尞鍩虹鍒楄〃 */
     getList() {
+      if (!this.selecttime || this.selecttime.length !== 2) {
+        this.$modal.msgWarning("璇烽�夋嫨鏃堕棿鑼冨洿鍚庡啀鏌ヨ");
+        return;
+      }
       listanlstatistics(this.queryParams).then(res => {
         this.jxidata = res.rows;
         this.jxidata.forEach(($obj, $index) => {
@@ -486,7 +490,6 @@
   //鐢熷懡鍛ㄦ湡 - 鍒涘缓瀹屾垚锛堝彲浠ヨ闂綋鍓峵his瀹炰緥锛�
   created() {
     //鑾峰彇鍒楄〃
-    this.getList();
     this.listDept();
   }
   // //鐢熷懡鍛ㄦ湡 - 鎸傝浇瀹屾垚锛堝彲浠ヨ闂瓺OM鍏冪礌锛�
diff --git a/src/views/project/statistics/chargeStatistics/index.vue b/src/views/project/statistics/chargeStatistics/index.vue
index 826eacf..d5ec2bc 100644
--- a/src/views/project/statistics/chargeStatistics/index.vue
+++ b/src/views/project/statistics/chargeStatistics/index.vue
@@ -337,6 +337,10 @@
 
     /** 鏌ヨ鏀舵缁熻 */
     getList() {
+      if (!this.selecttime || this.selecttime.length !== 2) {
+        this.$modal.msgWarning("璇烽�夋嫨鏃堕棿鑼冨洿鍚庡啀鏌ヨ");
+        return;
+      }
       this.loading = true;
       listsfeistatistics(this.queryParams)
         .then(res => {
diff --git a/src/views/project/statistics/performanceStaristics/index.vue b/src/views/project/statistics/performanceStaristics/index.vue
index a93897b..36744ee 100644
--- a/src/views/project/statistics/performanceStaristics/index.vue
+++ b/src/views/project/statistics/performanceStaristics/index.vue
@@ -281,6 +281,10 @@
 
     /** 鏌ヨ鎹愮尞鍩虹鍒楄〃 */
     getList() {
+      if (!this.selecttime || this.selecttime.length !== 2) {
+        this.$modal.msgWarning("璇烽�夋嫨鏃堕棿鑼冨洿鍚庡啀鏌ヨ");
+        return;
+      }
       listjixstatistics(this.buildQueryParams()).then(res => {
         this.jxidata = res.rows;
         this.jxidata.forEach(($obj, $index) => {
@@ -447,7 +451,6 @@
   //鐢熷懡鍛ㄦ湡 - 鍒涘缓瀹屾垚锛堝彲浠ヨ闂綋鍓峵his瀹炰緥锛�
   created() {
     //鑾峰彇鍒楄〃
-    this.getList();
     this.listDept();
   }
   // //鐢熷懡鍛ㄦ湡 - 鎸傝浇瀹屾垚锛堝彲浠ヨ闂瓺OM鍏冪礌锛�
diff --git a/src/views/project/tallage/computingBill/index.vue b/src/views/project/tallage/computingBill/index.vue
index dbf2747..b1412ce 100644
--- a/src/views/project/tallage/computingBill/index.vue
+++ b/src/views/project/tallage/computingBill/index.vue
@@ -439,8 +439,17 @@
         :close-on-click-modal="false"
         :title="pdftitle"
         :visible.sync="pdfVisible"
+        :fullscreen="pdfFullscreen"
         width="60%"
+        custom-class="pdf-resize-dialog"
+        @closed="pdfFullscreen = false"
       >
+        <template slot="title">
+          <span>{{ pdftitle }}</span>
+          <el-button class="pdf-fullscreen-btn" size="mini"
+            :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'"
+            @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "杩樺師" : "鍏ㄥ睆" }}</el-button>
+        </template>
         <div class="pdfimg">
           <div class="box-pdf">
             <div>
@@ -526,19 +535,7 @@
             </div>
           </div>
 
-          <div v-if="this.previewpdf && pdfimgsrcList.length" class="pdfimgmin">
-            <!-- <img :src="pdfimg" /> -->
-            <el-image
-              style="width: 95%; height: 90%"
-              :src="pdfimg"
-              :preview-src-list="pdfimgsrcList"
-            >
-              <!-- <div slot="error" class="image-slot">
-                <i class="el-icon-picture-outline"></i>
-              </div> -->
-            </el-image>
-          </div>
-          <div v-else class="pdfimgmins">{{ hintitle }}</div>
+          <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" />
         </div>
       </el-dialog>
     </div>
@@ -751,6 +748,7 @@
 
   created() {
     console.log(234);
+    this.Networkheader = window.location.origin;
     this.GetMaxTaxid();
 
     //鑾峰彇鍙傛暟
@@ -1201,25 +1199,23 @@
       const config = {
         headers: { Authorization: "Bearer " + this.ICDtoken }
       };
-      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+      const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
       //鑾峰彇绁ㄦ嵁淇℃伅浣嶇疆
       if (response.code == 200) {
         this.previewpdf = true;
-        fetch(pdfimg, config)
-          .then(response => response.blob())
-          .then(blob => {
-            // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-            this.pdfimg = URL.createObjectURL(blob);
-            this.pdfimgsrcList.push(URL.createObjectURL(blob));
-            this.fileListto.push({
-              name: file.name,
-              url: URL.createObjectURL(blob)
-            });
-          })
-          .catch(error => {
-            console.error("Error loading image", error);
-            return;
-          });
+        const localBlob = file.raw;
+        const localUrl = URL.createObjectURL(localBlob);
+        this.pdfimg = localUrl;
+        this.embeddedFile = {
+          name: file.name,
+          url: localUrl,
+          type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+        };
+        this.pdfimgsrcList.push(localUrl);
+        this.fileListto.push({
+          name: file.name,
+          url: localUrl
+        });
 
         this.$modal.msgSuccess(response.msg);
 
@@ -1257,7 +1253,7 @@
       if (this.donorchargeorgans[index].annexFilesList) {
         const fetchPromises = this.donorchargeorgans[index].annexFilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -1296,28 +1292,32 @@
       );
     },
 
-    // 鐐瑰嚮宸蹭笂浼犳枃浠�
+    // 鐐瑰嚮宸蹭笂浼犳枃浠讹細鍦ㄩ檮浠跺脊绐楀彸渚у唴宓岄瑙�
     downFile(item) {
+      if (this.operationType == "detail") {
+        const list = (this.fileListto || []).map(f => ({
+          name: f.name,
+          url: f.url
+        }));
+        const index = list.findIndex(f => f.url === item.url);
+        this.$previewFile(list, index > -1 ? index : 0);
+        return;
+      }
+      const ext = String(item.name || "").toLowerCase().split(".").pop();
+      const isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext);
+      if (ext !== "pdf" && !isImage) {
+        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
+        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
+        return;
+      }
+      this.embeddedFile = {
+        name: item.name,
+        url: item.url,
+        type: ext === "pdf" ? "pdf" : "image"
+      };
       this.pdftitle =
         "鍏�" + this.pdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-      let name = item.name.split(".");
-      if (name[1] == "pdf") {
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-      } else if (name[1] == "jpg" || "png") {
-        console.log(item, "灞曠ず");
-        this.previewpdf = true;
-        if (item.url) {
-          this.pdfimg = item.url;
-        } else {
-          this.pdfimg = "";
-        }
-      } else {
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
-      }
+      this.pdfVisible = true;
     },
     getIndexInArray(arr, obj) {
       return arr.indexOf(obj);
diff --git a/src/views/project/travelexpenseapply/edit.vue b/src/views/project/travelexpenseapply/edit.vue
index 4674f41..3c3a005 100644
--- a/src/views/project/travelexpenseapply/edit.vue
+++ b/src/views/project/travelexpenseapply/edit.vue
@@ -382,17 +382,19 @@
     },
     methods: {
         handleUploadError() { },
-        // 涓嬭浇鏂囦欢
+        // 棰勮/涓嬭浇鏂囦欢
         downFile(item) {
-
+            const ext = String(item.name || '').split('.').pop().toLowerCase();
+            if (['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)) {
+                this.$previewFile([{ name: item.name, url: item.url }]);
+                return;
+            }
             const url = process.env.VUE_APP_BASE_API + item.url
             var a = document.createElement('a');
             var event = new MouseEvent('click');
             a.download = item.name;
             a.href = url;
             a.dispatchEvent(event);
-
-
         },
         remove(file) {
 
diff --git a/src/views/project/travelexpenseapply/index.vue b/src/views/project/travelexpenseapply/index.vue
index 66ca263..9d63316 100644
--- a/src/views/project/travelexpenseapply/index.vue
+++ b/src/views/project/travelexpenseapply/index.vue
@@ -1265,8 +1265,16 @@
       console.log("涓婃姤", e);
     },
 
-    // 涓嬭浇鏂囦欢
+    // 棰勮/涓嬭浇鏂囦欢
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/travelexpenseapply/travelexpensedetail/index.vue b/src/views/project/travelexpenseapply/travelexpensedetail/index.vue
index 62443b8..cef13e4 100644
--- a/src/views/project/travelexpenseapply/travelexpensedetail/index.vue
+++ b/src/views/project/travelexpenseapply/travelexpensedetail/index.vue
@@ -3,37 +3,19 @@
     <div class="boxdiv">
       <div class="top-text">{{ title }}</div>
       <el-form ref="form" :model="form" :rules="rules" label-width="120px">
-        <el-row
-          ><el-col :span="5">
+        <el-row><el-col :span="5">
             <el-form-item label="鐢宠鏃ユ湡" prop="applyTime">
-              <el-date-picker
-                style="width: 100%"
-                v-model="form.applyTime"
-                type="date" format="yyyy-MM-dd"
-                value-format="yyyy-MM-dd HH:mm:ss"
-                placeholder="鐢宠鏃ユ湡"
-                :disabled="true"
-              >
+              <el-date-picker style="width: 100%" v-model="form.applyTime" type="date" format="yyyy-MM-dd"
+                value-format="yyyy-MM-dd HH:mm:ss" placeholder="鐢宠鏃ユ湡" :disabled="true">
               </el-date-picker>
             </el-form-item>
           </el-col>
           <el-col :span="5">
             <el-form-item label="缁忓姙浜�" prop="username">
-              <el-select
-                v-model="form.username"
-                clearable
-                filterable
-                allow-create
-                ref="getReportname"
-                default-first-option
-                placeholder="璇烽�夋嫨"
-              >
-                <el-option
-                  v-for="item in personsList"
-                  :key="item.reportNo"
-                  :label="item.reportName"
-                  :value="item.reportName"
-                >
+              <el-select v-model="form.username" clearable filterable allow-create ref="getReportname"
+                default-first-option placeholder="璇烽�夋嫨">
+                <el-option v-for="(item, index) in personsList" :key="item.reportNo + '-' + index"
+                  :label="item.reportName" :value="item.reportName">
                 </el-option>
               </el-select>
             </el-form-item>
@@ -58,87 +40,44 @@
           </el-col>
           <el-col :span="5">
             <el-form-item label="鎶ラ攢绫诲埆" prop="costtype">
-              <el-select
-                v-model="form.costtype"
-                value-key="value"
-                placeholder="璇烽�夋嫨鎶ラ攢浜哄憳绫诲埆"
-              >
-                <el-option
-                  v-for="dict in dict.type.sys_travelexpensebelong"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                ></el-option>
+              <el-select v-model="form.costtype" value-key="value" placeholder="璇烽�夋嫨鎶ラ攢浜哄憳绫诲埆">
+                <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label"
+                  :value="dict.value"></el-option>
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="5">
-            <el-form-item
-              label="鎹愮尞鑰�"
-              prop="infoid"
-              v-show="form.costtype == 3 || form.costtype == 4"
-            >
-              <el-select
-                v-model="form.infoid"
-                @change="selectbaseinfo"
-                clearable
-                filterable
-                placeholder="璇烽�夋嫨鎹愮尞鑰�"
-              >
-                <el-option
-                  v-for="item in baselist"
-                  :key="item.index"
-                  :label="item.name"
-                  :value="item.infoid"
-                >
+            <el-form-item label="鎹愮尞鑰�" prop="infoid" v-show="form.costtype == 3 || form.costtype == 4">
+              <el-select v-model="form.infoid" @change="selectbaseinfo" clearable filterable placeholder="璇烽�夋嫨鎹愮尞鑰�">
+                <el-option v-for="(item, index) in baselist" :key="item.index + '-' + index" :label="item.name"
+                  :value="item.infoid">
                 </el-option>
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="4">
             <div style="margin-left: 10px;">
-              <dict-tag
-                :options="dict.type.sys_DonationStatus"
-                :value="form.invoicecount"
-              />
+              <dict-tag :options="dict.type.sys_DonationStatus" :value="form.invoicecount" />
             </div>
           </el-col>
         </el-row>
         <el-row style="margin-top: 10px">
           <el-col :span="5">
             <el-form-item label="瀹℃牳鐘舵��" prop="flowlevel">
-              <el-select
-                v-model="form.recordstatus"
-                placeholder="璇烽�夋嫨瀹℃牳鐘舵��"
-                clearable
-                :disabled="true"
-                size="small"
-              >
-                <el-option
-                  v-for="dict in dict.type.sys_recordstatus"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                />
+              <el-select v-model="form.recordstatus" placeholder="璇烽�夋嫨瀹℃牳鐘舵��" clearable :disabled="true" size="small">
+                <el-option v-for="dict in dict.type.sys_recordstatus" :key="dict.value" :label="dict.label"
+                  :value="dict.value" />
               </el-select>
             </el-form-item>
           </el-col>
           <el-col :span="5">
             <el-form-item label="鎶ラ攢閲戦" prop="amountrequested">
-              <el-input
-                :disabled="true"
-                v-model="form.amountrequested"
-                placeholder="鎶ラ攢鍚堣閲戦"
-              />
+              <el-input :disabled="true" v-model="form.amountrequested" placeholder="鎶ラ攢鍚堣閲戦" />
             </el-form-item>
           </el-col>
           <el-col :span="8">
             <el-form-item label="澶у啓閲戦" prop="bigstrmoney">
-              <el-input
-                :disabled="true"
-                v-model="form.bigstrmoney"
-                placeholder="鎶ラ攢澶у啓閲戦"
-              />
+              <el-input :disabled="true" v-model="form.bigstrmoney" placeholder="鎶ラ攢澶у啓閲戦" />
             </el-form-item>
           </el-col>
         </el-row>
@@ -234,324 +173,145 @@
         <el-row v-if="jurisdiction">
           <!-- <el-alert title="褰撳墠涓烘煡鐪嬬姸鎬侊紝涓嶆敮鎸佷慨鏀瑰瓨鍌ㄣ��" type="warning">
           </el-alert> -->
-          <el-alert
-            title="褰撳墠涓烘煡鐪嬬姸鎬侊紝涓嶆敮鎸佷慨鏀瑰瓨鍌ㄣ��"
-            type="warning"
-            show-icon
-          >
+          <el-alert title="褰撳墠涓烘煡鐪嬬姸鎬侊紝涓嶆敮鎸佷慨鏀瑰瓨鍌ㄣ��" type="warning" show-icon>
           </el-alert>
         </el-row>
         <el-row style="margin-top: 25px; margin-bottom: 5px">
           <el-col :span="20">鎶ラ攢鏄庣粏</el-col>
         </el-row>
         <el-row>
-          <el-table
-            :data="rbDetails"
-            ref="table"
-            border
-            max-height="800"
-            highlight-current-row
-            :summary-method="getSummaries"
-            show-summary
-          >
-            <el-table-column
-              prop="orderno"
-              slot=""
-              label="搴忓彿"
-              align="center"
-              fixed
-              width="88"
-            >
+          <el-table :data="rbDetails" ref="table" border max-height="800" highlight-current-row
+            :summary-method="getSummaries" show-summary>
+            <el-table-column prop="orderno" slot="" label="搴忓彿" align="center" fixed width="88">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.orderno" placeholder="搴忓彿" />
               </template>
             </el-table-column>
             <!--涓婚敭銆佸涓嶅睍绀�-->
-            <el-table-column
-              prop="id"
-              slot=""
-              label="涓婚敭"
-              align="center"
-              fixed
-              width="95"
-              v-if="false"
-            >
+            <el-table-column prop="id" slot="" label="涓婚敭" align="center" fixed width="95" v-if="false">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.id" placeholder="id" />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="rbid"
-              slot=""
-              label="澶栭敭"
-              align="center"
-              fixed
-              width="95"
-              v-if="false"
-            >
+            <el-table-column prop="rbid" slot="" label="澶栭敭" align="center" fixed width="95" v-if="false">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.rbid" placeholder="rbid" />
               </template>
             </el-table-column>
 
-            <el-table-column
-              prop="persontype"
-              slot=""
-              label="浜哄憳绫诲埆"
-              align="center"
-              fixed
-              width="130"
-            >
+            <el-table-column prop="persontype" slot="" label="浜哄憳绫诲埆" align="center" fixed width="130">
               <template slot-scope="scope">
-                <el-select
-                  v-model="scope.row.persontype"
-                  value-key="value"
-                  placeholder="浜哄憳绫诲埆"
-                  @change="getPersons(scope.row)"
-                >
-                  <el-option
-                    v-for="dict in dict.type.sys_travelexpensebelong"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.label"
-                  ></el-option>
+                <el-select v-model="scope.row.persontype" value-key="value" placeholder="浜哄憳绫诲埆"
+                  @change="getPersons(scope.row)">
+                  <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label"
+                    :value="dict.label"></el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="personname"
-              slot=""
-              label="璐圭敤浜哄憳"
-              align="center"
-              fixed
-              width="110"
-            >
+            <el-table-column prop="personname" slot="" label="璐圭敤浜哄憳" align="center" fixed width="110">
               <template slot-scope="scope">
-                <el-select
-                  v-model="scope.row.personname"
-                  clearable
-                  filterable
-                  allow-create
-                  default-first-option
-                  placeholder="璇烽�夋嫨"
-                >
-                  <el-option
-                    v-for="item in personsSel"
-                    :key="item.id"
-                    :label="item.reportNameDesc"
-                    :value="item.reportName"
-                  >
+                <el-select v-model="scope.row.personname" clearable filterable allow-create default-first-option
+                  placeholder="璇烽�夋嫨">
+                  <el-option v-for="item in personsSel" :key="item.id" :label="item.reportNameDesc"
+                    :value="item.reportName">
                   </el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="starttime"
-              slot=""
-              label="寮�濮嬫棩鏈�"
-              fixed
-              align="center"
-              width="150"
-            >
+            <el-table-column prop="starttime" slot="" label="寮�濮嬫棩鏈�" fixed align="center" width="150">
               <template slot-scope="scope">
-                <el-date-picker
-                  :picker-options="{
-                    disabledDate: time => {
-                      if (scope.row.endtime) {
-                        return (
-                          time.getTime() >
-                          new Date(scope.row.endtime.replace(/-/g, '/'))
-                        );
-                      }
+                <el-date-picker :picker-options="{
+                  disabledDate: time => {
+                    if (scope.row.endtime) {
+                      return (
+                        time.getTime() >
+                        new Date(scope.row.endtime.replace(/-/g, '/'))
+                      );
                     }
-                  }"
-                  clearable
-                  size="small"
-                  style="width: 100%"
-                  v-model="scope.row.starttime"
-                  type="date" format="yyyy-MM-dd"
-                  value-format="yyyy-MM-dd HH:mm:ss"
-                  placeholder="寮�濮嬫棩鏈�"
-                  @blur="getdays(scope.row)"
-                >
+                  }
+                }" clearable size="small" style="width: 100%" v-model="scope.row.starttime" type="date"
+                  format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="寮�濮嬫棩鏈�" @blur="getdays(scope.row)">
                 </el-date-picker>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="endtime"
-              slot=""
-              label="缁撴潫鏃ユ湡"
-              align="center"
-              fixed
-              width="150"
-            >
+            <el-table-column prop="endtime" slot="" label="缁撴潫鏃ユ湡" align="center" fixed width="150">
               <template slot-scope="scope">
-                <el-date-picker
-                  :picker-options="{
-                    disabledDate: time => {
-                      if (scope.row.starttime) {
-                        return (
-                          time.getTime() <
-                          new Date(scope.row.starttime.replace(/-/g, '/'))
-                        );
-                      }
+                <el-date-picker :picker-options="{
+                  disabledDate: time => {
+                    if (scope.row.starttime) {
+                      return (
+                        time.getTime() <
+                        new Date(scope.row.starttime.replace(/-/g, '/'))
+                      );
                     }
-                  }"
-                  clearable
-                  size="small"
-                  style="width: 100%"
-                  v-model="scope.row.endtime"
-                  type="date" format="yyyy-MM-dd"
-                  value-format="yyyy-MM-dd HH:mm:ss"
-                  placeholder="缁撴潫鏃ユ湡"
-                  @blur="getdays(scope.row)"
-                >
+                  }
+                }" clearable size="small" style="width: 100%" v-model="scope.row.endtime" type="date"
+                  format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="缁撴潫鏃ユ湡" @blur="getdays(scope.row)">
                 </el-date-picker>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="departure"
-              slot=""
-              label="鍑哄彂鍦�"
-              align="center"
-              width="100"
-            >
+            <el-table-column prop="departure" slot="" label="鍑哄彂鍦�" align="center" width="100">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.departure" placeholder="鍑哄彂鍦�" />
               </template>
             </el-table-column>
-            <el-table-column
-              label="鍒拌揪鍦�"
-              prop="destination"
-              align="center"
-              width="140"
-            >
+            <el-table-column label="鍒拌揪鍦�" prop="destination" align="center" width="140">
               <template slot-scope="scope">
                 <!--  <el-input v-model="scope.row.destination" placeholder="鍒拌揪鍦�" @blur="getallowance(scope.row)" /> -->
-                <el-select
-                  filterable
-                  allow-create
-                  v-model="scope.row.destination"
-                  value-key="value"
-                  placeholder="鍒拌揪鍦�"
-                  @change="getallowance(scope.row)"
-                >
-                  <el-option
-                    v-for="dict in dict.type.sys_area_name"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.label"
-                  ></el-option>
+                <el-select filterable allow-create v-model="scope.row.destination" value-key="value" placeholder="鍒拌揪鍦�"
+                  @change="getallowance(scope.row)">
+                  <el-option v-for="dict in dict.type.sys_area_name" :key="dict.value" :label="dict.label"
+                    :value="dict.label"></el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="days"
-              label="澶╂暟"
-              width="100"
-              align="center"
-            >
+            <el-table-column prop="days" label="澶╂暟" width="100" align="center">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.days"
-                  @blur="getallowance(scope.row)"
-                  placeholder="澶╂暟"
-                />
+                <el-input v-model="scope.row.days" @blur="getallowance(scope.row)" placeholder="澶╂暟" />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="traffictype"
-              label="鍑哄彂浜ら�氬伐鍏�"
-              align="center"
-              width="100"
-            >
+            <el-table-column prop="traffictype" label="鍑哄彂浜ら�氬伐鍏�" align="center" width="100">
               <template slot-scope="scope">
-                <el-select
-                  v-model="scope.row.traffictype"
-                  placeholder="鍑哄彂浜ら�氬伐鍏�"
-                >
-                  <el-option
-                    v-for="dict in dict.type.sys_traffictype"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.label"
-                  ></el-option>
+                <el-select v-model="scope.row.traffictype" placeholder="鍑哄彂浜ら�氬伐鍏�">
+                  <el-option v-for="dict in dict.type.sys_traffictype" :key="dict.value" :label="dict.label"
+                    :value="dict.label"></el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="traffictype2"
-              label="杩斿洖浜ら�氬伐鍏�"
-              align="center"
-              width="100"
-            >
+            <el-table-column prop="traffictype2" label="杩斿洖浜ら�氬伐鍏�" align="center" width="100">
               <template slot-scope="scope">
-                <el-select
-                  v-model="scope.row.traffictype2"
-                  placeholder="杩斿洖浜ら�氬伐鍏�"
-                >
-                  <el-option
-                    v-for="dict in dict.type.sys_traffictype"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.label"
-                  ></el-option>
+                <el-select v-model="scope.row.traffictype2" placeholder="杩斿洖浜ら�氬伐鍏�">
+                  <el-option v-for="dict in dict.type.sys_traffictype" :key="dict.value" :label="dict.label"
+                    :value="dict.label"></el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="trafficexpense"
-              label="浜ら�氳垂"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="trafficexpense" label="浜ら�氳垂" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.trafficexpense"
-                  placeholder="浜ら�氳垂"
-                  @blur="
-                    val => {
-                      sumRowFee(scope.row);
-                    }
-                  "
-                />
+                <el-input v-model="scope.row.trafficexpense" placeholder="浜ら�氳垂" @blur="
+                  val => {
+                    sumRowFee(scope.row);
+                  }
+                " />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="cityfee"
-              label="甯傚唴浜ら�氳垂"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="cityfee" label="甯傚唴浜ら�氳垂" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.cityfee"
-                  placeholder="甯傚唴浜ら�氳垂"
-                  @blur="
-                    val => {
-                      sumRowFee(scope.row);
-                    }
-                  "
-                  >{{ Number(scope.row.cityfee).toFixed(2) }}
+                <el-input v-model="scope.row.cityfee" placeholder="甯傚唴浜ら�氳垂" @blur="
+                  val => {
+                    sumRowFee(scope.row);
+                  }
+                ">{{ Number(scope.row.cityfee).toFixed(2) }}
                 </el-input>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="hotelexpense"
-              label="浣忓璐�"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="hotelexpense" label="浣忓璐�" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.hotelexpense"
-                  placeholder="浣忓璐�"
-                  @blur="
-                    val => {
-                      sumRowFee(scope.row);
-                    }
-                  "
-                />
+                <el-input v-model="scope.row.hotelexpense" placeholder="浣忓璐�" @blur="
+                  val => {
+                    sumRowFee(scope.row);
+                  }
+                " />
               </template>
             </el-table-column>
 
@@ -573,118 +333,55 @@
                 />
               </template>
             </el-table-column> -->
-            <el-table-column
-              prop="foodallowance"
-              label="浼欓琛ュ姪"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="foodallowance" label="浼欓琛ュ姪" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.foodallowance"
-                  placeholder="浼欓璐硅ˉ鍔�"
-                  @blur="
-                    val => {
-                      sumRowFee(scope.row);
-                    }
-                  "
-                />
+                <el-input v-model="scope.row.foodallowance" placeholder="浼欓璐硅ˉ鍔�" @blur="
+                  val => {
+                    sumRowFee(scope.row);
+                  }
+                " />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="otherexpense"
-              label="鍏潅璐硅ˉ鍔�"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="otherexpense" label="鍏潅璐硅ˉ鍔�" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.otherexpense"
-                  placeholder="鏉傝垂"
-                  @blur="
-                    val => {
-                      sumRowFee(scope.row);
-                    }
-                  "
-                />
+                <el-input v-model="scope.row.otherexpense" placeholder="鏉傝垂" @blur="
+                  val => {
+                    sumRowFee(scope.row);
+                  }
+                " />
               </template>
             </el-table-column>
 
-            <el-table-column
-              prop="otherfeeamount"
-              label="鍏朵粬璐圭敤"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="otherfeeamount" label="鍏朵粬璐圭敤" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.otherfeeamount"
-                  placeholder="鍏朵粬璐圭敤"
-                  @blur="
-                    val => {
-                      sumRowFee(scope.row);
-                    }
-                  "
-                />
+                <el-input v-model="scope.row.otherfeeamount" placeholder="鍏朵粬璐圭敤" @blur="
+                  val => {
+                    sumRowFee(scope.row);
+                  }
+                " />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="departure"
-              slot=""
-              label="鍏朵粬璐圭敤璇存槑"
-              align="center"
-              width="120"
-            >
+            <el-table-column prop="departure" slot="" label="鍏朵粬璐圭敤璇存槑" align="center" width="120">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.otherfeedesc"
-                  placeholder="鍏朵粬璐圭敤璇存槑"
-                />
+                <el-input v-model="scope.row.otherfeedesc" placeholder="鍏朵粬璐圭敤璇存槑" />
               </template>
             </el-table-column>
 
-            <el-table-column
-              prop="total"
-              label="鍚堣"
-              align="center"
-              width="110"
-              fixed="right"
-            >
+            <el-table-column prop="total" label="鍚堣" align="center" width="110" fixed="right">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.total" placeholder="鍚堣" />
               </template>
             </el-table-column>
-            <el-table-column
-              fixed="right"
-              label="鎿嶄綔"
-              align="center"
-              width="120"
-            >
+            <el-table-column fixed="right" label="鎿嶄綔" align="center" width="120">
               <template slot-scope="scope">
-                <el-button
-                  type="text"
-                  size="mini"
-                  @click="addDetailRow(scope.$index)"
-                  v-if="operationType == 'edit'"
-                  >鏂板</el-button
-                >
-                <el-button
-                  @click.native.prevent="
-                    deleteDetailRow(scope.$index, rbDetails, scope.row)
-                  "
-                  type="text"
-                  size="small"
-                  v-if="operationType == 'edit'"
-                  >鍒犻櫎</el-button
-                >
-                <el-button
-                  @click.native.prevent="
-                    Filepopup(scope.$index, rbDetails, scope.row)
-                  "
-                  type="text"
-                  size="small"
-                  >绁ㄦ嵁</el-button
-                >
+                <el-button type="text" size="mini" @click="addDetailRow(scope.$index)"
+                  v-if="operationType == 'edit'">鏂板</el-button>
+                <el-button @click.native.prevent="
+                  deleteDetailRow(scope.$index, rbDetails, scope.row)
+                  " type="text" size="small" v-if="operationType == 'edit'">鍒犻櫎</el-button>
+                <el-button @click.native.prevent="
+                  Filepopup(scope.$index, rbDetails, scope.row)
+                  " type="text" size="small">绁ㄦ嵁</el-button>
               </template>
             </el-table-column>
           </el-table>
@@ -693,154 +390,60 @@
           <el-col :span="20">鎵撴鏄庣粏</el-col>
         </el-row>
         <el-row style="margin-top: 5px">
-          <el-table
-            :data="rbPayees"
-            border
-            max-height="400"
-            highlight-current-row
-            :summary-method="getSummaries"
-            show-summary
-          >
-            <el-table-column
-              prop="orderno"
-              slot=""
-              label="搴忓彿"
-              align="center"
-              fixed
-              width="65"
-            >
+          <el-table :data="rbPayees" border max-height="400" highlight-current-row :summary-method="getSummaries"
+            show-summary>
+            <el-table-column prop="orderno" slot="" label="搴忓彿" align="center" fixed width="65">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.orderno" placeholder="搴忓彿" />
               </template>
             </el-table-column>
 
             <!--涓婚敭銆佸閿笉灞曠ず-->
-            <el-table-column
-              prop="id"
-              slot=""
-              label="涓婚敭"
-              align="center"
-              fixed
-              width="95"
-              v-if="false"
-            >
+            <el-table-column prop="id" slot="" label="涓婚敭" align="center" fixed width="95" v-if="false">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.id" placeholder="id" />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="rbid"
-              slot=""
-              label="澶栭敭"
-              align="center"
-              fixed
-              width="95"
-              v-if="false"
-            >
+            <el-table-column prop="rbid" slot="" label="澶栭敭" align="center" fixed width="95" v-if="false">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.rbid" placeholder="rbid" />
               </template>
             </el-table-column>
 
-            <el-table-column
-              prop="persontype"
-              slot=""
-              label="鏀舵浜虹被鍒�"
-              align="center"
-              fixed
-              width="150"
-            >
+            <el-table-column prop="persontype" slot="" label="鏀舵浜虹被鍒�" align="center" fixed width="150">
               <template slot-scope="scope">
-                <el-select
-                  v-model="scope.row.persontype"
-                  value-key="value"
-                  placeholder="鏀舵浜虹被鍒�"
-                  @change="getPersons(scope.row)"
-                >
-                  <el-option
-                    v-for="dict in dict.type.sys_travelexpensebelong"
-                    :key="dict.value"
-                    :label="dict.label"
-                    :value="dict.label"
-                  ></el-option>
+                <el-select v-model="scope.row.persontype" value-key="value" placeholder="鏀舵浜虹被鍒�"
+                  @change="getPersons(scope.row)">
+                  <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label"
+                    :value="dict.label"></el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="personname"
-              slot=""
-              label="鏀舵浜�"
-              align="center"
-              fixed
-              width="200"
-            >
+            <el-table-column prop="personname" slot="" label="鏀舵浜�" align="center" fixed width="200">
               <template slot-scope="scope">
-                <el-select
-                  v-model="scope.row.personname"
-                  clearable
-                  filterable
-                  allow-create
-                  ref="getReportname"
-                  default-first-option
-                  placeholder="璇烽�夋嫨"
-                  @change="getAccountinfo2(scope.row, scope.row.persontype)"
-                >
-                  <el-option
-                    v-for="item in personsSel"
-                    :key="item.id"
-                    :label="item.reportNameDesc"
-                    :value="item.id"
-                  >
+                <el-select v-model="scope.row.personname" clearable filterable allow-create ref="getReportname"
+                  default-first-option placeholder="璇烽�夋嫨" @change="getAccountinfo2(scope.row, scope.row.persontype)">
+                  <el-option v-for="item in personsSel" :key="item.id" :label="item.reportNameDesc" :value="item.id">
                   </el-option>
                 </el-select>
               </template>
             </el-table-column>
-            <el-table-column
-              prop="bankname"
-              slot=""
-              label="鏀舵閾惰"
-              align="center"
-              fixed
-              width="250"
-            >
+            <el-table-column prop="bankname" slot="" label="鏀舵閾惰" align="center" fixed width="250">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.bankname" placeholder="鏀舵閾惰" />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="bankcardno"
-              slot=""
-              label="閾惰璐﹀彿"
-              align="center"
-              fixed
-              width="200"
-            >
+            <el-table-column prop="bankcardno" slot="" label="閾惰璐﹀彿" align="center" fixed width="200">
               <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.bankcardno"
-                  placeholder="閾惰璐﹀彿"
-                />
+                <el-input v-model="scope.row.bankcardno" placeholder="閾惰璐﹀彿" />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="amount"
-              slot=""
-              label="鎵撴閲戦"
-              align="center"
-              fixed
-              width="130"
-            >
+            <el-table-column prop="amount" slot="" label="鎵撴閲戦" align="center" fixed width="130">
               <template slot-scope="scope">
                 <el-input v-model="scope.row.amount" placeholder="鎵撴閲戦" />
               </template>
             </el-table-column>
-            <el-table-column
-              prop="remark"
-              slot=""
-              label="璇锋璇存槑"
-              align="center"
-              fixed
-            >
+            <el-table-column prop="remark" slot="" label="璇锋璇存槑" align="center" fixed>
               <template slot-scope="scope">
                 <el-input v-model="scope.row.remark" placeholder="璇存槑" />
               </template>
@@ -853,74 +456,36 @@
                 </el-date-picker>
               </template>
             </el-table-column>-->
-            <el-table-column
-              label="鎿嶄綔"
-              align="center"
-              width="100"
-              v-if="operationType == 'edit'"
-            >
+            <el-table-column label="鎿嶄綔" align="center" width="100" v-if="operationType == 'edit'">
               <template slot-scope="scope">
-                <el-button
-                  type="text"
-                  size="mini"
-                  @click="addPayeeRow(scope.$index)"
-                  >鏂板</el-button
-                >
-                <el-button
-                  @click.native.prevent="
-                    deletePayeeRow(scope.$index, rbPayees, scope.row)
-                  "
-                  type="text"
-                  size="small"
-                >
+                <el-button type="text" size="mini" @click="addPayeeRow(scope.$index)">鏂板</el-button>
+                <el-button @click.native.prevent="
+                  deletePayeeRow(scope.$index, rbPayees, scope.row)
+                  " type="text" size="small">
                   鍒犻櫎
                 </el-button>
               </template>
             </el-table-column>
           </el-table>
         </el-row>
-        <el-row
-          style="margin-top: 25px; margin-bottom: 5px"
-          v-if="operationType != 'edit'"
-        >
+        <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType != 'edit'">
           <el-col :span="20">瀹℃牳璁板綍</el-col>
         </el-row>
         <el-row v-if="operationType != 'add'">
           <el-table :data="fundflowList" border>
-            <el-table-column
-              label="瀹℃牳鏃ユ湡"
-              align="center"
-              width="200"
-              prop="createTime"
-            />
-            <el-table-column
-              label="瀹℃牳浜�"
-              align="center"
-              width="150"
-              prop="checkusername"
-            />
-            <el-table-column
-              label="瀹℃牳缁撴灉"
-              align="center"
-              width="200"
-              prop="flowconclusion"
-            >
+            <el-table-column label="瀹℃牳鏃ユ湡" align="center" width="200" prop="createTime" />
+            <el-table-column label="瀹℃牳浜�" align="center" width="150" prop="checkusername" />
+            <el-table-column label="瀹℃牳缁撴灉" align="center" width="200" prop="flowconclusion">
               <template slot-scope="scope">
                 <span v-if="scope.row.flowconclusion == 1">閫氳繃</span>
                 <span v-if="scope.row.flowconclusion == 2">涓嶉�氳繃</span>
               </template>
             </el-table-column>
-            <el-table-column
-              label="瀹℃牳澶囨敞"
-              align="center"
-              prop="flowcontent"
-            />
+            <el-table-column label="瀹℃牳澶囨敞" align="center" prop="flowcontent" />
           </el-table>
         </el-row>
-        <el-row
-          style="margin-top: 25px; margin-bottom: 5px"
-          v-if="operationType == 'check' && userprofile.nickName == '闄堟厱鍗�'"
-        >
+        <el-row style="margin-top: 25px; margin-bottom: 5px"
+          v-if="operationType == 'check' && userprofile.nickName == '闄堟厱鍗�'">
           <el-col :span="12">
             <el-form-item label="棰勫鏉愭枡" prop="infoid">
               <el-radio-group v-model="form.checkstatus" align="left">
@@ -941,10 +506,7 @@
           </el-col>
         </el-row>
 
-        <el-row
-          style="margin-top: 25px; margin-bottom: 5px"
-          v-if="operationType == 'check'"
-        >
+        <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType == 'check'">
           <el-col :span="7">
             <el-form-item label="瀹℃牳缁撴灉" align="left">
               <el-radio-group v-model="checkObj.flowlevelone" align="left">
@@ -963,42 +525,50 @@
         </el-row>
       </el-form>
       <div slot="footer" class="dialog-footer">
-        <el-button
-          type="primary"
-          @click="submitForm"
-          v-if="operationType == 'edit' || userprofile.nickName == '闄堟厱鍗�'"
-          >淇� 瀛�</el-button
-        >
-        <el-button
-          type="primary"
-          @click="checksubmit"
-          v-if="operationType == 'check'"
-          >鎻愪氦瀹℃牳</el-button
-        >
+        <el-button type="primary" @click="submitForm" v-if="operationType == 'edit' || userprofile.nickName == '闄堟厱鍗�'">淇�
+          瀛�</el-button>
+        <el-button type="primary" @click="checksubmit" v-if="operationType == 'check'">鎻愪氦瀹℃牳</el-button>
         <!--<el-button @click="cancel">閫� 鍑�</el-button>-->
       </div>
     </div>
 
-    <el-dialog
-      v-dialogDrags
-      :modal="false"
-      :close-on-click-modal="false"
-      :title="pdftitle"
-      :visible.sync="pdfVisible"
-      width="60%"
-    >
+    <el-dialog v-dialogDrags :modal="false" :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible"
+      :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false">
+      <template slot="title">
+        <span>{{ pdftitle }}</span>
+        <el-button class="pdf-fullscreen-btn" size="mini"
+          :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="pdfFullscreen = !pdfFullscreen">{{
+            pdfFullscreen ? "杩樺師" : "鍏ㄥ睆" }}</el-button>
+      </template>
+      <el-alert
+        :title="
+          activeName == 2
+            ? '褰撳墠姝e湪鎿嶄綔锛氬彂绁ㄦ枃浠讹紙璇风‘璁ょエ鎹睘浜庡彂绁級'
+            : '褰撳墠姝e湪鎿嶄綔锛氭櫘閫氶檮浠讹紙璇峰嬁鍦ㄦ涓婁紶鍙戠エ锛�'
+        "
+        :type="activeName == 2 ? 'success' : 'warning'"
+        :closable="false"
+        show-icon
+        style="margin-bottom: 10px;"
+      />
       <div style="margin-bottom: 10px;">
         <el-table :data="tableDatatop" style="width: 100%">
           <el-table-column prop="orderno" label="搴忓彿"> </el-table-column>
           <el-table-column prop="personname" label="璐圭敤浜哄憳">
           </el-table-column>
-          <el-table-column prop="starttime" label="寮�濮嬫棩鏈�"> </el-table-column>
-          <el-table-column prop="endtime" label="缁撴潫鏃ユ湡"> </el-table-column>
+          <el-table-column prop="starttime" label="寮�濮嬫棩鏈�">
+            <template slot-scope="scope">
+              {{ scope.row.starttime ? parseTime(scope.row.starttime, "{y}-{m}-{d}") : "" }}
+            </template>
+          </el-table-column>
+          <el-table-column prop="endtime" label="缁撴潫鏃ユ湡">
+            <template slot-scope="scope">
+              {{ scope.row.endtime ? parseTime(scope.row.endtime, "{y}-{m}-{d}") : "" }}
+            </template>
+          </el-table-column>
           <el-table-column prop="departure" label="鍑哄彂鍦�"> </el-table-column>
           <el-table-column prop="destination" label="鍒拌揪鍦�"> </el-table-column>
           <el-table-column prop="days" label="澶╂暟"> </el-table-column>
-        </el-table>
-        <el-table :data="tableDatatop" style="width: 100%">
           <el-table-column prop="traffictype" label="鍑哄彂浜ら�氬伐鍏�">
           </el-table-column>
           <el-table-column prop="traffictype2" label="杩斿洖浜ら�氬伐鍏�">
@@ -1016,66 +586,27 @@
           </el-table-column>
         </el-table>
       </div>
-      <el-alert
-        title="鏂颁笂浼犳枃浠堕渶鍦ㄦ彁浜や繚瀛樺悗鎵嶅彲杩涜妗堜緥鍏宠仈锛屽惁鍒欒涓烘斁寮�"
-        type="error"
-        show-icon
-        close-text="鐭ラ亾浜�"
-      >
+      <el-alert title="鏂颁笂浼犳枃浠堕渶鍦ㄦ彁浜や繚瀛樺悗鎵嶅彲杩涜妗堜緥鍏宠仈锛屽惁鍒欒涓烘斁寮�" type="error" show-icon close-text="鐭ラ亾浜�">
       </el-alert>
-      <el-tabs
-        style="margin-top: 20px;"
-        v-model="activeName"
-        type="border-card"
-        @tab-click="handleClick"
-      >
+      <el-tabs style="margin-top: 20px;" v-model="activeName" type="border-card" @tab-click="handleClick">
         <el-tab-pane label="鏅�氶檮浠�" :name="1">
           <div class="pdfimg">
             <div class="box-pdf">
               <div>
-                <el-upload
-                  size="mini"
-                  class="upload-demo"
-                  :action="uploadFileUrl"
-                  :file-list="fileListto"
-                  :show-file-list="false"
-                  multiple
-                  drag
-                  :headers="headers"
-                  :on-success="
-                    (response, file, fileList) =>
+                <el-upload size="mini" class="upload-demo" :action="uploadFileUrl" :file-list="fileListto"
+                  :show-file-list="false" multiple drag :headers="headers" :on-success="(response, file, fileList) =>
                       uploadSccess(response, file, fileList)
-                  "
-                  :on-preview="downFile"
-                  :disabled="operationType == 'detail'"
-                  :on-error="handleUploadError"
-                  :on-remove="remove"
-                  accept="image/*,.pdf"
-                >
+                    " :on-preview="downFile" :disabled="operationType == 'detail'" :on-error="handleUploadError"
+                  :on-remove="remove" accept="image/*,.pdf">
                   <i class="el-icon-upload"></i>
                   <div class="el-upload__text">
                     灏嗙エ鎹嫋鍒版澶勶紝鎴�
-                    <em
-                      ><el-button
-                        :disabled="operationType == 'detail'"
-                        size="small"
-                        type="primary"
-                        >鐐瑰嚮涓婁紶</el-button
-                      ></em
-                    >
+                    <em><el-button :disabled="operationType == 'detail'" size="small"
+                        type="primary">鐐瑰嚮涓婁紶</el-button></em>
                   </div>
                 </el-upload>
-                <el-table
-                  :data="fileListto"
-                  @row-click="downFile"
-                  style="width: 100%"
-                  height="400"
-                >
-                  <el-table-column
-                    prop="name"
-                    :show-overflow-tooltip="true"
-                    label="鍚嶇О"
-                  >
+                <el-table :data="fileListto" @row-click="downFile" style="width: 100%" height="400">
+                  <el-table-column prop="name" :show-overflow-tooltip="true" label="鍚嶇О">
                     <template slot-scope="scope">
                       <i style="color:#409EFF" class=" el-icon-s-order" />{{
                         scope.row.name
@@ -1083,110 +614,39 @@
                     </template>
                   </el-table-column>
 
-                  <el-table-column
-                    prop="name"
-                    width="180"
-                    :show-overflow-tooltip="true"
-                    label="鍔熻兘"
-                  >
+                  <el-table-column prop="name" width="180" :show-overflow-tooltip="true" label="鍔熻兘">
                     <template slot-scope="scope">
-                      <el-button
-                        type="danger"
-                        size="mini"
-                        @click.native.prevent.stop="deletedowfile(scope.row)"
-                        >鍒犻櫎</el-button
-                      >
-                      <el-button
-                        type="primary"
-                        size="mini"
-                        @click.native.prevent.stop="moveupdowfile(scope.row)"
-                        >涓婄Щ</el-button
-                      >
+                      <el-button type="danger" size="mini"
+                        @click.native.prevent.stop="deletedowfile(scope.row)">鍒犻櫎</el-button>
+                      <el-button type="primary" size="mini"
+                        @click.native.prevent.stop="moveupdowfile(scope.row)">涓婄Щ</el-button>
                     </template>
                   </el-table-column>
                 </el-table>
               </div>
             </div>
 
-            <div
-              v-if="this.previewpdf && pdfimgsrcList.length"
-              class="pdfimgmin"
-            >
-              <!-- <img :src="pdfimg" /> -->
-              <!-- <el-image
-                style="width: 95%; height: 90%"
-                :src="pdfimg"
-                :preview-src-list="pdfimgsrcList"
-              > -->
-              <el-image
-                ref="imagePreview"
-                style="width: 95%; height: 90%"
-                :src="pdfimg"
-                @click="handleImageClick(initialIndex)"
-              >
-              </el-image>
-              <custom-image-viewer
-                :url-list="pdfimgsrcList"
-                :initial-index="currentIndex"
-                :visible="viewerVisible"
-                @update:visible="viewerVisible = $event"
-                @close="handleViewerClose"
-              />
-              <!-- <div slot="error" class="image-slot">
-              <i class="el-icon-picture-outline"></i>
-            </div> -->
-              <!-- </el-image> -->
-            </div>
-            <div v-else class="pdfimgmins">{{ hintitle }}</div>
+            <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" />
           </div>
         </el-tab-pane>
         <el-tab-pane label="鍙戠エ鏂囦欢" :name="2">
           <div class="pdfimg">
             <div class="box-pdf">
               <div>
-                <el-upload
-                  size="mini"
-                  class="upload-demo"
-                  :action="uploadFileUrl"
-                  :file-list="invoicefileList"
-                  :show-file-list="false"
-                  multiple
-                  drag
-                  :headers="headers"
-                  :on-success="
-                    (response, file, fileList) =>
+                <el-upload size="mini" class="upload-demo" :action="uploadFileUrl" :file-list="invoicefileList"
+                  :show-file-list="false" multiple drag :headers="headers" :on-success="(response, file, fileList) =>
                       uploadSccess(response, file, fileList)
-                  "
-                  :on-preview="downFile"
-                  :disabled="operationType == 'detail'"
-                  :on-error="handleUploadError"
-                  :on-remove="remove"
-                  accept="image/*,.pdf"
-                >
+                    " :on-preview="downFile" :disabled="operationType == 'detail'" :on-error="handleUploadError"
+                  :on-remove="remove" accept="image/*,.pdf">
                   <i class="el-icon-upload"></i>
                   <div class="el-upload__text">
                     灏嗗彂绁ㄦ枃浠舵嫋鍒版澶勶紝鎴�
-                    <em
-                      ><el-button
-                        :disabled="operationType == 'detail'"
-                        size="small"
-                        type="primary"
-                        >鐐瑰嚮涓婁紶</el-button
-                      ></em
-                    >
+                    <em><el-button :disabled="operationType == 'detail'" size="small"
+                        type="primary">鐐瑰嚮涓婁紶</el-button></em>
                   </div>
                 </el-upload>
-                <el-table
-                  :data="invoicefileListto"
-                  @row-click="downFile"
-                  style="width: 100%"
-                  height="400"
-                >
-                  <el-table-column
-                    prop="name"
-                    :show-overflow-tooltip="true"
-                    label="鍚嶇О"
-                  >
+                <el-table :data="invoicefileListto" @row-click="downFile" style="width: 100%" height="400">
+                  <el-table-column prop="name" :show-overflow-tooltip="true" label="鍚嶇О">
                     <template slot-scope="scope">
                       <i style="color:#409EFF" class=" el-icon-s-order" />{{
                         scope.row.name
@@ -1194,64 +654,28 @@
                     </template>
                   </el-table-column>
 
-                  <el-table-column
-                    prop="name"
-                    width="180"
-                    :show-overflow-tooltip="true"
-                    label="鍔熻兘"
-                  >
+                  <el-table-column prop="name" width="180" :show-overflow-tooltip="true" label="鍔熻兘">
                     <template slot-scope="scope">
-                      <el-button
-                        type="primary"
-                        size="mini"
-                        @click.native.prevent.stop="deletedowfile(scope.row)"
-                        >鍒犻櫎</el-button
-                      >
-                      <el-button
-                        type="primary"
-                        size="mini"
-                        @click.native.prevent.stop="moveupdowfile(scope.row)"
-                        >涓婄Щ</el-button
-                      >
+                      <el-button type="primary" size="mini"
+                        @click.native.prevent.stop="deletedowfile(scope.row)">鍒犻櫎</el-button>
+                      <el-button type="primary" size="mini"
+                        @click.native.prevent.stop="moveupdowfile(scope.row)">涓婄Щ</el-button>
                     </template>
                   </el-table-column>
                 </el-table>
               </div>
             </div>
 
-            <div
-              v-if="this.previewpdf && invoicepdfimgsrcList.length"
-              class="pdfimgmin"
-            >
-              <!-- <img :src="pdfimg" /> -->
-              <el-image
-                style="width: 95%; height: 90%"
-                :src="invoicepdfimg"
-                @click="invoicehandleImageClick(initialIndex)"
-              >
-              </el-image>
-              <custom-image-viewer
-                :url-list="invoicepdfimgsrcList"
-                :initial-index="invoicecurrentIndex"
-                :visible="invoiceviewerVisible"
-                @update:visible="invoiceviewerVisible = $event"
-                @close="invoicehandleViewerClose"
-              />
-            </div>
-            <div v-else class="pdfimgmins">{{ hintitle }}</div>
+            <attachment-preview-pane :file="invoiceEmbeddedFile" style="flex: 1; min-width: 0;" />
           </div>
         </el-tab-pane>
       </el-tabs>
     </el-dialog>
     <el-dialog title="鎻愮ず" :visible.sync="Savereminder" width="30%">
-      <el-alert
-        :title="
-          '鎮ㄥ凡娣诲姞' +
-            totalquantity +
-            '鏉℃暟鎹紝涓洪槻姝㈡暟鎹涪澶辨槸鍚︽彁浜や繚瀛樺啀缁х画娣诲姞銆�'
-        "
-        type="warning"
-      >
+      <el-alert :title="'鎮ㄥ凡娣诲姞' +
+        totalquantity +
+        '鏉℃暟鎹紝涓洪槻姝㈡暟鎹涪澶辨槸鍚︽彁浜や繚瀛樺啀缁х画娣诲姞銆�'
+        " type="warning">
       </el-alert>
       <span slot="footer" class="dialog-footer">
         <el-button @click="unsave">鍙� 娑�</el-button>
@@ -1340,13 +764,14 @@
       personsList: [],
       //涓嬫媺鍙互閫夋嫨浜哄憳鍒楄〃
       personsSel: [],
-      activeName: 1, //鏂囦欢绫诲瀷
+      activeName: 2, //鏂囦欢绫诲瀷锛氶粯璁ゅ彂绁ㄦ枃浠�
       // 閮ㄩ棬鏍戦�夐」
 
       deptOptions: undefined,
       //绁ㄦ嵁鏂囦欢
       pdftitle: "",
       pdfimg: "",
+      invoiceEmbeddedFile: null,
       pdfVisible: false,
       costtypeobj: {
         value: 0,
@@ -1655,17 +1080,8 @@
     handleUploadError() { },
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      console.log(window.location.href);
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-        console.log(this.Networkheader);
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-        console.log(this.Networkheader);
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
     // 鍙戠エ鍒囨崲
     handleClick(tab, event) {
@@ -1693,7 +1109,7 @@
     //鏂囦欢涓婁紶鎴愬姛鍥炶皟
     /**
      * 2026-10-15锛氫笂浼犳椂鏍¢獙闄勪欢鏂囦欢鍚嶏紙涓氬姟瑕佹眰锛氫笉鍚堟牸绔嬪嵆鎻愮ず涓斾笉鍔犲叆鍒楄〃锛夈��
-     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細蹇呴』鍚腑鏂� / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
+     * 瑙勫垯涓庡悗绔� AttachmentNameValidator 鍚屽彛寰勶細涓嶅己鍒跺惈涓枃 / 鍘绘帀鎵╁睍鍚嶅悗涓诲共 鈮�20 瀛� /
      * 涓嶅惈绌烘牸鍙� / \ : * ? " < > | # % 绛夌壒娈婂瓧绗︺��
      */
     checkUploadFileName(file) {
@@ -1732,33 +1148,27 @@
       const config = {
         headers: { Authorization: "Bearer " + this.ICDtoken }
       };
-      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+      const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
       //鑾峰彇绁ㄦ嵁淇℃伅浣嶇疆
       if (this.activeName == 1) {
         if (response.code == 200) {
           this.previewpdf = true;
 
-          fetch(pdfimg, config)
-            .then(response => response.blob())
-            .then(blob => {
-              // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-              this.pdfimg = URL.createObjectURL(blob);
-              this.pdfimgsrcList.push(URL.createObjectURL(blob));
-              this.fileListto.push({
-                name: file.name,
-                url: URL.createObjectURL(blob)
-              });
-              // 2026-10-15锛氬垹闄よ繖閲岀殑绗簩娆� push銆傚師鏉ヤ竴娆′笂浼犱細鍚� fileListto / pdfimgsrcList
-              // 鍚勫啓涓ゆ潯锛屼笖绗簩鏉$殑 name 鍙栫殑鏄� file.response.fileName锛堝瓨鍌ㄨ矾寰勶級锛涜�� remove()
-              // 浼氭妸鏁翠釜 fileListto 鍥炲啓鍒� rbDetails[atpresent].annexfilesList锛屽鑷存槑缁嗛檮浠堕噷
-              // 娣峰叆璺緞褰㈡�佺殑 name锛岃闄勪欢鏂囦欢鍚嶆牎楠岃鎷︼紙鍓嶇娌℃湁"璺緞褰㈡�佽烦杩�"璞佸厤锛夛紝
-              // 鍚屾椂绁ㄦ嵁鍒楄〃浼氬鍑轰竴琛屻��
-              console.log(URL.createObjectURL(blob), "ur杞崲");
-            })
-            .catch(error => {
-              console.error("Error loading image", error);
-              return;
-            });
+          // 鏂颁笂浼犳枃浠剁洿鎺ヤ娇鐢ㄦ祻瑙堝櫒鏈湴 File锛岄伩鍏嶆湇鍔$鏂囦欢鍦板潃/Token
+          // 寮傚父鏃舵妸 JSON 閿欒鍝嶅簲褰撴垚鍥剧墖鎴� PDF 棰勮銆�
+          const localBlob = file.raw;
+          const localUrl = URL.createObjectURL(localBlob);
+          this.pdfimg = localUrl;
+          this.embeddedFile = {
+            name: file.name,
+            url: localUrl,
+            type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+          };
+          this.pdfimgsrcList.push(localUrl);
+          this.fileListto.push({
+            name: file.name,
+            url: localUrl
+          });
 
           this.$modal.msgSuccess(response.msg);
 
@@ -1777,21 +1187,19 @@
       } else {
         if (response.code == 200) {
           this.previewpdf = true;
-          fetch(pdfimg, config)
-            .then(response => response.blob())
-            .then(blob => {
-              // 灏嗚幏鍙栫殑鏁版嵁娴佽浆鎹负URL
-              this.invoicepdfimg = URL.createObjectURL(blob);
-              this.invoicepdfimgsrcList.push(URL.createObjectURL(blob));
-              this.invoicefileListto.push({
-                name: file.name,
-                url: URL.createObjectURL(blob)
-              });
-            })
-            .catch(error => {
-              console.error("Error loading image", error);
-              return;
-            });
+          const localBlob = file.raw;
+          const localUrl = URL.createObjectURL(localBlob);
+          this.invoicepdfimg = localUrl;
+          this.invoiceEmbeddedFile = {
+            name: file.name,
+            url: localUrl,
+            type: /\.pdf$/i.test(file.name) ? "pdf" : "image"
+          };
+          this.invoicepdfimgsrcList.push(localUrl);
+          this.invoicefileListto.push({
+            name: file.name,
+            url: localUrl
+          });
 
           this.$modal.msgSuccess(response.msg);
 
@@ -1827,7 +1235,7 @@
       if (this.rbDetails[index].annexfilesList) {
         const fetchPromises = this.rbDetails[index].annexfilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -1860,7 +1268,7 @@
       if (this.rbDetails[index].invoicefilesList) {
         const fetchPromises = this.rbDetails[index].invoicefilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -1894,7 +1302,7 @@
         this.pdftitle = "";
       }
 
-      if (this.activeName == "common") {
+      if (this.activeName == 1) {
         this.pdftitle = "鍏�" + this.pdfimgsrcList.length + "椤�";
       } else {
         this.pdftitle = "鍏�" + this.invoicepdfimgsrcList.length + "椤�";
@@ -1903,50 +1311,17 @@
       console.log(this.rbDetails[index].annexfilesList, "annexfilesList");
     },
 
-    // 鐐瑰嚮宸蹭笂浼犳枃浠�
+    // 宸梾鎶ラ攢锛氶檮浠剁粺涓�浣跨敤鐙珛 FilePreview锛堝綍鍏ャ�佸鎵广�佽鎯呬竴鑷达級
     downFile(item) {
-      if (this.activeName == 1) {
-        this.pdftitle =
-          "鍏�" + this.pdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-        let name = item.name.split(".");
-        if (name[1] == "pdf") {
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        } else if (name[1] == "jpg" || "png") {
-          console.log(item, "灞曠ず");
-          this.previewpdf = true;
-          if (item.url) {
-            this.pdfimg = item.url;
-          } else {
-            this.pdfimg = "";
-          }
-        } else {
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-        }
-      } else {
-        this.pdftitle =
-          "鍏�" + this.invoicepdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-        let name = item.name.split(".");
-        if (name[1] == "pdf") {
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-        } else if (name[1] == "jpg" || "png") {
-          this.previewpdf = true;
-          if (item.url) {
-            this.invoicepdfimg = item.url;
-          } else {
-            this.invoicepdfimg = "";
-          }
-        } else {
-          this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-          this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-          this.previewpdf = false;
-        }
+      const source =
+        this.activeName == 1 ? this.fileListto : this.invoicefileListto;
+      let list = (source || []).map(f => ({ name: f.name, url: f.url }));
+      let index = list.findIndex(f => f.url === item.url);
+      if (index < 0 && item && item.url) {
+        list = [{ name: item.name, url: item.url }];
+        index = 0;
       }
+      this.$previewFile(list, index > -1 ? index : 0);
     },
     getIndexInArray(arr, obj) {
       return arr.indexOf(obj);
@@ -2182,8 +1557,8 @@
             row.otherexpense = "";
           } else if (
             tempStr.includes("妗愬簮") ||
-          tempStr.includes("寤哄痉") ||
-          tempStr.includes("娣冲畨")
+            tempStr.includes("寤哄痉") ||
+            tempStr.includes("娣冲畨")
           ) {
             row.otherexpense = (parseInt(row.days) * 60).toString();
           } else {
@@ -2775,7 +2150,7 @@
                 path: this.$route.path,
                 query: { id: next.id, pos: 4 }
               })
-              .catch(() => {});
+              .catch(() => { });
           })
           .catch(() => {
             this.exitToPage();
@@ -2882,7 +2257,7 @@
             //淇濆瓨鏄庣粏
             for (let i = 0; i < rbDetails.length; i++) {
               if (rbDetails[i].rbid != null) {
-                if (rbDetails[i].persontype == "瀹跺睘"||rbDetails[i].persontype == "涓撳") {
+                if (rbDetails[i].persontype == "瀹跺睘" || rbDetails[i].persontype == "涓撳") {
                   if (this.form.infoid) {
                     updateReimbursementdetail(rbDetails[i]);
                   } else {
diff --git a/src/views/project/travelexpensecheck/index.vue b/src/views/project/travelexpensecheck/index.vue
index 8cbfa53..2afb72d 100644
--- a/src/views/project/travelexpensecheck/index.vue
+++ b/src/views/project/travelexpensecheck/index.vue
@@ -1443,8 +1443,21 @@
       }
     },
 
-    // 涓嬭浇鏂囦欢
+    // 棰勮/涓嬭浇鏂囦欢
     downFile(item) {
+      const ext = String(item.name || "")
+        .split(".")
+        .pop()
+        .toLowerCase();
+      if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        const list = (this.fileList || []).map(f => ({
+          name: f.name,
+          url: f.url
+        }));
+        const index = list.findIndex(f => f.url === item.url);
+        this.$previewFile(list, index > -1 ? index : 0);
+        return;
+      }
       const url = process.env.VUE_APP_BASE_API + item.url;
       var a = document.createElement("a");
       var event = new MouseEvent("click");
diff --git a/src/views/project/unitCost/particulars/index.vue b/src/views/project/unitCost/particulars/index.vue
index b3e2771..4cbc82a 100644
--- a/src/views/project/unitCost/particulars/index.vue
+++ b/src/views/project/unitCost/particulars/index.vue
@@ -489,6 +489,7 @@
         :title="pdftitle"
         :visible.sync="pdfVisible"
         width="60%"
+        custom-class="pdf-resize-dialog"
       >
         <div class="pdfimg">
           <div class="box-pdf">
@@ -981,14 +982,8 @@
     },
     // 鑾峰彇璇锋眰澶�
     Getnetworkheader() {
-      let string = window.location.href;
-      if (string.includes("9091")) {
-        const index = string.indexOf("9091");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇9091鍙婂叾鍓嶉儴瀛楃
-      } else {
-        const index = string.indexOf("8032");
-        this.Networkheader = string.slice(0, index + 4); // 鎴彇8032鍙婂叾鍓嶉儴瀛楃
-      }
+      // 浠ュ綋鍓嶉〉闈� origin 涓哄噯锛屽吋瀹� 80/8032/9091 鍙婂悗缁鍙h皟鏁�
+      this.Networkheader = window.location.origin;
     },
     // 琛ㄥ崟閲嶇疆
     reset() {
@@ -1255,7 +1250,7 @@
       const config = {
         headers: { Authorization: "Bearer " + this.ICDtoken }
       };
-      const pdfimg = this.Networkheader + "/prod-api" + response.fileName;
+      const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName;
       //鑾峰彇绁ㄦ嵁淇℃伅浣嶇疆
       if (response.code == 200) {
         this.previewpdf = true;
@@ -1311,7 +1306,7 @@
       if (this.donorchargeorgans[index].annexFilesList) {
         const fetchPromises = this.donorchargeorgans[index].annexFilesList.map(
           (value, indexson) => {
-            const pdfimg = this.Networkheader + "/prod-api" + value.url;
+            const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url;
             return fetch(pdfimg, config)
               .then(response => response.blob())
               .then(blob => {
@@ -1354,19 +1349,13 @@
     downFile(item) {
       this.pdftitle =
         "鍏�" + this.pdfimgsrcList.length + "椤癸紝褰撳墠閫変腑" + item.name;
-      let name = item.name.split(".");
-      if (name[1] == "pdf") {
-        this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");
-        this.previewpdf = false;
-        this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
-      } else if (name[1] == "jpg" || "png") {
-        console.log(item, "灞曠ず");
-        this.previewpdf = true;
-        if (item.url) {
-          this.pdfimg = item.url;
-        } else {
-          this.pdfimg = "";
-        }
+      const ext = String(item.name || "pdf").toLowerCase().split(".").pop();
+      if (ext === "pdf") {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
+      } else if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) {
+        this.$previewFile([{ name: item.name, url: item.url }]);
+        return;
       } else {
         this.hintitle = "褰撳墠鏂囦欢鏆備笉鏀寔棰勮";
         this.$modal.msgWarning("褰撳墠鏂囦欢鏆備笉鏀寔棰勮");

--
Gitblit v1.9.3