先上效果
运用到的技术
- vue-pdf
- setasign/fpdf
- setasign/fpdi
- vue-esign
前端实现
pdf封装
<template>
<div>
<pdf
v-for="i in numPages"
:key="i"
:src="src"
:page="i"
style="display: block; width: 100%; border-bottom: 1px solid;"
class="pdf-page"
></pdf>
</div>
</template>
<script>
import pdf from "vue-pdf";
export default {
props: ['url'],
components: {
pdf
},
data() {
return {
src: "",
numPages: undefined
};
},
watch: {
numPages: function(){
this.$nextTick(() => {
console.log('success')
})
}
},
mounted() {
this.src = pdf.createLoadingTask(this.url);
this.src.promise.then(pdf => {
this.numPages = pdf.numPages;
this.$emit('closeLoadding', false)
});
}
};
</script>
使用 + 签名
<template>
<div class="pdfContainer" v-loading="loadding">
<div class="header">
<h2>{{ title }}</h2>
<span class="no">contact No: {{ trno }}</span>
<br />
</div>
<div class="content">
<pdf :url="contract_pdf_url" @closeLoadding="closeLoadding"/>
<div class="pdf">
<img :src="signatureImg" alt="签名图片" ref="signatureImg" class="signatureImg" v-show="signatureImg">
</div>
<el-divider></el-divider>
<div class="signature">
<br />
<strong>签字:</strong> 请在下面进行签字
<el-divider></el-divider>
<vue-esign
ref="signature"
:width="800"
:height="230"
:isCrop="isCrop"
:lineWidth="lineWidth"
:lineColor="lineColor"
:bgColor.sync="bgColor"
/>
<el-button type="warning" class="restore" @click="restore">清除</el-button>
<el-button type="primary" class="button" @click="confirm">确认</el-button>
</div>
</div>
</div>
</template>
<script>
import vueEsign from "vue-esign";
import { Message } from 'element-ui';
import { contractSign } from "@/api/web";
import Pdf from "@/components/Pdf/Index"
export default {
components: { Pdf, vueEsign },
props: ['showNext', 'contract_pdf_url'],
data() {
return {
title: "Talk 100",
trno: "TRCN-0007776669",
src: null,
numPages: 6,
isCrop: false,
positionX: 0,
positionY: 0,
lineColor: "#000000",
bgColor: "",
lineWidth: 6,
signatureImg: "",
loadding: true
};
},
methods: {
confirm() {
this.$refs.signature
.generate()
.then(res => {
this.signatureImg = res
this.$refs.signature.reset();
this.$emit('update:showNext', 1)
})
.catch(err => {
Message.error(err)
});
},
restore() {
this.$refs.signature.reset();
this.showNext = false
},
savePdf() {
return new Promise((resolve) => {
contractSign({sign: localStorage.getItem('sign'), img: this.signatureImg}).then( r => {
if( r.code == 200) {
resolve()
}
})
})
},
/**
* 控制整个页面的显示
*/
closeLoadding(isShowLoadding) {
this.loadding = isShowLoadding
}
}
};
</script>
<style lang="scss">
html {
font-size: 20px;
}
body {
font-size: 16px;
}
.header {
h2 {
width: 100%;
text-align: center;
}
.no {
float: right;
margin-right: 2rem;
clear: both;
}
.prompt {
color: #33363b;
}
}
.pdfContainer {
.pdf {
position: relative;
margin-top: 3rem;
margin-left: 20%;
span {
display: block;
width: 60% !important;
left: 5rem;
}
img {
width: 400px;
height: 120px;
position: absolute;
right: 150px;
bottom: 50px;
}
}
.signature {
border: 1px solid springgreen;
width: 80%;
margin: 0px auto;
canvas {
width: 100%;
}
.el-divider--horizontal{
margin: 24px 0 0 0;
}
}
}
</style>
前端主要进行pdf渲染到页面中,然后我们通过组件vue-esign
得到一个签字画版,当签字确认后,我们可以通过方法generate()
来得到一张签名图,由此我们将图片添加dom节点导pdf中
同时进行将图片传递给后端
后端实现
核心方法如下
public function contractPdf($sign_img, $user_id, $app_id)
{
# 处理上传的图片
# 企业合同地址
$train = (new CorpService())->getTrain($app_id, $user_id);
$pdf_path = $this->createContractPdf(Arr::get($train, 'contract_path'));
$file = str_replace('data:image/png;base64,', '', $sign_img);
$file = base64_decode($file);
$filename = storage_path("temp/" . Str::random(40) . '.' . "png");
file_put_contents($filename, $file);
# 保存pdf
$pdf = new Fpdi();
$pageCount = $pdf->setSourceFile($pdf_path);
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++){
$templateId = $pdf->importPage($pageNo);
$size = $pdf->getTemplateSize($templateId);
if ($size['width'] > $size['height']){
$pdf->AddPage('L', array($size['width'], $size['height']));
}else {
$pdf->AddPage('P', array($size['width'], $size['height']));
}
$pdf->useTemplate($templateId);
if($pageNo == $pageCount) {
$w = $size['width']/5;
$h = $size['height']/5;
$center_x = $w * 3.5; $center_y = $h * 4;
$pdf->image($filename, $center_x, $center_y, 80);//中间水印
}
}
$end_path = "contract/$user_id.pdf";
$pdf->Output('F',storage_path("$end_path"),false);
# 删除临时文件
Storage::delete($filename);
return $end_path;
}
将签字后的图片进行保存写入pdf中,完成整个操作链
本文由 邓尘锋 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Mar 22, 2021 at 04:47 pm