一、主体流程
- 点击icon
- 跳转到拍照页面(路由:/packageCommon/pages/camera/index),此页面使用
<camera><camera/>
区域相机组件 - 点击拍照按钮,进行拍照,使用
const ctx = uni.createCameraContext()
创建并返回 camera 组件的上下文 cameraContext 对象;调用ctx.takePhoto
方法,它的success
回调中可以获取到临时路径。
- 3.1 uniapp中当前页面如何调用上一个页面的方法?----可以使用
getCurrentPages()
方法获取到pages,再拿到prevPage:const prevPage = pages.length > 1 ? pages[pages.length - 2] : null
,prevPage.$vm.xxx()
就可以调用上一个页面的方法了
- 临时路径作为
uni.uploadFile
的filePath
,上传至文件服务器,这里文件服务器的url是/common/ocr
- 文件服务器(ocr)返回真实的图片地址,并且返回身份证上的信息,用来回显页面
二、相关代码
js
<u-popup
v-model="popupShow"
closeable
safe-area-inset-bottom
border-radius="14"
mode="center"
>
<view>
<view class="pop-title">担保征信查询</view>
<scroll-view
scroll-y="true"
style="padding: 0 40rpx; box-sizing: border-box"
>
<view style="max-height: 800rpx">
<u-form-item
label-width="200"
label-position='top'
label="身份证人像面"
required
:border-bottom="false"
>
<view class="idCrad_card">
<view class="idCrad_card__item" @click="cameraFront('front')">
<image :src="idCardFront.image" mode="aspectFit" class="img1">
</image>
<image :src="idCardFront.image2" class="img2">
</image>
</view>
</view>
</u-form-item>
<u-form-item
v-show="form.idCard"
label-width="200"
label="姓名"
required
:border-bottom="false"
>
<view style="display: flex; align-items: center;">
<u-input
v-model="form.name"
placeholder="请输入姓名"
:border="true"
maxlength="10"
/>
<image style="width: 20px; height: 20px; margin-left: 10px;" :src="imagesConfig.realName.ic_edit" mode="aspectFit" />
</view>
</u-form-item>
<u-form-item
v-show="form.idCard"
label-width="200"
label="身份证号"
required
:border-bottom="false"
>
<view>{{form.idCard}}</view>
</u-form-item>
</view>
</scroll-view>
<view class="pop-footer" style="justify-content: center">
<app-button
borderRadius="3rpx"
width="160rpx"
height="60rpx"
type="info"
@click="handleAdd"
text="提交"
></app-button>
</view>
</view>
</u-popup>
data:
// 新增征信查询表单数据
form: {
idCardAUrl: '',
idCardBUrl: '',
address: '',
nation: '',
signOrg: '',
startDate: '',
endDate: '',
name: '',
idCard: '',
},
computed: {
// 身份证正面展示图片
idCardFront() {
return {
image: this.form.idCardAUrl ? this.form.idCardAUrl : imagesConfig.realName.ic_idcard_a,
image2: imagesConfig.realName.ic_take_phone,
}
},
// 身份证反面展示图片
idCardBack() {
return {
image: this.form.idCardBUrl ? this.form.idCardBUrl : imagesConfig.realName.ic_idcard_b,
image2: imagesConfig.realName.ic_take_phone,
}
},
},
methods:
// 身份证上传-开始
// 打开摄像头
cameraFront(ocrType) {
// front-人像面 back-国徽面
uni.showLoading({
title: '努力加载中',
mask: true
});
this.$utils.canOpenCamera().then(() => {
uni.hideLoading()
const data = {
uploadCallBackHandler: 'onUploadHandle',
isIdCardOcr: 1,
ocrType,
ref: "photoWay",
title: "拍照识别",
callBackParams: {
type: ocrType == 'front' ? '0' : '1'
}
}
uni.navigateTo({
url: `/packageCommon/pages/camera/index?data=${encodeURIComponent(JSON.stringify(data))}`
})
}).catch(() => {
uni.hideLoading()
})
},
// 身份证识别
onUploadHandle(filePath, data) {
console.log('onUploadHandle被调用',filePath, data)
this.curOcr = data.type
let type = data.type
if (type == 1) { // 国徽面
this.frontStartTime = this.$utils.dateToStr(new Date())
} else {
this.backStartTime = this.$utils.dateToStr(new Date())
}
uni.showLoading({
title: '努力加载中',
mask: true
});
this.uniUploadFile({
url: "/common/ocr",
// url: "/kfbjd/common/ocr.do",
filePath,
name: 'fileUpload',
formData: {
fileType: type,
wxId: this.unionId,
token: this.userInfo && this.userInfo.token,
bankCode: this.bankCode,
openId: this.openId,
memberType: '0',
needEncrypt: '1',
phone: this.userInfo.phone,
},
success: (uploadFileRes) => {
console.log('ocr上传返回结果',uploadFileRes)
uni.hideLoading()
if(uploadFileRes.flag){
this.handleUpload(uploadFileRes)
}else{
uni.showModal({
title: '提示',
content: uploadFileRes.errMsg || '服务器异常,请稍后重试。',
showCancel: false,
confirmText: '我知道了'
})
}
},
fail: (err) => {
uni.hideLoading();
}
})
},
/**
* 上传文件到服务器(包含加解密功能)
* @param {Object} options 配置项:url 接口请求地址 filePath待上传的图片本地路径 name文件流名称 formData额外参数 success成功回调 fail失败回调
*/
uniUploadFile(options) {
let needEncrypt;
let url = ""
if (options.url.indexOf('kfbjd') != -1) {
needEncrypt = options.formData.needEncrypt
// url = config.baseUrl + options.url
url = 'https://www.hfkxjf.com/lydev/fins-appsply-sso' + options.url
} else {
needEncrypt = config.needEncrypt
// url = config.baseUrl + options.url
url = 'https://www.hfkxjf.com/lydev/fins-appsply-sso' + options.url
}
// 加密
if (needEncrypt == '1') {
const req = aes.encrypt(JSON.stringify(options.formData))
if (options.url.indexOf('kfbjd') != -1) {
options.formData = {
data: req
}
} else {
options.formData = {
data: queryString.stringify({
data: req
})
}
}
}
console.log("文件上传参数", options.formData)
uni.uploadFile({
url: url,
filePath: options.filePath,
name: options.name,
formData: options.formData,
headers: {
'Content-Type': 'multipart/form-data'
},
success: (res) => {
console.log(res)
let result = null
if (needEncrypt == '1') {
result = JSON.parse(aes.decrypt(res.data) || '{}')
} else {
result = this.$utils.isJSON(res.data) ? JSON.parse(res.data) : {}
}
console.log("文件上传结果:", result)
options.success && options.success(result)
},
fail: (err) => {
console.log("文件上传失败:", err)
options.fail && options.fail(err)
}
})
},
// ocr获取身份证信息
handleUpload(uploadFileRes) {
let result = uploadFileRes.data || {}
if (result && result.idCard && result.username) {
wx.getImageInfo({
src: result.imagePath,
success: (image) => {
console.log("上传后的图片方向", image.orientation)
}
})
// 人像面
this.form.idCard = result.idCard
this.form.idCardAUrl = result.imagePath
this.form.nation = result.nation
this.form.name = result.username
this.form.address = result.address
} else if (result && result.startDate && result.endDate) {
// 国徽面
this.form.startDate = result.startDate
this.form.endDate = result.endDate
this.form.signOrg = result.signOrg
this.form.idCardBUrl = result.imagePath
let start = this.form.startDate ? this.formatD(this.form.startDate) : ''
let end = this.form.endDate ? this.formatD(this.form.endDate) : ''
this.period = start && end ? start + '-' + end : ''
}
},
// 身份证起止日期过滤
formatD(day) {
let isNum = /^\d+$/.test(day)
if (isNum) {
return day.slice(0, 4) + '.' + day.slice(4, 6) + '.' + day.slice(6)
} else {
return day
}
},
// 身份证上传-结束
utils/index.js
js
/**
* 判断是否有打开摄像头的权限,没有的话会提示用户打开摄像头
*/
canOpenCamera: () => {
return new Promise((resolve, reject) => {
wx.getSetting({
success: (res) => {
console.log(res, 'canOpenCamera---res');
let flag = res.authSetting['scope.camera']
if (flag === false) {
// 相册
uni.showModal({
content: "请打开小程序摄像头功能!",
cancelText: "取消",
confirmText: "去设置",
success: res => {
if (res.confirm) {
wx.openSetting()
} else if (res.cancel) {}
}
})
} else {
console.log('canOpenCamera---else');
resolve()
}
}
})
})
},
camera/index.vue:
js
<!-- 人脸识别:拍照 -->
<template>
<view class="bg ocr">
<!-- 相机拍照 -->
<view v-if="isCamera" style="display: flex;
align-items: center;
justify-content: center;">
<camera :device-position="devicePosition" flash="off" @error="error" class="camera"></camera>
<view v-if="isIdCardOcr">
<image class="icon icon--left-top" :src="iconMap.ic_right_top" mode="aspectFill"></image>
<image class="icon icon--right-top" :src="iconMap.ic_left_top" mode="aspectFill"></image>
<image class="icon icon--right-bottom" :src="iconMap.ic_right_bottom" mode="aspectFill"></image>
<image class="icon icon--left-bottom" :src="iconMap.ic_left_bottom" mode="aspectFill"></image>
<image v-if="ocrType=='front'" class="geren" :src="iconMap.ic_geren" mode="aspectFill"></image>
<image v-if="ocrType=='back'" class="guohui" :src="iconMap.ic_guohui" mode="aspectFill"></image>
</view>
<view class="action">
<view class="action__button" data-monitor-key="cancelPhoto" @click="backEvt">
<!-- <van-icon name="close" color="#fff" size="44rpx" /> -->
<u-icon name="close-circle" color="#fff" size="44rpx" />
<view class="mt-1">取消拍摄</view>
</view>
<view class="action__camera" data-monitor-key="takePhoto" @click="takePhotoEvt">
<image :src="iconMap.ic_photo" mode="aspectFill"></image>
</view>
<view>
</view>
</view>
</view>
<!-- 照片查看 -->
<view v-else style="display: flex;
align-items: center;
justify-content: center;">
<view class="img">
<image :src="src" mode="aspectFit"></image>
</view>
<view class="action action--success">
<view @click="rePhotoEvt" data-monitor-key="reTakePhoto">
<!-- <van-icon name="close" color="#fff" size="70rpx" /> -->
<u-icon name="close-circle" color="#fff" size="70rpx" />
</view>
<view @click="uploadEvt" data-monitor-key="confirmPhoto">
<!-- <van-icon name="success" color="#fff" size="80rpx" /> -->
<u-icon name="checkbox-mark" color="#fff" size="80rpx" />
</view>
</view>
</view>
</view>
</template>
<script>
import imagesConfig from '@/config/images.config.js'
export default {
data() {
return {
iconMap: imagesConfig.mine,
isCamera: true,
devicePosition: 'back',
isIdCardOcr: false, // 是否是上传身份证
ocrType: "", // 身份证正面还是反面 front正面 back反面
src: null,
uploadCallBackHandler: "", // 回调函数
callBackParams: null, // 回调函数入参
ref: ""
}
},
onLoad(query) {
const data = JSON.parse(decodeURIComponent(query.data || "{}"))
this.isIdCardOcr = data.isIdCardOcr == '1'
this.ocrType = data.ocrType || ""
this.uploadCallBackHandler = data.uploadCallBackHandler || ""
this.callBackParams = data.callBackParams || {}
this.ref = data.ref || ""
uni.setNavigationBarTitle({
title: data.title || ""
});
},
methods: {
//拍照
takePhotoEvt() {
const ctx = uni.createCameraContext();
ctx.takePhoto({
quality: 'high',
success: (res) => {
console.log(res)
this.src = res.tempImagePath
if (this.src != null) {
this.isCamera = false
}
}
});
},
//上传
uploadEvt() {
const pages = getCurrentPages()
const prevPage = pages.length > 1 ? pages[pages.length - 2] : null
console.log('pages',{pages,prevPage})
uni.navigateBack({
delta: 1,
success: () => {
console.log('触发onUploadHandle',this.src, this.callBackParams)
prevPage.$vm.onUploadHandle(this.src, this.callBackParams)
// if (this.uploadCallBackHandler) {
// if (this.ref) {
// prevPage.$vm.$refs[this.ref][this.uploadCallBackHandler](this.src, this.callBackParams)
// } else {
// prevPage.$vm[this.uploadCallBackHandler](this.src, this.callBackParams)
// }
// }
}
});
},
//摄像头启动失败
error(e) {
console.log(e.detail);
},
//返回
backEvt() {
uni.navigateBack()
},
//重拍
rePhotoEvt() {
this.isCamera = true
}
}
}
</script>
<style lang="less" scoped>
.ocr {
// .flex-display();
padding-top: 30rpx;
box-sizing: border-box;
background-color: #000000FF;
}
.camera {
position: relative;
width: 690rpx;
height: 75vh;
box-sizing: border-box;
border: 5rpx solid orange;
}
.icon {
position: absolute;
width: 65rpx;
height: 65rpx;
&--left-top {
top: 78rpx;
left: 67rpx;
}
&--right-top {
top: 78rpx;
right: 67rpx;
}
&--left-bottom {
bottom: calc(25vh + 33rpx);
right: 67rpx;
}
&--right-bottom {
bottom: calc(25vh + 33rpx);
left: 67rpx;
}
}
.geren {
position: absolute;
width: 232rpx;
height: 245rpx;
right: 200rpx;
bottom: calc(25vh + 140rpx);
}
.guohui {
position: absolute;
width: 233rpx;
height: 221rpx;
right: 170rpx;
top: 190rpx;
}
.action {
// .flex-display(@flexDirection: row, @justifyContent: center);
display: flex;
flex-direction: row;
justify-content: center;
width: 100%;
height: calc(25vh - 30rpx);
position: fixed;
left: 0;
bottom: -70rpx;
box-sizing: border-box;
&__button {
position: absolute;
left: 100rpx;
color: #fff;
font-size: 22rpx;
text-align: center;
}
&__camera {
width: 110rpx;
height: 110rpx;
image {
width: 100%;
height: 100%;
}
}
&--success {
padding: 0 100rpx;
justify-content: space-between;
}
}
.img {
width: 690rpx;
height: 75vh;
// .flex-display();
image {
width: 100%;
height: 100%;
}
}
</style>