上传事件的页面:
<template>
<view>
<view class="authState">
<image src="/static/auth/auth-1.png" mode=""></image>
</view>
<view class="sfzInfo">
<view class="title">请上传身份证的正反面</view>
<view class="phoneCt">
<view class="name">
<view>头像面</view>
<text>上传您的身份证头像面</text>
</view>
<view class="imgCt" @click="uploadImg('idCardFront')">
<image v-if="!idCardFront" src="../../../static/auth/sfz-1.png" mode=""></image>
<image v-else :src="'data:image/jpg;base64,'+ idCardFront" />
</view>
</view>
<view class="phoneCt">
<view class="name">
<view>国徽面</view>
<text>上传您的身份证国徽面</text>
</view>
<view class="imgCt" @click="uploadImg('idCardBack')">
<image v-if="!idCardBack" src="../../../static/auth/sfz-2.png" mode=""></image>
<image v-else :src="'data:image/jpg;base64,'+ idCardBack" />
</view>
</view>
<view class="title">请完善您的个人信息</view>
<view class="int">
<view class="label">
<view class="star">*</view>
<view class="name">姓名:</view>
</view>
<uni-easyinput v-model="userName" borderBottom="5" class="int" textAlign="right" :inputBorder="false" placeholder="请输入姓名" clearable trim/>
</view>
<view class="int">
<view class="label">
<view class="star">*</view>
<view class="name">身份证号:</view>
</view>
<uni-easyinput v-model="idCardNo" borderBottom="5" class="int" textAlign="right" :inputBorder="false" placeholder="请输入身份证号" clearable trim/>
</view>
<view class="btn" @click="stepToPage()">下一步</view>
</view>
<helang-compress ref="helangCompress"></helang-compress>
</view>
</template>
<script>
import {pathToBase64,base64ToPath} from '@/common/mmmm-image-tools/index.js'
import helangCompress from '@/components/helang-compress/helang-compress';
export default {
components: {
helangCompress
},
data() {
return {
idCardFront:'',//身份证正面
idCardBack:'',//身份证反面
idCardNo:'',//身份证号码
userName:'',//身份证名字
isHaveInfo:false
}
},
onLoad() {
},
methods: {
uploadImg(type){
let that = this
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
// sourceType: ['album'], //从相册选择
success: function (res) {
that.setImg({path: res.tempFilePaths[0],dotype:type})
}
});
},
setImg(e){
console.log(e)
pathToBase64(e.path).then(base64 => {
base64ToPath(base64).then(path => {
// 压缩图片
this.$refs.helangCompress.compress({
src: path,
maxSize: 800,
fileType: 'jpg',
quality: 0.85,
minSize: 640 //最小压缩尺寸,图片尺寸小于该时值不压缩,非H5平台有效。若需要忽略该设置,可设置为一个极小的值,比如负数。
}).then((pathImg) => {
switch (e.dotype) {
case 'idCardFront':
this.idCardFrontReverse(pathImg)
break;
case 'idCardBack':
this.idCardBackReverse(pathImg)
break;
default:
uni.showToast({
icon: 'none',
title: '图片类型识别错误'
})
}
// 压缩成功回调
}).catch((err) => {
console.log('压缩后失败', err)
})
})
})
},
idCardFrontReverse(path){
pathToBase64(path).then(base64 => {
let url = "/checkImage";
this.$u.post(url,{
content: base64.split(',')[1],
imageType: 'idcard'
}).then(res => {
this.idCardFront = base64.split(',')[1]
var ocr = JSON.parse(res.object)
this.userName = ocr.words_result['姓名'].words
this.idCardNo = ocr.words_result['公民身份号码'].words
});
})
},
idCardBackReverse(path) {
pathToBase64(path).then(base64 => {
this.idCardBack = base64.split(',')[1]
})
},
stepToPage(){
this.$u.route('/pages/subpackage/auth/authXyk')
const regex = /^(?:\d{15}|\d{17}[\dXx])$/;
if (!this.idCardFront) {
return this.$mytip.toast('请上传身份证人像面')
}
if (!this.idCardBack) {
return this.$mytip.toast('请上传身份证国徽面')
}
if (!this.userName) {
return this.$mytip.toast('请输入姓名')
}
if (!this.idCardNo) {
return this.$mytip.toast('请输入身份证号码')
}
if (this.idCardNo.length !== 18) {
return this.$mytip.toast('请输入正确对身份证号码')
}
if (!regex.test(this.idCardNo)) {
return this.$mytip.toast('请输入正确的身份证号码')
}
const data = {
idCardBack: this.idCardBack,
idCardFront: this.idCardFront,
idCardNo: this.idCardNo,
userName: this.userName
}
let url = "/uploadIdCard";
this.$u.post(url,data).then(res => {
this.$mytip.toast('身份证上传成功')
setTimeout(()=>{
this.$u.route('/pages/subpackage/auth/authXyk')
},1000)
});
}
}
}
</script>
<style lang="scss">
page{
background: #fff;
}
.authState{
width: 100%;
height: 116rpx;
image{
width: 100%;
height: 116rpx;
}
}
.sfzInfo{
padding: 0 48rpx;
.title{
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
color:#1B1919;
font-weight: 500;
}
.phoneCt{
margin-bottom: 20rpx;
padding: 40rpx 30rpx;
display: flex;
justify-content: space-between;
width: 100%;
background: #F4F6F8;
.name{
view{
display: block;
margin-bottom: 10rpx;
font-size: 30rpx;
color:#1B1919;
font-weight: bold;
}
text{
font-size: 28rpx;
color:#666;
}
}
.imgCt{
width: 240rpx;
height: 168rpx;
image{
width: 240rpx;
height: 168rpx;
}
}
}
.int{
display: flex;
justify-content: left;
align-items: center;
height: 80rpx;
line-height: 80rpx;
border-bottom: 1rpx solid #eee;
.label{
width: 24%;
display: flex;
justify-content: left;
align-items: center;
.star{
font-size: 28rpx;
color:#D91616
}
.name{
font-size: 28rpx;
color:#1B1919;
}
}
.icon{
width: 40rpx;
height: 40rpx;
image{
width: 40rpx;
height: 40rpx;
}
}
}
.btn{
margin: 60rpx auto 40rpx;
width: 86%;
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
color:#fff;
text-align: center;
background: linear-gradient( 90deg, #D91616 0%, #EE0808 100%);
border-radius: 16rpx;
}
}
</style>
index.js 文件夹
function getLocalFilePath(path) {
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
return path
}
if (path.indexOf('file://') === 0) {
return path
}
if (path.indexOf('/storage/emulated/0/') === 0) {
return path
}
if (path.indexOf('/') === 0) {
var localFilePath = plus.io.convertAbsoluteFileSystem(path)
if (localFilePath !== path) {
return localFilePath
} else {
path = path.substr(1)
}
}
return '_www/' + path
}
function dataUrlToBase64(str) {
var array = str.split(',')
return array[array.length - 1]
}
var index = 0
function getNewFileId() {
return Date.now() + String(index++)
}
function biggerThan(v1, v2) {
var v1Array = v1.split('.')
var v2Array = v2.split('.')
var update = false
for (var index = 0; index < v2Array.length; index++) {
var diff = v1Array[index] - v2Array[index]
if (diff !== 0) {
update = diff > 0
break
}
}
return update
}
export function pathToBase64(path) {
return new Promise(function(resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
if (typeof FileReader === 'function') {
var xhr = new XMLHttpRequest()
xhr.open('GET', path, true)
xhr.responseType = 'blob'
xhr.onload = function() {
if (this.status === 200) {
let fileReader = new FileReader()
fileReader.onload = function(e) {
resolve(e.target.result)
}
fileReader.onerror = reject
fileReader.readAsDataURL(this.response)
}
}
xhr.onerror = reject
xhr.send()
return
}
var canvas = document.createElement('canvas')
var c2x = canvas.getContext('2d')
var img = new Image
img.onload = function() {
canvas.width = img.width
canvas.height = img.height
c2x.drawImage(img, 0, 0)
resolve(canvas.toDataURL())
canvas.height = canvas.width = 0
}
img.onerror = reject
img.src = path
return
}
if (typeof plus === 'object') {
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
entry.file(function(file) {
var fileReader = new plus.io.FileReader()
fileReader.onload = function(data) {
resolve(data.target.result)
}
fileReader.onerror = function(error) {
reject(error)
}
fileReader.readAsDataURL(file)
}, function(error) {
reject(error)
})
}, function(error) {
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
wx.getFileSystemManager().readFile({
filePath: path,
encoding: 'base64',
success: function(res) {
resolve('data:image/png;base64,' + res.data)
},
fail: function(error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
export function base64ToPath(base64) {
return new Promise(function(resolve, reject) {
if (typeof window === 'object' && 'document' in window) {
base64 = base64.split(',')
var type = base64[0].match(/:(.*?);/)[1]
var str = atob(base64[1])
var n = str.length
var array = new Uint8Array(n)
while (n--) {
array[n] = str.charCodeAt(n)
}
return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))
}
var extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/)
if (extName) {
extName = extName[1]
} else {
reject(new Error('base64 error'))
}
var fileName = getNewFileId() + '.' + extName
if (typeof plus === 'object') {
var basePath = '_doc'
var dirPath = 'uniapp_temp'
var filePath = basePath + '/' + dirPath + '/' + fileName
if (!biggerThan(plus.os.name === 'Android' ? '1.9.9.80627' : '1.9.9.80472', plus.runtime.innerVersion)) {
plus.io.resolveLocalFileSystemURL(basePath, function(entry) {
entry.getDirectory(dirPath, {
create: true,
exclusive: false,
}, function(entry) {
entry.getFile(fileName, {
create: true,
exclusive: false,
}, function(entry) {
entry.createWriter(function(writer) {
writer.onwrite = function() {
resolve(filePath)
}
writer.onerror = reject
writer.seek(0)
writer.writeAsBinary(dataUrlToBase64(base64))
}, reject)
}, reject)
}, reject)
}, reject)
return
}
var bitmap = new plus.nativeObj.Bitmap(fileName)
bitmap.loadBase64Data(base64, function() {
bitmap.save(filePath, {}, function() {
bitmap.clear()
resolve(filePath)
}, function(error) {
bitmap.clear()
reject(error)
})
}, function(error) {
bitmap.clear()
reject(error)
})
return
}
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
var filePath = wx.env.USER_DATA_PATH + '/' + fileName
wx.getFileSystemManager().writeFile({
filePath: filePath,
data: dataUrlToBase64(base64),
encoding: 'base64',
success: function() {
resolve(filePath)
},
fail: function(error) {
reject(error)
}
})
return
}
reject(new Error('not support'))
})
}
helang-compress.vue 文件
<template>
<view class="compress" v-if="canvasId">
<canvas :canvas-id="canvasId" :style="{ width: canvasSize.width,height: canvasSize.height}"></canvas>
</view>
</template>
<script>
export default {
data() {
return {
pic:'',
canvasSize: {
width: 0,
height: 0
},
canvasId:""
}
},
mounted() {
if(!uni || !uni._helang_compress_canvas){
uni._helang_compress_canvas = 1;
}else{
uni._helang_compress_canvas++;
}
this.canvasId = `compress-canvas${uni._helang_compress_canvas}`;
},
methods: {
// 压缩
compressFun(params) {
return new Promise(async (resolve, reject) => {
// 等待图片信息
let info = await this.getImageInfo(params.src).then(info=>info).catch(()=>null);
if(!info){
reject('获取图片信息异常');
return;
}
// 设置最大 & 最小 尺寸
const maxSize = params.maxSize || 1080;
const minSize = params.minSize || 640;
// 当前图片尺寸
let {width,height} = info;
// 非 H5 平台进行最小尺寸校验
// #ifndef H5
if(width <= minSize && height <= minSize){
resolve(params.src);
return;
}
// #endif
// 最大尺寸计算
if (width > maxSize || height > maxSize) {
if (width > height) {
height = Math.floor(height / (width / maxSize));
width = maxSize;
} else {
width = Math.floor(width / (height / maxSize));
height = maxSize;
}
}
// 设置画布尺寸
this.$set(this,"canvasSize",{
width: `${width}px`,
height: `${height}px`
});
// Vue.nextTick 回调在 App 有异常,则使用 setTimeout 等待DOM更新
setTimeout(() => {
const ctx = uni.createCanvasContext(this.canvasId, this);
ctx.clearRect(0,0,width, height)
ctx.drawImage(info.path, 0, 0, width, height);
ctx.draw(false, () => {
uni.canvasToTempFilePath({
x: 0,
y: 0,
width: width,
height: height,
destWidth: width,
destHeight: height,
canvasId: this.canvasId,
fileType: params.fileType || 'png',
quality: params.quality || 0.9,
success: (res) => {
// 在H5平台下,tempFilePath 为 base64
resolve(res.tempFilePath);
},
fail:(err)=>{
reject(null);
}
},this);
});
}, 300);
});
},
// 获取图片信息
getImageInfo(src){
return new Promise((resolve, reject)=>{
uni.getImageInfo({
src,
success: (info)=> {
resolve(info);
},
fail: () => {
reject(null);
}
});
});
},
// 批量压缩
compress(params){
// index:进度,done:成功,fail:失败
let [index,done,fail] = [0,0,0];
// 压缩完成的路径集合
let paths = [];
// 待压缩的图片
let waitList = [];
if(typeof params.src == 'string'){
waitList = [params.src];
}else{
waitList = params.src;
}
// 批量压缩方法
let batch = ()=>{
return new Promise((resolve, reject)=>{
// 开始
let start = async ()=>{
// 等待图片压缩方法返回
let path = await next().catch(()=>null);
if(path){
done++;
paths.push(path);
}else{
fail++;
}
params.progress && params.progress({
done,
fail,
count:waitList.length
});
index++;
// 压缩完成
if(index >= waitList.length){
resolve(true);
}else{
start();
}
}
start();
});
}
// 依次调用压缩方法
let next = ()=>{
return this.compressFun({
src:waitList[index],
maxSize:params.maxSize,
fileType:params.fileType,
quality:params.quality,
minSize:params.minSize
})
}
// 全部压缩完成后调用
return new Promise(async (resolve, reject)=>{
// 批量压缩方法回调
let res = await batch();
if(res){
if(typeof params.src == 'string'){
// 为解决漏网之鱼,部分机型压缩不到的使用uni自带的压缩
uni.getFileInfo({
filePath:paths[0],
success:imgInfo=>{
//console.log('这是uni压缩前的',imgInfo)
// 压缩完 如果还大于500Kb 则调用uni的方法再次压缩
if(imgInfo.size >= (500*1024)){
uni.compressImage({
src: paths[0],
quality: 10,
success: res => {
resolve(res.tempFilePath);
}
})
}else{
resolve(paths[0]);
}
}
})
}else{
resolve(paths);
}
}else{
reject(null);
}
});
}
}
}
</script>
<style lang="scss" scoped>
.compress{
position: fixed;
width: 12px;
height: 12px;
overflow: hidden;
top: -99999px;
left: 0;
}
</style>
效果如下图展示:上传头像面可自动识别出来姓名和身份证号