Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 194 KiB |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 20 KiB |
@ -0,0 +1,77 @@ |
|||||
|
*, |
||||
|
*::before, |
||||
|
*::after { |
||||
|
box-sizing: border-box; |
||||
|
} |
||||
|
.signature-pad { |
||||
|
position: relative; |
||||
|
display: -webkit-box; |
||||
|
display: -ms-flexbox; |
||||
|
display: flex; |
||||
|
-webkit-box-orient: vertical; |
||||
|
-webkit-box-direction: normal; |
||||
|
-ms-flex-direction: column; |
||||
|
flex-direction: column; |
||||
|
font-size: 10px; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
max-width: 700px; |
||||
|
max-height: 460px; |
||||
|
border: 1px solid #e8e8e8; |
||||
|
background-color: #fff; |
||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset; |
||||
|
border-radius: 4px; |
||||
|
padding: 16px; |
||||
|
} |
||||
|
.signature-pad::before, |
||||
|
.signature-pad::after { |
||||
|
position: absolute; |
||||
|
z-index: -1; |
||||
|
content: ""; |
||||
|
width: 40%; |
||||
|
height: 10px; |
||||
|
bottom: 10px; |
||||
|
background: transparent; |
||||
|
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.4); |
||||
|
} |
||||
|
.signature-pad::before { |
||||
|
left: 20px; |
||||
|
-webkit-transform: skew(-3deg) rotate(-3deg); |
||||
|
transform: skew(-3deg) rotate(-3deg); |
||||
|
} |
||||
|
.signature-pad::after { |
||||
|
right: 20px; |
||||
|
-webkit-transform: skew(3deg) rotate(3deg); |
||||
|
transform: skew(3deg) rotate(3deg); |
||||
|
} |
||||
|
.signature-pad--body { |
||||
|
position: relative; |
||||
|
-webkit-box-flex: 1; |
||||
|
-ms-flex: 1; |
||||
|
flex: 1; |
||||
|
border: 1px solid #f4f4f4; |
||||
|
} |
||||
|
.signature-pad--body canvas { |
||||
|
position: absolute; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
border-radius: 4px; |
||||
|
box-shadow: 0 0 5px rgba(0, 0, 0, 0.02) inset; |
||||
|
} |
||||
|
.signature-pad--footer { |
||||
|
color: #c3c3c3; |
||||
|
text-align: center; |
||||
|
font-size: 1.2em; |
||||
|
margin-top: 8px; |
||||
|
} |
||||
|
.signature-pad--actions { |
||||
|
display: -webkit-box; |
||||
|
display: -ms-flexbox; |
||||
|
display: flex; |
||||
|
-webkit-box-pack: justify; |
||||
|
-ms-flex-pack: justify; |
||||
|
justify-content: space-between; |
||||
|
margin-top: 8px; |
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
<template> |
||||
|
<div id="signature-pad" class="signature-pad"> |
||||
|
<div class="signature-pad--body"> |
||||
|
<canvas v-show="!signImageUrl" class="canvasId" style="border: 2px dashed #f7f7f7;" /> |
||||
|
</div> |
||||
|
<img v-if="signImageUrl" :src="signImageUrl"> |
||||
|
<p class="desc-text">请在上面区域完成签名 然后点击确"确认"按钮</p> |
||||
|
<div v-if="!signImageUrl"> |
||||
|
<el-button plain size="mini" type="danger" @click="clear">清除</el-button> |
||||
|
<el-button plain size="mini" type="warning" @click="undo">回撤</el-button> |
||||
|
<el-button size="mini" type="success" @click="savePng">确认</el-button> |
||||
|
</div> |
||||
|
<div v-if="signImageUrl"> |
||||
|
<el-button size="mini" type="primary" @click="reSign">重签</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import SignaturePad from 'signature_pad' |
||||
|
|
||||
|
export default { |
||||
|
name: 'SignPad', |
||||
|
components: {}, |
||||
|
data() { |
||||
|
return { |
||||
|
signaturePad: null, |
||||
|
canvas: null, |
||||
|
signImageUrl: '', |
||||
|
config: { |
||||
|
minWidth: 1, |
||||
|
maxWidth: 3, |
||||
|
penColor: 'rgb(66, 133, 244)' |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
this.init() |
||||
|
window.onresize = () => { |
||||
|
return (() => { |
||||
|
this.resizeCanvas() |
||||
|
})() |
||||
|
} |
||||
|
this.resizeCanvas() |
||||
|
}, |
||||
|
methods: { |
||||
|
resizeCanvas() { |
||||
|
console.log('resizeCanvas') |
||||
|
let canvas = this.canvas |
||||
|
// When zoomed out to less than 100%, for some very strange reason, |
||||
|
// some browsers report devicePixelRatio as less than 1 |
||||
|
// and only part of the canvas is cleared then. |
||||
|
let ratio = Math.max(window.devicePixelRatio || 1, 1) |
||||
|
// This part causes the canvas to be cleared |
||||
|
canvas.width = canvas.offsetWidth * ratio |
||||
|
canvas.height = canvas.offsetHeight * ratio |
||||
|
canvas.getContext('2d').scale(ratio, ratio) |
||||
|
|
||||
|
// This library does not listen for canvas changes, so after the canvas is automatically |
||||
|
// cleared by the browser, SignaturePad#isEmpty might still return false, even though the |
||||
|
// canvas looks empty, because the internal data of this library wasn't cleared. To make sure |
||||
|
// that the state of this library is consistent with visual state of the canvas, you |
||||
|
// have to clear it manually. |
||||
|
this.signaturePad.clear() |
||||
|
}, |
||||
|
init() { |
||||
|
this.canvas = document.querySelector('.canvasId') |
||||
|
let canvas = this.canvas |
||||
|
this.signaturePad = new SignaturePad(canvas, this.config) |
||||
|
// canvas.height = 300 |
||||
|
// canvas.width = 500 |
||||
|
}, |
||||
|
clear() { |
||||
|
this.signaturePad.clear() |
||||
|
}, |
||||
|
undo() { |
||||
|
let data = this.signaturePad.toData() |
||||
|
if (data) { |
||||
|
data.pop() // remove the last dot or line |
||||
|
this.signaturePad.fromData(data) |
||||
|
} |
||||
|
}, |
||||
|
savePng() { |
||||
|
if (this.signaturePad.isEmpty()) { |
||||
|
this.msgError('请先填写') |
||||
|
return |
||||
|
} |
||||
|
let data = this.signaturePad.toDataURL('image/png') |
||||
|
let file = this.dataURLtoFile(data, `${new Date().getTime()}.png`) |
||||
|
let param = new FormData() // 创建form对象 |
||||
|
param.append('file', file) // 通过append向form对象添加数据 |
||||
|
let config = { |
||||
|
headers: {'Content-Type': 'multipart/form-data'} |
||||
|
} |
||||
|
this.$api.post('/project/file/upload/77f1648542af4caf98deb8345a3d0406', param, config).then(res => { |
||||
|
this.signImageUrl = res.data |
||||
|
}) |
||||
|
}, |
||||
|
reSign() { |
||||
|
this.signImageUrl = '' |
||||
|
this.signaturePad.clear() |
||||
|
}, |
||||
|
dataURLtoFile(dataurl, filename) { |
||||
|
// 获取到base64编码 |
||||
|
const arr = dataurl.split(',') |
||||
|
// 将base64编码转为字符串 |
||||
|
const bstr = window.atob(arr[1]) |
||||
|
let n = bstr.length |
||||
|
const u8arr = new Uint8Array(n) // 创建初始化为0的,包含length个元素的无符号整型数组 |
||||
|
while (n--) { |
||||
|
u8arr[n] = bstr.charCodeAt(n) |
||||
|
} |
||||
|
return new File([u8arr], filename, { |
||||
|
type: 'image/png' |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
<style scoped> |
||||
|
@import "index.css"; |
||||
|
.sign-pad-container { |
||||
|
padding: 1px; |
||||
|
} |
||||
|
</style> |
@ -1,46 +1,25 @@ |
|||||
<template> |
<template> |
||||
<div> |
<div> |
||||
<image-select v-model="radio" :options="options" :multiple="false" /> |
<sign-pad /> |
||||
<el-radio-group v-model="radio"> |
|
||||
<el-radio :label="3">备选项</el-radio> |
|
||||
<el-radio :label="6">备选项</el-radio> |
|
||||
<el-radio :label="9">备选项</el-radio> |
|
||||
</el-radio-group> |
|
||||
</div> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script> |
<script> |
||||
|
import SignPad from '@/components/form/SignPad' |
||||
|
|
||||
export default { |
export default { |
||||
name: 'App', |
name: 'App', |
||||
components: { |
components: { |
||||
|
SignPad |
||||
}, |
}, |
||||
data() { |
data() { |
||||
return { |
return { |
||||
options: [{ |
|
||||
'label': '选项一', |
|
||||
'value': 1, |
|
||||
'image': 'https://freebrio.oss-cn-shanghai.aliyuncs.com/05f1fb3e58764a48a5094f0bc9351bd3.png' |
|
||||
}, { |
|
||||
'label': '选项二', |
|
||||
'value': 2, |
|
||||
'image': 'https://freebrio.oss-cn-shanghai.aliyuncs.com/062cf61ad5724ac3bc99f0341b3770da.png' |
|
||||
}], |
|
||||
radio: [1] |
|
||||
} |
} |
||||
}, |
}, |
||||
mounted() { |
mounted() { |
||||
|
|
||||
}, |
}, |
||||
methods: { |
methods: { |
||||
success(params) { |
|
||||
// eslint-disable-next-line no-debugger |
|
||||
// params 返回的二次验证参数, 和登录参数一起回传给登录接口,方便后台进行二次验证 |
|
||||
console.log(params) |
|
||||
}, |
|
||||
useVerify() { |
|
||||
this.$refs.verify.show() |
|
||||
} |
|
||||
} |
} |
||||
} |
} |
||||
</script> |
</script> |
||||
|