1. 效果
2. 完整代码
<template>
<view :style="{ height: windowHeight + 'px' }">
<!-- 相机区域 -->
<camera mode="normal" :device-position="devicePosition" :flash="flashStyle" :style="{ height: cameraHeight + 'px' }" @error="errorCamera">
<cover-view class="controls" style="width: 100%; height: 100%">
<cover-view class="controls1-bgcolor"></cover-view>
<cover-view class="camera-bgcolor">
<cover-view class="center-top"></cover-view>
<cover-view class="center" id="myCamera">
<!-- 身份证正面 -->
<cover-image v-if="photoType == 'idCardCopy'" class="cover_img" src="../../static/images/sfzz.png" mode="widthFix" />
<!-- 身份证反面 -->
<cover-image v-else-if="photoType == 'idCardNational'" class="cover_img" src="../../static/images/sfzf.png" mode="widthFix" />
<!-- 银行卡正面或反面 -->
<cover-image
v-else-if="photoType == 'bankCardPicFront' || photoType == 'bankCardPicBack'"
class="cover_img"
src="../../static/images/bank.png"
mode="widthFix"
/>
</cover-view>
<cover-view class="center-bottom"></cover-view>
</cover-view>
<cover-view class="controls3-bgcolor"></cover-view>
</cover-view>
</camera>
<!-- 底部操作区域 -->
<view class="bottom bottom-box">
<view class="wrap">
<!-- 相册 -->
<view @click="chooseImage">
<image :src="picture" mode="" style="width: 60rpx; height: 60rpx"></image>
</view>
<!-- 相机 -->
<view @click="takePhoto">
<image class="take-box" :src="icon"></image>
</view>
<!-- 切换前后摄像头 -->
<view class="back" @click="switchBtn">
<image :src="flip" mode="" style="width: 60rpx; height: 60rpx"></image>
</view>
</view>
</view>
<canvas class="cop" canvas-id="image-canvas"></canvas>
</view>
</template>
<script>
export default {
data() {
return {
flip: '../../static/images/fz.png', // 反转
icon: '../../static/images/pho.png', // 相机
picture: '../../static/images/xc.png', // 照片
cameraContext: {},
windowHeight: '',
cameraHeight: '',
idcardFrontSide: true,
photoType: '',
devicePosition: 'back', // 摄像头默认后置
flashStyle: 'off',
tokens: ''
};
},
onLoad(options) {
if (uni.createCameraContext) {
this.cameraContext = uni.createCameraContext();
} else {
// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
uni.showModal({
title: '提示',
content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
});
}
this.photoType = options.photoType;
this.devicePosition = 'back';
this.tokens = uni.getStorageSync('usertoken');
},
onShow() {
const systemInfo = uni.getSystemInfoSync();
this.windowHeight = systemInfo.windowHeight;
this.cameraHeight = systemInfo.windowHeight - 160;
},
methods: {
errorCamera(e) {
const that = this;
uni.getSetting({
success(res) {
if (!res.authSetting['scope.camera']) {
uni.showModal({
title: '提示',
content: '请开启摄像头权限,否则无法拍照',
confirmText: '去开启',
success(res) {
if (res.confirm) {
uni.openSetting({
success(res) {
if (res.authSetting['scope.camera']) {
uni.navigateBack({
delta: 1
});
} else {
uni.navigateBack({
delta: 1
});
}
}
});
} else if (res.cancel) {
uni.navigateBack({
delta: 1
});
}
}
});
}
}
});
},
// 拍照
takePhoto() {
uni.showLoading({
title: '拍摄中'
});
this.cameraContext.takePhoto({
quality: 'normal',
success: (res) => {
console.log('拍摄照片', res);
let idPhoto = res.tempImagePath;
this.loadTempImagePath(idPhoto);
uni.showToast({
title: '拍照成功',
icon: 'none',
duration: 1200
});
},
fail: (err) => {
uni.showToast({
title: '拍照失败,请检查系统是否授权',
icon: 'none',
duration: 1200
});
}
});
},
//rpx转px
rpx2px(rpx) {
const screenWidth = uni.getSystemInfoSync().screenWidth;
return (screenWidth * Number.parseInt(rpx)) / 750;
},
loadTempImagePath(url) {
let { windowWidth, windowHeight } = uni.getSystemInfoSync();
const camera = uni.createSelectorQuery().select('#myCamera'); // 获取camera组件
camera
.boundingClientRect((data) => {
const x = data.left; // 取景框左上角的x坐标
const y = data.top; // 取景框左上角的y坐标
const width = data.width; // 取景框的宽度
const height = data.height + 120; // 取景框的高度
console.log(x, y, width, height, 'x, y, width, height');
let testc = uni.createCanvasContext('image-canvas');
testc.drawImage(url, 0, 0, windowWidth, windowHeight);
testc.draw(false, () => {
uni.canvasToTempFilePath({
x: x, //设置图片x轴起始点
y: y, //设置图片y轴起始点
width: width,
height: height,
canvasId: 'image-canvas',
fileType: 'jpg',
quality: 1,
complete: (res2) => {
console.log(res2.tempFilePath, 'res2.tempFilePath88');
this.chosePhoto(res2.tempFilePath);
}
});
});
})
.exec();
},
// 从相册选取
chooseImage() {
uni.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album'],
success: (res) => {
let idPhoto = res.tempFilePaths[0];
this.chosePhoto(idPhoto);
},
fail: (err) => {}
});
},
//反转
switchBtn() {
if (this.devicePosition == 'front') {
this.devicePosition = 'back';
} else {
this.devicePosition = 'front';
}
},
// 选择图片跳转
chosePhoto(item) {
console.log(item, this.photoType, '拍摄完成');
if (this.photoType == 'idCardCopy' || this.photoType == 'bankCardPicFront') {
// 身份证正面 银行卡正面
this.ocrCard(item);
} else if (this.photoType == 'idCardNational' || this.photoType == 'bankCardPicBack') {
// 身份证反面 银行卡反面
this.uploadCard(item);
}
},
// 身份证正面/银行卡 ocr识别
ocrCard(item) {
uni.uploadFile({
url: this.photoType == 'idCardCopy' ? getApp().globalData.globalOcrCardUrl : getApp().globalData.globalOcrBankUrl,
filePath: item,
header: {
'Blade-Auth': 'bearer ' + this.tokens,
'Tenant-Id': '000000',
'Blade-Requested-With': 'BladeHttpRequest'
},
name: 'file',
complete: (res) => {
console.log('res', JSON.parse(res.data));
let link = JSON.parse(res.data);
if (link.code == 200) {
if (this.photoType == 'idCardCopy') {
uni.$emit('onOcrCard', link);
} else {
uni.$emit('onOcrBank', link);
}
uni.navigateBack({
delta: 1
});
} else {
uni.showToast({
title: link.msg,
icon: 'none'
});
}
}
});
},
// 身份证反面/银行卡反面上传
uploadCard(item) {
uni.uploadFile({
url: getApp().globalData.uploadUrl,
filePath: item,
name: 'file',
header: {
'Blade-Auth': 'bearer ' + this.tokens,
'Tenant-Id': '000000',
'Blade-Requested-With': 'BladeHttpRequest'
},
success: (res) => {
let data = JSON.parse(res.data);
if (this.photoType == 'idCardNational') {
uni.$emit('onCard', data);
} else {
uni.$emit('onBank', data);
}
uni.navigateBack({
delta: 1
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.top-box {
height: 200rpx;
background-color: #000;
}
.camera-box {
display: flex;
align-items: center;
justify-content: center;
// flex-direction: column;
}
.camera-con {
width: 520rpx;
height: 100%;
}
.camera-bgcolor {
// width: 66%;
width: 520rpx;
height: 100%;
}
.center {
width: 100%;
height: 750rpx;
display: flex;
align-items: center;
justify-content: center;
}
.center-top {
width: 100%;
height: calc((100% - 750rpx) / 2);
background-color: rgba(248, 248, 248, 0.6);
}
.center-bottom {
width: 100%;
height: calc((100% - 750rpx) / 2);
background-color: rgba(248, 248, 248, 0.6);
}
.bottom {
width: 100%;
background-color: #000;
}
.wrap {
display: flex;
align-items: center;
justify-content: space-between;
height: 320rpx;
padding: 0 73rpx;
}
.take-box {
width: 131rpx;
height: 131rpx;
}
.bottom-box {
font-size: 36rpx;
color: #fff;
}
.controls {
display: flex;
align-items: center;
justify-content: center;
// flex-direction: column;
}
.controls1-bgcolor {
list-style: none;
padding: 0;
margin: 0;
// width: 22%;
width: calc((100% - 522rpx) / 2);
height: 100%;
background-color: rgba(248, 248, 248, 0.6);
}
.camera-bgcolor {
// width: 66%;
width: 520rpx;
height: 100%;
}
.center {
width: 100%;
height: 750rpx;
display: flex;
align-items: center;
justify-content: center;
}
.center-top {
width: 100%;
height: calc((100% - 750rpx) / 2);
background-color: rgba(248, 248, 248, 0.6);
}
.center-bottom {
width: 100%;
height: calc((100% - 750rpx) / 2);
background-color: rgba(248, 248, 248, 0.6);
}
.cover_img {
width: 520rpx;
}
.controls3-bgcolor {
list-style: none;
padding: 0;
margin: 0;
width: calc((100% - 520rpx) / 2);
height: 100%;
background-color: rgba(248, 248, 248, 0.6);
}
.cop {
width: 100%;
height: 100vh;
}
</style>