vue项目实现前端预览word和pdf格式文件

news2024/11/17 23:26:56

最近做vue项目遇到一个需求,就是前端实现上传word或pdf文件后,后端返回文件对应的文件流,前端需要在页面上展示出来。word预览简单一些,pdf预览我试过pdfjs,vue-pdf总是报各种奇奇怪怪的bug,但最终总算解决了问题,先看一下页面最终呈现效果吧:

页面上传pdf文件效果如下:

在这里插入图片描述

页面预览pdf文件效果如下:

在这里插入图片描述

页面上传word文件效果如下:

在这里插入图片描述

页面预览word文件效果如下:

在这里插入图片描述
这里先从上传组件页面说起,上传页面组件完整代码如下,按钮里面v-show=“$checkPermission([‘Register_tuotpUpload’])“都是给这个按钮设置了按钮权限的,我们只需要关注上传那一部分的代码即可,我们用了el-upload组件实现的手动上传,由于需求要求只能上传word和pdf,所以能看到属性设置的有 accept=”.pdf, .doc, .docx”,然后不展示上传成功的文件的列表设置的属性有:show-file-list=“false”,而handleExceed回调函数和limit都是为了限制只能上传一个文件,上传前的回调钩子函数beforeAvatarUpload里进行了文件类型判断与提醒,手动上传是通过UploadFile里进行完成的,需要注意的是由于docx-preview这个插件只能预览后缀为docx的word文件,如果是doc后缀格式的word文件一定要让后端强制将上传doc格式的文件改为docx格式,目前对于doc格式的word文件实现网页在线预览我只想到了docx-preview这个插件和这个解决办法

<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>

上传功能实现之后,我们再看预览功能。我们需求是点击预览按钮之后跳到一个新页面进行预览,我先是对文件是否为空是否没上传进行了一个判断拦截,由于预览页面组件与当前页面组件既非父子关系,又非爷孙关系,八竿子打不着的关系,我们就不能通过绑定和sessionStorage来进行流文件的传递,只能在预览页面再发一次请求获取文件流,我们可以把参数通过路由带上,预览按钮对应的方法代码如下:

  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
        }
      });
    }

再来看预览页面,也就是TuotpPreview.vue组件。word预览比较简单,先通过命令cnpm i docx-preview --save安装插件docx-preview,需要注意的是这个插件只能预览后缀为docx的word文件,如果是doc后缀格式的word文件一定要让后端强制将上传doc格式的文件改为docx格式,然后当前页面组件就直接import { defaultOptions, renderAsync } from “docx-preview”;引入,最后在data里进行docxOptions配置,然后在页面上 要显示的div上绑定一个 id="bodyContainer"的,因为下面要通过document.getElementById来获取dom并操作dom,最后调用renderAsync方法即可。

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:启用额外的日志记录
  },

pdf文件的预览是通过获取到blob文件流之后,直接通过window.open打开新窗口,通过浏览器就能预览pdf,还有一种就是我现在的这种需求,要在页面上预览pdf,那就需要通过iframe,然后把blob流对应的src地址赋值回显即可。完整代码如下:

<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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/409706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HttpServletResponse 类

a)HttpServletResponse 类的作用 HttpServletResponse 类和 HttpServletRequest 类一样。每次请求进来&#xff0c;Tomcat 服务器都会创建一个 Response 对象传 递给 Servlet 程序去使用。HttpServletRequest 表示请求过来的信息&#xff0c;HttpServletResponse 表示所有响应…

解决TypeError: Cannot read properties of null (reading ‘xxx‘)的错误

文章目录1. 文章目录2. 分析问题3. 解决错误4. 问题总结1. 文章目录 今天测试小姐姐&#xff0c;在测试某页面时&#xff0c;报出如下图的错误&#xff1a; TypeError: Cannot read properties of null (reading type)at w (http://...xxx.../assets/index.a9f96e7f.js:1052:19…

前端基础,超全html常用标签大汇总

<html></html>标签&#xff0c;整个html文件都会放在html标签里面 <head></head>标签&#xff0c;表示网页的头部信息&#xff0c;一般是为浏览器提供对应的网站需要的相关信息&#xff0c;浏览器中是不会显示的&#xff1b;比如&#xff1a;标题titl…

vue中PC端使用高德地图 -- 实现搜索定位、地址标记、弹窗显示定位详情

PC端高德地图使用步骤&#xff1a; 1、注册并登录高德开放平台获取 2、安装高德依赖&#xff08;amap-jsapi-loader&#xff09; 3、初始化地图 4、首次打开地图获取当前定位并标记 5、根据已有地址自动定位到指定地址并标记 6、新增、清除标记及自定义信息窗体 7、鼠标点击地…

iframe嵌套其它网站页面及相关知识点详解

在开发过程中会遇到需要 在一个页面中嵌套另外一个页面&#xff0c;就要使用到框架 标签&#xff0c;然后指定src就可以了。 基本语法&#xff1a; <iframe src"需要展示的网站页面的URL"></iframe>用法举例&#xff1a; <!DOCTYPE html> <h…

css ::before ::after 添加伪元素不生效

需求&#xff1a;想用伪元素来写蓝色小标 HTML结构&#xff1a; <div> <span class"course-configname">教程配置</span> </div> 1.一开始这样写&#xff1a;&#xff08;不生效&#xff09; .course-configname::before{content: ;width…

vue3.0-axios拦截器、proxy跨域代理

