电子签名
This commit is contained in:
parent
f90e3120e0
commit
6293881de0
|
|
@ -0,0 +1,167 @@
|
|||
<template>
|
||||
<view class="whole canvas-autograph flexc" @touchmove.prevent.stop @wheel.prevent.stop v-show="modelValue">
|
||||
<canvas class="scroll-view" id="mycanvas" canvas-id="mycanvas"
|
||||
@touchstart="touchstart"
|
||||
@touchmove="touchmove"
|
||||
@touchend="touchend"/>
|
||||
<view class="fun-box">
|
||||
<view class="fun-box-btn clear flex" @click="clear">
|
||||
<text>清空</text>
|
||||
</view>
|
||||
<view class="fun-box-btn confirm flex" @click="confirm">
|
||||
<text>确认</text>
|
||||
</view>
|
||||
<view class="fun-box-btn cancel flex" @click="cancel">
|
||||
<text>取消</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/*
|
||||
使用如下
|
||||
<canvas-autograph v-model="isCanvas" @complete="complete"/>
|
||||
|
||||
// 打开、关闭
|
||||
let isCanvas = ref(false)
|
||||
// 确认事件
|
||||
const complete = e=>{
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
*/
|
||||
import { ref, reactive, watch, getCurrentInstance } from 'vue'
|
||||
|
||||
const emits = defineEmits(['update:modelValue','complete'])
|
||||
|
||||
const props = defineProps({
|
||||
modelValue:Boolean,
|
||||
})
|
||||
const _this = getCurrentInstance()
|
||||
watch(()=>props.modelValue,e=>{
|
||||
// 这里可进行 tabbar 的 显示、隐藏 不要也可以
|
||||
// 自己写
|
||||
},{
|
||||
immediate:true, // 是否默认执行一次 默认为false
|
||||
})
|
||||
|
||||
let points = reactive([]) //路径点集合
|
||||
|
||||
let canvaCtx = reactive(uni.createCanvasContext('mycanvas', _this)) //创建绘图对象
|
||||
//设置画笔样式
|
||||
canvaCtx.lineWidth = 4;
|
||||
canvaCtx.lineCap = 'round'
|
||||
canvaCtx.lineJoin = 'round'
|
||||
|
||||
|
||||
//触摸开始,获取到起点
|
||||
const touchstart = e=>{
|
||||
let startX = e.changedTouches[0].x
|
||||
let startY = e.changedTouches[0].y
|
||||
let startPoint = {X:startX,Y:startY}
|
||||
points.push(startPoint);
|
||||
//每次触摸开始,开启新的路径
|
||||
canvaCtx.beginPath();
|
||||
}
|
||||
//触摸移动,获取到路径点
|
||||
const touchmove = e=>{
|
||||
let moveX = e.changedTouches[0].x
|
||||
let moveY = e.changedTouches[0].y
|
||||
let movePoint = {X:moveX,Y:moveY}
|
||||
points.push(movePoint) //存点
|
||||
let len = points.length
|
||||
if(len>=2){
|
||||
draw()
|
||||
}
|
||||
}
|
||||
//绘制路径
|
||||
const draw = ()=> {
|
||||
let point1 = points[0]
|
||||
let point2 = points[1]
|
||||
points.shift()
|
||||
canvaCtx.moveTo(point1.X, point1.Y)
|
||||
canvaCtx.lineTo(point2.X, point2.Y)
|
||||
canvaCtx.stroke()
|
||||
canvaCtx.draw(true)
|
||||
}
|
||||
// 触摸结束,将未绘制的点清空防止对后续路径产生干扰
|
||||
const touchend = e=>{
|
||||
points = [];
|
||||
}
|
||||
// 清空画布
|
||||
const clear = ()=>{
|
||||
return uni.getSystemInfo()
|
||||
.then(res=>{
|
||||
canvaCtx.clearRect(0, 0, res.windowWidth, res.windowHeight);
|
||||
canvaCtx.draw(true);
|
||||
return res
|
||||
})
|
||||
.catch(err=>{
|
||||
// console.log(err);
|
||||
})
|
||||
}
|
||||
// 确认
|
||||
const confirm = ()=>{
|
||||
uni.canvasToTempFilePath({ canvasId: 'mycanvas', }, _this, _this.parent)
|
||||
.then(res=>{
|
||||
console.log(res.tempFilePath);
|
||||
emits('complete',res.tempFilePath)
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
// 取消
|
||||
const cancel = ()=>{
|
||||
clear().then(res=>emits('update:modelValue',false))
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.canvas-autograph {
|
||||
position: fixed;
|
||||
z-index: 998;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.scroll-view {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.fun-box {
|
||||
position: absolute;
|
||||
height: 90rpx;
|
||||
right: 0;
|
||||
bottom: 0px;
|
||||
height: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.fun-box-btn {
|
||||
width: 100rpx;
|
||||
height: 160rpx;
|
||||
color: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
border: 1rpx solid #C0C0C0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
}
|
||||
.clear {
|
||||
color: #909399;
|
||||
background-color: #F4F4F5;
|
||||
}
|
||||
.confirm {
|
||||
background-color: #409EFF;
|
||||
}
|
||||
.cancel {
|
||||
background-color: #F67D7D;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
@ -57,7 +57,7 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "新购绑定"
|
||||
}
|
||||
},//编码扫码
|
||||
}, //编码扫码
|
||||
{
|
||||
"path": "pages/new-purchase/bind/coding-scan",
|
||||
"style": {
|
||||
|
|
@ -130,19 +130,19 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "编码出库"
|
||||
}
|
||||
},// 3. 编码出库
|
||||
}, // 3. 编码出库
|
||||
{
|
||||
"path": "pages/picking/outbound/code-outScan",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编码出库"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/picking/outbound/codeOutScan",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编码出库"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/picking/outbound/codeOutScan",
|
||||
"style": {
|
||||
"navigationBarTitleText": "编码出库"
|
||||
}
|
||||
},
|
||||
// 4. 数量出库
|
||||
{
|
||||
"path": "pages/picking/outbound/num-outbound",
|
||||
|
|
@ -167,10 +167,10 @@
|
|||
{
|
||||
"path": "pages/back/addBack",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
"navigationStyle": "custom"
|
||||
// "navigationBarTitleText": "新增退料任务"
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"path": "pages/back/backCodeAdd",
|
||||
"style": {
|
||||
|
|
@ -182,7 +182,8 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "退料编码"
|
||||
}
|
||||
},{
|
||||
},
|
||||
{
|
||||
"path": "pages/back/backCodeScan",
|
||||
"style": {
|
||||
"navigationBarTitleText": "退料编码"
|
||||
|
|
@ -207,25 +208,24 @@
|
|||
}
|
||||
},
|
||||
//配件-------------------------------
|
||||
{
|
||||
"path": "pages/part/part-lease/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配件领用"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/part/part-lease/applyList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配件领用记录"
|
||||
}
|
||||
},
|
||||
"path": "pages/part/part-lease/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配件领用"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/part/part-lease/applyDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配件领用详情"
|
||||
}
|
||||
},
|
||||
|
||||
"path": "pages/part/part-lease/applyList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配件领用记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/part/part-lease/applyDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "配件领用详情"
|
||||
}
|
||||
},
|
||||
|
||||
/* 维修及其页面 */
|
||||
// 1. 维修列表
|
||||
|
|
@ -281,7 +281,7 @@
|
|||
{
|
||||
"path": "pages/repair/testedInBound/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
"navigationStyle": "custom"
|
||||
// "navigationBarTitleText": "修试入库"
|
||||
}
|
||||
},
|
||||
|
|
@ -307,12 +307,12 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/standardBox/index",
|
||||
"path": "pages/standardBox/index",
|
||||
"style": {
|
||||
"navigationStyle": "custom"
|
||||
// "navigationBarTitleText": "标准箱管理"
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"path": "pages/standardBox/addBox",
|
||||
"style": {
|
||||
|
|
@ -324,7 +324,8 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "标准箱录入"
|
||||
}
|
||||
},{
|
||||
},
|
||||
{
|
||||
"path": "pages/standardBox/codeView",
|
||||
"style": {
|
||||
"navigationBarTitleText": "标准箱查看"
|
||||
|
|
@ -341,9 +342,13 @@
|
|||
"style": {
|
||||
"navigationBarTitleText": "标准箱接收"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/signature",
|
||||
"style": {
|
||||
"navigationBarTitleText": "电子签名"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
],
|
||||
"tabBar": {
|
||||
"color": "#2c2c2c",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<view class="user-info"> 用户: {{ userInfo.nickName }} </view>
|
||||
<view class="user-info"> 用户: {{ userInfo.userName }} </view>
|
||||
<view class="user-info"> 手机号:{{ userInfo.phonenumber || '13655555' }} </view>
|
||||
<view class="user-info exit-btn" @click="onSignature"> 电子签名 </view>
|
||||
<view class="user-info exit-btn" @tap="onExit"> 退出登录 </view>
|
||||
</view>
|
||||
</template>
|
||||
|
|
@ -20,6 +21,11 @@ const onExit = () => {
|
|||
memberStore.clearToken()
|
||||
uni.navigateTo({ url: '/pages/login/index' })
|
||||
}
|
||||
|
||||
// 电子签名页
|
||||
const onSignature = () => {
|
||||
uni.navigateTo({ url: '/pages/my/signature' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,185 @@
|
|||
<template>
|
||||
<view>
|
||||
<div class="img" :class="{ rotate: isRotate }" v-if="imgPath">
|
||||
<image :src="imgPath" @click="preview"></image>
|
||||
</div>
|
||||
<div class="img" v-else>暂无数据</div>
|
||||
<div class="tips">
|
||||
个人电子签名维护,支持手机拍照、上传图片以及手写签名,推荐使用手写签名
|
||||
</div>
|
||||
<div class="btns">
|
||||
<button class="btn" type="primary" @click="handlePhoto">拍照/上传</button>
|
||||
<button class="btn" type="primary" @click="open">手写签名</button>
|
||||
</div>
|
||||
<miliu-autograph v-model="isCanvas" @complete="complete"></miliu-autograph>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { pathToBase64, base64ToPath } from 'image-tools'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { getSign, updateSign } from '@/services/signature.js'
|
||||
import { baseURL } from '@/utils/http'
|
||||
|
||||
let isCanvas = ref(false)
|
||||
let imgPath = ref('')
|
||||
let isRotate = ref(false)
|
||||
let actionUrl = `${baseURL}/file/upload`
|
||||
let signType = ref(0)
|
||||
|
||||
onMounted(() => {
|
||||
getSignData()
|
||||
})
|
||||
// 获取签名
|
||||
const getSignData = () => {
|
||||
getSign()
|
||||
.then((res) => {
|
||||
imgPath.value = res.data.signUrl
|
||||
signType.value = res.data.signType
|
||||
if (res.data.signType == 1) {
|
||||
isRotate.value = false
|
||||
} else {
|
||||
isRotate.value = true
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('🚀 ~ getSignData ~ err:', err)
|
||||
})
|
||||
}
|
||||
|
||||
// 签名完成
|
||||
const complete = (e) => {
|
||||
console.log(e) // 返回本地生成的base图片路径
|
||||
toBase64(e)
|
||||
.then((res) => {
|
||||
console.log('🚀 ~ .then ~ res:', res)
|
||||
// imgPath.value = res
|
||||
// isRotate.value = true
|
||||
const params = {
|
||||
signUrl: res,
|
||||
signType: 0,
|
||||
}
|
||||
updateSign(params)
|
||||
.then((res) => {
|
||||
console.log('🚀 ~ .updateSign ~ res:', res)
|
||||
getSignData()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('🚀 ~ .updateSign ~ err:', err)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
|
||||
// 转base64
|
||||
const toBase64 = (filePath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
pathToBase64(filePath)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// base64转路径
|
||||
const toPath = (base64) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
base64ToPath(base64)
|
||||
.then((res) => {
|
||||
resolve(res)
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 打开签名
|
||||
const open = () => {
|
||||
console.log('打开签名')
|
||||
isCanvas.value = true
|
||||
}
|
||||
|
||||
// 预览
|
||||
const preview = () => {
|
||||
console.log('预览')
|
||||
uni.previewImage({
|
||||
urls: [imgPath.value],
|
||||
})
|
||||
}
|
||||
// 拍照/上传
|
||||
const handlePhoto = () => {
|
||||
console.log('拍照/上传')
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
// imgPath.value = res.tempFilePaths[0]
|
||||
// isRotate.value = false
|
||||
uploadImg(res.tempFilePaths[0])
|
||||
},
|
||||
})
|
||||
}
|
||||
// 上传
|
||||
const uploadImg = (path) => {
|
||||
uni.uploadFile({
|
||||
url: actionUrl,
|
||||
filePath: path,
|
||||
name: 'file',
|
||||
header: {
|
||||
// Authorization: this.token,
|
||||
},
|
||||
success: (res) => {
|
||||
// imgPath.value = JSON.parse(res.data).data.url
|
||||
const params = {
|
||||
signUrl: JSON.parse(res.data).data.url,
|
||||
signType: 1,
|
||||
}
|
||||
updateSign(params)
|
||||
.then((res) => {
|
||||
console.log('🚀 ~ .then ~ res:', res)
|
||||
getSignData()
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log('🚀 ~ .then ~ err:', err)
|
||||
})
|
||||
},
|
||||
fail: (err) => {},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.img {
|
||||
height: 300px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.rotate {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.tips {
|
||||
padding: 15px;
|
||||
font-size: 14px;
|
||||
color: #e24f48;
|
||||
background-color: #f5f5f5;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.btn {
|
||||
width: 30%;
|
||||
&:first-child {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { http } from '@/utils/http'
|
||||
|
||||
// 获取签名
|
||||
export const getSign = (data) => {
|
||||
return http({
|
||||
method: 'GET',
|
||||
url: '/material/archives/getSign',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
// 更新签名
|
||||
export const updateSign = (data) => {
|
||||
return http({
|
||||
method: 'POST',
|
||||
url: '/material/archives/updateSign',
|
||||
data,
|
||||
})
|
||||
}
|
||||
Loading…
Reference in New Issue