add id card ocr api

This commit is contained in:
weichengwu 2025-11-26 22:46:29 +08:00
parent 167916057e
commit faba34294a
3 changed files with 171 additions and 123 deletions

View File

@ -93,26 +93,26 @@
</button> </button>
</div> </div>
<div v-if="formData.qrCode"> <div v-if="formData.qrCode">
<div> <div>
<h3 class="text-base text-gray-800 mb-1 font-bold">您已成功领取喜礼</h3> <h3 class="text-base text-gray-800 mb-1 font-bold">您已成功领取喜礼</h3>
<span class="text-sm text-gray-600">下面是您的专属核销二维码请在领取站点出示给工作人员扫码核销</span> <span class="text-sm text-gray-600">下面是您的专属核销二维码请在领取站点出示给工作人员扫码核销</span>
</div> </div>
<div class="mt-4 flex flex-col items-center"> <div class="mt-4 flex flex-col items-center">
<div class="flex justify-center items-center relative h-[210px] w-[210px]" ref="qrCodeWrapper"> <div class="flex justify-center items-center relative h-[210px] w-[210px]" ref="qrCodeWrapper">
<div v-if="formData.status == 1" <div v-if="formData.status == 1"
class="h-[210px] w-[210px] bg-white/90 rounded-md flex justify-center items-center absolute z-10"> class="h-[210px] w-[210px] bg-white/90 rounded-md flex justify-center items-center absolute z-10">
<span class="text-[#E8424D] text-lg font-bold">二维码已核销</span> <span class="text-[#E8424D] text-lg font-bold">二维码已核销</span>
</div> </div>
<qrcode-vue class="absolute opacity-0 pointer-events-none" :value="formData.qrCode" :size="200" <qrcode-vue class="absolute opacity-0 pointer-events-none" :value="formData.qrCode" :size="200"
level="H" render-as="canvas" /> level="H" render-as="canvas" />
<img v-if="qrImageSrc" :src="qrImageSrc" alt="核销二维码" <img v-if="qrImageSrc" :src="qrImageSrc" alt="核销二维码"
class="h-[210px] w-[210px] rounded-md shadow-[0_10px_24px_rgba(232,66,77,0.18)] bg-white object-contain" /> class="h-[210px] w-[210px] rounded-md shadow-[0_10px_24px_rgba(232,66,77,0.18)] bg-white object-contain" />
</div> </div>
<div class="mt-3 text-xs text-gray-500">长按二维码保存至相册</div> <div class="mt-3 text-xs text-gray-500">长按二维码保存至相册</div>
</div> </div>
</div> </div>
</div> </div>
<div v-if="activityInfo.status === 2"> <div v-if="activityInfo.status === 2">
<!-- 活动结束状态 --> <!-- 活动结束状态 -->
@ -204,32 +204,32 @@
<script setup lang="ts"> <script setup lang="ts">
import apiService from '../../services/apiService' import apiService from '../../services/apiService'
import { ref, onMounted, nextTick } from 'vue' import { ref, onMounted, nextTick } from 'vue'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import QrcodeVue from 'qrcode.vue' import QrcodeVue from 'qrcode.vue'
import { showLoading, hideLoading } from '../../components/loading' import { showLoading, hideLoading } from '../../components/loading'
import { showDialog } from 'vant'; import { showDialog } from 'vant';
import 'vant/es/dialog/style'; import 'vant/es/dialog/style';
const ocrUploadId = ref<HTMLInputElement>(); const ocrUploadId = ref<HTMLInputElement>();
const qrCodeWrapper = ref<HTMLDivElement | null>(null); const qrCodeWrapper = ref<HTMLDivElement | null>(null);
const qrImageSrc = ref(''); const qrImageSrc = ref('');
const syncQrImage = () => { const syncQrImage = () => {
nextTick(() => { nextTick(() => {
const canvas = qrCodeWrapper.value?.querySelector('canvas') as HTMLCanvasElement | null; const canvas = qrCodeWrapper.value?.querySelector('canvas') as HTMLCanvasElement | null;
if (!canvas) { if (!canvas) {
qrImageSrc.value = ''; qrImageSrc.value = '';
return; return;
} }
try { try {
qrImageSrc.value = canvas.toDataURL('image/png'); qrImageSrc.value = canvas.toDataURL('image/png');
} catch (error) { } catch (error) {
console.error('生成二维码图片失败:', error); console.error('生成二维码图片失败:', error);
qrImageSrc.value = ''; qrImageSrc.value = '';
} }
}); });
}; };
// //
const formData = ref({ const formData = ref({
@ -296,15 +296,15 @@ const clearPhone = () => {
formData.value.marriageNo = ''; formData.value.marriageNo = '';
formData.value.husbandName = ''; formData.value.husbandName = '';
formData.value.wifeName = ''; formData.value.wifeName = '';
formData.value.registerDate = ''; formData.value.registerDate = '';
formData.value.qrCode = ''; formData.value.qrCode = '';
formData.value.status = 0; formData.value.status = 0;
qrImageSrc.value = ''; qrImageSrc.value = '';
countdown.value = 0; countdown.value = 0;
if (countdownTimer) { if (countdownTimer) {
clearInterval(countdownTimer); clearInterval(countdownTimer);
countdownTimer = null; countdownTimer = null;
} }
localStorage.removeItem('userAs'); localStorage.removeItem('userAs');
if (ocrUploadId.value) ocrUploadId.value.value = ''; if (ocrUploadId.value) ocrUploadId.value.value = '';
} }
@ -373,34 +373,34 @@ const verifyCode = (flag: any) => {
mobile: formData.value.phone, mobile: formData.value.phone,
smsCode: smsCode, smsCode: smsCode,
type: 3, type: 3,
}).then((res) => { }).then((res) => {
localStorage.setItem('userAs', JSON.stringify({ localStorage.setItem('userAs', JSON.stringify({
phone: formData.value.phone, phone: formData.value.phone,
smsCode: formData.value.smsCode, smsCode: formData.value.smsCode,
})); }));
formData.value.verifyCode = true; formData.value.verifyCode = true;
// //
countdown.value = 0; countdown.value = 0;
// //
if (res?.data?.code) { if (res?.data?.code) {
formData.value = { formData.value = {
...formData.value, ...formData.value,
qrCode: res.data.code, qrCode: res.data.code,
status: res.data.status, status: res.data.status,
} }
syncQrImage(); syncQrImage();
} else { } else {
formData.value = { formData.value = {
...formData.value, ...formData.value,
marriageNo: "", marriageNo: "",
husbandName: "", husbandName: "",
wifeName: "", wifeName: "",
registerDate: "", registerDate: "",
qrCode: "" qrCode: ""
} }
} }
}).catch((error) => { }).catch((error) => {
localStorage.removeItem('userAs'); localStorage.removeItem('userAs');
@ -408,21 +408,21 @@ const verifyCode = (flag: any) => {
flag && showDialog({ flag && showDialog({
message: error.msg || '验证码验证失败,请重试', message: error.msg || '验证码验证失败,请重试',
}); });
formData.value = { formData.value = {
...formData.value, ...formData.value,
smsCode: "", smsCode: "",
marriageNo: "", marriageNo: "",
husbandName: "", husbandName: "",
wifeName: "", wifeName: "",
registerDate: "", registerDate: "",
qrCode: "" qrCode: ""
} }
qrImageSrc.value = ''; qrImageSrc.value = '';
}).finally(() => { }).finally(() => {
hideLoading(); hideLoading();
}) })
} }
// //
function resetMarriageInfo() { function resetMarriageInfo() {
formData.value = { formData.value = {
...formData.value, ...formData.value,
@ -456,7 +456,7 @@ const handleImageChange = () => {
showLoading(); showLoading();
apiService.uploadOcrImage(formFormData).then((response: any) => { apiService.uploadOcrImage(formFormData).then((response: any) => {
apiService.parseOcrInfo({ apiService.marriageParseOcrInfo({
mobile: formData.value.phone, mobile: formData.value.phone,
smsCode: formData.value.smsCode, smsCode: formData.value.smsCode,
uploadId: response.data.uploadId, uploadId: response.data.uploadId,
@ -492,11 +492,11 @@ const handleImageChange = () => {
// //
const submitForm = () => { const submitForm = () => {
if (!formData.value.phone || !formData.value.smsCode) { if (!formData.value.phone || !formData.value.smsCode) {
showDialog({ showDialog({
message: '请完善所有信息', message: '请完善所有信息',
}); });
return return
} }
@ -506,22 +506,22 @@ const submitForm = () => {
receiveName: formData.value.husbandName, receiveName: formData.value.husbandName,
receiveMobile: formData.value.phone, receiveMobile: formData.value.phone,
smsCode: formData.value.smsCode, smsCode: formData.value.smsCode,
}).then((res: any) => { }).then((res: any) => {
formData.value.qrCode = res.data.code; formData.value.qrCode = res.data.code;
syncQrImage(); syncQrImage();
}).catch((error) => { }).catch((error) => {
showDialog({ showDialog({
message: error?.msg || '提交失败,请稍后重试', message: error?.msg || '提交失败,请稍后重试',
}); });
}).finally(() => { }).finally(() => {
hideLoading(); hideLoading();
}) })
} }
// //
import { onUnmounted } from 'vue' import { onUnmounted } from 'vue'
onUnmounted(() => { onUnmounted(() => {
if (countdownTimer) { if (countdownTimer) {
clearInterval(countdownTimer) clearInterval(countdownTimer)
} }
}) })

View File

@ -13,14 +13,53 @@ export interface OcrUploadResponse {
uploadId: string uploadId: string
} }
export interface OcrParseResponse { export interface IdCardOcrParseResponse {
raw: string raw: string
words: string[] words: string[]
parsed: { parsed: {
marriageNo: string birthday?: string
husbandName: string id_number: string
wifeName: string address: string
registerDate: string image_status:
| 'normal'
| 'reversed_side'
| 'non_idcard'
| 'blurred'
| 'other_type_card'
| 'over_exposure'
| 'over_dark'
| 'unknown'
risk_type:
| 'normal'
| 'copy'
| 'scan'
| 'temporary'
| 'screen'
| 'screenshot'
| 'unknown'
gender: '男' | '女' | '未知' | null | undefined
name?: string
nationality?: string
}
}
export interface MarriageOcrParseResponse {
raw: string
words: string[]
parsed: {
marriageNo?: string
registerDate?: string
certificateHolder?: string
wifeId?: string
wifeName?: string
wifeBirthDate?: string
wifeNationality?: string
wifeGender?: '男' | '女' | '未知' | null | undefined
husbandId?: string
husbandName?: string
husbandGender?: '男' | '女' | '未知' | null | undefined
husbandBirthDate?: string
husbandNationality?: string
} }
} }
@ -86,12 +125,21 @@ export const apiService = {
}, },
// OCR识别并返回证件信息 // OCR识别并返回证件信息
parseOcrInfo(data: { marriageParseOcrInfo(data: {
mobile: string mobile: string
smsCode: string smsCode: string
uploadId: string uploadId: string
}) { }) {
return request.post<OcrParseResponse>('/marriage/ocr/parse', data) return request.post<MarriageOcrParseResponse>('/marriage/ocr/parse', data)
},
// OCR 识别身份证
idCardParseOcrInfo(data: {
mobile: string
smsCode: string
uploadId: string
}) {
return request.post<IdCardOcrParseResponse>('/marriage/ocr/parseIdCard', data)
}, },
// 领取流程相关接口 // 领取流程相关接口

View File

@ -13,7 +13,7 @@ export interface OcrUploadResponse {
uploadId: string uploadId: string
} }
export interface OcrParseResponse { export interface MarriageOcrParseResponse {
raw: string raw: string
words: string[] words: string[]
parsed: { parsed: {
@ -70,7 +70,7 @@ export interface ApiService {
sendSms(data: CommSmsDTO): Promise<any> sendSms(data: CommSmsDTO): Promise<any>
// OCR识别并返回证件信息 // OCR识别并返回证件信息
parseOcrInfo(data: { marriageParseOcrInfo(data: {
mobile: string mobile: string
smsCode: string smsCode: string
uploadId: string uploadId: string