feat(api): 新增取餐盘时刻上报接口及相关调用

- 在 ApiServiceV2 中添加 platePickup 接口用于上报用户开始就餐时刻
- 新增请求体 IdDTO,封装用户 id(餐盘号)字段
- RemoteRepositoryV2 添加对应的 platePickup 方法调用接口
- NetViewModelV2 实现业务方法 platePickup,支持异步回调上报结果
- LoginByFaceActivity 中识别成功出盘后及新用户注册成功后调用 platePickup 上报时刻
- reportPlatePickup 方法完善调用逻辑及日志记录,错误时不会影响主流程
This commit is contained in:
mazengfei
2026-07-10 09:37:41 +08:00
parent 5b29c99b34
commit c9dd294f87
5 changed files with 92 additions and 0 deletions
@@ -467,6 +467,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
return return
} }
SoundPoolUtil.getInstance().play(successSound, 0) SoundPoolUtil.getInstance().play(successSound, 0)
// 已注册用户:出盘成功且有盘时,上报取餐盘时刻(P-09a)
if (successSound == RECOGNIZE_SUCCESS) {
reportPlatePickup(currentUserId, "recognize")
}
checkRemainingPlate() checkRemainingPlate()
} }
@@ -479,6 +483,30 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
goInitActivity() 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=$successmsg=$msg")
}
}
/** /**
* 出盘成功后查询剩余餐盘状态,无盘则播放提示音 * 出盘成功后查询剩余餐盘状态,无盘则播放提示音
*/ */
@@ -936,6 +964,8 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>(),
loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}") loadLogInfo("collectFace,sendFaceData: ----------12,发送人脸数据成功但接口返回为null,faceData=${faceData}")
return@addUserFace return@addUserFace
} }
// 新用户:注册成功拿到真实 userId 后,上报取餐盘时刻(P-09a)
reportPlatePickup(faceModel.userId, "collect")
lifecycleScope.launch(Dispatchers.IO) { lifecycleScope.launch(Dispatchers.IO) {
saveFaceInfo(faceModel) { saveFaceInfo(faceModel) {
runOnUiThread { runOnUiThread {
@@ -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
)
@@ -3,6 +3,7 @@ package com.sw.platecabinet.network.api
import com.sw.platecabinet.GlobalData import com.sw.platecabinet.GlobalData
import com.sw.platecabinet.model.DeviceConfigV2 import com.sw.platecabinet.model.DeviceConfigV2
import com.sw.platecabinet.model.request.FeatureBody 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.ApiResponse
import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModel
import com.sw.platecabinet.model.response.UserFaceModelV2 import com.sw.platecabinet.model.response.UserFaceModelV2
@@ -62,4 +63,16 @@ interface ApiServiceV2 {
@Part file: MultipartBody.Part, @Part file: MultipartBody.Part,
): ApiResponse<String?> ): ApiResponse<String?>
/**
* 取餐盘(P-09a):记录用户开始就餐时刻
* 调用一次即 upsert 到主单 plate_pickup_time,是 P-09 提交就餐记录的强前置。
* @param param IdDTOid 为用户 id(餐盘号 = userId
* @return ApiResponse<String?>data 为主单 recordNo
*/
@POST
suspend fun platePickup(
@Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/pickup/plate-pickup",
@Body param: IdDTO
): ApiResponse<String?>
} }
@@ -2,6 +2,7 @@ package com.sw.platecabinet.repository
import com.sw.platecabinet.model.DeviceConfigV2 import com.sw.platecabinet.model.DeviceConfigV2
import com.sw.platecabinet.model.request.FeatureBody 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.ApiResponse
import com.sw.platecabinet.model.response.UserFaceModel import com.sw.platecabinet.model.response.UserFaceModel
import com.sw.platecabinet.model.response.UserFaceModelV2 import com.sw.platecabinet.model.response.UserFaceModelV2
@@ -69,4 +70,13 @@ class RemoteRepositoryV2 constructor(
} }
} }
} }
/**
* 取餐盘(P-09a):上报用户开始就餐时刻
* @param userId 用户 id(餐盘号 = userId
* @return ApiResponse<String?>data 为主单 recordNo
*/
suspend fun platePickup(userId: Long): ApiResponse<String?> {
return safeApiCall { apiService.platePickup(param = IdDTO(id = userId)) }
}
} }
@@ -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? { private fun base64ToByteArray(base64: String?): ByteArray? {
base64 ?: return null base64 ?: return null
return try { return try {