From 5b29c99b34801860271e9e118324261f453d21a2 Mon Sep 17 00:00:00 2001 From: mazengfei <331023091@qq.com> Date: Wed, 8 Jul 2026 18:30:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(login):=20=E4=BC=98=E5=8C=96=E5=87=BA?= =?UTF-8?q?=E7=9B=98=E6=B5=81=E7=A8=8B=E5=B9=B6=E5=A2=9E=E5=BC=BA=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 抽取出盘成功与失败的统一处理方法,简化代码逻辑 - 新增新用户注册采集成功后立即出盘功能,避免与识别成功逻辑冲突 - 出盘成功后取消识别倒计时并控制出盘开关,防止重复出盘 - 出盘失败时统一提示错误并跳转回初始页 - 采集成功后立即异步出盘,确保上传失败时仍能出盘 - 调整识别失败计数重置逻辑,避免无人脸短暂丢帧导致计数异常 - 在人脸离开时重置识别失败计数,保证下次重新累计 - 网络请求增加异常捕获,防止因异常导致回调阻塞无反馈 --- .../activity/LoginByFaceActivity.kt | 81 ++++++++++++++----- .../platecabinet/viewmodel/NetViewModelV2.kt | 26 +++--- 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt index e6da7db..0176637 100644 --- a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt +++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt @@ -417,29 +417,68 @@ class LoginByFaceActivity : BaseActivity(), PlcHelper.getInstance(this@LoginByFaceActivity) .outPlate(object : PlcCallback { override fun onSuccess(result: String) { - plateEnable = false - recognizeCountDownUtil.cancelCountDown() - // result 为 false 时表示出盘后无餐盘,直接播放无盘提示音 - if (result.equals("false", ignoreCase = true)) { - loadLogInfo("collectFace,openPlate: result=false,餐盘已空") - SoundPoolUtil.getInstance().play(NO_PLATE_REMIND, 0) - goInitActivity() - return - } loadLogInfo("collectFace,openPlate: 出盘完成,result=$result,开始查询剩余餐盘") - // result 为 true,出盘成功,再查询是否还有剩余餐盘 - SoundPoolUtil.getInstance().play(RECOGNIZE_SUCCESS, 0) - checkRemainingPlate() + onOutPlateSuccess(result, RECOGNIZE_SUCCESS) } override fun onError(message: String) { - ToastUtils.showToast("出盘失败,message=$message") - loadLogInfo("collectFace,openPlate: 出盘失败,message=$message") - goInitActivity() + onOutPlateError(message) } }) } + /** + * 新用户注册采集成功后立即出盘(与上传后台并行,互不阻塞)。 + * 故意不经过 recognizeSuccess:避免使用临时 userId、避免与识别成功的防抖语义混淆。 + */ + private fun outPlateForRegister() { + loadLogInfo("collectFace,outPlateForRegister: 新用户采集成功,立即出盘,plateEnable=$plateEnable") + if (plateEnable.not()) return + + PlcHelper.getInstance(this@LoginByFaceActivity) + .outPlate(object : PlcCallback { + override fun onSuccess(result: String) { + loadLogInfo("collectFace,outPlateForRegister: 出盘完成,result=$result") + onOutPlateSuccess(result, COLLECT_SUCCESS) + } + + override fun onError(message: String) { + onOutPlateError(message) + } + }) + } + + /** + * 出盘成功后的统一处理: + * 1. 置 plateEnable=false、取消识别倒计时,防止重复出盘; + * 2. result 为 "false" 表示出盘后已无餐盘,播放无盘提示音并跳转; + * 3. 否则播放提示音并查询剩余餐盘状态。 + * + * @param result PLC 返回结果("false" 表示出盘后无餐盘) + * @param successSound 出盘成功播放的提示音 key(识别成功 / 采集成功) + */ + private fun onOutPlateSuccess(result: String, successSound: String) { + plateEnable = false + recognizeCountDownUtil.cancelCountDown() + if (result.equals("false", ignoreCase = true)) { + loadLogInfo("collectFace,onOutPlateSuccess: result=false,餐盘已空") + SoundPoolUtil.getInstance().play(NO_PLATE_REMIND, 0) + goInitActivity() + return + } + SoundPoolUtil.getInstance().play(successSound, 0) + checkRemainingPlate() + } + + /** + * 出盘失败后的统一处理:提示失败并跳转回初始页 + */ + private fun onOutPlateError(message: String) { + ToastUtils.showToast("出盘失败,message=$message") + loadLogInfo("collectFace,onOutPlateError: 出盘失败,message=$message") + goInitActivity() + } + /** * 出盘成功后查询剩余餐盘状态,无盘则播放提示音 */ @@ -617,7 +656,9 @@ class LoginByFaceActivity : BaseActivity(), userFaceInfo = null binding.btnCollect.tag = "" binding.tvSimilarValue.text = "" - retryFailCount = 0 + // 注意:此处不再重置 retryFailCount。 + // 人脸检测会抖动(短暂丢帧),若每次无人脸就清零,"尝试几次失败"将无法累计。 + // 失败计数仅在识别成功、会话重启、确认用户离开时清零。 // 人脸离开时,发送空帧清除 ViewModel 内部识别缓存,防止再次进入时使用旧数据 recognizeViewModel.onPreviewFrame(emptyFrame, true) if (binding.llCollectButton.isVisible) { @@ -922,6 +963,9 @@ class LoginByFaceActivity : BaseActivity(), //block(faceData, headBmp) isCollecting.set(false) isCollectFace = false + // 采集成功后立即出盘,与上传后台并行执行,确保上传失败时仍能吐盘 + outPlateForRegister() + // 异步上传后台(上传成功后才入库),不阻塞出盘 sendFaceData(faceData, headBmp) } @@ -950,9 +994,8 @@ class LoginByFaceActivity : BaseActivity(), recognizeViewModel.refreshFaceList() loadLogInfo("collectFace,saveFaceInfo: ----------11,刷新人脸数据-----------") runOnUiThread { - //采集完成,不再识别,直接提示成功 + //采集完成,停止识别(出盘已在采集成功时由 outPlateForRegister 触发,此处仅负责入库) isRecognition = false - recognizeSuccess("${System.currentTimeMillis()}") } loadLogInfo("---------------------------------") collectCount = 0 @@ -984,6 +1027,8 @@ class LoginByFaceActivity : BaseActivity(), loadLogInfo("leftCountDown.onFinish-人脸未离开,不跳转") return@startCountDown } + // 确认用户已离开画面,重置识别失败计数,下次进入重新累计 + retryFailCount = 0 goInitActivity() }) } diff --git a/app/src/main/java/com/sw/platecabinet/viewmodel/NetViewModelV2.kt b/app/src/main/java/com/sw/platecabinet/viewmodel/NetViewModelV2.kt index 261d2e2..0b6d8c1 100644 --- a/app/src/main/java/com/sw/platecabinet/viewmodel/NetViewModelV2.kt +++ b/app/src/main/java/com/sw/platecabinet/viewmodel/NetViewModelV2.kt @@ -249,18 +249,24 @@ class NetViewModelV2 : ViewModel() { */ fun addUserFace(faceData: String, imageFile: File, block: (Boolean, UserFaceModelV2?) -> Unit) { viewModelScope.launch { - val imageResp = repository.uploadImage(imageFile) - val imageUrl = imageResp.data ?: "" - if (imageUrl.isBlank()) { + try { + val imageResp = repository.uploadImage(imageFile) + val imageUrl = imageResp.data ?: "" + if (imageUrl.isBlank()) { + block(false, null) + return@launch + } + val faceResp = repository.addUserFace(faceData, imageUrl) + if (faceResp.isSuccess().not()) { + block(false, null) + return@launch + } + block(true, faceResp.data) + } catch (e: Exception) { + // 网络或解析异常时同样回调失败,避免 block 永不触发导致上层无反馈 + e.printStackTrace() block(false, null) - return@launch } - val faceResp = repository.addUserFace(faceData, imageUrl) - if (faceResp.isSuccess().not()) { - block(false, null) - return@launch - } - block(true, faceResp.data) } }