The vue project implements front-end preview of word and pdf format files

Recently, I encountered a requirement in the Vue project, that is, after the front-end realizes uploading word or pdf files, the back-end returns the file stream corresponding to the file, and the front-end needs to display it on the page. Word preview is simpler, pdf preview I tried pdfjs, vue-pdf always reported various strange bugs, but finally solved the problem, first look at the final rendering effect of the page:

The effect of uploading a pdf file on the page is as follows:

insert image description here

The effect of the page preview pdf file is as follows:

insert image description here

The effect of uploading a word file on the page is as follows:

insert image description here

The effect of the page preview word file is as follows:

insert image description here
Let’s start with the upload component page. The complete code of the upload page component is as follows. The button v-show="$checkPermission(['Register_tuotpUpload'])" in the button sets the button permission for this button. We only need to pay attention to the upload Part of the code is enough. We use the el-upload component to implement manual upload. Since the requirements require that only word and pdf can be uploaded, we can see that the attribute settings are accept=".pdf, .doc, .docx", and then The attributes that do not display the list of successfully uploaded files are: show-file-list="false", and the handleExceed callback function and limit are used to limit only one file to be uploaded. The callback hook function beforeAvatarUpload before uploading the file Type judgment and reminder. Manual upload is done through UploadFile. It should be noted that the docx-preview plug-in can only preview word files with docx suffix. If it is a word file with doc suffix format, the backend must force the Upload the file in doc format to docx format. At present, for the word file in doc format to realize the online preview of the web page, I only think of the docx-preview plug-in and this solution :

<template>
  <div class="app-container">
    <div class="cardWhite">
      <div class="itemBox">
        <div class="headerTitle">基本信息</div>
        <el-form
          :model="ruleForm"
          :rules="rules"
          ref="ruleForm"
          label-width="120px"
          class="demo-ruleForm"
        >
          <el-row>
            <el-col :span="12">
              <el-form-item label="链路名称" prop="name">
                <el-input
                  v-model="ruleForm.name"
                  placeholder="请输入链路名称"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="链路类型" prop="linkType">
                <el-select
                  v-model="ruleForm.linkType"
                  placeholder="请选择链路类型"
                  style="width:100%"
                  clearable
                >
                  <el-option
                    v-for="item in linkTypeList"
                    :key="item.val"
                    :label="item.key"
                    :value="item.val"
                  ></el-option>
                </el-select>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="链路走向" prop="go">
                <el-row>
                  <el-col :span="10">
                    <el-select
                      v-model="ruleForm.srcNetwork"
                      placeholder="请选择"
                      style="width:100%"
                      clearable
                      @clear="clearSrc"
                      @change="srcChange"
                    >
                      <el-option
                        v-for="item in scrList"
                        :key="item.val"
                        :label="item.key"
                        :value="item.val"
                      ></el-option>
                    </el-select>
                  </el-col>

                  <el-col :span="4">
                    <div style="text-align: center;width:100%">
                      <img
                        src="@/assets/toRight.png"
                        style="width:3.75rem;height:0.75rem;margin:0 auto"
                      />
                    </div>
                  </el-col>

                  <el-col :span="10">
                    <el-select
                      v-model="ruleForm.dstNetwork"
                      placeholder="请选择"
                      style="width:100%"
                      :clearable="false"
                      @clear="clearDst"
                      @change="dstChange"
                    >
                      <el-option
                        v-for="item in dstList"
                        :key="item.val"
                        :label="item.key"
                        :value="item.val"
                      ></el-option>
                    </el-select>
                  </el-col>
                </el-row>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="物理位置" prop="physicalPosition">
                <el-input
                  v-model="ruleForm.physicalPosition"
                  placeholder="请输入链路物理位置"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="所属机构" prop="orangeName">
                <el-input
                  v-model="ruleForm.orangeName"
                  placeholder="例:xx市公安局"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="行政区编码" prop="organCode">
                <el-input
                  v-model="ruleForm.organCode"
                  placeholder="请输入行政区编码,例:027"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="责任人" prop="dutyPerson">
                <el-input
                  v-model="ruleForm.dutyPerson"
                  placeholder="请输入链路责任人"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="责任人电话" prop="dutyTel">
                <el-input
                  v-model="ruleForm.dutyTel"
                  placeholder="请输入链路责任人电话"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>
          </el-row>

          <el-row>
            <el-col :span="12">
              <el-form-item label="公安网邮箱" prop="dutyEmail">
                <el-input
                  v-model="ruleForm.dutyEmail"
                  placeholder="请输入负责人公安网邮箱"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>
          </el-row>

          <el-row>
            <el-col :span="12">
              <el-form-item label="链路IP地址" prop="ip">
                <el-input
                  v-model="ruleForm.ip"
                  placeholder="请输入链路IP地址"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>

            <el-col :span="12">
              <el-form-item label="链路端口" prop="port">
                <el-input-number
                  placeholder="请输入链路端口"
                  type="text"
                  :min="0"
                  :controls="false"
                  v-model.trim="ruleForm.port"
                  style="width:100%"
                ></el-input-number>
              </el-form-item>
            </el-col>
          </el-row>

          <el-row>
            <el-col :span="12">
              <el-form-item label="管理页面" prop="webUrl">
                <el-input
                  v-model="ruleForm.webUrl"
                  placeholder="请输入链路管理页面"
                  clearable
                ></el-input>
              </el-form-item>
            </el-col>
          </el-row>

          <el-row>
            <el-col :push="2">
              <el-button
                class="filter-item"
                type="primary"
                icon="el-icon-plus"
                @click="saveForm"
                v-show="$checkPermission(['Register_boundarySave'])"
              >
                保存
              </el-button>
            </el-col>
          </el-row>
        </el-form>
      </div>

      <div class="itemBox">
        <div class="headerTitle">链路拓扑图</div>
        <el-form :model="tuopuForm" ref="tuopuForm" label-width="120px">
          <el-row>
            <el-col :span="12">
              <el-form-item label="拓扑图" prop="fileName">
                <el-input
                  v-model="tuopuForm.fileName"
                  placeholder="请选择电脑中拓扑图文件"
                  clearable
                  disabled
                >
                  <el-upload
                    accept=".pdf, .doc, .docx"
                    action="string"
                    :limit="1"
                    :on-exceed="handleExceed"
                    :before-upload="beforeAvatarUpload"
                    :http-request="UploadFile"
                    slot="append"
                    :show-file-list="false"
                  >
                    <el-button
                      type="primary"
                      v-show="$checkPermission(['Register_tuotpUpload'])"
                      icon="el-icon-upload2"
                      style="background:#1890ff;color:#fff;border-top-left-radius:0;border-bottom-left-radius:0"
                      >上传</el-button
                    >
                  </el-upload>
                </el-input>
              </el-form-item>
            </el-col>

            <el-col :span="3" :push="1">
              <el-button
                class="filter-item"
                type="primary"
                icon="el-icon-view"
                @click="preview"
                v-show="$checkPermission(['Register_tuotpPreview'])"
              >
                预览
              </el-button>
            </el-col>
          </el-row>
        </el-form>
      </div>

      <div class="itemBox">
        <div class="headerTitle">设备信息列表</div>
        <el-row type="flex" justify="end" style="margin:0.5rem 0;">
          <el-button
            class="filter-item"
            type="primary"
            icon="el-icon-plus"
            @click="addEquipment"
            v-show="$checkPermission(['Register_equipmentAdd'])"
          >
            添加
          </el-button>
        </el-row>

        <div>
          <commonTable
            :tableHead="tableHead"
            :tableData="tableData"
            :dataFiter="true"
            :selectionFlag="false"
            :dropdownList="[]"
            :resizable="true"
            :tableLoading="tableLoading"
            :showListD="showListD"
            :toolBoxFlag="false"
            @sortChange="() => {}"
            @selection-change="() => {}"
            @selectAction="() => {}"
            @addData="() => {}"
            :actionFlag="false"
            :actionList="[]"
            :freeElfFlag="false"
            :xuhaoFlag="true"
            :freeWidth="480"
          >
            <template
              slot-scope="scope"
              slot="doSomething"
              fixed="right"
              align="left"
            >
              <el-button
                icon="el-icon-edit"
                type="primary"
                @click="handlerUpdate(scope.rows)"
                v-show="$checkPermission(['Register_equipmentEdit'])"
                >编辑</el-button
              >

              <el-button
                icon="el-icon-delete"
                type="danger"
                @click="handlerDelete(scope.rows)"
                v-show="$checkPermission(['Register_equipmentDelete'])"
                style="margin-left:-0.015rem"
                >删除</el-button
              >
            </template>
          </commonTable>
        </div>
      </div>

      <div class="itemBox">
        <div class="headerTitle">链路注册</div>
        <el-row type="flex" justify="end" style="margin:0.5rem 0;">
          <el-button
            class="filter-item"
            type="primary"
            icon="el-icon-plus"
            @click="addRegister"
            v-show="$checkPermission(['Register_registerAdd'])"
          >
            添加
          </el-button>
        </el-row>

        <div>
          <commonTable
            :tableHead="Register_tableHead"
            :tableData="Register_tableData"
            :dataFiter="true"
            :selectionFlag="false"
            :dropdownList="[]"
            :resizable="true"
            :tableLoading="Register_tableLoading"
            :showListD="Register_showListD"
            :toolBoxFlag="false"
            @sortChange="() => {}"
            @selection-change="() => {}"
            @selectAction="() => {}"
            @addData="() => {}"
            :actionFlag="false"
            :actionList="[]"
            :freeElfFlag="false"
            :xuhaoFlag="true"
            :freeWidth="480"
          >
            <template slot-scope="scope" slot="status">
              <el-tag v-if="scope.rows.status == 1">已注册</el-tag>
              <el-tag type="success" v-if="scope.rows.status == 0"
                >未注册</el-tag
              >
              <el-tag type="danger" v-if="scope.rows.status == 2"
                >注册失败</el-tag
              >
            </template>

            <template
              slot-scope="scope"
              slot="doSomething"
              fixed="right"
              align="left"
            >
              <el-button
                icon="el-icon-edit"
                type="primary"
                v-if="
                  scope.rows.status == 1 &&
                    $checkPermission(['Register_registerOff'])
                "
                @click="handlerLogoff(scope.rows)"
                >注销</el-button
              >

              <el-button
                icon="el-icon-edit"
                type="primary"
                v-if="
                  ($checkPermission(['Register_registerGo']) &&
                    scope.rows.status == 0) ||
                    scope.rows.status == 2
                "
                @click="handlerLogoff(scope.rows)"
                >注册</el-button
              >

              <el-button
                icon="el-icon-delete"
                type="danger"
                v-if="$checkPermission(['Register_registerDelete'])"
                @click="Register_handlerDelete(scope.rows)"
                style="margin-left:-0.015rem"
                >删除</el-button
              >
            </template>
          </commonTable>
        </div>
      </div>
    </div>

    <!-- 添加和编辑设备弹窗 -->
    <el-dialog
      :title="textMap[dialogStatus]"
      :visible.sync="dialogFormVisible"
      width="800px"
      :before-close="handleClose"
      :close-on-click-modal="false"
    >
      <add-edit
        @refresh="fetchData"
        @closeDialog="dialogFormVisible = false"
        class="AddEdit"
        ref="AddEdit"
        :devTypeList="EquipmentList"
        v-if="dialogFormVisible"
      />

      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">
          取消
        </el-button>

        <el-button type="primary" @click="submitForm()">
          确定
        </el-button>
      </div>
    </el-dialog>

    <!-- 链路注册弹窗 -->
    <el-dialog
      title="链路注册"
      :visible.sync="Register_dialogFormVisible"
      width="800px"
      :before-close="Register_handleClose"
      :close-on-click-modal="false"
    >
      <register-add
        @reg_refresh="Register_fetchData"
        @reg_closeDialog="Register_dialogFormVisible = false"
        ref="RegisterAdd"
        v-if="Register_dialogFormVisible"
      />

      <div slot="footer" class="dialog-footer">
        <el-button @click="Register_dialogFormVisible = false">
          取消
        </el-button>

        <el-button type="primary" @click="Register_submitForm()">
          确定
        </el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import commonTable from "@/components/common-table";
import Pagination from "@/components/Pagination";
import AddEdit from "./EquipmentAddEdit.vue";
import RegisterAdd from "./RegisterAdd.vue";

import * as api from "@/api/datax-register.js";

import axios from "axios";
import {
    
     getToken } from "@/utils/auth";

export default {
    
    
  components: {
    
    
    Pagination,
    commonTable,
    AddEdit,
    RegisterAdd
  },
  data() {
    
    
    const validateGo = (rule, value, callback) => {
    
    
      // if (!value) {
    
    
      //   callback("请输入平台IP地址");
      // } else {
    
    
      //   let index = value.indexOf("/");
      //   let findHengT = value.indexOf("-");
      //   let findHengP = value.indexOf("——");
      //   if (index > -1 || findHengT > -1 || findHengP > -1) {
    
    
      //     callback("请输入正确格式的平台IP地址");
      //   } else {
    
    
      //     validator.IpArea(rule, value, callback);
      //   }
      // }

      if (!this.ruleForm.srcNetwork || !this.ruleForm.dstNetwork) {
    
    
        callback("请选择链路走向");
      } else {
    
    
        callback();
      }
    };
    return {
    
    
      ruleForm: {
    
    
        name: "",
        linkType: "",
        srcNetwork: "",
        dstNetwork: "",
        physicalPosition: "",
        orangeName: "",
        organCode: "",
        dutyPerson: "",
        dutyTel: "",
        dutyEmail: "",
        ip: "",
        port: undefined,
        webUrl: ""
      },
      rules: {
    
    
        name: [{
    
     required: true, message: "请输入链路名称", trigger: "blur" }],
        linkType: [
          {
    
     required: true, message: "请选择链路类型", trigger: "blur" }
        ],
        go: [
          {
    
    
            required: true,

            message: "请选择链路走向",
            trigger: "blur",
            validator: validateGo
          }
        ],
        physicalPosition: [
          {
    
     required: false, message: "请输入链路物理位置", trigger: "blur" }
        ],
        orangeName: [
          {
    
     required: true, message: "请输入所属机构", trigger: "blur" }
        ],

        organCode: [
          {
    
     required: true, message: "请输入行政区编码", trigger: "blur" }
        ],

        dutyPerson: [
          {
    
     required: true, message: "请输入链路责任人", trigger: "blur" }
        ],
        dutyTel: [
          {
    
     required: true, message: "请输入链路责任人电话", trigger: "blur" }
        ],
        dutyEmail: [
          {
    
    
            required: false,
            message: "请输入负责人公安网邮箱",
            trigger: "blur"
          }
        ],

        ip: [{
    
     required: false, message: "请输入链路IP地址", trigger: "blur" }],
        port: [{
    
     required: true, message: "请输入链路端口", trigger: "blur" }],
        webUrl: [
          {
    
     required: false, message: "请输入链路管理页面", trigger: "blur" }
        ]
      },
      linkTypeList: [],
      scrList: [],
      dstList: [],

      tuopuForm: {
    
    
        fileName: "",
        fileUrl: ""
      },
      tableHead: [
        {
    
    
          label: "设备名称",
          prop: "name",
          type: "normal",
          sortable: false
        },
        {
    
    
          label: "设备类型",
          prop: "devType",
          type: "normal",
          sortable: false
          // width: 150
        },

        {
    
    
          label: "厂商",
          prop: "manufacturer",
          type: "normal",
          sortable: false
          // width: 150
        },

        {
    
    
          label: "型号",
          prop: "model",
          type: "normal",
          sortable: false
          // width: 150
        },

        {
    
    
          label: "设备IP",
          prop: "devIp",
          type: "normal",
          sortable: false
        },

        {
    
    
          label: "子网掩码",
          prop: "ipMask",
          type: "normal",
          sortable: false
          // width: 150
        },
        {
    
    
          label: "网关",
          prop: "ipGaway",
          type: "normal",
          sortable: false
          // width: 150
        },

        {
    
    
          label: "安装时间",
          prop: "installTime",
          type: "normal",
          sortable: false,
          width: 180
        },
        {
    
    
          label: "操作",
          prop: "doSomething",
          type: "slot",
          sortable: false,
          slotName: "doSomething",
          width: 220
        }

        // {
    
    
        //   label: "任务详情",
        //   prop: "log_text",
        //   type: "slot",
        //   sortable: false,
        //   slotName: "log_text",
        //   width: 100
        // }
      ],
      showListD: [
        "name",
        "devType",

        "manufacturer",

        "model",
        "devIp",
        "ipMask",
        "ipGaway",

        "installTime",
        "doSomething"

        // "log_text"
      ],
      dialogStatus: "",
      dialogFormVisible: false,
      textMap: {
    
    
        update: "编辑设备",
        Edit: "编辑设备",
        edit: "编辑设备",
        create: "添加设备"
      },
      tableData: [],

      tableLoading: false,

      Register_tableHead: [
        {
    
    
          label: "平台名称",
          prop: "name",
          type: "normal",
          sortable: false
        },
        {
    
    
          label: "平台IP地址",
          prop: "ip",
          type: "normal",
          sortable: false
        },

        {
    
    
          label: "平台端口",
          prop: "port",
          type: "normal",
          sortable: false
        },

        {
    
    
          label: "平台唯一标识",
          prop: "uniquePlatformCode",
          type: "normal",
          sortable: false
        },

        {
    
    
          label: "注册时间",
          prop: "lastTime",
          type: "normal",

          sortable: false,
          width: 180
        },

        {
    
    
          label: "注册状态",
          prop: "status",
          type: "slot",
          slotName: "status",
          sortable: false
        },

        {
    
    
          label: "操作",
          prop: "doSomething",
          type: "slot",
          sortable: false,
          slotName: "doSomething",
          width: 220
        }

        // {
    
    
        //   label: "任务详情",
        //   prop: "log_text",
        //   type: "slot",
        //   sortable: false,
        //   slotName: "log_text",
        //   width: 100
        // }
      ],

      Register_tableData: [],

      Register_tableLoading: false,

      Register_showListD: [
        "name",
        "ip",
        "port",
        "uniquePlatformCode",
        "lastTime",
        "status",

        "doSomething"

        // "log_text"
      ],
      Register_dialogFormVisible: false,
      fileList: null, //拓扑图文件列表

      tuotpData: null,
      EquipmentList: [],
      originalList: []
    };
  },
  created() {
    
    
    this.getNews();
  },
  methods: {
    
    
    getNews() {
    
    
      //获取边界信息
      this.getBoundaryDetail();

      //获取拓扑图
      this.getTuotp();

      //获取设备列表
      this.fetchData();
      //获取链路注册列表
      this.Register_fetchData();

      //获取公共下拉
      this.getSelect();
    },
    saveForm() {
    
    
      this.$refs["ruleForm"].validate(valid => {
    
    
        if (valid) {
    
    
          let params = {
    
    
            ...this.ruleForm
          };

          console.log("修改入参", params);
          //修改
          api
            .boundaryEdit(params)
            .then(res => {
    
    
              console.log("修改", res);
              if (res.code == 200) {
    
    
                this.$notify({
    
    
                  title: "成功",
                  message: "边界信息修改成功",
                  type: "success",
                  duration: 2000
                });
              }
            })
            .catch(err => {
    
    });
        }
      });
    },
    preview() {
    
    
      console.log("预览", this.fileList, this.tuopuForm);
      if (!this.fileList) {
    
    
        this.$message.error(
          "拓扑图文件为空不能预览,请先上传拓扑图文件后再预览",
          6000
        );

        return false;
      }

      this.$router.push({
    
    
        path: "TuotpPreview",
        query: {
    
    
          fileName: this.tuopuForm.fileName,
          fileUrl: this.tuopuForm.fileUrl
        }
      });
    },
    addEquipment() {
    
    
      this.dialogStatus = "create";
      this.dialogFormVisible = true;
      setTimeout(() => {
    
    
        this.$refs["AddEdit"].dialogStatus = "create";
        // this.$refs.AddEdit.resetTransferDetail();
        // this.getCommonData();
      }, 1);
    },

    //获取公共下拉
    getSelect() {
    
    
      api
        .getLinkEquimentSelect({
    
    
          clsName: "link_direction"
        })
        .then(res => {
    
    
          console.log("链路走向下拉", res);
          this.scrList = res.data;
          this.dstList = res.data;
          this.originalList = res.data;
        })
        .catch(err => {
    
    });

      api
        .getLinkEquimentSelect({
    
    
          clsName: "link_type"
        })
        .then(res => {
    
    
          console.log("链路类型下拉", res);
          this.linkTypeList = res.data;
        })
        .catch(err => {
    
    });

      api
        .getLinkEquimentSelect({
    
    
          clsName: "dev_type"
        })
        .then(res => {
    
    
          console.log("设备类型下拉", res);
          this.EquipmentList = res.data;
        })
        .catch(err => {
    
    });
    },

    //获取边界信息
    getBoundaryDetail() {
    
    
      api
        .boundaryDetail()
        .then(res => {
    
    
          // console.log("获取边界信息", res);
          this.ruleForm = res.data;
          this.ruleForm.port = res.data.port ? res.data.port : undefined;
        })
        .catch(err => {
    
    });
    },

    //获取拓扑图
    getTuotp() {
    
    
      api
        .boundaryTuopoDetail()
        .then(res => {
    
    
          // console.log("获取拓扑图成功", res);
          this.tuopuForm = res.data;
          this.tuopuPreview();
        })
        .catch(err => {
    
    
          // console.log("获取拓扑图失败", err);
        });
    },

    //获取设备列表
    fetchData() {
    
    
      this.tableLoading = true;

      api
        .equipmentList({
    
    
          page: 1,
          page_size: 99999,
          ip: ""
        })
        .then(res => {
    
    
          // console.log("设备列表", res);

          if (res.code == 200) {
    
    
            this.tableData = res.data.list;

            this.tableLoading = false;
          }
        })
        .catch(err => {
    
    });
    },

    //编辑
    handlerUpdate(row) {
    
    
      // console.log("点了修改", row);

      this.dialogStatus = "Edit";
      this.dialogFormVisible = true;
      setTimeout(() => {
    
    
        this.$refs["AddEdit"].setData(row);
        this.$refs["AddEdit"].dialogStatus = "Edit";
      }, 1);
    },

    handleClose() {
    
    
      this.dialogFormVisible = false;
    },

    submitForm() {
    
    
      this.$refs["AddEdit"].submitForm();
    },

    //删除
    handlerDelete(row) {
    
    
      this.$confirm("确定删除吗?", "提示", {
    
    
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(() => {
    
    
        api
          .equipmentDelete(row)
          .then(response => {
    
    
            if (response.code == 200) {
    
    
              this.fetchData();
              this.$notify({
    
    
                title: "成功",
                message: "删除成功",
                type: "success",
                duration: 2000
              });
            }
          })
          .catch(err => {
    
    });
      });

      // const index = this.list.indexOf(row)
    },

    //注销
    handlerLogoff(row) {
    
    
      api
        .registerStatusSwitch({
    
    
          id: row.id,
          status: row.status == 1 ? 2 : 1
        })
        .then(res => {
    
    
          this.Register_fetchData();
        })
        .catch(err => {
    
    });
    },

    //链路删除
    Register_handlerDelete(row) {
    
    
      this.$confirm("确定删除吗?", "提示", {
    
    
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning"
      }).then(() => {
    
    
        let id = row.id;
        api.VideoTaskDelete(id).then(response => {
    
    
          if (response.code == 200) {
    
    
            this.fetchData();
            this.$notify({
    
    
              title: "成功",
              message: "删除成功",
              type: "success",
              duration: 2000
            });
          }
        });
      });
    },

    //链路添加
    addRegister() {
    
    
      this.$refs["ruleForm"].validate(valid => {
    
    
        if (valid) {
    
    
          this.Register_dialogFormVisible = true;
          setTimeout(() => {
    
    
            // this.$refs["AddEdit"].dialogStatus = "create";
            // this.$refs.AddEdit.resetTransferDetail();
            // this.getCommonData();
          }, 1);
        } else {
    
    
          this.$message.error("基本信息为空不能添加,请先补充基本信息", 6000);
        }
      });
    },

    Register_handleClose() {
    
    
      this.Register_dialogFormVisible = false;
    },

    Register_submitForm() {
    
    
      this.$refs["RegisterAdd"].submitForm();
    },
    //获取链路注册列表
    Register_fetchData() {
    
    
      this.Register_tableLoading = true;

      api
        .registerList({
    
    
          page: 1,
          page_size: 99999,
          ip: ""
        })
        .then(res => {
    
    
          console.log("注册列表", res);

          if (res.code == 200) {
    
    
            this.Register_tableData = res.data.list;

            this.Register_tableLoading = false;
          }
        })
        .catch(err => {
    
    });
    },

    handleExceed(files, fileList) {
    
    
      if (files.length > 1) {
    
    
        this.$message.warning(
          `当前限制最多选择1个文件上传,本次选择了${
      
      files.length}个文件`
        );
      }
    },

    //文件上传前的钩子
    beforeAvatarUpload(file) {
    
    
      console.log("文件上传前的钩子", file);
      // 文件类型判断
      var testmsg = file.name.substring(file.name.lastIndexOf(".") + 1);
      const extension = testmsg === "doc";
      const extension2 = testmsg === "pdf";
      const extension3 = testmsg === "docx";

      if (!extension && !extension2 && !extension3) {
    
    
        this.$message({
    
    
          message: "上传的拓扑图文件只能是word、pdf格式,请重新上传!",
          type: "error",
          duration: 6000
        });

        this.fileList = null;

        return false;
      } else {
    
    
        this.fileList = file;
      }
    },

    //自定义上传
    UploadFile() {
    
    
      // 参数拼接
      let fileData = new FormData();
      fileData.append("file", this.fileList);
      // 调用接口

      axios({
    
    
        url: `${
      
      window.g.API_URL}/api/cascade/topo/upload`,
        method: "post",
        data: fileData,
        headers: {
    
    
          "Content-Type": "multipart/form-data",
          Authorization: getToken()
        }
      })
        .then(res => {
    
    
          console.log("上传成功", res);
          if (res.data.code == 200) {
    
    
            this.tuopuForm = res.data.data;

            //拓扑预览
            this.tuopuPreview();
          } else {
    
    
            console.log("上传失败1");
            this.$message({
    
    
              message: "上传拓扑图文件失败,请稍后重试!",
              type: "error",
              duration: 6000
            });
          }
        })
        .catch(err => {
    
    
          console.log("上传失败2", err);

          this.$message({
    
    
            message: "上传拓扑图文件失败,请稍后重试!",
            type: "error",
            duration: 6000
          });
        });
    },

    tuopuPreview() {
    
    
      axios({
    
    
        url: `${
      
      window.g.API_URL}/api/cascade/topo/preview`,
        method: "get",
        params: {
    
    
          fileUrl: this.tuopuForm.fileUrl
        },
        headers: {
    
    
          Authorization: getToken()
        },
        responseType: "arraybuffer"
      })
        .then(res => {
    
    
          console.log("拓扑预览获取成功", res);
          if (res.status == 200) {
    
    
            this.fileList = res.data;
          }
        })
        .catch(err => {
    
    
          console.log("拓扑预览失败失败", err);
        });
    },

    srcChange(val) {
    
    
      console.log("srcChange", val);

      if (val == this.ruleForm.dstNetwork) {
    
    
        this.ruleForm.dstNetwork = "";
      }

      this.dstList = this.originalList.filter(k => {
    
    
        return k.val != val;
      });
    },
    clearSrc() {
    
    
      this.scrList = JSON.parse(JSON.stringify(this.originalList));
    },
    dstChange(val) {
    
    
      console.log("dstChange", val);

      if (val == this.ruleForm.srcNetwork) {
    
    
        this.ruleForm.srcNetwork = "";
      }

      this.scrList = this.originalList.filter(k => {
    
    
        return k.val != val;
      });
    },
    clearDst() {
    
    
      this.dstList = JSON.parse(JSON.stringify(this.originalList));
    }
  }
};
</script>

<style lang="scss" scoped>
.app-container {
    
    
  .cardWhite {
    
    
    .itemBox {
    
    
      margin-bottom: 1.5rem;
      .headerTitle {
    
    
        font-size: 1rem;
        font-weight: bold;
      }
    }
  }
}

::v-deep .el-input-number .el-input__inner {
    
    
  text-align: left;
}
</style>

After the upload function is implemented, let's look at the preview function. Our requirement is to jump to a new page to preview after clicking the preview button. I first judge whether the file is empty or not uploaded. Since the preview page component and the current page component are neither parent-child nor grandfather-grandchild relationship, There is no relationship between eight poles. We can't transfer stream files through binding and sessionStorage. We can only send a request to obtain the file stream on the preview page. We can bring the parameters through the route, and the method code corresponding to the preview button as follows:

  preview() {
    
    
      console.log("预览", this.fileList, this.tuopuForm);
      if (!this.fileList) {
    
    
        this.$message.error(
          "拓扑图文件为空不能预览,请先上传拓扑图文件后再预览",
          6000
        );

        return false;
      }

      this.$router.push({
    
    
        path: "TuotpPreview",
        query: {
    
    
          fileName: this.tuopuForm.fileName,
          fileUrl: this.tuopuForm.fileUrl
        }
      });
    }

Let's look at the preview page, which is the TuotpPreview.vue component. The word preview is relatively simple. First, install the plug-in docx-preview through the command cnpm i docx-preview --save. It should be noted that this plug-in can only preview word files with the suffix docx. The terminal forces the uploaded doc format file to docx format , and then the current page component directly import { defaultOptions, renderAsync } from “docx-preview”; import, and finally configure docxOptions in data, and then display the div on the page Bind an id="bodyContainer" on the top, because the dom will be obtained and manipulated through document.getElementById, and finally the renderAsync method can be called.

cnpm i docx-preview --save //安装word预览插件docx-preview
import {
    
     defaultOptions, renderAsync } from "docx-preview"; //引入docx-preview插件对应的方法
 docxOptions: {
    
    
        className: "kaimo-docx-666", // string:默认和文档样式类的类名/前缀
        inWrapper: true, // boolean:启用围绕文档内容的包装器渲染
        ignoreWidth: false, // boolean:禁用页面的渲染宽度
        ignoreHeight: false, // boolean:禁止渲染页面高度
        ignoreFonts: false, // boolean:禁用字体渲染
        breakPages: true, // boolean:在分页符上启用分页
        ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分页
        experimental: false, // boolean:启用实验功能(制表符停止计算)
        trimXmlDeclaration: true, // boolean:如果为true,解析前会从​​ xml 文档中移除 xml 声明
        useBase64URL: false, // boolean:如果为true,图片、字体等会转为base 64 URL,否则使用URL.createObjectURL
        useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
        showChanges: false, // boolean:启用文档更改的实验性渲染(插入/删除)
        debug: false // boolean:启用额外的日志记录
  },

The preview of the pdf file is to directly open a new window through window.open after obtaining the blob file stream, and the pdf can be previewed through the browser. There is another kind of demand that I need now. To preview the pdf on the page, then It needs to go through the iframe, and then assign and echo the src address corresponding to the blob stream. The complete code is as follows:

<template>
  <div>
    <!-- 拓扑图预览 -->
    <div class="app-container">
      <div class="cardWhite">
        <div class="topArea">
          <div class="backBox">
            <img src="@/assets/goBack.png" @click="goBack" alt="" />
          </div>

          <div class="titleBox">
            {
    
    {
    
     myTitle }}
          </div>
        </div>

        <div class="previewBox">
          <div id="bodyContainer">
        
            <iframe :src="pdfUrl" width="100%" height="750px" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import axios from "axios";
import {
    
     getToken } from "@/utils/auth";
import {
    
     defaultOptions, renderAsync } from "docx-preview";
export default {
    
    
  data() {
    
    
    return {
    
    
      myTitle: "",
      previewData: null,
      docxOptions: {
    
    
        className: "kaimo-docx-666", // string:默认和文档样式类的类名/前缀
        inWrapper: true, // boolean:启用围绕文档内容的包装器渲染
        ignoreWidth: false, // boolean:禁用页面的渲染宽度
        ignoreHeight: false, // boolean:禁止渲染页面高度
        ignoreFonts: false, // boolean:禁用字体渲染
        breakPages: true, // boolean:在分页符上启用分页
        ignoreLastRenderedPageBreak: true, // boolean:在 lastRenderedPageBreak 元素上禁用分页
        experimental: false, // boolean:启用实验功能(制表符停止计算)
        trimXmlDeclaration: true, // boolean:如果为true,解析前会从​​ xml 文档中移除 xml 声明
        useBase64URL: false, // boolean:如果为true,图片、字体等会转为base 64 URL,否则使用URL.createObjectURL
        useMathMLPolyfill: false, // boolean:包括用于 chrome、edge 等的 MathML polyfill。
        showChanges: false, // boolean:启用文档更改的实验性渲染(插入/删除)
        debug: false // boolean:启用额外的日志记录
      },
      num: 1,
      numPages: 0,
      pdfUrl: ""
    };
  },
  created() {
    
    
    console.log("接收", this.$route.query);
    this.resetTitle();
    this.getFile();
  },
  methods: {
    
    
    goBack() {
    
    
      this.$router.go(-1);
    },

    //获取文件流
    getFile() {
    
    
      axios({
    
    
        url: `${
      
      window.g.API_URL}/api/cascade/topo/preview`,
        method: "get",
        params: {
    
    
          fileUrl: this.$route.query.fileUrl
        },
        headers: {
    
    
          Authorization: getToken()
        },
        responseType: "arraybuffer"
      })
        .then(res => {
    
    
          console.log("文件流获取成功", res);
          if (res.status == 200) {
    
    
            this.previewData = res.data;
            if (
              this.$route.query.fileName &&
              this.$route.query.fileName.indexOf(".docx") &&
              this.$route.query.fileName.indexOf(".pdf") == -1
            ) {
    
    
              //word--docx格式
              this.wordPreview(res.data);
            } else if (
              this.$route.query.fileName &&
              this.$route.query.fileName.indexOf(".doc") &&
              this.$route.query.fileName.indexOf(".pdf") == -1
            ) {
    
    
              //word--doc格式
              this.wordPreview(res.data);
            } else if (
              this.$route.query.fileName &&
              this.$route.query.fileName.indexOf(".pdf")
            ) {
    
    
              //pdf
              this.pdfPreview(res.data);
            }
          }
        })
        .catch(err => {
    
    
          console.log("文件流获取失败", err);
          this.$message.error("获取文件信息失败,请稍后重试", 6000);
        });
    },

    //重置标题
    resetTitle() {
    
    
      let fileName = this.$route.query.fileName;
      console.log("fileName", fileName);

      if (
        fileName &&
        fileName.indexOf(".docx") &&
        fileName.indexOf(".pdf") == -1
      ) {
    
    
        //word--docx格式
        let wordDocxArr = fileName.split(".docx");
        console.log("wordDocxArr", wordDocxArr);
        this.myTitle = wordDocxArr[0];
      } else if (
        fileName &&
        fileName.indexOf(".doc") &&
        fileName.indexOf(".pdf") == -1
      ) {
    
    
        //word--doc格式

        let wordDocArr = fileName.split(".docx");
        console.log("wordDocArr", wordDocArr);
        this.myTitle = wordDocArr[0];
      } else if (fileName && fileName.indexOf(".pdf")) {
    
    
        //pdf
        let pdfArr = fileName.split(".pdf");
        console.log("pdfArr", pdfArr);
        this.myTitle = pdfArr[0];
      }
    },

    // word文档预览
    wordPreview(buffer) {
    
    
      console.log("文档buffer", buffer);
      let bodyContainer = document.getElementById("bodyContainer");
      renderAsync(
        buffer, // Blob | ArrayBuffer | Uint8Array, 可以是 JSZip.loadAsync 支持的任何类型
        bodyContainer, // HTMLElement 渲染文档内容的元素,
        null, // HTMLElement, 用于呈现文档样式、数字、字体的元素。如果为 null,则将使用 bodyContainer。
        this.docxOptions // 配置
      )
        .then(res => {
    
    
          console.log("res---->", res);
        })
        .catch(err => {
    
    
          console.log("err---->", err);
        });
    },

    //pdf预览
    pdfPreview(data) {
    
    
      // data是一个ArrayBuffer格式,也是一个buffer流的数据
      console.log("pdf流", data);

      const binaryData = [];

      binaryData.push(data);

      //获取blob链接

      let pdfUrl = window.URL.createObjectURL(
        new Blob(binaryData, {
    
     type: "application/pdf" })
      );
      console.log("pdfUrl", pdfUrl);
      // window.open(pdfUrl); 这种方式是直接打开新浏览器窗口预览
      this.pdfUrl = pdfUrl;
    }
  }
};
</script>

<style lang="scss" scoped>
.app-container {
    
    
  .cardWhite {
    
    
    display: flex;
    flex-direction: column;

    .topArea {
    
    
      display: flex;
      position: relative;
      .backBox {
    
    
        margin-bottom: 1rem;
        img {
    
    
          cursor: pointer;
        }
      }

      .titleBox {
    
    
        text-align: center;
        background: #fff;
        color: #000000;
        position: absolute;
        top: 0;
        left: 50%;
        width: auto;
      }
    }
  }
}
</style>

Guess you like

Origin blog.csdn.net/qq_37635012/article/details/128298394