| @ -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> | |||||