Commit 8480bd31 by sunchao

电子签

parent 3514211c
...@@ -116,30 +116,30 @@ ...@@ -116,30 +116,30 @@
this.applyParam.birthday = e.detail.value; this.applyParam.birthday = e.detail.value;
}, },
saveInfo(){ saveInfo(){
if(!this.applyParam.name){ // if(!this.applyParam.name){
uni.showToast({ // uni.showToast({
title: '请输入姓名', // title: '请输入姓名',
duration: 2000, // duration: 2000,
icon: 'none' // icon: 'none'
}) // })
return; // return;
} // }
if(!this.applyParam.idType){ // if(!this.applyParam.idType){
uni.showToast({ // uni.showToast({
title: '请选择证件类型', // title: '请选择证件类型',
duration: 2000, // duration: 2000,
icon: 'none' // icon: 'none'
}) // })
return; // return;
} // }
if(!this.applyParam.idNo){ // if(!this.applyParam.idNo){
uni.showToast({ // uni.showToast({
title: '请输入证件号', // title: '请输入证件号',
duration: 2000, // duration: 2000,
icon: 'none' // icon: 'none'
}) // })
return; // return;
} // }
uni.setStorageSync('applyParam',JSON.stringify(this.applyParam)) uni.setStorageSync('applyParam',JSON.stringify(this.applyParam))
uni.navigateTo({ uni.navigateTo({
url:'work-experience' url:'work-experience'
......
...@@ -58,14 +58,14 @@ ...@@ -58,14 +58,14 @@
}, },
saveInfo(){ saveInfo(){
console.log(this.isAllAgree) console.log(this.isAllAgree)
if (!this.isAllAgree) { // if (!this.isAllAgree) {
uni.showToast({ // uni.showToast({
title: '请详细阅读全部条款!', // title: '请详细阅读全部条款!',
duration: 2000, // duration: 2000,
icon: 'none' // icon: 'none'
}); // });
return; // return;
} // }
uni.navigateTo({ uni.navigateTo({
url:'signature' url:'signature'
}) })
......
<template> <template>
<view class="container"> <view class="container">
<view class="title"> <view class="title">
<view> <view>
<text class="line"></text>电子签名 <text class="line"></text>电子签名<text style="font-size: 20rpx;font-weight: normal;">(请书写工整,字迹清晰)</text>
</view>
<text class="page_mark"> 8/8</text>
</view>
<view class="signatureContent">
<!-- <signature-pad *ngIf="!isSignatureShow" #signaturePad [options]="signaturePadOptions" (onBeginEvent)="drawStart()" (onEndEvent)="drawComplete()">
</signature-pad> -->
<!-- <img [src]="imgStr" alt="签名" *ngIf="isSignatureShow"> -->
<view style="width: 750rpx ;height: 750rpx;">
<l-signature disableScroll backgroundColor="#ddd" ref="signatureRef" :penColor="penColor" :penSize="penSize" :openSmooth="openSmooth" ></l-signature>
</view> </view>
<text class="page_mark">8/8</text> <!-- <view>
</view> <button @click="onClick('clear')">清空</button>
<navigator class="fixed" url="bank-card"> <button @click="onClick('undo')">撤消</button>
<button @click="onClick('save')">保存</button>
<button @click="onClick('openSmooth')">压感{{openSmooth?'开':'关'}}</button>
</view> -->
</view>
<div class="signature_action">
<image src="../../static/clear.png" alt="清除" @click="onClick('clear')"></image>
<image src="../../static/revoke.png" alt="上一步" @click="onClick('undo')"></image>
</div>
<view class="fixed" url="bank-card">
保存并下一步 保存并下一步
</navigator> </view>
</view> </view>
</template> </template>
<script> <script>
export default{ export default {
data(){ data() {
return { return {
title: 'Hello',
} penColor: 'red',
}, penSize: 5,
components:{}, url: '',
onLoad(){ openSmooth: true
}
}, },
methods:{ methods: {
onClick(type) {
} if(type == 'openSmooth') {
this.openSmooth = !this.openSmooth
return
}
if (type == 'save') {
this.$refs.signatureRef.canvasToTempFilePath({
success: (res) => {
// 是否为空画板 无签名
console.log(res.isEmpty)
// 生成图片的临时路径
// app | H5 | 微信小程序 生成的是base64
this.url = res.tempFilePath
}
})
return
}
if (this.$refs.signatureRef)
this.$refs.signatureRef[type]()
}
}
} }
</script> </script>
<style lang="scss"> <style lang="scss">
@import 'applyCommon.scss'; @import 'applyCommon.scss';
.signatureContent{
margin: 0 13px 20px 13px;
background: #f8f8f8;
}
.signature_action{
display: flex;
justify-content: space-evenly;
margin-top: 20px;
uni-image{max-width: 60px;max-height: 60px;}
}
</style> </style>
\ No newline at end of file
## 1.0.0(2022-10-27)
- feat: 增加背景色
- feat: 修复 app canvasToTempFilePath 无操作只能执行一次的问题
## 0.8.0(2022-08-22)
- feat: 增加beforeDelay 延时初始化,可用于手写板在弹窗里时
## 0.7.0(2022-08-16)
- fix: 修复缺少 canvasWidth
## 0.6.0(2022-07-16)
- fix: 修复 success is no defined
## 0.5.0(2022-07-09)
- feat: canvasToTempFilePath success 增加返回 isEmpty
- fix: 修复 微信小程序 canvasToTempFilePath 无效问题
## 0.4.0(2022-07-04)
- fix: 生成图片缺少最后一笔
## 0.3.0(2022-05-24)
- chore: 支持多端 H5 小程序 APP APP-NVUE
## 0.2.0(2021-07-09)
- chore: 统一命名规范,无须主动引入组件
- fix: 修复错位问题
## 0.1.0(2021-03-07)
- 首次上传
- 撤消、清空、保存、模拟压感等功能
export const uniContext = (ctx) => {
const ALIAS_ATTRS_MAP = [
'lineCap',
'strokeStyle',
'lineWidth',
'fillStyle',
]
ALIAS_ATTRS_MAP.forEach(style => {
Object.defineProperty(ctx, style, {
set: value => {
if(value)
ctx[`set${style.charAt(0).toUpperCase()}${style.slice(1)}`](value)
}
})
})
ctx.uniDrawImage = ctx.drawImage
ctx.drawImage = (image,...agrs) => {
ctx.uniDrawImage(image.src, ...agrs)
}
return ctx
}
class Image {
constructor() {
this.currentSrc = null
this.naturalHeight = 0
this.naturalWidth = 0
this.width = 0
this.height = 0
this.tagName = 'IMG'
}
set src(src) {
this.currentSrc = src
uni.getImageInfo({
src,
success: (res) => {
this.naturalWidth = this.width = res.width
this.naturalHeight = this.height = res.height
this.onload()
},
fail: () => {
this.onerror()
}
})
}
get src() {
return this.currentSrc
}
}
export const createImage = () => {
return new Image()
}
export const toDataURL = (canvasId, com) => {
return new Promise((resolve, reject) => {
uni.canvasToTempFilePath({
canvasId,
success: (res) => {
resolve(res.tempFilePath)
},
fail: reject
}, com)
})
}
\ No newline at end of file
export function compareVersion(v1, v2) {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i], 10)
const num2 = parseInt(v2[i], 10)
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
export const getCanvas2d = () => {
let {SDKVersion, uniPlatform} = uni.getSystemInfoSync()
if(!uniPlatform) {
// #ifdef MP-WEIXIN
uniPlatform = 'mp-weixin'
// #endif
// #ifdef MP-MP-ALIPAY
SDKVersion = my.SDKVersion
uniPlatform = 'mp-alipay'
// #endif
// #ifdef MP-MP-ALIPAY
uniPlatform = 'mp-toutiao'
// #endif
}
const MAP = {
'mp-weixin': '2.9.7',
'mp-toutiao': '1.78.0',
'mp-alipay': '2.7.0'
}[uniPlatform]
return MAP && SDKVersion && compareVersion(SDKVersion, MAP) >= 1
}
export const wrapEvent = (e) => {
if (!e) return;
if (!e.preventDefault) {
e.preventDefault = function() {};
}
return e;
}
export const requestAnimationFrame = (cb) => {
setTimeout(cb, 30)
}
/**
* base64转路径
* @param {Object} base64
*/
export function base64ToPath(base64) {
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
return new Promise((resolve, reject) => {
const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
bitmap.loadBase64Data(base64, () => {
if (!format) {
reject(new Error('ERROR_BASE64SRC_PARSE'))
}
const time = new Date().getTime();
const filePath = `_doc/uniapp_temp/${time}.${format}`
bitmap.save(filePath, {},
() => {
bitmap.clear()
resolve(filePath)
},
(error) => {
bitmap.clear()
reject(error)
})
}, (error) => {
bitmap.clear()
reject(error)
})
})
}
export function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay))
}
\ No newline at end of file
<template>
</template>
<script>
</script>
<style>
</style>
\ No newline at end of file
{
"id": "lime-signature",
"displayName": "手写板-签名",
"version": "1.0.0",
"description": "手写板签名组件: 一款能跑在uniapp各端中的签名插件,支持签名颜色笔画大小等功能",
"keywords": [
"canvas",
"写字",
"签名",
"涂鸦"
],
"repository": "",
"engines": {
"HBuilderX": "^3.5.4"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "u",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}
\ No newline at end of file
# signature 写字板
> uniapp 写字板,可用业务签名等场景
> [查看更多 站点1](https://limeui.qcoon.cn/#/signature) <br>
> [查看更多 站点2](http://liangei.gitee.io/limeui/#/signature)
> Q群:1169785031
## 平台兼容
| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
| √ | √ | 未测 | 未测 | 未测 | 未测 | √ |
## 代码演示
### 基本用法
```html
<view style="width: 750rpx ;height: 750rpx;">
<l-signature disableScroll backgroundColor="#ddd" ref="signatureRef" :penColor="penColor" :penSize="penSize" :openSmooth="openSmooth" ></l-signature>
</view>
<view>
<button @click="onClick('clear')">清空</button>
<button @click="onClick('undo')">撤消</button>
<button @click="onClick('save')">保存</button>
<button @click="onClick('openSmooth')">压感{{openSmooth?'开':'关'}}</button>
</view>
```
```js
export default {
data() {
return {
title: 'Hello',
penColor: 'red',
penSize: 5,
url: '',
openSmooth: true
}
},
methods: {
onClick(type) {
if(type == 'openSmooth') {
this.openSmooth = !this.openSmooth
return
}
if (type == 'save') {
this.$refs.signatureRef.canvasToTempFilePath({
success: (res) => {
// 是否为空画板 无签名
console.log(res.isEmpty)
// 生成图片的临时路径
// app | H5 | 微信小程序 生成的是base64
this.url = res.tempFilePath
}
})
return
}
if (this.$refs.signatureRef)
this.$refs.signatureRef[type]()
}
}
}
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| -------------- | ------------ | ---------------- | ------------ |
| penSize | 画笔大小 | <em>number</em> | `2` |
| minLineWidth | 线条最小宽 | <em>number</em> | `2` |
| maxLineWidth | 线条最大宽 | <em>number</em> | `6` |
| penColor | 画笔颜色 | <em>string</em> | `black` |
| backgroundColor | 背景颜色 | <em>string</em> | `` |
| type | 指定 canvas 类型 | <em>string</em> | `2d` |
| openSmooth | 是否模拟压感 | <em>boolean</em> | `false` |
| beforeDelay | 延时初始化,在放在弹窗里可以使用 (毫秒) | <em>number</em> | `0` |
| maxHistoryLength | 限制历史记录数,即最大可撤销数,传入0则关闭历史记录功能 | <em>boolean</em> | `20` |
### 事件 Events
| 事件名 | 说明 | 回调 |
| ------- | ------------ | -------------- |
| undo | 撤消,回退到上一步 | |
| clear | 清空,清空画板 | |
| canvasToTempFilePath | 保存,生成图片,与官方保持一致,但不需要传canvasId | |
### 常见问题
- 放在弹窗里时,尺寸不对 可以延时手写板出现时机,给手写板加vif或beforeDelay="300"
### 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
![输入图片说明](https://static-6d65bd90-8508-4d6c-abbc-a4ef5c8e49e7.bspapp.com/image/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")
![输入图片说明](https://static-6d65bd90-8508-4d6c-abbc-a4ef5c8e49e7.bspapp.com/image/wxplay.jpg "wxplay.jpg")
\ No newline at end of file
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title></title>
<style type="text/css">
html,
body,
canvas {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
overflow-y: hidden;
background-color: transparent;
}
</style>
</head>
<body>
<canvas id="lime-signature"></canvas>
<script type="text/javascript" src="./uni.webview.1.5.3.js"></script>
<script type="text/javascript" src="./signature.js"></script>
<script>
var signature = null;
var timer = null;
var isStart = false;
var options = null
console.log = function(...args) {
postMessage(args);
};
// function stringify(key, value) {
// if (typeof value === 'object' && value !== null) {
// if (cache.indexOf(value) !== -1) {
// return;
// }
// cache.push(value);
// }
// return value;
// };
function emit(event, data) {
postMessage({
event,
data: typeof data !== "object" && data !== null ? data : JSON.stringify(data),
});
// cache = [];
}
function postMessage(data) {
uni.postMessage({
data
});
}
function update(v = {}) {
if (signature) {
options = v
signature.pen.setOption(v);
} else {
signature = new Signature.Signature({el: "lime-signature"});
canvasEl = signature.canvas.get("el");
options = v
signature.pen.setOption(v)
const width = signature.canvas.get("width");
const height = signature.canvas.get("height");
emit({changeSize: {width,height}})
}
}
function clear() {
signature.clear()
}
function undo() {
signature.undo()
}
function isEmpty() {
const isEmpty = signature.isEmpty()
emit({isEmpty});
}
function save(args) {
// delete args.success;
// delete args.fail;
clearTimeout(timer);
timer = setTimeout(() => {
let path = canvasEl.toDataURL()
if(options.backgroundColor) {
const canvas = document.createElement('canvas')
const width = signature.canvas.get('width')
const height = signature.canvas.get('height')
const pixelRatio = signature.canvas.get('pixelRatio')
canvas.width = width * pixelRatio
canvas.height = height * pixelRatio
const context = canvas.getContext('2d')
context.scale(pixelRatio, pixelRatio)
context.fillStyle = backgroundColor
context.fillRect(0,0, width, height)
context.drawImage(signature.canvas.get('el'), 0, 0, width, height)
path = canvas.toDataURL()
canvas.remove()
}
if (typeof path == "string") {
const index = Math.ceil(path.length / 8);
for (var i = 0; i < 8; i++) {
if (i == 7) {
emit({"success": path.substr(i * index, index)});
} else {
emit({"file": path.substr(i * index, index)});
}
}
} else {
console.error("canvas no data");
emit({"fail": "canvas no data"});
}
}, 30);
}
</script>
</body>
</html>
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e=e||self).uni=n()}(this,(function(){"use strict";try{var e={};Object.defineProperty(e,"passive",{get:function(){!0}}),window.addEventListener("test-passive",null,e)}catch(e){}var n=Object.prototype.hasOwnProperty;function i(e,i){return n.call(e,i)}var t=[];function o(){return window.__dcloud_weex_postMessage||window.__dcloud_weex_}var r=function(e,n){var i={options:{timestamp:+new Date},name:e,arg:n};if(o()){if("postMessage"===e){var r={data:[n]};return window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessage(r):window.__dcloud_weex_.postMessage(JSON.stringify(r))}var a={type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}};window.__dcloud_weex_postMessage?window.__dcloud_weex_postMessageToService(a):window.__dcloud_weex_.postMessageToService(JSON.stringify(a))}if(!window.plus)return window.parent.postMessage({type:"WEB_INVOKE_APPSERVICE",data:i,pageId:""},"*");if(0===t.length){var d=plus.webview.currentWebview();if(!d)throw new Error("plus.webview.currentWebview() is undefined");var s=d.parent(),w="";w=s?s.id:d.id,t.push(w)}if(plus.webview.getWebviewById("__uniapp__service"))plus.webview.postMessageToUniNView({type:"WEB_INVOKE_APPSERVICE",args:{data:i,webviewIds:t}},"__uniapp__service");else{var u=JSON.stringify(i);plus.webview.getLaunchWebview().evalJS('UniPlusBridge.subscribeHandler("'.concat("WEB_INVOKE_APPSERVICE",'",').concat(u,",").concat(JSON.stringify(t),");"))}},a={navigateTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("navigateTo",{url:encodeURI(n)})},navigateBack:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.delta;r("navigateBack",{delta:parseInt(n)||1})},switchTab:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("switchTab",{url:encodeURI(n)})},reLaunch:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("reLaunch",{url:encodeURI(n)})},redirectTo:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=e.url;r("redirectTo",{url:encodeURI(n)})},getEnv:function(e){o()?e({nvue:!0}):window.plus?e({plus:!0}):e({h5:!0})},postMessage:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};r("postMessage",e.data||{})}},d=/uni-app/i.test(navigator.userAgent),s=/Html5Plus/i.test(navigator.userAgent),w=/complete|loaded|interactive/;var u=window.my&&navigator.userAgent.indexOf("AlipayClient")>-1;var g=window.swan&&window.swan.webView&&/swan/i.test(navigator.userAgent);var c=window.qq&&window.qq.miniProgram&&/QQ/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var v=window.tt&&window.tt.miniProgram&&/toutiaomicroapp/i.test(navigator.userAgent);var m=window.wx&&window.wx.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var p=window.qa&&/quickapp/i.test(navigator.userAgent);var f=window.ks&&window.ks.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);var l=window.tt&&window.tt.miniProgram&&/Lark|Feishu/i.test(navigator.userAgent);var _=window.jd&&window.jd.miniProgram&&/micromessenger/i.test(navigator.userAgent)&&/miniProgram/i.test(navigator.userAgent);for(var E,b=function(){window.UniAppJSBridge=!0,document.dispatchEvent(new CustomEvent("UniAppJSBridgeReady",{bubbles:!0,cancelable:!0}))},h=[function(e){if(d||s)return window.__dcloud_weex_postMessage||window.__dcloud_weex_?document.addEventListener("DOMContentLoaded",e):window.plus&&w.test(document.readyState)?setTimeout(e,0):document.addEventListener("plusready",e),a},function(e){if(m)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.wx.miniProgram},function(e){if(c)return window.QQJSBridge&&window.QQJSBridge.invoke?setTimeout(e,0):document.addEventListener("QQJSBridgeReady",e),window.qq.miniProgram},function(e){if(u){document.addEventListener("DOMContentLoaded",e);var n=window.my;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(g)return document.addEventListener("DOMContentLoaded",e),window.swan.webView},function(e){if(v)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(p){window.QaJSBridge&&window.QaJSBridge.invoke?setTimeout(e,0):document.addEventListener("QaJSBridgeReady",e);var n=window.qa;return{navigateTo:n.navigateTo,navigateBack:n.navigateBack,switchTab:n.switchTab,reLaunch:n.reLaunch,redirectTo:n.redirectTo,postMessage:n.postMessage,getEnv:n.getEnv}}},function(e){if(f)return window.WeixinJSBridge&&window.WeixinJSBridge.invoke?setTimeout(e,0):document.addEventListener("WeixinJSBridgeReady",e),window.ks.miniProgram},function(e){if(l)return document.addEventListener("DOMContentLoaded",e),window.tt.miniProgram},function(e){if(_)return window.JDJSBridgeReady&&window.JDJSBridgeReady.invoke?setTimeout(e,0):document.addEventListener("JDJSBridgeReady",e),window.jd.miniProgram},function(e){return document.addEventListener("DOMContentLoaded",e),a}],y=0;y<h.length&&!(E=h[y](b));y++);E||(E={});var B="undefined"!=typeof uni?uni:{};if(!B.navigateTo)for(var S in E)i(E,S)&&(B[S]=E[S]);return B.webView=E,B}));
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment