Przeglądaj źródła

esop和图纸优化。

jxq 1 tydzień temu
rodzic
commit
223e05ccad

+ 1 - 0
package.json

@@ -87,6 +87,7 @@
     "vue-pdf-embed": "2.0.2",
     "vue-qrcode": "^2.2.2",
     "vue-router": "^4.5.0",
+    "vue3-pdf-app": "^1.0.3",
     "vue3-print-nb": "^0.1.4",
     "xlsx": "^0.18.5"
   },

+ 12 - 0
pnpm-lock.yaml

@@ -149,6 +149,9 @@ importers:
       vue-router:
         specifier: ^4.5.0
         version: 4.5.0(vue@3.5.13(typescript@5.5.4))
+      vue3-pdf-app:
+        specifier: ^1.0.3
+        version: 1.0.3(vue@3.5.13(typescript@5.5.4))
       vue3-print-nb:
         specifier: ^0.1.4
         version: 0.1.4(typescript@5.5.4)
@@ -5257,6 +5260,11 @@ packages:
     peerDependencies:
       typescript: '>=5.0.0'
 
+  vue3-pdf-app@1.0.3:
+    resolution: {integrity: sha512-qegWTIF4wYKiocZ3KreB70wRXhqSdXWbdERDyyKzT7d5PbjKbS9tD6vaKkCqh3PzTM84NyKPYrQ3iuwJb60YPQ==}
+    peerDependencies:
+      vue: ^3.0.0
+
   vue3-print-nb@0.1.4:
     resolution: {integrity: sha512-LExI7viEzplR6ZKQ2b+V4U0cwGYbVD4fut/XHvk3UPGlT5CcvIGs6VlwGp107aKgk6P8Pgx4rco3Rehv2lti3A==}
 
@@ -10917,6 +10925,10 @@ snapshots:
       '@vue/language-core': 2.2.0(typescript@5.5.4)
       typescript: 5.5.4
 
+  vue3-pdf-app@1.0.3(vue@3.5.13(typescript@5.5.4)):
+    dependencies:
+      vue: 3.5.13(typescript@5.5.4)
+
   vue3-print-nb@0.1.4(typescript@5.5.4):
     dependencies:
       vue: 3.5.13(typescript@5.5.4)

+ 113 - 0
src/components/PDFDrawerView/index.vue

@@ -0,0 +1,113 @@
+<script setup lang="ts">
+import VuePdfApp from "vue3-pdf-app";
+// import this to use default icons for buttons
+import "vue3-pdf-app/dist/icons/main.css";
+
+const pdfSource = ref("");
+
+const visible = ref(false);
+
+const showPdf = (url) => {
+  localStorage.setItem("pdfjs.history", "");
+
+  visible.value = true;
+  nextTick(() => {
+    pdfSource.value = url;
+  });
+};
+
+const onDrawerClose = () => {
+  pdfSource.value = "";
+  // console.log(pdfSource.value, "aaa");
+  // localStorage.setItem("pdfjs.history", "");
+};
+
+defineExpose({
+  showPdf,
+});
+
+// 工具栏配置项
+const config = ref({
+  // 右侧其他区工具
+  sidebar: {
+    viewThumbnail: true, //启用缩略图视图
+    viewOutline: true, //启用大纲视图
+    viewAttachments: false, //启用附件视图
+  },
+  secondaryToolbar: {
+    secondaryPresentationMode: true, //启用演示模式
+    secondaryOpenFile: true, //启用打开文件功能
+    secondaryPrint: true, //启用打印功能
+    secondaryDownload: true, //启用下载功能
+    secondaryViewBookmark: true, //启用书签视图
+    firstPage: false, //启用跳转到第一页
+    lastPage: false, //启用跳转到最后一页
+    pageRotateCw: true, //启用顺时针旋转页面
+    pageRotateCcw: true, //启用逆时针旋转页面
+    cursorSelectTool: false, //启用选择工具
+    cursorHandTool: false, //启用手形工具
+    scrollVertical: false, //启用垂直滚动
+    scrollHorizontal: false, //启用水平滚动
+    scrollWrapped: false, //启用包裹滚动
+    spreadNone: false, //启用无跨页模式
+    spreadOdd: false, // 启用奇数页跨页模式
+    spreadEven: false, //启用偶数页跨页模式
+    documentProperties: false, //启用文档属性查看
+  },
+  // 配置左侧工具栏
+  toolbar: {
+    toolbarViewerLeft: {
+      findbar: false, //启用查找条
+      previous: true, // 启用上一页按钮
+      next: true, //启用下一页按钮
+      pageNumber: true, // 启用页码显示
+    },
+    //  配置右侧工具栏
+    toolbarViewerRight: {
+      presentationMode: true, //启用演示模式
+      openFile: false, //启用打开文件功能
+      print: true, //启用打印功能
+      download: true, // 启用下载功能
+      viewBookmark: false, // 启用书签视图
+    },
+    // 配置中间工具栏
+    toolbarViewerMiddle: {
+      zoomOut: true, // 启用缩小功能
+      zoomIn: true, //启用放大功能。
+      scaleSelectContainer: true, //启用缩放选择容器功能
+    },
+  },
+  errorWrapper: true, //启用错误包装,这可能用于显示错误信息或处理错误情况。
+});
+</script>
+
+<template>
+  <el-drawer
+    v-model="visible"
+    :footer="false"
+    :header="false"
+    :show-close="false"
+    destroy-on-close
+    direction="rtl"
+    :append-to-body="true"
+    @closed="onDrawerClose"
+    size="80%"
+  >
+    <VuePdfApp
+      v-if="pdfSource"
+      class="mid-pdf-box"
+      :pdf="pdfSource"
+      page-scale="page-fit"
+      :page-number="1"
+      :config="config"
+    ></VuePdfApp>
+  </el-drawer>
+</template>
+
+<style scoped lang="scss">
+.mid-pdf-box {
+  width: 100%;
+  min-height: calc(100vh - 100px);
+  height: 100%;
+}
+</style>

