基于vue前端pdf在线预览解决方案实践

  1. 需求描述:客户有10万多册的纸质档案的数据,需要电子化,电子化后可以通过查看界面查看基本的文本信息以及pdf和图片的信息
  2. 前端采用的技术为vue2.0,网上搜索了好做方案,大多数建议采用vue-pdf插件时间,所以本案例采用vue+vue-pdf实现pdf在线预览
  3. 在前端vue项目中安装vue-pdf插件,切换到vue项目根目录,执行命令:npm install --save vue-pdf
  4. 插件安装完成后,在所需的界面导入vue-pdf插件(import pdf from ‘vue-pdf’),然后进行插件的注册(components: {sider,UploadList,pdf}),我自己对应的查看页面代码如下,供大家参考:
<template>
  <div>
    <!--
    <i class="el-icon-circle-plus-outline"   @click="dialogFormVisible = true"></i> 通过图标触发新增
    <el-button type="primary" icon="el-icon-circle-plus-outline"  @click="dialogFormVisible = true">新增</el-button> -->  <!-- 通过按钮触发新增 -->
    <el-dialog title="查看房屋档案信息":visible.sync="houseInfoVisible" :before-close="handleClose">
      <el-form :model="dataForm"  ref="dataForm"  style="text-align: auto">
        <div class="item-content c1">
          <div class="item">
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="售卖单位:" prop="saleUnit">
                    <el-input v-model="dataForm.saleUnit" style="width: 100%" maxlength="30" placeholder="请填写售卖单位" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="楼盘名称:" prop="premName">
                   <el-input v-model="dataForm.premName" style="width: 100%" maxlength="30" placeholder="请填写楼盘名称" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="楼栋名称:" prop="buildName">
                    <el-input v-model="dataForm.buildName" style="width: 100%" maxlength="30" placeholder="请填写楼栋名称" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="单元名称:" prop="unitName">
                   <el-input v-model="dataForm.unitName" style="width: 100%" maxlength="30" placeholder="请填单元名称" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="房号:" prop="houseNo">
                    <el-input v-model="dataForm.houseNo" style="width: 100%" maxlength="30" placeholder="请填写房号" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="建筑面积(㎡):" prop="builtUpArea">
                   <el-input type="number" min="0" v-model="dataForm.builtUpArea" style="width: 100%" maxlength="30" v-input-format="{ min: 0, max: 100000000, precision: 2 }" placeholder="请填写建筑面积" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="套内面积(㎡):" prop="insideArea">
                    <el-input type="number" min="0" v-model="dataForm.insideArea" style="width: 100%" maxlength="30" v-input-format="{ min: 0, max: 100000000, precision: 2 }" placeholder="请填写套内面积" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="公摊面积(㎡):" prop="sharedArea">
                   <el-input type="number" min="0" v-model="dataForm.sharedArea" style="width: 100%" maxlength="30" v-input-format="{ min: 0, max: 100000000, precision: 2 }" placeholder="请填公摊面积" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="成交价格(元):" prop="houseTotalPrice">
                    <el-input type="number" v-model="dataForm.houseTotalPrice" style="width: 100%" maxlength="30" v-input-format="{ min: 0, max: 100000000, precision: 2 }" placeholder="请填写房屋总价" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="房屋间数:" prop="fwjs">
                   <el-input v-model="dataForm.fwjs" style="width: 100%" maxlength="30" placeholder="房屋件数" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="所在层数:" prop="szcs">
                    <el-input v-model="dataForm.szcs" style="width: 100%" maxlength="30" placeholder="请填写所在层数" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="建筑结构:" prop="jzjg">
                   <el-input v-model="dataForm.jzjg" style="width: 100%" maxlength="30" placeholder="请填写建筑结构" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="24">
                <el-form-item label="房屋座落:" prop="housePosition">
                    <el-input v-model="dataForm.housePosition" style="width: 100%" maxlength="30" placeholder="请填写房屋座落" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="买受人:" prop="buyPerson">
                    <el-input v-model="dataForm.buyPerson" style="width: 100%" maxlength="30" placeholder="请填写买受人" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="买受人证件号:" prop="certificateNo">
                   <el-input v-model="dataForm.certificateNo" style="width: 100%" maxlength="60" placeholder="请填写买受人证件号" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="法人代表:" prop="legalPerson">
                    <el-input v-model="dataForm.legalPerson" style="width: 100%" maxlength="30" placeholder="请填写法人代表" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
             <el-col :span="12">
               <el-form-item label="法人证件号:" prop="legalPersonCertificateNo">
                   <el-input v-model="dataForm.legalPersonCertificateNo" style="width: 100%" maxlength="60" placeholder="请填写法人证件号" :disabled="true"></el-input>
               </el-form-item>
             </el-col>
            </el-row>
            <el-row  :gutter="20">
              <el-col :span="12">
                <el-form-item label="产别:" prop="productionType">
                    <el-input v-model="dataForm.productionType" style="width: 100%" maxlength="30" placeholder="请输入产别:公产/私产" :disabled="true"></el-input>
                </el-form-item>
              </el-col>
            </el-row>
            <!-- <el-row  :gutter="20">
              <el-col :span="24">
                <el-form-item label="合同扫附件:" prop="htAttentments">
                 <upload-list :file-list="dataForm.htAttentment" :close-visible="!detail" :upload-visible="!detail" :disabled="true"></upload-list>
                </el-form-item>
              </el-col>
            </el-row> -->
          </div>
        </div>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <h3 style="text-align: left;">房屋档案附件列表</h3>
        <div class="arrow"  v-for="(item,index) in pdfs" :key="item.value" style="border-top:2px solid #000;">
              <!-- <button @click="item.Sub">上一页</button>
                 {{item.currentPage}}/{{item.pageCount}}
              <button @click="item.Add">下一页</button>
              <pdf ref="pdf" style="width:800px"
                    :src="item.src"
                    :page="item.currentPage"
                    @num-pages="item.pageCount=$event"
                    @page-loaded="item.currentPage=$event"
                    @loaded="item.lr">
              </pdf> -->
              <pdf :src="item.url" :page="currentArr[index].currentPage" @num-pages="currentArr[index].pageCount=$event" @page-loaded="currentArr[index].currentPage=$event" @loaded="loadPdfHandler" style="height: auto;"></pdf>
              <p style="text-align: left;">
                <span style="font-weight:bold;color:#1E90FF;font-size: large;">{{currentArr[index].currentPage}}</span><span> / </span> <span style="font-weight:bold;font-size: large;">{{currentArr[index].pageCount}}</span>
              </p>
              <el-button-group style="text-align: center;">
                <el-button style="font-size: large;"  @click="changePdfPage(0,index)" class="turn" :class="{grey: currentArr[index].currentPage==1}" type="text" icon="el-icon-arrow-left">上一页</el-button>
                <el-button style="font-size: large;margin-left:20px;" @click="changePdfPage(1,index)" class="turn" :class="{grey: currentArr[index].currentPage==currentArr[index].pageCount}" type="text">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
              </el-button-group>
              <el-button style="font-size: large;margin-left: 50px;" type="text" @click="downloadPdf(item.url)">{{item.name}}</el-button>

        </div>
        <div v-for="(item,index) in images" :key="item.value" style="border-top:2px solid #000 ;">
          <ul style="width: 800px;">
            <img v-bind:src="item.url" v-bind:alt="item.name" style="width: 100%;height: auto;">
            <p><el-button style="font-size: large;" type="text" @click="downloadPdf(item.url)">{{item.name}}</el-button></p>
          </ul>
        </div>
       <!-- <el-button @click="houseInfoVisible = false">取 消</el-button> -->
        <el-button @click="dataFormCancel()">关 闭</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
  import { isEmpty, isDouble } from '@/utils/validate'
  import sider from '@/components/sider'
  import UploadList from '@/components/upload-list'
  import pdf from 'vue-pdf'
  export default {
    components: {sider,UploadList,pdf},
    data () {
      // var validateHtAttentments = (rule, value, callback) => {
      //   if (!this.dataForm.htAttentment || this.dataForm.htAttentment.length === 0) {
      //     return callback(new Error('请上传合同附件'));
      //   } else {
      //     return callback()
      //   }
      // }
      return {
        houseInfoVisible: false,
        pdfs:[],
        currentArr:[],
        images:[],
        dataForm: {
          htAttentment: []
        },
        detail: false,
        formLabelWidth: '120px'
      }
    },
    created() {
      //this.initPdfPage()
    },
    methods: {
      init(id){
        this.dataForm = {
          saleUnit:'',
          premName:'',
          buildName:'',
          unitName:'',
          houseNo:'',
          builtUpArea:'',
          insideArea:'',
          sharedArea:'',
          houseTotalPrice:'',
          fwjs:'',
          szcs:'',
          jzjg:'',
          housePosition:'',
          buyPerson:'',
          certificateNo:'',
          legalPerson:'',
          legalPersonCertificateNo:'',
          productionType:'',
          htAttentment:[]
        }
        this.dataForm.id = id || 0
        this.$nextTick(() => {
          this.visible = true
          this.$refs['dataForm'].resetFields()
        })
        if(this.dataForm.id){
          this.$http({
            url: this.$http.adornUrl(`/sl/contractInfo/info/${this.dataForm.id}`),
            method: 'get',
            params: this.$http.adornParams()
          }).then(({data}) => {
            if (data && data.code === 0) {
              this.dataForm = data.entity
              this.pdfs = data.entity.pdfs
              this.images = data.entity.images
              this.initPdfPage()
            } else {
              this.$message.error(data.msg)
            }
          })

        }

      },
      handleClose(done){
        this.$confirm('确认关闭详情界面码?')
                  .then(_ => {
                    done();
                  })
                  .catch(_ => {})
        //this.houseInfoVisible = true

      },
      dataFormCancel () {
        this.houseInfoVisible = false
        this.dataForm.htAttentment = []
      },
      onSubmit (formName) {
        console.log("执行方法")
        this.$refs[formName].validate((valid) => {
          if (valid) {
            this.$http({
              url: this.$http.adornUrl(`/sl/contractInfo/${!this.dataForm.id ? 'save' : 'update'}`),
              method: 'post',
              data: this.$http.adornData(this.dataForm)
            }).then(({data}) =>{
              if(data && data.code === 0){
                console.log('请求成功!')
                this.houseInfoVisible = false;
                this.$emit('refreshDataList')
              }else{
                console.log('请求失败')
              }
            })
          }
        })
      },
      initPdfPage(){
        for (var i = 0; i < this.pdfs.length; i++) {
          this.currentArr.push({
            currentPage: 0, // pdf文件页码
            pageCount: 0 // pdf文件总页数
          })
        }
      },
      changePdfPage (val, index) {
            if (val === 0 && this.currentArr[index].currentPage > 1) {
              this.currentArr[index].currentPage--
            }
            if (val === 1 && this.currentArr[index].currentPage < this.currentArr[index].pageCount) {
              this.currentArr[index].currentPage++
            }
          },
          // pdf加载时
          loadPdfHandler (e) {
            // this.currentPage = 1 // 加载的时候先加载第一页
            for (var i = 0; i < this.currentArr.length; i++) {
              this.currentArr[i].currentPage = 1
            }
          },
          downloadPdf(url){
            window.open(url);
          }
    }

  }
