5 changed files with 0 additions and 323 deletions
@ -1,26 +0,0 @@ |
|||||
<template> |
|
||||
<p :style="{'color':color,'text-align':textAlign}"> |
|
||||
{{ value }} |
|
||||
</p> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'DescText', |
|
||||
props: { |
|
||||
value: { |
|
||||
type: String, |
|
||||
default: '' |
|
||||
}, |
|
||||
color: { |
|
||||
type: String, |
|
||||
default: '#000000' |
|
||||
}, |
|
||||
textAlign: { |
|
||||
type: String, |
|
||||
default: 'left' |
|
||||
} |
|
||||
}, |
|
||||
methods: {} |
|
||||
} |
|
||||
</script> |
|
@ -1,115 +0,0 @@ |
|||||
<template> |
|
||||
<div> |
|
||||
<el-radio-group |
|
||||
v-if="!multiple" |
|
||||
v-model="selectValue" |
|
||||
> |
|
||||
<div v-for="option in options" :key="option.value" class="img-radio-item"> |
|
||||
<el-image |
|
||||
:preview-src-list="[option.image]" |
|
||||
:src="option.image" |
|
||||
class="image" |
|
||||
fit="scale-down" |
|
||||
> |
|
||||
<div slot="error" class="image-slot"> |
|
||||
<i class="el-icon-picture-outline" /> |
|
||||
</div> |
|
||||
</el-image> |
|
||||
<el-radio :label="option.value">{{ option.label }}</el-radio> |
|
||||
</div> |
|
||||
</el-radio-group> |
|
||||
<el-checkbox-group |
|
||||
v-else |
|
||||
v-model="selectValue" |
|
||||
> |
|
||||
<div v-for="option in options" :key="option.value" class="img-radio-item"> |
|
||||
<el-image |
|
||||
:preview-src-list="[option.image]" |
|
||||
:src="option.image" |
|
||||
class="image" |
|
||||
fit="scale-down" |
|
||||
> |
|
||||
<div slot="error" class="image-slot"> |
|
||||
<i class="el-icon-picture-outline" /> |
|
||||
</div> |
|
||||
</el-image> |
|
||||
<el-checkbox :label="option.value">{{ option.label }}</el-checkbox> |
|
||||
</div> |
|
||||
</el-checkbox-group> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script> |
|
||||
export default { |
|
||||
name: 'ImageSelect', |
|
||||
props: { |
|
||||
value: { |
|
||||
type: Number, |
|
||||
default: 1 |
|
||||
}, |
|
||||
options: { |
|
||||
type: Array, |
|
||||
default: function() { |
|
||||
return [] |
|
||||
}, |
|
||||
required: true |
|
||||
}, |
|
||||
multiple: { |
|
||||
type: Boolean, |
|
||||
default: false |
|
||||
} |
|
||||
}, |
|
||||
data() { |
|
||||
return { |
|
||||
selectValue: this.value |
|
||||
} |
|
||||
}, |
|
||||
watch: { |
|
||||
selectValue(val) { |
|
||||
this.$emit('input', val) |
|
||||
}, |
|
||||
value(val) { |
|
||||
this.selectValue = val |
|
||||
} |
|
||||
}, |
|
||||
methods: { |
|
||||
|
|
||||
} |
|
||||
} |
|
||||
</script> |
|
||||
<style lang="scss" scoped> |
|
||||
::v-deep .el-radio-button__inner, |
|
||||
.el-radio-group, |
|
||||
.el-checkbox-group { |
|
||||
display: flex !important; |
|
||||
flex-wrap: wrap; |
|
||||
} |
|
||||
.img-radio-item { |
|
||||
display: flex; |
|
||||
flex-direction: column !important; |
|
||||
align-content: center !important; |
|
||||
align-items: center !important; |
|
||||
border: 1px solid rgba(0, 0, 0, 0.1) !important; |
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important; |
|
||||
margin: 3px !important; |
|
||||
background-color: #fff; |
|
||||
.image { |
|
||||
width: 100px; |
|
||||
height: 100px; |
|
||||
margin: 2px 15px 4px 15px; |
|
||||
} |
|
||||
.el-radio { |
|
||||
margin: 4px; |
|
||||
} |
|
||||
} |
|
||||
::v-deep .image-slot { |
|
||||
display: flex; |
|
||||
justify-content: center; |
|
||||
align-items: center; |
|
||||
width: 100%; |
|
||||
height: 100%; |
|
||||
//background: #f5f7fa; |
|
||||
color: #909399; |
|
||||
font-size: 30px; |
|
||||
} |
|
||||
</style> |
|
@ -1,49 +0,0 @@ |
|||||
*, |
|
||||
*::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: 900px; |
|
||||
max-height: 460px; |
|
||||
background-color: #fff; |
|
||||
border-radius: 4px; |
|
||||
padding: 16px; |
|
||||
} |
|
||||
.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; |
|
||||
} |
|
@ -1,125 +0,0 @@ |
|||||
<template> |
|
||||
<div id="signature-pad" class="signature-pad"> |
|
||||
<div class="signature-pad--body" style="min-height: 300px; width: 100%;"> |
|
||||
<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,8 +0,0 @@ |
|||||
const ImageSelect = require('./ImageSelect/index').default |
|
||||
const DescText = require('./DescText/index').default |
|
||||
export default { |
|
||||
install: Vue => { |
|
||||
Vue.component(ImageSelect.name, ImageSelect) |
|
||||
Vue.component(DescText.name, DescText) |
|
||||
} |
|
||||
} |
|
Loading…
Reference in new issue