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 0176637..9b1889b 100644 --- a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt +++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt @@ -467,6 +467,10 @@ class LoginByFaceActivity : BaseActivity(), return } SoundPoolUtil.getInstance().play(successSound, 0) + // 已注册用户:出盘成功且有盘时,上报取餐盘时刻(P-09a) + if (successSound == RECOGNIZE_SUCCESS) { + reportPlatePickup(currentUserId, "recognize") + } checkRemainingPlate() } @@ -479,6 +483,30 @@ class LoginByFaceActivity : BaseActivity(), goInitActivity() } + /** + * 上报取餐盘时刻(P-09a):记录用户开始就餐时刻,是后续就餐记录(P-09)的强前置。 + * + * 调用时机: + * - 已注册用户:识别成功且出盘成功(有盘)后,userId 取自 [currentUserId](来源 "recognize"); + * - 新用户:addUserFace 注册成功拿到真实 userId 后(出盘已由 outPlateForRegister 并行触发,来源 "collect")。 + * + * 上报失败仅记录日志,不影响吐盘主流程。 + * + * @param userId 用户 id(餐盘号 = userId),为空或非数字时跳过 + * @param source 调用来源标识,仅用于日志区分 + */ + private fun reportPlatePickup(userId: String?, source: String) { + val id = userId?.toLongOrNull() + if (id == null) { + loadLogInfo("collectFace,reportPlatePickup[$source]: userId 为空或非数字,跳过上报,userId=$userId") + return + } + loadLogInfo("collectFace,reportPlatePickup[$source]: 上报取餐盘时刻,userId=$id") + netViewModelV2.platePickup(id) { success, msg -> + loadLogInfo("collectFace,reportPlatePickup[$source]: 上报完成,success=$success,msg=$msg") + } + } + /** * 出盘成功后查询剩余餐盘状态,无盘则播放提示音 */ @@ -936,6 +964,8 @@ class LoginByFaceActivity : BaseActivity(), loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}") return@addUserFace } + // 新用户:注册成功拿到真实 userId 后,上报取餐盘时刻(P-09a) + reportPlatePickup(faceModel.userId, "collect") lifecycleScope.launch(Dispatchers.IO) { saveFaceInfo(faceModel) { runOnUiThread { diff --git a/app/src/main/java/com/sw/platecabinet/model/request/IdDTO.kt b/app/src/main/java/com/sw/platecabinet/model/request/IdDTO.kt new file mode 100644 index 0000000..971fa4a --- /dev/null +++ b/app/src/main/java/com/sw/platecabinet/model/request/IdDTO.kt @@ -0,0 +1,13 @@ +package com.sw.platecabinet.model.request + +/** + * 通用 ID 请求体 + * + * 用于按用户 id(餐盘号)查询或上报类的接口,例如: + * - P-09a 取餐盘(/neglect/pickup/plate-pickup) + * + * @property id 用户 id(餐盘号 = userId) + */ +data class IdDTO( + val id: Long +) diff --git a/app/src/main/java/com/sw/platecabinet/network/api/ApiServiceV2.kt b/app/src/main/java/com/sw/platecabinet/network/api/ApiServiceV2.kt index 9e9b956..de57df8 100644 --- a/app/src/main/java/com/sw/platecabinet/network/api/ApiServiceV2.kt +++ b/app/src/main/java/com/sw/platecabinet/network/api/ApiServiceV2.kt @@ -3,6 +3,7 @@ package com.sw.platecabinet.network.api import com.sw.platecabinet.GlobalData import com.sw.platecabinet.model.DeviceConfigV2 import com.sw.platecabinet.model.request.FeatureBody +import com.sw.platecabinet.model.request.IdDTO import com.sw.platecabinet.model.response.ApiResponse import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModelV2 @@ -62,4 +63,16 @@ interface ApiServiceV2 { @Part file: MultipartBody.Part, ): ApiResponse + /** + * 取餐盘(P-09a):记录用户开始就餐时刻 + * 调用一次即 upsert 到主单 plate_pickup_time,是 P-09 提交就餐记录的强前置。 + * @param param IdDTO,id 为用户 id(餐盘号 = userId) + * @return ApiResponse,data 为主单 recordNo + */ + @POST + suspend fun platePickup( + @Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/pickup/plate-pickup", + @Body param: IdDTO + ): ApiResponse + } \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/repository/RemoteRepositoryV2.kt b/app/src/main/java/com/sw/platecabinet/repository/RemoteRepositoryV2.kt index 9dc58a4..facd288 100644 --- a/app/src/main/java/com/sw/platecabinet/repository/RemoteRepositoryV2.kt +++ b/app/src/main/java/com/sw/platecabinet/repository/RemoteRepositoryV2.kt @@ -2,6 +2,7 @@ package com.sw.platecabinet.repository import com.sw.platecabinet.model.DeviceConfigV2 import com.sw.platecabinet.model.request.FeatureBody +import com.sw.platecabinet.model.request.IdDTO import com.sw.platecabinet.model.response.ApiResponse import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModelV2 @@ -69,4 +70,13 @@ class RemoteRepositoryV2 constructor( } } } + + /** + * 取餐盘(P-09a):上报用户开始就餐时刻 + * @param userId 用户 id(餐盘号 = userId) + * @return ApiResponse,data 为主单 recordNo + */ + suspend fun platePickup(userId: Long): ApiResponse { + return safeApiCall { apiService.platePickup(param = IdDTO(id = userId)) } + } } \ No newline at end of file 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 0b6d8c1..2714020 100644 --- a/app/src/main/java/com/sw/platecabinet/viewmodel/NetViewModelV2.kt +++ b/app/src/main/java/com/sw/platecabinet/viewmodel/NetViewModelV2.kt @@ -270,6 +270,32 @@ class NetViewModelV2 : ViewModel() { } } + /** + * 取餐盘上报(P-09a):记录用户开始就餐时刻,作为后续就餐记录(P-09)的强前置。 + * 失败仅回调通知,不阻断吐盘等业务主流程。 + * + * @param userId 用户 id(餐盘号 = userId) + * @param callback 上报结果回调:Boolean 是否成功,String? 成功为 recordNo、失败为错误信息 + */ + fun platePickup( + userId: Long, + callback: (Boolean, String?) -> Unit = { _, _ -> } + ) { + viewModelScope.launch { + try { + val response = repository.platePickup(userId) + if (response.isSuccess()) { + callback(true, response.data) + } else { + callback(false, response.msg) + } + } catch (e: Exception) { + e.printStackTrace() + callback(false, e.message) + } + } + } + private fun base64ToByteArray(base64: String?): ByteArray? { base64 ?: return null return try {