目录 1. vue-cli 1&#xff09;vue-cli 2&#xff09;安装vue-cli ①解决Windows PowerShell不识别vue命令的问题 3&#xff09;创建项目 4&#xff09;基于vue ui创建vue项目 5&#xff09;基于命令行创建vue项目 2. 组件库 1&#xff09;vue组件库 2&#xff09;v…

Three.js - 透视相机(PerspectiveCamera)(三)

简介 在three.js中&#xff0c;摄像机的作用就是不断的拍摄我们创建好的场景&#xff0c;然后通过渲染器渲染到屏幕中。想通过不同的角度观看场景&#xff0c;就需要修改摄像机的位置来拍摄场景。本文详细介绍的是透视相机&#xff08;PerspectiveCamera&#xff09; 它是用来…

React Hooks(钩子函数)

React Hooks什么是Hooks?UseState()useReducer()useContext()useEffect()useRef()自定义钩子函数React Hooks中可以对性能进行优化的函数useMemo()useCallback()useMemo()和useCallback()的区别什么是Hooks? 首先&#xff1a;React的组件创建方式&#xff0c;一种是类组件&a…

划水日常(16.5)关于出版图书有偿征集书名 ~

关于摸鱼日常已经断更两个月了&#xff0c;前段时间一直忙在项目上&#xff0c;再加上搭了个网站&#xff0c;你要说有事儿吧&#xff0c;其实事儿也不多。你要说没事儿吧&#xff0c;我就是不更。原因其实很简单&#xff0c;我懒&#xff01; 可直接跳过目录一&#xff0c;直至…

web自动化测试入门篇02——selenium安装教程

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

授予渔,从0开始搭建一个自己想要的网页

文章目录视频展示&#xff1a;张娜英网页一.开始阶段1.1考虑出基本的架构1.2填充思路1.3前提准备二.实现阶段2.1导航栏实现2.2点击切换视频2.3 左右特效2.4照片墙2.5视频轮播2.6底部2.7点击切换全局变量3.总结全部代码&#xff1a;☀️作者简介&#xff1a;大家好我是言不及行y…

【实战】React 必会第三方插件 —— Cron 表达式生成器(qnn-react-cron)

文章目录一、引子二、配置使用1.安装2.使用&#xff08;1&#xff09;直接调用&#xff08;2&#xff09;赋值到表单&#xff08;Form&#xff09;&#xff08;3&#xff09;自定义功能按钮&#xff08;4&#xff09;隐藏指定 Tab&#xff08;5&#xff09;其他三、常见问题及解…

【JavaScript 进阶教程】数组新增遍历方法的说明与使用

文章已收录专栏&#xff1a;JavaScript 进阶教程 作者&#xff1a;卡卡西最近怎么样 文章导读&#xff1a; 欢迎来到 JavaScript 进阶的学习&#xff0c;ES5 对 JS 的数组&#xff0c;字符串等内置对象的方法均有扩充。这篇文章我们要掌握的是新增的几个 Array 内置对象的常用迭…

【Web理论篇】Web应用程序安全与风险

目录&#x1f332;1.Web应用程序的发展历程&#x1f342;1.1 Web应用程序的常见功能&#x1f342;1.2 Web应用程序的优点&#x1f332;2.Web安全&#x1f342;2.1Web应用程序常见漏洞&#x1f342;2.2未对用户输入做过滤&#x1f342;2.3 造成这些漏洞的原因是什么呢&#xff1…

【实战分享】js生成word(docx),以及将word转成pdf解决方案分享

本文将记录如何用js生成word文件&#xff0c;并在node服务器端将word转换成pdf。记录的代码均是在真实业务场景中使用成功的代码&#xff0c;没有记录中间踩坑的过程。想直接抄答案的家人们可以跳转到1.2 程序编写部分&#xff0c;最终效果图可在1.2 程序编写部分中4. 效果展示…

【解决前端报错】Bad Request: Required request parameter ‘id‘ for method parameter type Long is not present

后端查询列表接口返回的对象里包含Long id,前端获取到这个id,执行通过Long id删除操作。这时删除操作报错400&#xff0c;大意是没找着Long类型的id. swagger相关接口截图&#xff1a; Long类型的在swagger显示是integer64 &#xff0c; integer是integer32. 这是前端请求后…

微信公众号 - 实现 H5 网页在微信内置浏览器中下载文件,可预览和下载 office 文件(doc / xls / ppt / pdf 等)适用于任何前端技术栈网站,兼容安卓和苹果系统!

前言 网上的教程都是让你写页面 “引导” 右上角三个点里,让用户自己去浏览器打开,其实这样用户体验并不好。 本文实现了 最新微信公众号 H5 网页(微信内置浏览器中),预览下载 office 文件,安卓和苹果全都支持! 您可以直接复制代码,移植到自己项目中去,任何前端项目(…

全网超详细的【Axure】Axure RP 9的下载、安装、中文字体、授权

文章目录1. 文章引言2. 下载Axure93. 安装Axure94. Axure9中文5. Axure9授权1. 文章引言 最近在学习原型图&#xff0c;针对画原型图的工具&#xff0c;反复对比墨刀、Axure、xiaopiu后&#xff0c;最终选择了Axure。 接下来&#xff0c;我便从Axure RP 9的下载、安装、中文字…

VUE实现微信扫码登录

获取access_token时序图&#xff1a; public中index.html引入 <script src"https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script> 微信登录操作 new WxLogin({// 以下操作把请求到的二维码嵌入到id为"weixin"的标签中i…