@ -0,0 +1,16 @@ | |||
/* components/canvas-drag/index.wxss */ | |||
.movable-label { | |||
margin-top: 300rpx; | |||
width: 750rpx; | |||
height: 400rpx; | |||
background: #eee; | |||
} | |||
.movable-block { | |||
width: 120rpx; | |||
height: 120rpx; | |||
background: #ccc; | |||
} | |||
.movable-block .image-con { | |||
width: 100%; | |||
height: 100%; | |||
} |
@ -0,0 +1,63 @@ | |||
export default { | |||
data() { | |||
return { | |||
} | |||
}, | |||
methods: { | |||
// 设置数据 | |||
setData: function(obj, callback) { | |||
let that = this; | |||
const handleData = (tepData, tepKey, afterKey) => { | |||
tepKey = tepKey.split('.'); | |||
tepKey.forEach(item => { | |||
if (tepData[item] === null || tepData[item] === undefined) { | |||
let reg = /^[0-9]+$/; | |||
tepData[item] = reg.test(afterKey) ? [] : {}; | |||
tepData = tepData[item]; | |||
} else { | |||
tepData = tepData[item]; | |||
} | |||
}); | |||
return tepData; | |||
}; | |||
const isFn = function(value) { | |||
return typeof value == 'function' || false; | |||
}; | |||
Object.keys(obj).forEach(function(key) { | |||
let val = obj[key]; | |||
key = key.replace(/\]/g, '').replace(/\[/g, '.'); | |||
let front, after; | |||
let index_after = key.lastIndexOf('.'); | |||
if (index_after != -1) { | |||
after = key.slice(index_after + 1); | |||
front = handleData(that, key.slice(0, index_after), after); | |||
} else { | |||
after = key; | |||
front = that; | |||
} | |||
if (front.$data && front.$data[after] === undefined) { | |||
Object.defineProperty(front, after, { | |||
get() { | |||
return front.$data[after]; | |||
}, | |||
set(newValue) { | |||
front.$data[after] = newValue; | |||
that.$forceUpdate(); | |||
}, | |||
enumerable: true, | |||
configurable: true | |||
}); | |||
front[after] = val; | |||
} else { | |||
that.$set(front, after, val); | |||
} | |||
}); | |||
// this.$forceUpdate(); | |||
isFn(callback) && this.$nextTick(callback); | |||
}, | |||
} | |||
} |
@ -0,0 +1,195 @@ | |||
<template> | |||
<view class="page"> | |||
<navbar title="电子合同" | |||
leftClick | |||
@leftClick="$utils.navigateBack"/> | |||
<view style="padding: 25rpx;"> | |||
<canvas-drag ref="canvasRef" | |||
id="canvas-drag" | |||
:graph="graph" | |||
:width="width" | |||
:height="height" | |||
bgColor="#fff" | |||
enableUndo="true"></canvas-drag> | |||
<!-- <canvas | |||
canvas-id="mycanvas" | |||
class="mycanvas" | |||
v-if="!imagePath" | |||
:style="{height : height + 'rpx', width : width + 'rpx'}" | |||
disable-scroll="true"></canvas> --> | |||
<image :src="imagePath" | |||
v-if="imagePath" | |||
style="width: 700rpx;" | |||
mode="widthFix"></image> | |||
</view> | |||
<view class="uni-color-btn" | |||
@click.stop="onChangeBgImage"> | |||
导入合同 | |||
</view> | |||
<view class="uni-color-btn" | |||
@click.stop="toSignature"> | |||
签名 | |||
</view> | |||
<view class="uni-color-btn" | |||
@click.stop="onExportJSON"> | |||
保存合同 | |||
</view> | |||
</view> | |||
</template> | |||
<script> | |||
import canvasDrag from "@/components/canvas-drag/index"; | |||
import setData from "@/components/canvas-drag/setData.js"; | |||
export default { | |||
components: { | |||
canvasDrag | |||
}, | |||
mixins : [setData], | |||
data() { | |||
return { | |||
id : 0, | |||
detail : {}, | |||
height: 750, | |||
width: 700, | |||
ctx : null, | |||
imagePath : 0, | |||
} | |||
}, | |||
onLoad({id}) { | |||
this.id = id | |||
this.getDetail() | |||
}, | |||
onShow() { | |||
this.initCanvas() | |||
this.syntheticSignature() | |||
}, | |||
methods: { | |||
// 获取合同内容 | |||
getDetail(){ | |||
let data = { | |||
contractId: this.id | |||
} | |||
if (uni.getStorageSync('token')) { | |||
// data.token = uni.getStorageSync('token') | |||
} | |||
this.$api('queryContracById', data, res => { | |||
if (res.code == 200) { | |||
this.detail = res.result | |||
} | |||
}) | |||
}, | |||
initCanvas() { | |||
this.ctx = uni.createCanvasContext("mycanvas") | |||
}, | |||
// 去签名 | |||
toSignature(){ | |||
uni.navigateTo({ | |||
url: `/pages_order/contract/electronicSignature?id=${this.id}&signature=1` | |||
}) | |||
}, | |||
// 导出合同 | |||
onExportJSON() { | |||
uni.showLoading({ | |||
title: '保存中...' | |||
}) | |||
this.$refs.canvasRef.exportFun().then(image => { | |||
console.log(image); | |||
uni.hideLoading() | |||
// this.imagePath = image | |||
uni.previewImage({ | |||
urls: [image], | |||
current: 0, | |||
}) | |||
}).catch(e => { | |||
uni.hideLoading() | |||
console.error(e); | |||
}); | |||
}, | |||
/** | |||
* 导入合同 | |||
*/ | |||
onChangeBgImage() { | |||
let self = this | |||
wx.chooseImage({ | |||
success: res => { | |||
uni.getImageInfo({ | |||
src: res.tempFilePaths[0], | |||
success: image => { | |||
let allwh = image.height + image.width | |||
let imgw = (image.width / allwh).toFixed(2) | |||
let imgh = (image.height / allwh).toFixed(2) | |||
self.height = imgh * Math.ceil(this.width / imgw) | |||
// this.width = image.width | |||
// this.height = image.height | |||
self.$nextTick(() => { | |||
this.$refs.canvasRef.changeBgImage(image.path) | |||
// this.ctx.drawImage(image.path, 0, 0, this.ctx.width, this.ctx.height) | |||
// this.ctx.stroke(); | |||
// this.ctx.draw(false, () => { | |||
// wx.canvasToTempFilePath({ | |||
// canvasId: 'mycanvas', | |||
// success: res => { | |||
// // this.imagePath = res.tempFilePath | |||
// uni.previewImage({ | |||
// urls: [res.tempFilePath], | |||
// current: 0, | |||
// }) | |||
// }, | |||
// fail: e => { | |||
// } | |||
// }, this); | |||
// }); | |||
}) | |||
} | |||
}) | |||
} | |||
}); | |||
}, | |||
// 合成签名 | |||
syntheticSignature(){ | |||
let url = uni.getStorageSync('electronicSignature') | |||
if(!url) return | |||
uni.removeStorageSync('electronicSignature') | |||
this.setData({ | |||
graph: { | |||
w: 100, | |||
h: 50, | |||
x : 0, | |||
y : 0, | |||
type: 'image', | |||
url, | |||
permitSelected : true, | |||
} | |||
}); | |||
// this.$nextTick(() => { | |||
// this.onExportJSON() | |||
// }) | |||
}, | |||
} | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page{ | |||
.mycanvas{ | |||
background-color: #fff; | |||
} | |||
} | |||
</style> |
@ -0,0 +1,88 @@ | |||
<template> | |||
<view class="page"> | |||
<navbar title="合同模板" | |||
leftClick | |||
@leftClick="$utils.navigateBack"/> | |||
<view class="content"> | |||
<view class="projectContent" | |||
@click="$utils.navigateTo('/pages_order/contract/contractManageEdit')" | |||
> | |||
<image src="../static/contract/contract.png" alt="" /> | |||
<view class="info"> | |||
<view class="projectName"> | |||
xxxx电子合同 | |||
</view> | |||
<view class="text"> | |||
甲方:湖南瀚海科技有限公司 | |||
</view> | |||
<view class="text"> | |||
乙方:四川特能博世科技有限公司 | |||
</view> | |||
</view> | |||
<view class="run" | |||
@click.stop="$utils.navigateTo('/pages_order/contract/contractManageEdit')"> | |||
<uv-icon | |||
name="arrow-right" | |||
color="#2979ff" | |||
size="30rpx"></uv-icon> | |||
</view> | |||
</view> | |||
</view> | |||
<image src="/static/image/1.png" mode=""></image> | |||
</view> | |||
</template> | |||
<script> | |||
export default { | |||
data() { | |||
return { | |||
} | |||
}, | |||
methods: { | |||
} | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page{ | |||
.content { | |||
width: 100%; | |||
height: 100%; | |||
.projectContent { | |||
background-color: #fff; | |||
display: flex; | |||
margin: 30rpx; | |||
border-radius: 20rpx; | |||
image { | |||
width: 140rpx; | |||
height: 120rpx; | |||
margin: 20rpx; | |||
} | |||
.info { | |||
margin: 28rpx 10rpx; | |||
.projectName { | |||
font-size: 32rpx; | |||
} | |||
.text { | |||
font-size: 24rpx; | |||
} | |||
} | |||
.run{ | |||
margin: auto; | |||
margin-right: 30rpx; | |||
height: 60rpx; | |||
width: 60rpx; | |||
border-radius: 50%; | |||
border: 1px solid $uni-color; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@ -0,0 +1,153 @@ | |||
<template> | |||
<view class="page"> | |||
<navbar title="编辑模板" leftClick @leftClick="$utils.navigateBack" /> | |||
<view style="padding: 25rpx;background-color: #fff;"> | |||
<canvas-drag ref="canvasRef" | |||
id="canvas-drag" :graph="graph" | |||
:width="width" :height="height" | |||
@onDrawArrChange="onDrawArrChange" | |||
enableUndo="true"></canvas-drag> | |||
</view> | |||
<view class="btn-list"> | |||
<view class="uni-color-btn" @tap="onAddImage">新建签名</view> | |||
<view class="uni-color-btn" @tap="onChangeBgImage">导入合同</view> | |||
<view class="uni-color-btn" @tap="onUndo">后退</view> | |||
<view class="uni-color-btn" @tap="onClearCanvas">清空</view> | |||
<view class="uni-color-btn" @tap="submit">保存</view> | |||
<!-- <view class="uni-color-btn" @tap="onExportJSON">导出模板</view> --> | |||
<!-- <view class="uni-color-btn" @tap="onAddText">添加文字</view> --> | |||
</view> | |||
</view> | |||
</template> | |||
<script> | |||
import canvasDrag from "@/components/canvas-drag/index"; | |||
import setData from "@/components/canvas-drag/setData.js"; | |||
export default { | |||
components: { | |||
canvasDrag | |||
}, | |||
mixins : [setData], | |||
data() { | |||
return { | |||
height: 750, | |||
width: 700, | |||
drawArr : [], | |||
} | |||
}, | |||
onLoad() { | |||
}, | |||
mounted() {}, | |||
methods: { | |||
// 签名位置更新时 | |||
onDrawArrChange(arr){ | |||
this.drawArr = arr | |||
}, | |||
/** | |||
* 添加签名位置 | |||
*/ | |||
onAddImage() { | |||
wx.chooseImage({ | |||
success: res => { | |||
this.setData({ | |||
graph: { | |||
w: 100, | |||
h: 50, | |||
type: 'image', | |||
url: res.tempFilePaths[0] | |||
} | |||
}); | |||
} | |||
}); | |||
}, | |||
/** | |||
* 导入合同 | |||
*/ | |||
onChangeBgImage() { | |||
let self = this | |||
wx.chooseImage({ | |||
success: res => { | |||
uni.getImageInfo({ | |||
src: res.tempFilePaths[0], | |||
success: image => { | |||
console.log(image); | |||
let allwh = image.height + image.width | |||
let imgw = (image.width / allwh).toFixed(2) | |||
let imgh = (image.height / allwh).toFixed(2) | |||
self.height = imgh * Math.ceil(this.width / imgw) | |||
self.$nextTick(() => { | |||
this.$refs.canvasRef.changeBgImage(image.path) | |||
}) | |||
} | |||
}) | |||
} | |||
}); | |||
}, | |||
// 后退 | |||
onUndo(event) { | |||
this.$refs.canvasRef.undo(); | |||
}, | |||
/** | |||
* 导出当前画布为模板 | |||
*/ | |||
onExportJSON() { | |||
this.$refs.canvasRef.exportFun().then(imgArr => { | |||
console.log(imgArr); | |||
uni.previewImage({ | |||
urls: [imgArr], | |||
current: 0, | |||
}) | |||
}).catch(e => { | |||
console.error(e); | |||
}); | |||
}, | |||
/** | |||
* 添加文本 | |||
*/ | |||
onAddText() { | |||
this.setData({ | |||
graph: { | |||
type: 'text', | |||
text: 'helloworld' | |||
} | |||
}); | |||
}, | |||
onClearCanvas(event) { | |||
let _this = this; | |||
_this.setData({ | |||
canvasBg: null | |||
}); | |||
this.$refs.canvasRef.clearCanvas(); | |||
}, | |||
submit() { | |||
uni.setStorageSync('drawArrJson', JSON.stringify(this.drawArr)) | |||
uni.navigateBack(-1) | |||
}, | |||
} | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.page { | |||
padding-bottom: 100rpx; | |||
.btn-list { | |||
display: flex; | |||
flex-wrap: wrap; | |||
padding: 20rpx; | |||
gap: 20rpx; | |||
.uni-color-btn { | |||
margin: 0; | |||
border-radius: 10rpx; | |||
} | |||
} | |||
} | |||
</style> |
@ -0,0 +1,188 @@ | |||
<template> | |||
<div class="contain"> | |||
<navbar | |||
title="电子签名" | |||
v-if="!crosswise" | |||
leftClick | |||
@leftClick="$utils.navigateBack"/> | |||
<view | |||
class="electronic-contract" | |||
:class="{crosswise}"> | |||
<canvas | |||
canvas-id="mycanvas" | |||
class="mycanvas" | |||
:style="{height, width}" | |||
disable-scroll="true" | |||
@touchstart="ontouchstart" | |||
@touchmove="touchmove"></canvas> | |||
<view class="title" | |||
v-if="crosswise"> | |||
请旋转屏幕,按文字方向开始签名 | |||
</view> | |||
</view> | |||
<view class="btn-list"> | |||
<view class="uni-color-btn" @click="clear"> | |||
清除 | |||
</view> | |||
<view class="uni-color-btn" @click="close"> | |||
完成 | |||
</view> | |||
</view> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
data() { | |||
return { | |||
oc: null, | |||
points: [], //路径点集合 | |||
show: true, | |||
height : '350rpx', | |||
width : '700rpx', | |||
crosswise : false, | |||
options : {}, | |||
} | |||
}, | |||
onReady() { | |||
this.open() | |||
}, | |||
onLoad(options) { | |||
this.options = options | |||
}, | |||
onShow() { | |||
this.initPM() | |||
}, | |||
methods: { | |||
initPM(){ | |||
if(!this.crosswise) return | |||
let info = uni.getSystemInfoSync(); | |||
console.log(info.windowWidth); | |||
console.log(info.windowHeight); | |||
}, | |||
open() { | |||
this.initCanvas(); | |||
}, | |||
close() { | |||
uni.canvasToTempFilePath({ | |||
canvasId: "mycanvas", | |||
success: (res) => { | |||
console.log(res.tempFilePath); | |||
const canvas = res.tempFilePath; | |||
uni.setStorageSync('electronicSignature', canvas) | |||
let o = this.options | |||
uni.navigateBack(-1) | |||
}, | |||
fail(error) { | |||
console.error("转化图片错误!", error) | |||
} | |||
}); | |||
}, | |||
initCanvas() { | |||
this.oc = uni.createCanvasContext("mycanvas"); | |||
}, | |||
ontouchstart(e) { | |||
this.points = [] | |||
const startX = e.changedTouches[0].x; | |||
const startY = e.changedTouches[0].y; | |||
let startPoint = { | |||
X: startX, | |||
Y: startY, | |||
}; | |||
this.points.push(startPoint); | |||
}, | |||
touchmove(e) { | |||
let moveX = e.changedTouches[0].x; | |||
let moveY = e.changedTouches[0].y; | |||
let movePoint = { | |||
X: moveX, | |||
Y: moveY, | |||
}; | |||
this.points.push(movePoint); | |||
let len = this.points.length; | |||
if (len >= 2) { | |||
this.draw(); //绘制路径 | |||
} | |||
}, | |||
draw() { | |||
if (this.points.length < 2) return; | |||
this.oc.beginPath(); | |||
this.oc.moveTo(this.points[0].X, this.points[0].Y); | |||
// for (let i = 1; i < this.points.length; i++) { | |||
// let point = this.points[i]; | |||
// this.oc.lineTo(point.X, point.Y); | |||
// } | |||
this.oc.lineTo(this.points[1].X, this.points[1].Y); | |||
this.points.shift() | |||
this.oc.setStrokeStyle('#000000'); | |||
this.oc.setLineWidth(5); | |||
this.oc.setLineCap('round'); | |||
this.oc.setLineJoin('round'); | |||
this.oc.stroke(); | |||
this.oc.draw(true); | |||
}, | |||
//清空画布 | |||
clear() { | |||
let that = this; | |||
uni.getSystemInfo({ | |||
success: (res) => { | |||
let canvasw = res.windowWidth; | |||
let canvash = res.windowHeight; | |||
that.oc.clearRect(0, 0, canvasw, canvash); | |||
that.oc.draw(true); | |||
}, | |||
}); | |||
}, | |||
} | |||
}; | |||
</script> | |||
<style lang="scss" scoped> | |||
.contain { | |||
position: relative; | |||
.mycanvas { | |||
background-color: #fff; | |||
border-radius: 20rpx; | |||
} | |||
.electronic-contract{ | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
margin: 25rpx; | |||
} | |||
.crosswise{ | |||
.title{ | |||
writing-mode: vertical-lr; /* 垂直从上到下 */ | |||
transform: skewY(180deg); /* 颠倒文本 */ | |||
display: inline-block; /* 需要设置为内联块 */ | |||
} | |||
} | |||
.btn-list { | |||
display: flex; | |||
padding: 20rpx; | |||
justify-content: space-around; | |||
.uni-color-btn { | |||
border-radius: 10rpx; | |||
margin: 0; | |||
padding: 20rpx 40rpx; | |||
} | |||
} | |||
} | |||
</style> |
@ -1,44 +0,0 @@ | |||
<template> | |||
<view class="page"> | |||
<navbar title="电子合同" | |||
leftClick | |||
@leftClick="$utils.navigateBack"/> | |||
</view> | |||
</template> | |||
<script> | |||
export default { | |||
data() { | |||
return { | |||
id : 0, | |||
detail : {}, | |||
} | |||
}, | |||
onLoad({id}) { | |||
this.id = id | |||
this.getDetail() | |||
}, | |||
methods: { | |||
getDetail(){ | |||
let data = { | |||
contractId: this.id | |||
} | |||
if (uni.getStorageSync('token')) { | |||
// data.token = uni.getStorageSync('token') | |||
} | |||
this.$api('queryContracById', data, res => { | |||
if (res.code == 200) { | |||
this.detail = res.result | |||
} | |||
}) | |||
}, | |||
} | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
</style> |