+ 5 - 5
src/components/PDFView/index.vue

@@ -43,11 +43,11 @@
 <script lang="ts" setup>
 import VuePdfEmbed from "vue-pdf-embed";
 // essential styles
-import "vue-pdf-embed/dist/style/index.css";
-
-// optional styles
-import "vue-pdf-embed/dist/style/annotationLayer.css";
-import "vue-pdf-embed/dist/style/textLayer.css";
+// import "vue-pdf-embed/dist/style/index.css";
+//
+// // optional styles
+// import "vue-pdf-embed/dist/style/annotationLayer.css";
+// import "vue-pdf-embed/dist/style/textLayer.css";
 
 // either URL, Base64, binary, or document proxy
 const props = defineProps({

+ 64 - 92
src/views/pro-operation/drawing/index.vue

@@ -1,144 +1,110 @@
 <template>
-  <el-scrollbar style="height: calc(100vh - 120px)">
+  <el-scrollbar>
     <div class="grid-container">
-      <div v-for="(box, index) in drawingData" :key="index" class="suit-box" :data-index="index">
-        <div class="pdf-box">
-          <PDFView
-            v-if="box.pdfPath && visiblePdfs[index]"
-            :need-to-show-pdf="true"
-            :pdf-source="baseUrl + box.pdfPath"
-            :key="'pdf-' + index + '-' + visiblePdfs[index]"
-          />
-          <div v-else class="pdf-placeholder">
-            <!-- 可以添加一个简单的PDF图标或提示文字 -->
-            <el-icon :size="40"><Document /></el-icon>
-          </div>
+      <div v-for="(box, index) in drawingData" :key="index" class="suit-box">
+        <div class="pdf-box" @click="toShowPDF(box)">
+          <el-image class="pdf-box" :src="baseUrl + box.pdfPath + '.jpg'">
+            <template #error>
+              <el-image class="pdf-box" :src="DefaultPDF" fit="cover" />
+            </template>
+          </el-image>
+          <!--          <PDFView :need-to-show-pdf="true" :pdf-source="baseUrl + box.pdfPath" />-->
         </div>
         <div class="suit-title">{{ box?.drawingTitle }}</div>
         <div class="suit-desc">{{ box?.created }}</div>
+        <el-button
+          class="download-btn"
+          type="primary"
+          @click="download(box)"
+          :key="box.drawingPath"
+          >下载</el-button
+        >
       </div>
     </div>
   </el-scrollbar>
+  <PDFDrawerView ref="PDFDrawerViewRef"></PDFDrawerView>
 </template>
 
 <script lang="ts" setup>
 import { drawingList } from "@/api/process/reportBreak";
 import { useProcessStore } from "@/store/modules/processView";
 import PDFView from "@/components/PDFView/index.vue";
-import { onMounted, ref, onBeforeUnmount } from "vue";
-import { Document } from '@element-plus/icons-vue';
+import DefaultPDF from "@/assets/images/401.gif";
 
 const processStore = useProcessStore();
 const drawingData = ref<any>([]);
-const visiblePdfs = ref<boolean[]>([]);
-const observer = ref<IntersectionObserver | null>(null);
-const lastVisibleIndex = ref<number>(-1);
 
 const baseUrl = import.meta.env.VITE_APP_UPLOAD_URL;
 
 onMounted(() => {
-  drawingList({ materialCode: processStore.scanInfo.materialCode }).then((res) => {
-    drawingData.value = res.data;
-    visiblePdfs.value = new Array(res.data.length).fill(false);
-    initIntersectionObserver();
-  });
-});
-
-onBeforeUnmount(() => {
-  cleanupObserver();
+  drawingList({ materialCode: processStore.scanInfo.materialCode }).then(
+    (res) => {
+      drawingData.value = res.data;
+    }
+  );
 });
 
-const initIntersectionObserver = () => {
-  cleanupObserver();
-  
-  observer.value = new IntersectionObserver((entries) => {
-    entries.forEach(entry => {
-      const index = parseInt(entry.target.getAttribute('data-index') || '0', 10);
-      
-      if (entry.isIntersecting) {
-        // 显示当前PDF
-        visiblePdfs.value[index] = true;
-        lastVisibleIndex.value = index;
-        
-        // 可以在这里添加预加载相邻PDF的逻辑
-        preloadAdjacentPdfs(index);
-      } else {
-        // 当元素离开视口时,根据策略决定是否卸载
-        if (shouldUnloadPdf(index, lastVisibleIndex.value)) {
-          visiblePdfs.value[index] = false;
-        }
-      }
-    });
-  }, {
-    rootMargin: '200px 0px', // 提前200px加载
-    threshold: 0.01
-  });
-
-  // 使用nextTick确保DOM已更新
-  setTimeout(() => {
-    document.querySelectorAll('.suit-box').forEach((box) => {
-      observer.value?.observe(box);
-    });
-  }, 0);
-};
-
-const preloadAdjacentPdfs = (currentIndex: number) => {
-  // 预加载前后各1个PDF
-  const preloadIndices = [currentIndex - 1, currentIndex + 1];
-  preloadIndices.forEach(i => {
-    if (i >= 0 && i < visiblePdfs.value.length && !visiblePdfs.value[i]) {
-      visiblePdfs.value[i] = true;
-    }
-  });
+const downloadBtnLoading = ref(false);
+const download = async (row: any) => {
+  downloadBtnLoading.value = true;
+  let url = import.meta.env.VITE_APP_UPLOAD_URL + row.drawingPath;
+
+  // 1. 获取资源并转为Blob
+  const response = await fetch(url);
+  const blob = await response.blob();
+
+  // 2. 创建临时对象URL
+  const tempUrl = URL.createObjectURL(blob);
+
+  // 3. 创建隐藏a标签触发下载
+  const link = document.createElement("a");
+  link.href = tempUrl;
+  link.download = row.fileName;
+  link.style.display = "none";
+  document.body.appendChild(link);
+  link.click();
+
+  // 4. 清理内存
+  URL.revokeObjectURL(tempUrl);
+  document.body.removeChild(link);
+  downloadBtnLoading.value = false;
 };
 
-const shouldUnloadPdf = (index: number, lastVisibleIndex: number) => {
-  // 只保留当前可见项和相邻项的PDF加载
-  return Math.abs(index - lastVisibleIndex) > 2;
-};
-
-const cleanupObserver = () => {
-  if (observer.value) {
-    observer.value.disconnect();
-    observer.value = null;
-  }
+const PDFDrawerViewRef = ref(null);
+const toShowPDF = (row) => {
+  let url = import.meta.env.VITE_APP_UPLOAD_URL + row.pdfPath;
+  PDFDrawerViewRef.value && PDFDrawerViewRef.value.showPdf(url);
 };
 </script>
 
 <style lang="scss" scoped>
 .grid-container {
   display: grid;
+  /*行间距*/
   grid-row-gap: 24px;
+  /*列间距*/
   grid-column-gap: 24px;
+
   overflow-y: auto;
   padding: 24px;
   width: calc(100% - 48px);
   grid-template-columns: 1fr 1fr 1fr;
+  height: calc(100vh - 100px);
 
   .suit-box {
     height: 343px;
     background-color: white;
-    border-radius: 16px;
+    border-radius: 16px 16px 16px 16px;
     display: flex;
     flex-direction: column;
     align-items: start;
     justify-content: center;
+    position: relative;
 
     .pdf-box {
       height: 263px;
       width: 100%;
       overflow: hidden;
-      position: relative;
-    }
-
-    .pdf-placeholder {
-      height: 100%;
-      width: 100%;
-      background-color: #f5f5f5;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      color: #999;
     }
 
     .suit-title {
@@ -155,6 +121,12 @@ const cleanupObserver = () => {
       text-align: left;
       margin-left: 24px;
     }
+
+    .download-btn {
+      position: absolute;
+      right: 20px;
+      top: 20px;
+    }
   }
 }
-</style>
+</style>

+ 67 - 147
src/views/pro-steps/components/ESOP.vue

@@ -1,75 +1,35 @@
 <template>
-  <div class="espoViewStyle">
-    <div class="header">
-      <!-- <div class="imgView">
-        <el-image class="img" :src="getImgurl(srcList[selectImgIndex]?.imgUrl)" :initial-index="selectImgIndex"
-          :preview-src-list="showSrcList" fit="cover" />
-      </div> -->
-      <div class="imgView">
-        <el-scrollbar ref="scrollbarRef" class="pdmView">
-          <!-- <PDFView :need-to-show-pdf="true" :show-pdf-number="3" :is-link="true"
-            pdf-source="http://192.168.101.4:9000/jgfile/2024/04/20/%E7%AC%AC08%E7%AB%A0_%E8%81%9A%E5%90%88%E5%87%BD%E6%95%B0.pdf" /> -->
-          <PDFView
-            :need-to-show-pdf="true"
-            :pageNumber="srcList[selectImgIndex]?.showAppointPageNum"
-            :is-link="true"
-            :pdf-source="baseUrl + srcList[selectImgIndex]?.filePath"
-          />
-          <Empty v-if="srcList.length < 1" />
-        </el-scrollbar>
-      </div>
-      <!-- <div class="textBox">
-        <el-scrollbar :max-height="scrollbarHeight">
-          <div class="title">{{ srcList[selectImgIndex]?.title }}</div>
-          <div class="describe">
-            {{ srcList[selectImgIndex]?.content }}
-          </div>
-        </el-scrollbar>
-      </div> -->
-    </div>
-
-    <div class="footer">
-      <el-scrollbar>
-        <div class="scrollbar-flex-content">
-          <div
-            :class="
-              selectImgIndex == index
-                ? 'scrollbar-demo-item '
-                : 'scrollbar-demo-item unScrollbarItemBorder'
-            "
-            v-for="(item, index) in srcList"
-            @click="setImgIndex(index)"
-          >
-            <span>{{ item.title }}</span>
-          </div>
+  <el-scrollbar>
+    <Empty v-if="srcList.length < 1" />
+    <div class="grid-container" v-else>
+      <div v-for="(box, index) in srcList" :key="index" class="suit-box">
+        <div class="pdf-box" @click="toShowPDF(box)">
+          <el-image class="pdf-box" :src="baseUrl + box.filePath + '.jpg'">
+            <template #error>
+              <el-image class="pdf-box" :src="DefaultPDF" fit="cover" />
+            </template>
+          </el-image>
+          <!--          <PDFView :need-to-show-pdf="true" :pdf-source="baseUrl + box.pdfPath" />-->
         </div>
-      </el-scrollbar>
+        <div class="suit-title">{{ box?.title }}</div>
+        <div class="suit-desc">{{ box?.created }}</div>
+      </div>
+      <PDFDrawerView ref="PDFDrawerViewRef"></PDFDrawerView>
     </div>
-  </div>
+  </el-scrollbar>
 </template>
 
 <script lang="ts" setup>
 import { esopData } from "@/api/prosteps/espo";
 import { useProcessStore } from "@/store";
-import PDFView from "@/components/PDFView/index.vue";
+
+import DefaultPDF from "@/assets/images/401.gif";
 const store = useProcessStore();
 const baseUrl = import.meta.env.VITE_APP_UPLOAD_URL;
 defineOptions({
   name: "Esop",
 });
-//配置当前div高度
-const scrollbarHeight = ref(0);
-const scrollbarRef = ref(null);
-//选取的图片索引
-const selectImgIndex = ref(0);
-const setImgIndex = (index: number) => {
-  selectImgIndex.value = index;
-  toTop();
-};
-const setScrollbarHeight = () => {
-  const viewportHeight = window.innerHeight;
-  scrollbarHeight.value = viewportHeight - 300;
-};
+
 const srcList = ref([]);
 const getPdfListData = async () => {
   const { data } = await esopData({
@@ -79,107 +39,67 @@ const getPdfListData = async () => {
   });
   srcList.value = data.records;
 };
-const toTop = () => {
-  scrollbarRef.value!.setScrollTop(0);
-};
-onMounted(async () => {
-  setScrollbarHeight();
-  await getPdfListData();
+
+onMounted(() => {
+  getPdfListData();
 });
+
+const PDFDrawerViewRef = ref(null);
+const toShowPDF = (row) => {
+  let url = import.meta.env.VITE_APP_UPLOAD_URL + row.filePath;
+  PDFDrawerViewRef.value && PDFDrawerViewRef.value.showPdf(url);
+};
 </script>
 
 <style lang="scss" scoped>
-.espoViewStyle {
-  display: flex;
-  max-height: calc(100vh - 234px);
-  width: calc(100vw / 6 * 5 - 50px);
-  flex-direction: column;
-}
-
-.header {
-  flex: 1;
-  display: flex;
-  position: relative;
-
-  .imgView {
-    flex: 1;
-    height: calc(100vh - 368px);
-    @include flex;
+.grid-container {
+  display: grid;
+  /*行间距*/
+  grid-row-gap: 24px;
+  /*列间距*/
+  grid-column-gap: 24px;
+
+  overflow-y: auto;
+  //padding: 24px;
+  width: calc(100% - 48px);
+  grid-template-columns: 1fr 1fr 1fr;
+  height: calc(100vh - 260px);
+
+  .suit-box {
+    height: 343px;
+    background-color: white;
+    border-radius: 16px 16px 16px 16px;
+    display: flex;
+    flex-direction: column;
+    align-items: start;
     justify-content: center;
-    padding: $p10 0;
-
-    .pdmView {
-      width: 100%;
-      padding: $p20;
-    }
-
-    .img {
-      height: 100%;
-      border: 0px solid;
-    }
-  }
-
-  .textBox {
-    width: 30%;
-    min-width: 250px;
-    padding: $p5 $p20;
-    right: 0;
+    position: relative;
 
-    .title {
-      font-size: $f24;
-      font-weight: $Medium;
+    .pdf-box {
+      height: 263px;
       width: 100%;
+      overflow: hidden;
     }
 
-    .describe {
-      font-size: $f20;
-      color: $font-default-60;
+    .suit-title {
+      font-weight: 500;
+      font-size: 20px;
+      color: rgba(0, 0, 0, 0.9);
+      text-align: left;
+      margin-left: 24px;
     }
-  }
-}
-
-.footer {
-  height: 20%;
-  min-height: 110px;
-  padding: 0 $p10;
-
-  .scrollbar-flex-content {
-    display: flex;
-
-    .scrollbar-demo-item {
-      flex-shrink: 0;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      width: 110px;
-      height: 110px;
-      margin-right: 10px;
-      @include flex;
-      border: 2px solid #0a59f7;
-      border-radius: 16px;
-      box-sizing: border-box;
-      color: #0a59f7;
-
-      span {
-        white-space: nowrap;
-        overflow: hidden;
-        text-overflow: ellipsis;
-        padding: 5px;
-      }
 
-      .bottomImgBox {
-        width: 90px;
-        height: 90px;
-        border-radius: 16px;
-        background-color: white;
-        @include flex;
-      }
+    .suit-desc {
+      font-size: 20px;
+      color: rgba(0, 0, 0, 0.6);
+      text-align: left;
+      margin-left: 24px;
     }
 
-    .unScrollbarItemBorder {
-      border: 2px solid black;
-      color: black;
-      background-color: transparent;
+    .download-btn {
+      position: absolute;
+      right: 20px;
+      top: 20px;
     }
   }
 }