liubp
2025-12-15 f7c144a330c1612be098bd182d06816f28adb189
修改docx预览组件
3个文件已修改
91 ■■■■■ 已修改文件
package-lock.json 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/demo/page/desc/detailkehu/index.vue 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -35,6 +35,7 @@
        "cropperjs": "^1.6.2",
        "crypto-js": "^4.2.0",
        "dayjs": "^1.11.13",
        "docx-preview": "^0.3.7",
        "dom-align": "^1.12.4",
        "echarts": "^5.6.0",
        "emoji-mart-vue-fast": "^15.0.3",
@@ -8239,6 +8240,15 @@
        "node": ">=6.0.0"
      }
    },
    "node_modules/docx-preview": {
      "version": "0.3.7",
      "resolved": "https://registry.npmmirror.com/docx-preview/-/docx-preview-0.3.7.tgz",
      "integrity": "sha512-Lav69CTA/IYZPJTsKH7oYeoZjyg96N0wEJMNslGJnZJ+dMUZK85Lt5ASC79yUlD48ecWjuv+rkcmFt6EVPV0Xg==",
      "license": "Apache-2.0",
      "dependencies": {
        "jszip": ">=3.0.0"
      }
    },
    "node_modules/dom-align": {
      "version": "1.12.4",
      "resolved": "https://registry.npmmirror.com/dom-align/-/dom-align-1.12.4.tgz",
package.json
@@ -49,6 +49,7 @@
    "cropperjs": "^1.6.2",
    "crypto-js": "^4.2.0",
    "dayjs": "^1.11.13",
    "docx-preview": "^0.3.7",
    "dom-align": "^1.12.4",
    "echarts": "^5.6.0",
    "emoji-mart-vue-fast": "^15.0.3",
src/views/demo/page/desc/detailkehu/index.vue
@@ -47,7 +47,7 @@
              </div>
              <div v-if="isFilePreviewOpen(file)" class="docx-preview">
                <div v-if="isReviewFile(file) && getFileUrl(file)">
                  <vue-office-docx :src="getFileUrl(file)" style="width: 100%; height: 600px;" v-if="isDocxFile(file)"/>
                  <div :ref="el => setDocxContainer(file, el)" v-if="isDocxFile(file)" style="width: 100%; height: 600px; overflow: auto;"></div>
                  <vue-office-excel :src="getFileUrl(file)" style="width: 100%; height: 600px;" v-if="isXlsxFile(file)"/>
                  <vue-office-pdf :src="getFileUrl(file)" style="width: 100%; height: 600px;" v-if="isPdfFile(file)"/>
                  <template v-if="isTxtFile(file)">
@@ -80,7 +80,7 @@
              </div>
              <div v-if="isFilePreviewOpen(file)" class="docx-preview">
                <div v-if="isReviewFile(file) && getFileUrl(file)">
                  <vue-office-docx :src="getFileUrl(file)" style="width: 100%; height: 600px;" v-if="isDocxFile(file)"/>
                  <div :ref="el => setDocxContainer(file, el)" v-if="isDocxFile(file)" style="width: 100%; height: 600px; overflow: auto;"></div>
                  <vue-office-excel :src="getFileUrl(file)" style="width: 100%; height: 600px;" v-if="isXlsxFile(file)"/>
                  <vue-office-pdf :src="getFileUrl(file)" style="width: 100%; height: 600px;" v-if="isPdfFile(file)"/>
                  <template v-if="isTxtFile(file)">
@@ -133,21 +133,19 @@
  </PageWrapper>
</template>
<script lang="ts">
  import { defineComponent, reactive, ref, onMounted } from 'vue';
  import { defineComponent, reactive, ref, onMounted, nextTick } from 'vue';
  import { PageWrapper } from '/@/components/Page';
  import { message } from 'ant-design-vue';
  import { useRoute, useRouter } from 'vue-router';
  import { defHttp } from '/@/utils/http/axios';
  import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
  import VueOfficeDocx from '@vue-office/docx';
  import { renderAsync } from 'docx-preview';
  import VueOfficeExcel from '@vue-office/excel';
  import VueOfficePdf from '@vue-office/pdf';
  import '@vue-office/docx/lib/index.css';
  import '@vue-office/excel/lib/index.css';
  export default defineComponent({
    name: 'DescDetailKehu',
    components: { PageWrapper, VueOfficeDocx, VueOfficeExcel, VueOfficePdf },
    components: { PageWrapper, VueOfficeExcel, VueOfficePdf },
    setup() {
      const route = useRoute();
      const router = useRouter();
@@ -204,6 +202,8 @@
      const filePreviewState = reactive<Record<string, boolean>>({});
      const txtContentMap = reactive<Record<string, string>>({});
      const txtLoadingMap = reactive<Record<string, boolean>>({});
      const docxContainerMap = reactive<Record<string, HTMLElement | null>>({});
      const docxRenderedMap = reactive<Record<string, boolean>>({});
      // 加载客户数据
      const loadCustomerData = async () => {
@@ -414,6 +414,61 @@
        return !!txtLoadingMap[key];
      };
      // 渲染 DOCX 文件
      const renderDocx = async (file: any, container: HTMLElement) => {
        const fileId = getFileKey(file);
        if (!fileId || !container || docxRenderedMap[fileId]) return;
        // 标记为正在渲染,避免重复渲染
        docxRenderedMap[fileId] = true;
        try {
          const url = getFileUrl(file);
          if (!url) {
            docxRenderedMap[fileId] = false; // 重置状态
            throw new Error('DOCX 文件地址不存在');
          }
          const response = await fetch(url);
          if (!response.ok) {
            docxRenderedMap[fileId] = false; // 重置状态
            throw new Error(`请求失败:${response.status}`);
          }
          const arrayBuffer = await response.arrayBuffer();
          // 确保容器存在且可见
          if (container && container.parentElement) {
            // 清空容器内容,避免重复渲染
            container.innerHTML = '';
            await renderAsync(arrayBuffer, container);
          }
        } catch (error) {
          console.error('DOCX 文件渲染失败', error);
          docxRenderedMap[fileId] = false; // 重置状态以便重试
          message.error('DOCX 文件预览失败');
        }
      };
      // 设置 DOCX 容器引用
      const setDocxContainer = (file: any, el: any) => {
        const fileId = getFileKey(file);
        if (!fileId) return;
        if (el) {
          docxContainerMap[fileId] = el;
          // 如果预览已打开且未渲染,则在 nextTick 后渲染
          if (filePreviewState[fileId] && !docxRenderedMap[fileId]) {
            nextTick(() => {
              if (docxContainerMap[fileId] && filePreviewState[fileId]) {
                renderDocx(file, el);
              }
            });
          }
        } else {
          docxContainerMap[fileId] = null;
        }
      };
      // 切换文件预览状态
      const toggleFilePreview = (file: any) => {
        const fileId = getFileKey(file);
@@ -425,6 +480,16 @@
        // 打开 TXT 时加载内容
        if (nextState && isTxtFile(file) && !txtContentMap[fileId]) {
          fetchTxtContent(file);
        }
        // 打开 DOCX 时渲染
        if (nextState && isDocxFile(file)) {
          nextTick(() => {
            const container = docxContainerMap[fileId];
            if (container && !docxRenderedMap[fileId]) {
              renderDocx(file, container);
            }
          });
        }
      };
@@ -505,6 +570,7 @@
        isFilePreviewOpen,
        formatPrice,
        formatRanking,
        setDocxContainer,
      };
    },
  });