Kaynağa Gözat

添加插件实现全流程管理中的文件在线预览功能,修复主页card组件异常报错问题。

DESKTOP-6LTVLN7\Liumouren 2 yıl önce
ebeveyn
işleme
4c14843dc4

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 9967
package-lock.json


+ 3 - 0
package.json

@@ -10,11 +10,14 @@
     "axios": "^1.1.3",
     "core-js": "^3.8.3",
     "deep-clone": "^3.0.3",
+    "docx-preview": "^0.1.4",
     "echarts": "^5.4.0",
     "element-ui": "^2.15.10",
     "html2canvas": "^1.4.1",
     "jquery": "^3.6.1",
+    "jszip": "^3.10.1",
     "vue": "^2.6.14",
+    "vue-pdf": "^4.3.0",
     "vue-router": "^3.5.1",
     "vuex": "^3.6.2"
   },

BIN
public/static/word/test.docx


BIN
public/static/word/test.pdf


+ 9 - 0
src/assets/global.css

@@ -262,4 +262,13 @@ th {
 .is-process{
   color: #FFF !important;
   border-color: #FFF !important;
+}
+.docx-wrapper{
+  background: transparent !important;
+  justify-content: flex-start !important;
+  padding:0 !important;
+  
+}
+.docx-wrapper .docx{
+    width: 100% !important;
 }

+ 132 - 0
src/components/common/FilePreView.vue

@@ -0,0 +1,132 @@
+<template>
+  <!--  图片、pdf、docx 预览
+          "docx-preview": "^0.1.4",
+          "jszip": "^3.10.0",-->
+  <div>
+    <div title="文件预览" v-if="showDoc || showPdf || showImg" width="750px">
+      <template slot="closeIcon">
+        <el-icon icon="close-circle" class="closeIcon" />
+      </template>
+      <template slot="footer">
+        <div v-if="showPdf" class="pdf-layout-page">
+          <el-button @click="changePdfPage(0)" :disabled="currentPage === 1" name="上一页" />
+          {{ currentPage }} / {{ pageCount }}
+          <el-button @click="changePdfPage(1)" :disabled="currentPage === pageCount" name="下一页" />
+        </div>
+        <el-button name="取消" @click="cancel" />
+      </template>
+      <div class="modal-body form">
+        <div v-if="showImg">
+          <img :src="images" preview="1" preview-text="" style="width: 100%" />
+        </div>
+
+        <div v-show="showDoc" ref="word">
+          <iframe v-if="fileUrl" frameborder="0" :src="fileUrl" width="100%" height="100%"> </iframe>
+        </div>
+        <div v-show="showPdf" class="pdf-layout" id="top">
+          <pdf-view
+            ref="pdf"
+            :src="pdfPath"
+            :page="currentPage"
+            @num-pages="pageCount = $event"
+            @page-loaded="currentPage = $event"
+            @loaded="loadPdfHandler"
+          />
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import pdfView from "vue-pdf";
+import axios from "axios";
+const docxPre = require("docx-preview");
+window.JSZip = require("jszip");
+export default {
+  name: "FilePreView",
+  components: { pdfView },
+  data() {
+    return {
+      showDoc: false, //判断如果是否为word文件显示
+      showPdf: false, //判断如果是否为pdf文件显示
+      showImg: false, //判断如果是否为图片显示
+      fileUrl: "", //pdf链接
+      pdfPath: "", //pdf地址
+      images: "", //图片链接
+      currentPage: 0, // pdf文件页码
+      pageCount: 0 // pdf文件总页数
+    };
+  },
+  methods: {
+    showView(filePath) {
+      let that = this;
+      let type = filePath.split(".")[filePath.split(".").length - 1];
+      if (type === "jpg" || type === "png" || type === "jpeg") {
+        that.images = filePath;
+        that.showImg = true;
+      } else if (type === "pdf") {
+        that.loadPdfHandler(); //重置pdf第一页展示
+        that.pdfPath = filePath;
+        that.showPdf = true;
+      } else if (type === "doc") {
+        //word预览
+        that.fileUrl = "https://view.officeapps.live.com/op/view.aspx?src=" + filePath;
+        that.showDoc = true;
+      } else if (type === "docx") {
+        //word预览
+        that.showDoc = true;
+        that.previewWord(filePath);
+      }
+    },
+    // 后端返回二进制流
+    previewWord(filePath) {
+      let that = this;
+      // 这里需要提起打开弹窗,因为有时很找不到word的ref 会报错
+      axios({
+        method: "get",
+        responseType: "blob", // 因为是流文件,所以要指定blob类型
+        url: filePath
+      }).then(({ data }) => {
+        docxPre.renderAsync(data, this.$refs.word);
+      });
+    },
+    //pdf上一页下一页操作
+    changePdfPage(val) {
+      if (val === 0 && this.currentPage > 1) {
+        this.currentPage--;
+      }
+      if (val === 1 && this.currentPage < this.pageCount) {
+        this.currentPage++;
+        this.top();
+      }
+    },
+    top() {
+      document.querySelector("#top").scrollIntoView(true);
+    },
+    // pdf加载时
+    loadPdfHandler(e) {
+      this.currentPage = 1; // 加载的时候先加载第一页
+    },
+    cancel() {
+      this.showDoc = false; //判断如果是否为word文件显示
+      this.showPdf = false; //判断如果是否为pdf文件显示
+      this.showImg = false; //判断如果是否为图片显示
+    }
+  }
+};
+</script>
+<style lang="less" scoped>
+.form {
+  height: 600px;
+  overflow: auto;
+}
+.pdf-layout-page {
+  left: 30%;
+  margin: auto;
+  display: inline-block;
+  text-align: center;
+  font-size: 14px;
+  position: absolute;
+}
+</style>

+ 96 - 5
src/components/common/StepsMyBox.vue

@@ -51,7 +51,47 @@
           </el-steps>
         </div>
         <div class="stepsInfoBox">
+          <!-- 流程明细文字描述 -->
           <div>{{ stepsList[stepsIndex - 1].info.text }}</div>
+          <!-- 流程明细文件预览(通知和报告会用到文件预览) -->
+          <!-- <div ref="fileView" v-show="fileView"></div> -->
+          <FilePreView ref="filePreview" v-show="fileView" />
+          <!-- 流程明细-实施列表 -->
+          <div v-if="stepsList[stepsIndex - 1].info.infos">
+            <div v-for="item in stepsList[stepsIndex - 1].info.infos" :key="item.id" style="padding-bottom: 1rem">
+              <span>{{ item.title }}</span
+              ><el-button size="mini" type="primary" class="infoBut" style="margin-left: 2rem" @click="getInfoById(item.id)"
+                >查看详情</el-button
+              >
+            </div>
+          </div>
+          <!-- 流程明细-整改表格 -->
+          <div v-if="stepsList[stepsIndex - 1].info.tableData">
+            <div class="flexBox">
+              <div v-for="(value, key) in stepsList[stepsIndex - 1].info.props" :key="key">
+                <div class="tableTitle">{{ value }}</div>
+              </div>
+            </div>
+            <div
+              v-for="(item, index) in stepsList[stepsIndex - 1].info.tableData"
+              :key="item.id"
+              class="flexBox"
+              style="padding: 0.5rem 0"
+            >
+              <div v-for="(value, key) in stepsList[stepsIndex - 1].info.props" :key="key">
+                <span v-if="key != 'opt'">{{ stepsList[stepsIndex - 1].info.tableData[index][key] }}</span>
+                <el-button
+                  v-else
+                  size="mini"
+                  type="primary"
+                  class="infoBut"
+                  @click="getInfoById(stepsList[stepsIndex - 1].info.tableData[index].id)"
+                >
+                  查看详情
+                </el-button>
+              </div>
+            </div>
+          </div>
         </div>
       </div>
     </div>
@@ -63,22 +103,41 @@
  * @author: LiuMengxiang
  * @Date: 2022年11月21-25日
  */
+import FilePreView from "./FilePreView.vue";
 export default {
   name: "StepsMyBox",
+  components: { FilePreView },
   data() {
     return {
       // 当前或默认选中的步骤条下标加一
       stepsIndex: 1,
+      // 是否显示在线文档预览
+      fileView: false,
       // 步骤条列表
       stepsList: [
         { title: "立项", info: { text: "2018-05-12 2018年张江基本农田审计项目通过立项" } },
         {
           title: "通知",
-          info: { text: "2018年张江基本农田审计项目审计通知书.pdf", filePath: "" }
+          // info: { text: "2018年张江基本农田审计项目审计通知书.pdf", filePath: "/upload/20221031/20221031100727BCH5OSMr.jpg" }
+          info: { text: "2018年张江基本农田审计项目审计通知书.pdf", filePath: "./static/word/test.pdf" }
+        },
+        {
+          title: "实施",
+          info: {
+            infos: [
+              { title: "用户A 完成张江镇xxx片区的审计", id: "001" },
+              { title: "用户B 完成张江镇xxx片区的审计", id: "002" },
+              { title: "用户C 完成张江镇xxx片区的审计", id: "003" }
+            ]
+          }
         },
-        { title: "实施", info: { infos: [{ title: "用户A 完成张江镇xxx片区的审计", id: "001" }] } },
         {
           title: "报告",
+          // info: { text: "2018年张江基本农田审计项目审计通知书.pdf", filePath: "/upload/20221128/20221128230553I6Nf00TN.docx" }
+          info: { text: "2018年张江基本农田审计项目审计通知书.docx", filePath: "./static/word/test.docx" }
+        },
+        {
+          title: "整改",
           info: {
             tableData: [
               {
@@ -99,10 +158,10 @@ export default {
                 status: "已完成",
                 endTime: "2023-01-12"
               }
-            ]
+            ],
+            props: { desc: "问题描述", status: "当前状态", endTime: "整改期限", opt: "操作" }
           }
-        },
-        { title: "整改", info: { text: "2018-05-12 2018年张江基本农田审计项目通过立项" } }
+        }
       ]
     };
   },
@@ -110,6 +169,10 @@ export default {
   mounted() {},
   watch: {},
   methods: {
+    // 流程管理【实施】节点,根据id查看详情
+    getInfoById(id) {
+      console.log("流程管理【实施】节点,根据id查看详情id:", id);
+    },
     // 返回上级
     backEvent() {
       this.$emit("hideStepsMyBoxState");
@@ -117,6 +180,15 @@ export default {
     // 切换步骤条
     changeStepsIndex(index) {
       this.stepsIndex = index;
+      if (this.fileView) {
+        this.$refs.filePreview.cancel();
+        this.fileView = false;
+      }
+      // 判断流程明细是否存在文件,存在的话自动请求文件并渲染
+      if (this.stepsList[this.stepsIndex - 1].info.filePath) {
+        this.fileView = true;
+        this.$refs.filePreview.showView(this.stepsList[this.stepsIndex - 1].info.filePath);
+      }
     }
   }
 };
@@ -202,6 +274,25 @@ export default {
         font-family: pingfangSC;
         line-height: 30px;
         color: #ffffff;
+        .flexBox {
+          display: flex;
+          width: 100%;
+          justify-content: space-evenly;
+          align-items: center;
+          align-content: space-around;
+          flex-wrap: nowrap;
+          flex-direction: row;
+          .tableTitle {
+            font-size: 20px;
+            font-family: pingfangSC;
+            font-weight: 400;
+            color: #4dc3ff;
+            padding-bottom: 0.5rem;
+          }
+          & > div {
+            width: 100%;
+          }
+        }
       }
     }
   }

+ 8 - 6
src/components/layout/MenuCard.vue

@@ -2,7 +2,7 @@
   <!-- 外边框 -->
   <div
     ref="menuCard"
-    :class="$ifLeftMenu(menuData.index) ? 'menuMainBoxA' : 'menuMainBox'"
+    :class="$ifLeftMenu(menuData.index != undefined ? menuData.index : '') ? 'menuMainBoxA' : 'menuMainBox'"
     :style="{
       width: menuData.boxWidth ? menuData.boxWidth + 'px' : '410px',
       height: menuData.boxHeight ? menuData.boxHeight + 'px' : 'auto',
@@ -18,7 +18,7 @@
         <!-- 左侧箭头图标 -->
         <div class="menuMainBox_top_left_iconS" v-if="menuData.type !== 'imageMenu'"></div>
         <div class="menuMainBox_top_left_iconR" v-if="menuData.type === 'imageMenu'">
-          <div class="menuMainBox_top_left_iconR_active" v-if="$ifLeftMenu(menuData.index)"></div>
+          <div class="menuMainBox_top_left_iconR_active" v-if="$ifLeftMenu(menuData.index != undefined ? menuData.index : '')"></div>
         </div>
         <!-- 标题 -->
         <div class="menuMainBox_top_left_title">{{ menuData.title }}</div>
@@ -143,10 +143,10 @@ export default {
   methods: {
     // 用户点击菜单标题时,调用全局函数,根据全局暂存对象
     changeMenu() {
-      if (this.menuData.index != undefined && this.menuData.title != undefined) {
+      if (this.menuData != undefined && this.menuData.index != undefined && this.menuData.title != undefined) {
         this.$store.commit("changeLeftMenuTitle", this.menuData.title);
       }
-      if (this.menuData.gotoPageInfo != undefined) {
+      if (this.menuData != undefined && this.menuData.gotoPageInfo != undefined) {
         this.$store.commit("changeNavSelect", this.menuData.gotoPageInfo);
       }
     },
@@ -161,7 +161,7 @@ export default {
     },
     // 组件显示隐藏时,动画样式返回。
     showChange() {
-      if (this.menuData.menuIndex) {
+      if (this.menuData != undefined && this.menuData.menuIndex != undefined) {
         if (this.$ifMenu(this.menuData.menuIndex, this.menuData.subMenuIndex)) {
           // 立即修改display为block
           this.$refs.menuCard.style.display = "block";
@@ -234,7 +234,9 @@ export default {
   watch: {
     "$store.state.navSelect": {
       handler() {
-        this.showChange();
+        this.$nextTick(() => {
+          this.showChange();
+        });
       },
       deep: true
     }

+ 24 - 1
src/utils/request.js

@@ -13,6 +13,15 @@ const service = axios.create({
   }
 })
 
+const fileService = axios.create({
+  baseURL: '',
+  timeout: 60000, // 请求超时时间,
+  headers: {
+    'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
+  },
+  responseType: 'blob'
+})
+
 const err = (error) => {
   if (error.response) {
     // 可在此处统一处理服务器端报错
@@ -72,6 +81,19 @@ function get(url, params) {
   })
 }
 
+function getFile(url) {
+  return new Promise((resolve, reject) => {
+    fileService({
+      method: 'GET',
+      url
+    }).then(res => {
+      resolve(res)
+    }).catch(err => {
+      reject(err)
+    })
+  })
+}
+
 function post(url, data) {
   return new Promise((resolve, reject) => {
     service({
@@ -204,5 +226,6 @@ export {
   putform,
   postform,
   delform,
-  postFile
+  postFile,
+  getFile
 }

+ 1 - 4
src/views/HomeView.vue

@@ -117,10 +117,6 @@
       <MenuCard :menuData="menus.left[4]"> </MenuCard>
       <MenuCard :menuData="menus.left[5]"> </MenuCard>
       <MenuCard :menuData="menus.left[6]"> </MenuCard>
-      <MenuCard :menuData="menus.left[7]"> </MenuCard>
-      <MenuCard :menuData="menus.left[8]"> </MenuCard>
-      <MenuCard :menuData="menus.left[9]"> </MenuCard>
-      <MenuCard :menuData="menus.left[10]"> </MenuCard>
     </div>
     <!-- 中部菜单列 -->
     <div id="mainMenus">
@@ -408,6 +404,7 @@ export default {
             menuIndex: "1",
             position: "right",
             minDomWidth: 1000,
+            gotoPageInfo: { index: "5", subIndex: "2", name: "频发问题" }
           },
           {
             type: "card",

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor