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

w-笔记:uni-app的H5平台和非H5平台的拍照识别功能:

uni-app的H5平台和非H5平台的拍照识别功能:

<template><view class="humanVehicleBinding"><view v-if="warn" class="shadow"></view><view class="header"><uni-nav-bar left-icon="left" shadow :border="false" height="44" title="人车绑定" @clickLeft="back"></uni-nav-bar></view><view class="body"><uni-forms :modelValue="formData" label-position="top"><uni-forms-item label="使用车辆"><view class="useCar"><template v-if="dataReversion.code"><text class="textValue">{{dataReversion.code}}</text></template><template v-else><w-select v-model="vehicleListValue" :list="vehicleList" valueName="text" keyName="value":filterable="true" @change="vehicleValueChange" /></template><uni-icons type="scan" size="30" class="scan" @click="takePhoto"></uni-icons></view></uni-forms-item><uni-forms-item label="车辆类型" class="disable"><text class="textValue">{{dataReversion.vehicleType ? dataReversion.vehicleType : "--:--"}}</text></uni-forms-item><uni-forms-item label="使用人员" class="disable"><textclass="textValue">{{dataReversion.loginUserName ? dataReversion.loginUserName : "--:--"}}</text></uni-forms-item><uni-forms-item label="同行人"><view class="companions"><!-- <uni-data-picker :localdata="driverAccountNameList" popup-title="请选择同行人"v-model="dataReversion.driverAccountId" :map="{text:'text',value:'value'}"placeholder="请选择同行人" ref="companionsRef" @change="onchange" class="dataPicker"></uni-data-picker> --><!-- <select  multiple  v-model="dataReversion.driverAccountId"><option value="item.value" v-for="(item,index) in driverAccountNameList" :key="index">{{item.text}}</option></select> --><!-- 输入框用于触发弹出层 --><view class="trigger" @click="togglePopup" >{{ selectedLabels.length > 0 ? selectedLabels.join('、'): '请选择' }}</view><!-- uni-popup 弹出层 --><uni-popup ref="popup" type="bottom"><view class="popup-content"><view :class="isSelected(item) ? 'selected':'unselected'"  v-for="item in driverAccountNameList" :key="item.value" class="checkbox-item" @click="toggleSelection(item)"><text >{{ item.text }}</text></view><!-- <uni-list><uni-list-item v-for="item in driverAccountNameList" :key="item.value" :show-arrow="false"><template #default><view class="checkbox-item" @click="toggleSelection(item)"><text>{{ item.text }}</text><uni-icons v-if="isSelected(item)" type="checkbox-filled" size="18"color="#4CAF50"></uni-icons><uni-icons v-else type="circle" size="18" color="#999"></uni-icons></view></template></uni-list-item></uni-list> --><button @click="confirmSelection">确认</button></view></uni-popup><uni-icons type="forward" size="30" class="scan" @click="openDataPicker"></uni-icons></view></uni-forms-item><uni-forms-item label="使用开始时间" class="disable"><text class="textValue">{{dataReversion.beginTime ? dataReversion.beginTime : "--:--"}}</text></uni-forms-item><uni-forms-item label="使用结束时间" class="disable"><text class="textValue">{{dataReversion.endTime ? dataReversion.endTime : "--:--"}}</text></uni-forms-item></uni-forms><!-- <camera device-position="back" flash="auto" style="width: 100%; height: 100vh"></camera> --></view><view class="bottom"><view class="bottonBox"><button class="endUse" @click="usageEnd">结束使用</button><button class="startUse" @click="useAtOnce">立即使用</button></view></view></view>
</template><script setup>import {onMounted,ref,computed } from "vue";import permision from "@/common/permission.js";import {getVehicleList,getDataReversion,getDataReversion1,getCompanions,postUseAtOnce,postUsageEnd,getRecognize} from '../../../api/work/index.js'import SpeechSynthesisUtil from 'uniapp-text-to-speech';const basicText = ref('您已超速,请减缓速度,注意安全');const tts = new SpeechSynthesisUtil({API_KEY: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiJjeGwiLCJVc2VyTmFtZSI6ImN4bCIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxOTMzNzc2NTc5MDI0OTE3MTI0IiwiUGhvbmUiOiIxNzM0NTM2MTYzMSIsIkdyb3VwSUQiOiIxOTMzNzc2NTc5MDE2NTI4NzczIiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjUtMDYtMTcgMTc6MjM6MzMiLCJUb2tlblR5cGUiOjEsImlzcyI6Im1pbmltYXgifQ.bd8aLiydYgr_m2GhQV5_Di92JkiQSCCN_TPIXmLCKC8gr64ImSWbvJuolAVzGFASzDVer5n21F-cznURRCc04s9ZwRFwVoQNcPMM-A-ChupBU2IJooYiKQgywmgki-ae0f_R7N328N6-62eaDCaVDWa23bhnHIxm7vzl5AP5CY9vwmkQGy4LPPgylhGLcT6RGRS0GYeRuezfs9qQb8L8NmrD4yYDxfJYQ6yZzPETN2FfV1OgsWQf1j0KEIpv0KdgJtUZ0ugaCdNa_pnjDpCzOZWLH1rnIpT0q-86BJGV1aCRxETfq6HZ8BBXvVOHaIJ7vitZt2-JqFu3I6dUpYdhyg",// Minimax API密钥GroupId: '1933776579016528773', // Minimax 组IDMAX_QUEUE_LENGTH: 3, // 可选:音频队列最大长度// 可选:音频生成配置modelConfig: {model: 'speech-02-hd',voice_setting: {"voice_id": "Chinese (Mandarin)_Radio_Host","speed": 0.8,"vol": 1,}},// 其他配置...})const warn = ref(false)const vehicleList = ref([])const vehicleListValue = ref()const dataReversion = ref({"carId": 0,"code": "","simCode": "","vehicleType": "","loginUserId": 0,"loginUserName": "","driverAccountId": [0],"driverAccountName": [""],"bindStatus": 0,"beginTime": "","endTime": ""})const driverAccountNameList = ref([])const selectedCompanion = ref('')onMounted((option) => {getVehicleListValue()getCompanionsValue()getDataReversionValue()})// 当前选中项const selectedValues = ref([])const selectedLabels = computed(() =>selectedValues.value.map(val => {console.log(driverAccountNameList.value)console.log(val,"val")console.log(driverAccountNameList.value.find(opt => opt.value === val))if(driverAccountNameList.value.find(opt => opt.value === val)){return driverAccountNameList.value.find(opt => opt.value === val).text}else{return  ""}}))// popup 控制const popup = ref(null)const togglePopup = () => {popup.value.open()}// 切换选项选中状态const toggleSelection = (item) => {const index = selectedValues.value.indexOf(item.value)if (index === -1) {selectedValues.value.push(item.value)} else {selectedValues.value.splice(index, 1)}console.log(selectedValues.value)}// 检查是否已选中const isSelected = (item) => {return selectedValues.value.includes(item.value)}// 确认选择并关闭弹窗const confirmSelection = () => {popup.value.close()}const getVehicleListValue = async () => {const res = await getVehicleList()if (res && res.data) {vehicleList.value = res.data.map(item => {return {text: item.code,// value: item.id,value: item.simCode,}})}}const getCompanionsValue = async () => {const res = await getCompanions()if (res && res.data) {driverAccountNameList.value = res.data.map(item => {return {text: item.chinaName,value: item.id}})console.log(driverAccountNameList.value, "66666666666");}}const getDataReversionValue = async () => {const res = await getDataReversion()if (res && res.data) {dataReversion.value = res.data// 如果有车牌号,则设置下拉框值if (res.data.code) {vehicleListValue.value = res.data.code}// 如果有同行人数据,需要设置选中状态if (res.data.driverAccountName && res.data.driverAccountName.length > 0) {const selectedName = res.data.driverAccountName[0]selectedValues.value = res.data.driverAccountIdconsole.log("selectedValues.value",selectedLabels.value)// 在下拉列表中找到对应的idconst selectedPerson = driverAccountNameList.value.find(item => item.text === selectedName)console.log("selectedPerson", selectedPerson);if (selectedPerson) {// 设置选中的值为找到的id,这样下拉框会显示为选中状态dataReversion.value.driverAccountId = [selectedPerson.value]dataReversion.value.driverAccountName = [selectedName]}}}}const vehicleValueChange = async (e) => {// if (!vehicleListValue.value) returnconst res = await getDataReversion1(vehicleListValue.value)if (res && res.data) {dataReversion.value.vehicleType = res.data.vehicleTypedataReversion.value.loginUserName = red.data.loginUserName}}const onchange = (e) => {console.log('onchange:', e);if (e.detail.value && e.detail.value.length > 0) {const selectedItem = e.detail.value[0];const text = selectedItem.text; // 申文昊const value = selectedItem.value; // 41// 直接更新 dataReversion 中的数组dataReversion.value.driverAccountId = [value];dataReversion.value.driverAccountName = [text];// 同时更新 loginUserId 和 loginUserNamedataReversion.value.loginUserId = value;dataReversion.value.loginUserName = text;console.log('更新后的 driverAccountId:', dataReversion.value.driverAccountId);console.log('更新后的 driverAccountName:', dataReversion.value.driverAccountName);}};const submitData = ref()const updateData = () => {console.log(selectedValues.value)dataReversion.value.driverAccountId = selectedValues.valuesubmitData.value = {"carId": dataReversion.value.carId,"code": dataReversion.value.code,"simCode": dataReversion.value.simCode,"vehicleType": dataReversion.value.vehicleType,"loginUserId": dataReversion.value.loginUserId,"loginUserName": dataReversion.value.loginUserName,"driverAccountId": dataReversion.value.driverAccountId,"bindStatus": dataReversion.value.bindStatus}}const getCurrentTime = () => {const now = new Date();let nowYear = now.getFullYear();let nowMonth = now.getMonth() + 1;let nowDay = now.getDate();let nowHours = now.getHours();let nowMinutes = now.getMinutes();let nowSeconds = now.getSeconds();nowMonth = nowMonth > 9 ? nowMonth : '0' + nowMonth;nowDay = nowDay > 9 ? nowDay : '0' + nowDay;nowHours = nowHours > 9 ? nowHours : '0' + nowHours;nowMinutes = nowMinutes > 9 ? nowMinutes : '0' + nowMinutes;nowSeconds = nowSeconds > 9 ? nowSeconds : '0' + nowSeconds;return  `${nowYear}-${nowMonth}-${nowDay} ${nowHours}:${nowMinutes}:${nowSeconds}`}const useAtOnce = async () => {updateData()await postUseAtOnce(submitData.value)}const usageEnd = async () => {dataReversion.value.beginTime = getCurrentTime()updateData()await postUsageEnd(submitData.value)}const back = () => {uni.navigateBack({delta: 1})}const openDataPicker = () => {companionsRef.value.show()}const endUse = async () => {// warn.value = !warn.value// try {// 	await tts.textToSpeech(basicText.value);// } catch (error) {// 	console.log("播放失败", error)// }}// #ifdef H5function getBase64FromFileToWeb(file) {console.log('调用了 H5 端 getBase64FromFile');return new Promise((resolve, reject) => {const reader = new FileReader();reader.onload = (e) => {const base64 = e.target.result.split(',')[1];resolve(base64);};reader.onerror = (error) => {reject(error);};reader.readAsDataURL(file);});}// #endif// #ifndef H5function getBase64FromFile(filePath) {return new Promise((resolve, reject) => {try {// #ifdef APP-PLUSplus.io.resolveLocalFileSystemURL(filePath, (entry) => {entry.file((file) => {const fileReader = new plus.io.FileReader();fileReader.onload = function(e) {const base64 = e.target.result.split(',')[1];resolve(base64);};fileReader.onerror = function(error) {console.error('FileReader错误:', error);reject(new Error('读取文件失败'));};fileReader.readAsDataURL(file);}, (error) => {console.error('获取文件对象失败:', error);reject(new Error('获取文件对象失败'));});}, (error) => {console.error('解析文件路径失败:', error);reject(new Error('解析文件路径失败'));});// #endif// #ifdef MPconst fsm = uni.getFileSystemManager();fsm.readFile({filePath: filePath,encoding: 'base64',success: (res) => {if (res.data) {console.log('Base64转换成功');resolve(res.data);} else {reject(new Error('Base64数据为空'));}},fail: (error) => {console.error('读取文件失败:', error);reject(new Error('读取文件失败: ' + (error.errMsg || '未知错误')));}});// #endif} catch (error) {console.error('文件处理错误:', error);reject(new Error('文件处理错误: ' + (error.message || '未知错误')));}});}// #endifconst takePhoto = async () => {// #ifdef APP-PLUS// 只检测相机权限let status = await checkCameraPermission();if (status !== 1) {// 没有权限,直接 returnreturn;}// #endifuni.chooseImage({count: 1,sourceType: ['camera'],sizeType: ['original', 'compressed'],success: async (res) => {try {let base64 = '';// #ifdef H5base64 = await getBase64FromFileToWeb(res.tempFiles[0]);// #endif// #ifndef H5if (res.tempFilePaths && res.tempFilePaths.length > 0) {const filePath = res.tempFilePaths[0];console.log('开始转换图片,文件路径:', filePath);base64 = await getBase64FromFile(filePath);} else {throw new Error('未能获取到图片路径');}// #endifif (!base64) {throw new Error('Base64转换失败: 结果为空');}console.log('Base64转换成功,长度:', base64.length);await recognizeAndBind(base64);} catch (error) {console.error('图片处理错误:', error);uni.showToast({title: error.message || '图片处理失败',icon: 'none',duration: 2000});}},fail: (err) => {if (err && err.errMsg && err.errMsg.indexOf('cancel') !== -1) return;uni.showToast({title: '打开相机失败,请检查权限',icon: 'none',duration: 2000});console.error('chooseImage fail:', err);}});};const recognizeAndBind = async (base64) => {try {if (!base64) {throw new Error('Base64数据为空');}console.log('开始识别处理,Base64长度:', base64.length);const options = {"data.format": "text","thpu.parser": "single_line","ocr.cls": true,"ocr.limit_side_len": 2880,"ocr.language": "models/config_chinese.txt"};const res = await getRecognize({base64,options});console.log('识别结果:', res);if (!res) {throw new Error('识别接口返回为空');}if (res && res.data) {if (!res.data.statusBit) {// 未绑定,更新表单数据并自动绑定console.log("此时的使用人员和id", dataReversion.value);dataReversion.value = {...dataReversion.value,carId: res.data.id,code: res.data.code,simCode: res.data.simCode,vehicleType: res.data.vehicleType,loginUserId: dataReversion.value.loginUserId, // 直接取当前值loginUserName: dataReversion.value.loginUserName, // 直接取当前值// driverAccountId: [0],// driverAccountName: [""]driverAccountId: dataReversion.value.driverAccountId,driverAccountName: dataReversion.value.driverAccountName}await useAtOnce()uni.showToast({title: '自动绑定成功',icon: 'success',duration: 2000});} else {// 已绑定,弹窗确认uni.showModal({title: '提示',content: `当前车辆已被绑定,确认是否继续绑定,绑定后默认结束上一使用人绑定记录。`,success: async (modalRes) => {if (modalRes.confirm) {console.log("11此时的使用人员和id", dataReversion.value);console.log("此时的使用人员", dataReversion.value.loginUserName);// 用户确认,更新表单数据并绑定dataReversion.value = {...dataReversion.value,carId: res.data.id,code: res.data.code,simCode: res.data.simCode,vehicleType: res.data.vehicleType,// driverAccountId: [0],// driverAccountName: [""],driverAccountId: dataReversion.value.driverAccountId,driverAccountName: dataReversion.value.driverAccountName,loginUserId: dataReversion.value.loginUserId, // 直接取当前值loginUserName: dataReversion.value.loginUserName, // 直接取当前值}console.log("更新后的", dataReversion.value)await useAtOnce()uni.showToast({title: '绑定成功',icon: 'success',duration: 2000});}// 用户取消,不做任何处理,保持原有数据}});}} else {uni.showToast({title: '未识别到车牌号',icon: 'none',duration: 2000});}} catch (error) {console.error('识别绑定过程出错:', error);uni.showToast({title: '识别处理失败: ' + (error.message || '未知错误'),icon: 'none',duration: 2000});}};// 检查相机权限const checkCameraPermission = async () => {// iOSif (permision.isIOS) {let status = await permision.requestIOS('camera');if (status !== 1) {uni.showModal({content: "没有开启相机权限",confirmText: "去设置",success: function(res) {if (res.confirm) {permision.gotoAppSetting();}}});}return status;}// Androidlet status = await permision.requestAndroid('android.permission.CAMERA');if (status !== 1) {uni.showModal({content: "没有开启相机权限",confirmText: "去设置",success: function(res) {if (res.confirm) {permision.gotoAppSetting();}}});}return status;};
</script><style lang="scss">.humanVehicleBinding {width: 750rpx;height: 100%;background-color: rgba(242, 242, 246, 1);display: flex;flex-direction: column;justify-content: space-between;:deep(.uni-data-tree) {font-size: 28rpx;color: #000;}.shadow {position: fixed;width: 750rpx;height: 100%;box-shadow: inset 0px 0px 20rpx red;}.header {width: 100%;height: 88rpx;:deep(.uni-navbar__header) {height: 88rpx;font-size: 24rpx;}:deep(.uni-nav-bar-text) {font-size: 28rpx;}}.body {width: 100%;height: 100%;margin: 0 0 3% 0;background-color: #fff;// overflow-y:auto:deep(.uni-forms-item) {margin: 20rpx 32rpx 0 32rpx;border-bottom: 1px solid rgba(17, 31, 44, 0.12);height: 120rpx;}:deep(.uni-forms-item__label) {padding: 0;line-height: 48rpx;height: 60rpx;width: 100% !important;font-size: 34rpx;font-weight: 400;letter-spacing: 0px;color: rgba(23, 26, 29, 1);// font-family:'Noto Sans SC', sans-serif;}:deep(.uni-forms-item__content) {font-size: 34rpx;color: rgba(23, 26, 29, 0.4);}:deep(.uni-select__selector-empty) {line-height: 70rpx;font-size: 34rpx;}:deep(.uni-select__selector-item) {line-height: 70rpx;font-size: 34rpx;}.disable {:deep(.uni-forms-item__label) {color: rgba(23, 26, 29, 0.24);}.textValue {color: rgba(23, 26, 29, 0.24);}}:deep(.input-value) {padding-left: 0;height: 60rpx;padding: 0 0 8px;}.useCar {position: relative;// bottom: 5px;:deep(.w-select) {color: rgba(23, 26, 29, 0.4);}:deep(.w-select .select-wrap) {width: 100%;border: none;}:deep(.w-select .select-wrap .select-options) {padding: 0;}:deep(.input-arrow) {// position: absolute;// top: -12.5px;// right: 0;border-left: 0;border-bottom: 0;}:deep(.placeholder) {font-size: 34rpx;font-weight: 400;color: rgba(23, 26, 29, 0.4);}.select {width: 646rpx;height: 44rpx;:deep(.uni-select) {border: none;padding-left: 0;}:deep(.uni-select__input-placeholder) {font-size: 34rpx;font-weight: 400;color: rgba(23, 26, 29, 0.4);}:deep(.uni-icons) {color: #fff !important;}}.scan {position: absolute;width: 48rpx;height: 44rpx;top: -40rpx;right: 0;font-size: 60rpx !important;}}}.companions {position: relative;// bottom: 10rpx;:deep(.input-value-border) {border: none;border-radius: none;}.popup-content{background-color: #fff;.selected{color: rgba(0, 127, 255, 1);line-height: 72rpx;padding: 20rpx;}.unselected{line-height: 72rpx;padding: 20rpx;}}.dataPicker {:deep(.uni-icons) {color: #fff !important;}}:deep(.input-arrow) {// position: absolute;// top: -12.5px;// right: 0;border-left: 0;border-bottom: 0;}:deep(.placeholder) {font-size: 34rpx;font-weight: 400;color: rgba(23, 26, 29, 0.4);}:deep(.input-value) {padding-left: 0;height: 60rpx;}.scan {position: absolute;width: 32rpx;height: 32rpx;top: -40rpx;right: 0;font-size: 60rpx !important;}}.bottom {// height: 102px;width: 100%;flex: 2.55;background-color: #fff;.bottonBox {display: flex;align-items: center;margin: 24rpx 0;:deep(uni-button) {font-size: 36rpx;display: flex;align-items: center;justify-content: center;}:deep(uni-button:after) {border: none;}.endUse {width: 330rpx;height: 88rpx;color: rgba(0, 127, 255, 1);border: 1px solid rgba(0, 127, 255, 1);background-color: rgba(255, 255, 255, 1);border-radius: 16rpx;margin-right: 14rpx;}.startUse {width: 330rpx;height: 88rpx;color: #fff;border: 1px solid rgba(0, 127, 255, 1);background-color: rgba(0, 127, 255, 1);border-radius: 16rpx;margin-left: 14rpx;}}}}
</style>

@/common/permission.js:

/// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启var isIOSfunction album() {var result = 0;var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");var authStatus = PHPhotoLibrary.authorizationStatus();if (authStatus === 0) {result = null;} else if (authStatus == 3) {result = 1;} else {result = 0;}plus.ios.deleteObject(PHPhotoLibrary);return result;
}function camera() {var result = 0;var AVCaptureDevice = plus.ios.import("AVCaptureDevice");var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide');if (authStatus === 0) {result = null;} else if (authStatus == 3) {result = 1;} else {result = 0;}plus.ios.deleteObject(AVCaptureDevice);return result;
}function location() {var result = 0;var cllocationManger = plus.ios.import("CLLocationManager");var enable = cllocationManger.locationServicesEnabled();var status = cllocationManger.authorizationStatus();if (!enable) {result = 2;} else if (status === 0) {result = null;} else if (status === 3 || status === 4) {result = 1;} else {result = 0;}plus.ios.deleteObject(cllocationManger);return result;
}function push() {var result = 0;var UIApplication = plus.ios.import("UIApplication");var app = UIApplication.sharedApplication();var enabledTypes = 0;if (app.currentUserNotificationSettings) {var settings = app.currentUserNotificationSettings();enabledTypes = settings.plusGetAttribute("types");if (enabledTypes == 0) {result = 0;console.log("推送权限没有开启");} else {result = 1;console.log("已经开启推送功能!")}plus.ios.deleteObject(settings);} else {enabledTypes = app.enabledRemoteNotificationTypes();if (enabledTypes == 0) {result = 3;console.log("推送权限没有开启!");} else {result = 4;console.log("已经开启推送功能!")}}plus.ios.deleteObject(app);plus.ios.deleteObject(UIApplication);return result;
}function contact() {var result = 0;var CNContactStore = plus.ios.import("CNContactStore");var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);if (cnAuthStatus === 0) {result = null;} else if (cnAuthStatus == 3) {result = 1;} else {result = 0;}plus.ios.deleteObject(CNContactStore);return result;
}function record() {var result = null;var avaudiosession = plus.ios.import("AVAudioSession");var avaudio = avaudiosession.sharedInstance();var status = avaudio.recordPermission();console.log("permissionStatus:" + status);if (status === 1970168948) {result = null;} else if (status === 1735552628) {result = 1;} else {result = 0;}plus.ios.deleteObject(avaudiosession);return result;
}function calendar() {var result = null;var EKEventStore = plus.ios.import("EKEventStore");var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0);if (ekAuthStatus == 3) {result = 1;console.log("日历权限已经开启");} else {console.log("日历权限没有开启");}plus.ios.deleteObject(EKEventStore);return result;
}function memo() {var result = null;var EKEventStore = plus.ios.import("EKEventStore");var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1);if (ekAuthStatus == 3) {result = 1;console.log("备忘录权限已经开启");} else {console.log("备忘录权限没有开启");}plus.ios.deleteObject(EKEventStore);return result;
}function requestIOS(permissionID) {return new Promise((resolve, reject) => {switch (permissionID) {case "push":resolve(push());break;case "location":resolve(location());break;case "record":resolve(record());break;case "camera":resolve(camera());break;case "album":resolve(album());break;case "contact":resolve(contact());break;case "calendar":resolve(calendar());break;case "memo":resolve(memo());break;default:resolve(0);break;}});
}function requestAndroid(permissionID) {return new Promise((resolve, reject) => {plus.android.requestPermissions([permissionID],function(resultObj) {var result = 0;for (var i = 0; i < resultObj.granted.length; i++) {var grantedPermission = resultObj.granted[i];console.log('已获取的权限:' + grantedPermission);result = 1}for (var i = 0; i < resultObj.deniedPresent.length; i++) {var deniedPresentPermission = resultObj.deniedPresent[i];console.log('拒绝本次申请的权限:' + deniedPresentPermission);result = 0}for (var i = 0; i < resultObj.deniedAlways.length; i++) {var deniedAlwaysPermission = resultObj.deniedAlways[i];console.log('永久拒绝申请的权限:' + deniedAlwaysPermission);result = -1}resolve(result);},function(error) {console.log('result error: ' + error.message)resolve({code: error.code,message: error.message});});});
}function gotoAppPermissionSetting() {if (permission.isIOS) {var UIApplication = plus.ios.import("UIApplication");var application2 = UIApplication.sharedApplication();var NSURL2 = plus.ios.import("NSURL");var setting2 = NSURL2.URLWithString("app-settings:");application2.openURL(setting2);plus.ios.deleteObject(setting2);plus.ios.deleteObject(NSURL2);plus.ios.deleteObject(application2);} else {var Intent = plus.android.importClass("android.content.Intent");var Settings = plus.android.importClass("android.provider.Settings");var Uri = plus.android.importClass("android.net.Uri");var mainActivity = plus.android.runtimeMainActivity();var intent = new Intent();intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);var uri = Uri.fromParts("package", mainActivity.getPackageName(), null);intent.setData(uri);mainActivity.startActivity(intent);}
}const permission = {get isIOS(){return typeof isIOS === 'boolean' ? isIOS : (isIOS = uni.getSystemInfoSync().platform === 'ios')},requestIOS: requestIOS,requestAndroid: requestAndroid,gotoAppSetting: gotoAppPermissionSetting
}export default permission

核心流程:

  1. 权限检查
  2. 调用相机获取图片
  3. 图片 Base64 转换
  4. 图片识别与车辆绑定

uni-app 官网上的 camera 是不支持 App 和 H5 端的

H5 端拍照识别实现:H5 端的拍照识别功能主要依赖浏览器原生 API,通过条件编译 #ifdef H5 标识 H5 端特有代码:

  • 权限处理:H5 端相机权限由浏览器管理,无需额外处理,用户首次调用相机时浏览器会自动弹出请求权限
  • 图片获取:通过 uni.chooseImage 接口调用相机,设置 sourceType: ['camera'] 指定从相机获取图片
uni.chooseImage({count: 1,                 // 最多选择1张图片sourceType: ['camera'],   // 仅从相机获取sizeType: ['original', 'compressed'], // 获取原图和压缩图success: async (res) => {// 处理获取到的图片}
});
  • 图片转换为 Base64:H5 端使用 FileReader 将图片转换为 Base64 格式
// H5端特有函数,用于将图片转换为Base64
// #ifdef H5function getBase64FromFileToWeb(file) {console.log('调用了 H5 端 getBase64FromFile');return new Promise((resolve, reject) => {const reader = new FileReader();reader.onload = (e) => {const base64 = e.target.result.split(',')[1];resolve(base64);};reader.onerror = (error) => {reject(error);};reader.readAsDataURL(file);});}// #endif

