maven
2025-08-07 c1afd811abb7879a2b7359e419ce99d52235ded9
src/components/filePreview/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,202 @@
<template>
  <el-dialog v-model="dialogVisible" title="预览" width="100%" fullscreen align-center :before-close="handleClose" append-to-body>
    <div>
      <!-- å›¾ç‰‡é¢„览 -->
      <div v-if="isImage">
        <img :src="imgUrl" alt="Image Preview" />
      </div>
      <!-- PDF预览提示 -->
      <div v-if="isPdf" style="height: 100vh; display: flex; align-items: center; justify-content: center;">
        <p>正在准备PDF预览...</p>
      </div>
      <!-- Word文档预览 -->
      <div v-if="isDoc">
        <p v-if="!isDocShow">文档无法直接预览,请下载查看。</p>
        <a :href="fileUrl" v-if="!isDocShow">下载文件</a>
        <vue-office-docx
          v-else
          :src="fileUrl"
          style="height: 100vh;"
          @rendered="renderedHandler"
          @error="errorHandler"
        />
      </div>
      <!-- Excel文档预览 -->
      <div v-if="isXls">
        <p v-if="!isDocShow">文档无法直接预览,请下载查看。</p>
        <a :href="fileUrl" v-if="!isDocShow">下载文件</a>
        <vue-office-excel
          v-else
          :src="fileUrl"
          :options="options"
          style="height: 100vh;"
          @rendered="renderedHandler"
          @error="errorHandler"
        />
      </div>
      <!-- åŽ‹ç¼©æ–‡ä»¶å¤„ç† -->
      <div v-if="isZipOrRar">
        <p>压缩文件无法直接预览,请下载查看。</p>
        <a :href="fileUrl">下载文件</a>
      </div>
      <!-- ä¸æ”¯æŒçš„æ ¼å¼ -->
      <div v-if="!isSupported">
        <p>不支持的文件格式</p>
      </div>
    </div>
  </el-dialog>
</template>
<script setup>
import { ref, computed, getCurrentInstance, watch } from 'vue';
import VueOfficeDocx from '@vue-office/docx';
import '@vue-office/docx/lib/index.css';
import VueOfficeExcel from '@vue-office/excel';
import '@vue-office/excel/lib/index.css';
// å“åº”式变量
const fileUrl = ref('')
const dialogVisible = ref(false)
const { proxy } = getCurrentInstance();
const javaApi = proxy.javaApi;
// æ–‡æ¡£é¢„览状态
const isDocShow = ref(true);
const imgUrl = ref('');
const options = ref({
  xls: false,
  minColLength: 0,
  minRowLength: 0,
  widthOffset: 10,
  heightOffset: 10,
  beforeTransformData: (workbookData) => workbookData,
  transformData: (workbookData) => workbookData,
});
// è®¡ç®—属性 - åˆ¤æ–­æ–‡ä»¶ç±»åž‹
const isImage = computed(() => {
  const state = /\.(jpg|jpeg|png|gif)$/i.test(fileUrl.value);
  if (state) {
    imgUrl.value = fileUrl.value.replaceAll('word', 'img');
  }
  return state;
});
const isPdf = computed(() => {
  console.log(fileUrl.value)
  return /\.pdf$/i.test(fileUrl.value);
});
const isDoc = computed(() => {
  return /\.(doc|docx)$/i.test(fileUrl.value);
});
const isXls = computed(() => {
  const state = /\.(xls|xlsx)$/i.test(fileUrl.value);
  if (state) {
    options.value.xls = /\.(xls)$/i.test(fileUrl.value);
  }
  return state;
});
const isZipOrRar = computed(() => {
  return /\.(zip|rar)$/i.test(fileUrl.value);
});
const isSupported = computed(() => {
  return isImage.value || isPdf.value || isDoc.value || isXls.value || isZipOrRar.value;
});
// åŠ¨æ€åˆ›å»ºa标签并跳转预览PDF
const previewPdf = (url) => {
  // åˆ›å»ºa标签
  const link = document.createElement('a');
  // è®¾ç½®PDF文件URL
  link.href = url;
  // åœ¨æ–°æ ‡ç­¾é¡µæ‰“å¼€
  link.target = '_blank';
  // å®‰å…¨å±žæ€§ï¼Œé˜²æ­¢æ–°é¡µé¢è®¿é—®åŽŸé¡µé¢
  link.rel = 'noopener noreferrer';
  // å¯é€‰ï¼šè®¾ç½®é“¾æŽ¥æ–‡æœ¬
  link.textContent = '预览PDF';
  // å°†a标签添加到页面(部分浏览器要求必须在DOM中)
  document.body.appendChild(link);
  // è§¦å‘点击事件
  link.click();
  // ç§»é™¤a标签,清理DOM
  document.body.removeChild(link);
};
// ç›‘听PDF状态变化,自动触发跳转
watch(
  () => isPdf.value,
  (newVal) => {
    // å½“确认是PDF且文件URL有效时
    if (newVal && fileUrl.value) {
      // å…³é—­å¯¹è¯æ¡†
      dialogVisible.value = false;
      // åŠ ä¸ªå°å»¶è¿Ÿç¡®ä¿çŠ¶æ€æ›´æ–°å®Œæˆ
      setTimeout(() => {
        previewPdf(fileUrl.value);
        fileUrl.value = '';
      }, 100);
    }
  }
);
// æ–¹æ³•定义
const renderedHandler = () => {
  console.log("渲染完成");
  isDocShow.value = true;
  resetStyle();
};
const errorHandler = () => {
  console.log("渲染失败");
  isDocShow.value = false;
};
const open = (url) => {
  fileUrl.value = window.location.protocol+'//'+window.location.host+ url;
  dialogVisible.value = true;
};
const handleClose = () => {
  dialogVisible.value = false;
};
const resetStyle = () => {
  const elements = document.querySelectorAll('[style*="pt"]');
  for (const element of elements) {
    const style = element.getAttribute('style');
    if (style) {
      element.setAttribute('style', style.replace(/pt/g, 'px'));
    }
  }
};
// æš´éœ²open方法供外部调用
defineExpose({
  open
})
</script>
<style scoped>
img {
  max-width: 100%;
  display: block;
  margin: 0 auto;
}
.oneLine {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>