当前位置: 首页 > news >正文

uniapp小程序ocr-navigator身份证拍照上传替换方案

拍照上传身份证

原ocr代码(官方已废弃,无法使用)

<!--* @Date: 2024-02-22 18:53:33* @LastEditTime: 2025-07-29 13:49:25* @Description: 上传身份证
-->
<template><view class="wrap"><image class="bg-img" :src="TOP_BG_PNG" mode="widthFix" /><view class="main-content"><!-- 1-1.验证和识别通过,提示“验证通过”,并覆盖页面的身份证信息缓存(照片信息、格式化信息)1-2.验证不通过,报错“验证失败,请保证照片的清晰重新上传” --><view class="upload-wrap box-shadow"><view class="upload-label"><view class="label-title">头像面</view><view class="label-subtitle">拍摄或上传</view></view><view class="ocr-area"><ocr-navigator certificate-type="idCard" :opposite="false" @onSuccess="handleSuccessTop"><view class="upload-area"><view class="angle-wrap"><view class="angle top-left" /><view class="angle top-right" /><view class="angle bottom-right" /><view class="angle bottom-left" /></view><!-- 微信OCR --><view v-if="!viewCertImgUrl" class="inner-area" @click="handleUploadClick"><view class="upload-icon cross" /><view class="upload-text">拍照或上传身份证头像面</view></view><!-- 身份证照片 --><image v-else class="cert-image" :src="viewCertImgUrl" /></view></ocr-navigator></view></view><view v-if="!isInputShow && certNoLimit" class="forget-text" @click="showInput">忘记带身份证?</view><view v-else-if="isInputShow && certNoLimit" class="id-card-input-wrap box-shadow"><view class="input-label">请输入身份证号</view><view class="input-wrap"><inputtype="text"focusplaceholder="请输入身份证号"placeholder-class="input-placeholder"class="input input-id-card":disabled="ifOCR":value="idNumber"@input="handleInput"/></view></view></view><view class="button-wrap safe-padding-bottom"><view class="button button-primary" :class="{ disabled: isDisabled }" @click="onConfirm">提交值机</view></view><!-- 登录弹框 --><popup-login ref="popupLoginRef" /></view>
</template><script setup lang="ts">
import config from '@/../config/config';
import { checkIn, getServeOrderDetail } from '@/services/api-order';
import { subscribeMessage } from '@/utils/BusinessUtils';
import { getCheckInStorage } from '@/utils/Storage';
import { uploadFile } from '@/utils/UpLoadUtils';
import { computed, onMounted, onUnmounted, ref, toRaw } from 'vue';
import { useStore } from 'vuex';
import { goTabBarPage, goFlyGuidePage } from '@/utils/goPage';
const TOP_BG_PNG = `${config.assetPath}/images/fly/guide-bg.png`;const store = useStore();
let certNoLimit = store?.state?.configStore?.globalConfig?.certNoLimit !== 'APP_CONTEXT_CERT_NO_LIMIT_OFF'; // APP_CONTEXT_CERT_NO_LIMIT_OFF 隐藏证件号,APP_CONTEXT_CERT_NO_LIMIT_ON 不隐藏证件号
let isInputShow = ref(false);
let idNumber = ref();
let oCRInfo = ref({});
let viewCertImgUrl = ref('');
let serviceOrderInfo = ref({});
let serverOrderId = ref('');
let ifOCR = ref(false);
const isDisabled = computed(() => {return !oCRInfo.value?.certNo && !idNumber.value;
});const handleUploadClick = () => {// console.log('点击了上传按钮');
};const handleSuccessTop = async (e) => {const info = e.detail;if (!info?.id?.text) {uni.showToast({title: '验证失败,请保证照片的清晰重新上传',icon: 'none',});return;}let certImg;uploadFile({tempFilePath: info?.image_path,moduleName: 'certImg',}).then((res) => {certImg = res;viewCertImgUrl.value = info?.image_path;oCRInfo.value = {certImg,name: info?.name?.text,certNo: info?.id?.text,sex: info?.gender?.text === '男' ? 1 : info?.gender?.text === '女' ? 2 : 0,birthday: info?.birth?.text,nation: info?.nationality?.text,address: info?.address?.text,};idNumber.value = info?.id?.text;ifOCR.value = true;store.dispatch('setCertInfo', { ...toRaw(oCRInfo.value) });uni.showToast({title: '验证通过',icon: 'success',});}).catch((error) => {uni.showToast({title: error || '验证失败,请保证照片的清晰重新上传',icon: 'none',});});
};/** 身份证号输入 */
const handleInput = (event) => {if (isInputShow.value) {const { value } = event.detail;idNumber.value = value;store.dispatch('setCertInfoCerNo', idNumber.value);}
};/** 展示文本输入框 */
const showInput = () => {isInputShow.value = true;
};
let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
/** 提交值机 */
const onConfirm = async () => {const checkInInfo = await getCheckInStorage();if (!reg.test(checkInInfo?.certInfo?.certNo)) {uni.showToast({title: '请输入正确的身份证号',icon: 'none',});return;}const res = await checkIn({serverOrderId: checkInInfo?.serverOrderId,inviteTicket: checkInInfo?.inviteTicket,checkCode: checkInInfo?.checkCode,noticeSign: checkInInfo?.noticeSign,...checkInInfo?.certInfo,});const config = store?.state?.configStore?.globalConfig;const tempIds = [config.orderCompleteTemplateId];await subscribeMessage(tempIds).catch((err) => {uni.showToast({title: '订阅消息失败',icon: 'none',});}).finally(() => {//是否有值机完成图片/值机完成视频if (serviceOrderInfo.value?.checkedInImages?.length || serviceOrderInfo.value?.checkedInVideos?.length) {const type = 'CHECKIN';goFlyGuidePage(type, serverOrderId.value);} else {goTabBarPage('fly');}});
};const loadCheckInGuide = async () => {const { data } = await getServeOrderDetail({ id: serverOrderId.value });serviceOrderInfo.value = data || {};
};
const init = async () => {const info = await getCheckInStorage();serverOrderId.value = info?.serverOrderId;loadCheckInGuide();
};
onMounted(() => {init();
});onUnmounted(() => {//清除值机信息store.dispatch('setCheckInInfo', null);
});
</script><style lang="scss">
@import './index.scss';
</style>

方案一:使用chooseMedia上传身份证安卓机只需要确认一次才能上传(推荐)

<!--* @Date: 2024-02-22 18:53:33* @LastEditTime: 2025-07-29 13:49:25* @Description: 上传身份证
-->
<template><view class="wrap"><image class="bg-img" :src="TOP_BG_PNG" mode="widthFix" /><view class="main-content"><!-- 1-1.验证和识别通过,提示“验证通过”,并覆盖页面的身份证信息缓存(照片信息、格式化信息)1-2.验证不通过,报错“验证失败,请保证照片的清晰重新上传” --><view class="upload-wrap box-shadow"><view class="upload-label"><view class="label-title">头像面</view><view class="label-subtitle">拍摄或上传</view></view><view class="ocr-area"><view class="upload-area"><view class="angle-wrap"><view class="angle top-left" /><view class="angle top-right" /><view class="angle bottom-right" /><view class="angle bottom-left" /></view><!-- 微信OCR --><view v-if="!viewCertImgUrl" class="inner-area" @click="chooseImage"><view class="upload-icon cross" /><view class="upload-text">拍照或上传身份证头像面</view></view><!-- 身份证照片 --><image v-else class="cert-image" :src="viewCertImgUrl" /></view></view></view><view v-if="!isInputShow && certNoLimit" class="forget-text" @click="showInput">忘记带身份证?</view><view v-else-if="isInputShow && certNoLimit" class="id-card-input-wrap box-shadow"><view class="input-label">请输入身份证号</view><view class="input-wrap"><inputtype="text"focusplaceholder="请输入身份证号"placeholder-class="input-placeholder"class="input input-id-card":disabled="ifOCR":value="idNumber"@input="handleInput"/></view></view></view><view class="button-wrap safe-padding-bottom"><view class="button button-primary" :class="{ disabled: isDisabled }" @click="onConfirm">提交值机</view></view><!-- 登录弹框 --><popup-login ref="popupLoginRef" /></view>
</template><script setup lang="ts">
import config from '@/../config/config';
import { checkIn, getServeOrderDetail,idCardOCR } from '@/services/api-order';
import { subscribeMessage } from '@/utils/BusinessUtils';
import { getCheckInStorage } from '@/utils/Storage';
import { uploadFile } from '@/utils/UpLoadUtils';
import { computed, onMounted, onUnmounted, ref, toRaw } from 'vue';
import { useStore } from 'vuex';
import { goTabBarPage, goFlyGuidePage } from '@/utils/goPage';
const TOP_BG_PNG = `${config.assetPath}/images/fly/guide-bg.png`;const store = useStore();
let certNoLimit = store?.state?.configStore?.globalConfig?.certNoLimit !== 'APP_CONTEXT_CERT_NO_LIMIT_OFF'; // APP_CONTEXT_CERT_NO_LIMIT_OFF 隐藏证件号,APP_CONTEXT_CERT_NO_LIMIT_ON 不隐藏证件号
let isInputShow = ref(false);
let idNumber = ref();
let oCRInfo = ref({});
let viewCertImgUrl = ref('');
let serviceOrderInfo = ref({});
let serverOrderId = ref('');
let ifOCR = ref(false);
const isDisabled = computed(() => {return !oCRInfo.value?.certNo && !idNumber.value;
});const chooseImage = async () => {uni.chooseMedia({count: 1,sizeType: ['original', 'compressed'],mediaType: ['image'],sourceType: ['album', 'camera'],success: async (res) => {const tempFilePath = res.tempFiles[0].tempFilePath;viewCertImgUrl.value = tempFilePath; // 预览本地图片try {// 1. 上传图片到自己的服务器(示例:调用项目的上传方法)const uploadRes = await uploadFile({tempFilePath,moduleName: 'certImg',});const imageUrl = uploadRes; // 服务器返回的图片URL// 2. 调用后端OCR接口(需自行实现后端)const ocrRes = await idCardOCR({imageUrl,cardSide: 'FRONT', //FRONT:身份证有照片的一面(人像面),BACK:身份证有国徽的一面(国徽面),});// 3. 处理OCR结果(与原逻辑对齐)const info = ocrRes.data;oCRInfo.value = {certImg: imageUrl,name: info.name,certNo: info.idNum,sex: info?.sex === '男' ? 1 : info?.sex === '女' ? 2 : 0,birthday: info.birth,nation: info.nation,address: info.address,};idNumber.value = info.idNum;ifOCR.value = true;store.dispatch('setCertInfo', { ...toRaw(oCRInfo.value) });uni.showToast({title: '验证通过',icon: 'success',});} catch (error) {if (error?.retcode !== 0) {await nextTick(() => {oCRInfo.value = ''; //清空信息,置灰按钮idNumber.value = ''; //清空信息,置灰按钮viewCertImgUrl.value = ''; // 清空预览图});}}},fail: (err) => {uni.showToast({title: '选择图片失败,请重试',icon: 'none',});},});
};/** 身份证号输入 */
const handleInput = (event) => {if (isInputShow.value) {const { value } = event.detail;idNumber.value = value;store.dispatch('setCertInfoCerNo', idNumber.value);}
};/** 展示文本输入框 */
const showInput = () => {isInputShow.value = true;
};
let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
/** 提交值机 */
const onConfirm = async () => {const checkInInfo = await getCheckInStorage();if (!reg.test(checkInInfo?.certInfo?.certNo)) {uni.showToast({title: '请输入正确的身份证号',icon: 'none',});return;}const res = await checkIn({serverOrderId: checkInInfo?.serverOrderId,inviteTicket: checkInInfo?.inviteTicket,checkCode: checkInInfo?.checkCode,noticeSign: checkInInfo?.noticeSign,...checkInInfo?.certInfo,});const config = store?.state?.configStore?.globalConfig;const tempIds = [config.orderCompleteTemplateId];await subscribeMessage(tempIds).catch((err) => {uni.showToast({title: '订阅消息失败',icon: 'none',});}).finally(() => {//是否有值机完成图片/值机完成视频if (serviceOrderInfo.value?.checkedInImages?.length || serviceOrderInfo.value?.checkedInVideos?.length) {const type = 'CHECKIN';goFlyGuidePage(type, serverOrderId.value);} else {goTabBarPage('fly');}});
};const loadCheckInGuide = async () => {const { data } = await getServeOrderDetail({ id: serverOrderId.value });serviceOrderInfo.value = data || {};
};
const init = async () => {const info = await getCheckInStorage();serverOrderId.value = info?.serverOrderId;loadCheckInGuide();
};
onMounted(() => {init();
});onUnmounted(() => {//清除值机信息store.dispatch('setCheckInInfo', null);
});
</script><style lang="scss">
@import './index.scss';
</style>

方案二:使用chooseImage上传身份证安卓机需要两次确认才能上传

<!--* @Date: 2024-02-22 18:53:33* @LastEditTime: 2025-07-29 13:49:25* @Description: 上传身份证
-->
<template><view class="wrap"><image class="bg-img" :src="TOP_BG_PNG" mode="widthFix" /><view class="main-content"><!-- 1-1.验证和识别通过,提示“验证通过”,并覆盖页面的身份证信息缓存(照片信息、格式化信息)1-2.验证不通过,报错“验证失败,请保证照片的清晰重新上传” --><view class="upload-wrap box-shadow"><view class="upload-label"><view class="label-title">头像面</view><view class="label-subtitle">拍摄或上传</view></view><view class="ocr-area"><view class="upload-area"><view class="angle-wrap"><view class="angle top-left" /><view class="angle top-right" /><view class="angle bottom-right" /><view class="angle bottom-left" /></view><!-- 微信OCR --><view v-if="!viewCertImgUrl" class="inner-area" @click="chooseImage"><view class="upload-icon cross" /><view class="upload-text">拍照或上传身份证头像面</view></view><!-- 身份证照片 --><image v-else class="cert-image" :src="viewCertImgUrl" /></view></view></view><view v-if="!isInputShow && certNoLimit" class="forget-text" @click="showInput">忘记带身份证?</view><view v-else-if="isInputShow && certNoLimit" class="id-card-input-wrap box-shadow"><view class="input-label">请输入身份证号</view><view class="input-wrap"><inputtype="text"focusplaceholder="请输入身份证号"placeholder-class="input-placeholder"class="input input-id-card":disabled="ifOCR":value="idNumber"@input="handleInput"/></view></view></view><view class="button-wrap safe-padding-bottom"><view class="button button-primary" :class="{ disabled: isDisabled }" @click="onConfirm">提交值机</view></view><!-- 登录弹框 --><popup-login ref="popupLoginRef" /></view>
</template><script setup lang="ts">
import config from '@/../config/config';
import { checkIn, getServeOrderDetail,idCardOCR } from '@/services/api-order';
import { subscribeMessage } from '@/utils/BusinessUtils';
import { getCheckInStorage } from '@/utils/Storage';
import { uploadFile } from '@/utils/UpLoadUtils';
import { computed, onMounted, onUnmounted, ref, toRaw } from 'vue';
import { useStore } from 'vuex';
import { goTabBarPage, goFlyGuidePage } from '@/utils/goPage';
const TOP_BG_PNG = `${config.assetPath}/images/fly/guide-bg.png`;const store = useStore();
let certNoLimit = store?.state?.configStore?.globalConfig?.certNoLimit !== 'APP_CONTEXT_CERT_NO_LIMIT_OFF'; // APP_CONTEXT_CERT_NO_LIMIT_OFF 隐藏证件号,APP_CONTEXT_CERT_NO_LIMIT_ON 不隐藏证件号
let isInputShow = ref(false);
let idNumber = ref();
let oCRInfo = ref({});
let viewCertImgUrl = ref('');
let serviceOrderInfo = ref({});
let serverOrderId = ref('');
let ifOCR = ref(false);
const isDisabled = computed(() => {return !oCRInfo.value?.certNo && !idNumber.value;
});const chooseImage = async () => {uni.chooseImage({count: 1,sizeType: ['original', 'compressed'],sourceType: ['album', 'camera'],success: async (res) => {const tempFilePath = res.tempFilePaths[0];viewCertImgUrl.value = tempFilePath; // 预览本地图片try {// 1. 上传图片到自己的服务器(示例:调用项目的上传方法)const uploadRes = await uploadFile({tempFilePath,moduleName: 'certImg',});const imageUrl = uploadRes; // 服务器返回的图片URL// 2. 调用后端OCR接口(需自行实现后端)const ocrRes = await idCardOCR({imageUrl,cardSide: 'FRONT', //FRONT:身份证有照片的一面(人像面),BACK:身份证有国徽的一面(国徽面),});// 3. 处理OCR结果(与原逻辑对齐)const info = ocrRes.data;oCRInfo.value = {certImg: imageUrl,name: info.name,certNo: info.idNum,sex: info?.sex === '男' ? 1 : info?.sex === '女' ? 2 : 0,birthday: info.birth,nation: info.nation,address: info.address,};idNumber.value = info.idNum;ifOCR.value = true;store.dispatch('setCertInfo', { ...toRaw(oCRInfo.value) });uni.showToast({title: '验证通过',icon: 'success',});} catch (error) {if (error?.retcode !== 0) {await nextTick(() => {oCRInfo.value = ''; //清空信息,置灰按钮idNumber.value = ''; //清空信息,置灰按钮viewCertImgUrl.value = ''; // 清空预览图});}}},fail: (err) => {uni.showToast({title: '选择图片失败,请重试',icon: 'none',});},});
};/** 身份证号输入 */
const handleInput = (event) => {if (isInputShow.value) {const { value } = event.detail;idNumber.value = value;store.dispatch('setCertInfoCerNo', idNumber.value);}
};/** 展示文本输入框 */
const showInput = () => {isInputShow.value = true;
};
let reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
/** 提交值机 */
const onConfirm = async () => {const checkInInfo = await getCheckInStorage();if (!reg.test(checkInInfo?.certInfo?.certNo)) {uni.showToast({title: '请输入正确的身份证号',icon: 'none',});return;}const res = await checkIn({serverOrderId: checkInInfo?.serverOrderId,inviteTicket: checkInInfo?.inviteTicket,checkCode: checkInInfo?.checkCode,noticeSign: checkInInfo?.noticeSign,...checkInInfo?.certInfo,});const config = store?.state?.configStore?.globalConfig;const tempIds = [config.orderCompleteTemplateId];await subscribeMessage(tempIds).catch((err) => {uni.showToast({title: '订阅消息失败',icon: 'none',});}).finally(() => {//是否有值机完成图片/值机完成视频if (serviceOrderInfo.value?.checkedInImages?.length || serviceOrderInfo.value?.checkedInVideos?.length) {const type = 'CHECKIN';goFlyGuidePage(type, serverOrderId.value);} else {goTabBarPage('fly');}});
};const loadCheckInGuide = async () => {const { data } = await getServeOrderDetail({ id: serverOrderId.value });serviceOrderInfo.value = data || {};
};
const init = async () => {const info = await getCheckInStorage();serverOrderId.value = info?.serverOrderId;loadCheckInGuide();
};
onMounted(() => {init();
});onUnmounted(() => {//清除值机信息store.dispatch('setCheckInInfo', null);
});
</script><style lang="scss">
@import './index.scss';
</style>

http://www.lryc.cn/news/621882.html

相关文章:

  • 解决在uniapp真机运行上i18n变量获取不到问题
  • USB ADB 简介
  • 为什么游戏会出现“卡顿”:`clock.tick()` v.s. `clock.get_fps()`
  • 【Cuda 编程思想】LinearQaunt-分块量化矩阵乘法计算过程
  • 25. 移动端-uni-app
  • 【URP】[光栅阶段][光栅插值]Unity透视校正插值
  • 2025年最新政策下,劳务报酬的增值税应该如何计算?
  • MqSQL中的《快照读》和《当前读》
  • Prometheus 监控 Kubernetes Cluster 最新极简教程
  • [论文笔记] WiscKey: Separating Keys from Values in SSD-Conscious Storage
  • DeepSeek-V2:一种强大、经济且高效的混合专家语言模型
  • 在 macOS 上顺利安装 lapsolver
  • 从根本上解决MAC权限问题(关闭sip)
  • vue3 wangeditor5 编辑器,使用方法
  • demo 通讯录 + 城市选择器 (字母索引左右联动 ListItemGroup+AlphabetIndexer)笔记
  • 分布式锁:从理论到实战的深度指南
  • 【机器人-基础知识】ROS常见功能架构
  • 微软自曝Win 11严重漏洞:可导致全盘数据丢失
  • Kafka生产者原理深度解析
  • 从ChatGPT到智能助手:Agent智能体如何颠覆AI应用
  • Python爬虫反爬检测失效问题的代理池轮换与请求头伪装实战方案
  • 【121页PPT】智慧方案智慧综合体智能化设计方案(附下载方式)
  • java + html 图片点击文字验证码
  • 结构体(Struct)、枚举(Enum)的使用
  • 电源测试系统ATECLOUD-Power,让您告别电源模块测试痛点!
  • MLOps已死,AgenticOps当立:构建新一代AI智能体的全新工程范式
  • 【Redis】Redis典型应用——分布式锁
  • 【部署K8S集群】 1、安装前环境准备配置
  • k8s1.28.2集群部署istioctl的1.20.0版本(X86架构)
  • Mac(一)常用的快捷键整理