</script>
<style scoped>
  .el-icon-circle-plus-outline {
    margin: 50px 0 0 20px;
    font-size: 100px;
    float: left;
    cursor: pointer;
  }
  .mod-building-add-or-update {
    background: #f1f4f5;
  }
  .button-content {
    background: #fff;
    border-top: 1px solid #e9e9e9;
    height: 60px;
    line-height: 60px;
    padding-left: 20px;
    text-align: center;
  }
  .item-content {
    background: #fff;
  }
  .item-content .item-title {
      height: 40px;
      line-height: 40px;
      border-bottom: 1px solid #e9e9e9;
  }
  .item-content .item-title span {
    margin-left: 20px;
    font-weight: bold;
  }
  .item-content .item {
      padding: 10px;
  }
  .c2 {margin-top: 10px;}
  .col14{ width: 50%; margin: 0 1% 0 0;}
  .col34{ width: 65%;}
</style>
  1. 在date 的return中定义一个pdfs数据,接收后台返回的pdf集合
    在这里插入图片描述
  2. 通过上面的方法,前端pdf主句已经接收到了后台返回的pdf集合,接下来就是展示的问题了
  3. 界面上已经引入并注册了vue-pdf插件,所以在界面上直接使用pdf标签即可
<div class="arrow"  v-for="(item,index) in pdfs" :key="item.value" style="border-top:2px solid #000;">
              <pdf :src="item.url" :page="currentArr[index].currentPage" @num-pages="currentArr[index].pageCount=$event" @page-loaded="currentArr[index].currentPage=$event" @loaded="loadPdfHandler" style="height: auto;"></pdf>
              <p style="text-align: left;">
                <span style="font-weight:bold;color:#1E90FF;font-size: large;">{{currentArr[index].currentPage}}</span><span> / </span> <span style="font-weight:bold;font-size: large;">{{currentArr[index].pageCount}}</span>
              </p>
              <el-button-group style="text-align: center;">
                <el-button style="font-size: large;"  @click="changePdfPage(0,index)" class="turn" :class="{grey: currentArr[index].currentPage==1}" type="text" icon="el-icon-arrow-left">上一页</el-button>
                <el-button style="font-size: large;margin-left:20px;" @click="changePdfPage(1,index)" class="turn" :class="{grey: currentArr[index].currentPage==currentArr[index].pageCount}" type="text">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button>
              </el-button-group>
              <el-button style="font-size: large;margin-left: 50px;" type="text" @click="downloadPdf(item.url)">{{item.name}}</el-button>

        </div>
  1. 在div中通过for循环遍历pdf数组,使用pdf标签进行展示,这种方式是默认展示pdf的首页,通过上一页和下一页进行切换,所以需要定义一个数组,来存房每个pdf的当前页和总页数:
    在这里插入图片描述
  2. js中有四个方法需要重点说明一下:
initPdfPage(){
        for (var i = 0; i < this.pdfs.length; i++) {
          this.currentArr.push({
            currentPage: 0, // pdf文件页码
            pageCount: 0 // pdf文件总页数
          })
        }
      },
      changePdfPage (val, index) {
            if (val === 0 && this.currentArr[index].currentPage > 1) {
              this.currentArr[index].currentPage--
            }
            if (val === 1 && this.currentArr[index].currentPage < this.currentArr[index].pageCount) {
              this.currentArr[index].currentPage++
            }
          },
          // pdf加载时
          loadPdfHandler (e) {
            // this.currentPage = 1 // 加载的时候先加载第一页
            for (var i = 0; i < this.currentArr.length; i++) {
              this.currentArr[i].currentPage = 1
            }
          },
          downloadPdf(url){
            window.open(url);
          }
  1. initPdfPage(),在成功获取到基本信息后执行,changePdfPage()点击上一页下一页时进行页数切换,loadPdfHandler(),设置pdf加载第一页,downloadPdf(),点击文件名称时下载该文件,实现后的最终效果如下:
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值