案例
使用
npm i vue-esign
<template>
<div class="userSign">
<p class="sign-title pd-24">本地证明签署</p>
<p class="userSign-tip pd-24">请投保人【{{font}}】在下方签字,请您按照提示文字使用正楷公正书写,每次每格可写一个字,请确保提交的文件真实、准确、完整</p>
<div class="signBox">
<div class="mi"><div class='tian'><span class='mi1'></span><span class='mi2'></span></div></div>
<div class="signFont" :style="{'fontSize': width * 5/6 + 'px'}">{{ signFont }}</div>
<div class="sign-tip">请在此处签名,签名仅限于本次业务</div>
<vue-esign class="esign" ref="esign" :width="width" :height="width" :isCrop="isCrop" :lineWidth="lineWidth" :lineColor="lineColor" :bgColor.sync="bgColor" format="png" border />
</div>
<div class="canvasBox" :style="{'height': height}">
<div class="canvas-title" :style="{'height': height}">已签入文字</div>
<canvas ref="myCanvas" id="myCanvas" :width="width" :height="canvasHeight"></canvas>
</div>
<div class="btn-group pd-24">
<tsl-button @click.native="_next" type="primary" style="width: 100%">{{btnTitle}}</tsl-button>
<tsl-button class="no-hover" @click.native="clearSign" type="secondary" style="width: 100%; margin-top: 20px;">清空</tsl-button>
<tsl-button class="no-hover no-border" @click.native="$router.go(-1)" type="secondary" style="width: 100%; margin-top: 20px;">后退</tsl-button>
</div>
</div>
</template>
<script>
import vueEsign from 'vue-esign'
import { getToken, recognizeFont } from '@/api/sign' // 引入封装好的百度接口 具体文档地址 https://ai.baidu.com/ai-doc/OCR/hk3h7y2qq
export default {
components: {
vueEsign
},
data(){
return {
isCrop: false,
lineWidth: 9,
lineColor: '#000000',
bgColor: '',
width: 0,
font: '赵钱孙李周吴郑王',
signFont: '',
current: 0,
height: '120px',
canvasHeight: 80,
access_token: '',
btnTitle: '下一个'
}
},
created() {
this.getToken()
this.getSignWidth()
this.getSignFont()
},
methods: {
// 调用百度获取token接口(如果不需要识别出文字进行验证 可以不调用)
async getToken() {
const res = await getToken({ // 封装的百度获取识别文字token
grant_type: 'client_credentials', // 固定值
client_id: '**************', // 购买得id
client_secret: '*******************' // 购买得id
})
this.access_token = res.access_token
},
// 获取canvas结果
result() {
return this.$refs.myCanvas.toDataURL('image/png')
},
// 获取需要签署得字
getSignFont() {
this.signFont = this.font.slice(this.current, this.current + 1 )
},
// 获取视口宽度
getSignWidth() {
if(document.body.clientWidth > 1164) {
this.width = 318
}else {
this.width = document.body.clientWidth - 48
}
if(this.font && this.font.length > 8) {
this.height = '160px'
this.canvasHeight = 110
}
},
// 清空画布
clearSign() {
this.current = 0
this.btnTitle = '下一个'
this.getSignFont()
this.$refs['esign'].reset()
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
},
urlencode (str) {
str = (str + '').toString();
return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').
replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
},
// 下一个
async _next() {
try {
const that = this
const res = await this.$refs.esign.generate() // 1、这里获取得base64直接传给到百度会报错识别不到
// 创建一个Image对象
var image = new Image();
image.src = res;
// 当图片加载完成后执行
image.onload = async ()=> {
var canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
// 获取Canvas的2D上下文
var ctx = canvas.getContext('2d');
// 将图片绘制到Canvas上
ctx.drawImage(image, 0, 0);
// 绘制一个白色的矩形作为背景
ctx.globalCompositeOperation = 'destination-over'; // 设置绘制模式为在已有内容下方绘制新内容
ctx.fillStyle = '#ffffff'; // 设置填充颜色为白色
ctx.fillRect(0, 0, canvas.width, canvas.height); // 绘制白色矩形
// 将Canvas转换为base64格式的图片
var base64WithWhiteBackground = canvas.toDataURL('image/png');// 2、这样转换就可以被百度文字识别接口识别
const fontRes = await recognizeFont({ // 百度识别接口、如果不需要 此处可省略
image: base64WithWhiteBackground
}, this.access_token)
console.log(fontRes)
const canvasSelf = document.getElementById('myCanvas');
var myCtx = canvasSelf.getContext('2d');
if(that.current < 8) { // 绘画到canvas显示
myCtx.drawImage(image, that.width/8.175 * that.current, 0, that.width / 8.175, that.width / 8.175);
}else { // 换行
myCtx.drawImage(image, that.width / 8.175 * (that.current - 8), that.width / 8.175, that.width / 8.175, that.width / 8.175);
}
that.$refs['esign'].reset()
if(this.btnTitle == '完成') {
console.log(this.result())
}
that.current++
that.getSignFont()
if(this.current == this.font.length -1) {
this.btnTitle = '完成'
}else {
this.btnTitle = '下一个'
}
}
} catch (error) {
this.$tslNotify.error({ // 这是错误提示 自己封装的 你可以用组件库的提示组件
title: '请先签名!',
message: '',
showClose: false,
position: 'top'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.userSign {
width: 100%;
.pd-24 {
padding: 0 24px;
box-sizing: border-box;
}
.sign-title {
margin: 48px 0 32px 0;
color: #171A20;
font-feature-settings: 'clig' off, 'liga' off;
font-family: PingFang SC;
font-size: 28px;
font-style: normal;
font-weight: 600;
line-height: 36px; /* 128.571% */
}
.userSign-tip {
color: #171A20;
font-family: PingFang SC;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
margin-bottom: 24px;
}
.signBox {
position: relative;
width: 100%;
height: calc(100vw - 48px);
.esign {
position: absolute;
z-index: 9999;
top: 0;
left: 24px;
}
.signFont {
width: calc(100vw - 48px);
height: calc(100vw - 48px);
position: absolute;
top: -10px;
left: 24px;
color: #c4c4c5;
display: flex;
justify-content: center;
align-items: center;
font-weight: 300;
}
.sign-tip {
width: calc(100vw - 48px);
position: absolute;
left: 24px;
text-align: center;
bottom: 8px;
color: #5C5E62;
font-family: PingFang SC;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
}
.mi {
position: absolute;
top: 0;
left: 24px;
.tian {
width: calc(100vw - 48px);
height: calc(100vw - 48px);
border: 1px solid #E2E3E3;
position: relative;
float: left;
overflow: hidden;
border-radius: 4px;
}
.tian::before {
content: '';
display: block;
height: 100%;
left: 50%;
width: 1px;
top: 0px;
border-left: 1px dotted #E2E3E3;
position: absolute;
transform: translateX(-50%)
}
.tian::after {
content: '';
display: block;
width: 100%;
top: 50%;
left: 0px;
height: 1px;
border-top: 1px dotted #E2E3E3;
position: absolute;
transform: translateY(-50%)
}
.mi1 {
display: block;
width: 200%;
top: 50%;
left: 50%;
height: 1px;
border-top: 1px dotted #E2E3E3;
position: absolute;
transform: translate(-50%, -50%) rotate(45deg)
}
.mi2 {
display: block;
width: 200%;
top: 50%;
left: 50%;
height: 1px;
border-top: 1px dotted #E2E3E3;
position: absolute;
transform: translate(-50%, -50%) rotate(-45deg)
}
}
}
.canvasBox {
position: relative;
padding: 0 24px;
margin: 24px 0 48px 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.canvas-title {
width: 100%;
border-radius: 4px;
border: 1px solid #E2E3E3;
color: #E2E3E3;
text-align: center;
padding-top: 8px;
box-sizing: border-box;
}
#myCanvas {
position: absolute;
left: 24px;
bottom: 0;
}
}
}
@media screen and (min-width: 1164px){
.userSign {
display: flex;
flex-direction: column;
align-items: center;
.head-logo {
width: 100%;
}
.userSign-tip,.signBox,.canvasBox,.btn-group,.userSign-title,.sign-title, .sign-tip {
width: 318px !important;
padding: 0;
left: 0 !important;
}
.signFont,.mi,.tian,.signBox, .esign {
width: 318px !important;
height: 318px !important;
font-size: 256px !important;
padding: 0;
left: 0 !important;
}
#myCanvas {
width: 318px !important;
left: 0 !important;
}
}
}
</style>
<style lang="scss">
.no-hover.tsl-button--secondary {
&:hover {
background: #fff !important;
span {
color: #1a1720;
}
}
}
.no-border {
border: none !important;
}
</style>