调用示例:

const base64 = await getBase64FromFileToWeb(res.tempFiles[0]);
  • 图片识别与车辆绑定:将 Base64 格式的图片数据传递给 OCR 识别接口,并处理识别结果
const recognizeAndBind = async (base64) => {try {// 配置识别参数const options = {"data.format": "text","thpu.parser": "single_line","ocr.cls": true,"ocr.limit_side_len": 2880,"ocr.language": "models/config_chinese.txt"};// 调用识别接口const res = await getRecognize({base64,options});// 处理识别结果if (res && res.data) {if (!res.data.statusBit) {// 未绑定,更新表单数据并自动绑定dataReversion.value = {...dataReversion.value,carId: res.data.id,code: res.data.code,simCode: res.data.simCode,vehicleType: res.data.vehicleType,// 保留其他已填数据}await useAtOnce()} else {// 已绑定,弹窗确认是否覆盖uni.showModal({title: '提示',content: `当前车辆已被绑定,确认是否继续绑定,绑定后默认结束上一使用人绑定记录。`,success: async (modalRes) => {if (modalRes.confirm) {// 更新数据并绑定dataReversion.value = {...dataReversion.value,carId: res.data.id,code: res.data.code,// 保留其他已填数据}await useAtOnce()}}});}}} catch (error) {console.error('识别绑定过程出错:', error);uni.showToast({title: '识别处理失败: ' + (error.message || '未知错误'),icon: 'none',duration: 2000});}
};

非 H5 端(App / 小程序)拍照识别功能:非 H5 端(App / 小程序)拍照识别功能需要处理原生权限,并使用不同的文件系统 API,通过条件编译 #ifndef H5 标识相关代码

  • 权限检查:区分 iOS 和 Android 平台:
// 检查相机权限const checkCameraPermission = async () => {// iOS 平台处理if (permision.isIOS) {let status = await permision.requestIOS('camera');if (status !== 1) {uni.showModal({content: "没有开启相机权限",confirmText: "去设置",success: function(res) {if (res.confirm) {permision.gotoAppSetting();}}});}return status;}// Android 平台处理let status = await permision.requestAndroid('android.permission.CAMERA');if (status !== 1) {uni.showModal({content: "没有开启相机权限",confirmText: "去设置",success: function(res) {if (res.confirm) {permision.gotoAppSetting();}}});}return status;};
      • 针对 iOS 和 Android 平台分别调用对应的权限请求 API
      • 如权限未开启,弹出模态框引导用户进入系统设置开启权限
    1. 图片获取:使用 uni.chooseImage 接口获取图片,非 H5 端返回的是本地文件路径:
    uni.chooseImage({count: 1,sourceType: ['camera'],success: (res) => {const filePath = res.tempFilePaths[0]; // 本地文件路径// 转换为Base64}
    });
    • 图片转换为 Base64:根据不同平台使用不同的文件读取方式:
        • App 端(5+App)使用 plus.io 模块
        • 小程序端使用 uni.getFileSystemManager()
    // 非H5端特有函数,用于将图片转换为Base64
    function getBase64FromFile(filePath) {return new Promise((resolve, reject) => {try {// 5+App平台#ifdef APP-PLUSplus.io.resolveLocalFileSystemURL(filePath, (entry) => {entry.file((file) => {const fileReader = new plus.io.FileReader();fileReader.onload = (e) => {const base64 = e.target.result.split(',')[1];resolve(base64);};fileReader.readAsDataURL(file);}, (error) => {console.error('获取文件对象失败:', error);reject(new Error('获取文件对象失败'));});}, (error) => {console.error('解析文件路径失败:', error);reject(new Error('解析文件路径失败'));});#endif// 小程序平台#ifdef MPconst fsm = uni.getFileSystemManager();fsm.readFile({filePath: filePath,encoding: 'base64',success: (res) => {if (res.data) {console.log('Base64转换成功');resolve(res.data);} else {reject(new Error('Base64数据为空'));}},fail: (error) => {console.error('读取文件失败:', error);reject(new Error('读取文件失败: ' + (error.errMsg || '未知错误')));}});#endif} catch (error) {console.error('文件处理错误:', error);reject(new Error('文件处理错误: ' + (error.message || '未知错误')));}});
    }
    • 图片识别与车辆绑定:非 H5 端使用与 H5 端相同的recognizeAndBind函数处理识别和绑定逻辑,实现了跨平台的统一处理
    http://www.dtcms.com/a/263391.html

    相关文章:

  • 数据可视化:5 分钟读懂其核心价值与技术实践
  • PyTorch 中 nn.Linear() 参数详解与实战解析(gpt)
  • Python + Selenium 自动化爬取途牛动态网页
  • Qt Quick 与 QML(四)qml中的Delegate系列委托组件
  • 七天学会SpringCloud分布式微服务——05——OpenFeign
  • 基于时间策略+应用过滤的游戏防沉迷方案:技术实现与工具推荐
  • Python pandas-profiling 详解:一键生成数据分析报告的利器
  • 使用自定义注解完成redis缓存
  • Windows Excel文档办公工作数据整理小工具
  • SpringCloud系列(43)--搭建SpringCloud Config客户端
  • Install Ubuntu 24.04 System
  • SpringCloud系列(42)--搭建SpringCloud Config分布式配置总控中心(服务端)
  • ProPlus2024Retail 安装教程(详细步骤+激活方法)- 最新版安装包下载与使用指南
  • mysql运维语句
  • window显示驱动开发—在注册表中设置 DXGI 信息
  • SCAU期末笔记 - 操作系统 选填题
  • 【机器学习第四期(Python)】LightGBM 方法原理详解
  • 跨主机用 Docker Compose 部署 PostgreSQL + PostGIS 主从
  • [特殊字符]【联邦学习实战】用 PyTorch 从 0 搭建一个最简单的联邦学习系统(含完整代码)
  • 编程新手之环境搭建:node python
  • [论文阅读] Neural Architecture Search: Insights from 1000 Papers
  • 创客匠人解析知识变现赛道:从 IP 孵化到商业闭环的核心策略
  • xilinx axi datamover IP使用demo
  • 【STM32HAL-第1讲 基础篇-单片机简介】
  • C#数字格式化全解析:从基础到进阶的实战指南
  • 腾讯云空间,高性能显卡云,安装xinference报错,pip install 空间不够用了
  • leedcode:找到字符串中所有字母异位词
  • 04密码加密
  • 中钧科技参加中亚数字经济对话会,引领新疆企业数字化新征程!
  • 【Teensy】在ArduinoIDE中配置Teensy4.1