feat(face): 优化人脸数据同步及类型映射

- 新增接口注释,完善全量及增量人脸数据获取说明
- FaceVO中faceUpdateTimestamp由Long改为String以防JS大数精度丢失
- 增加personType字段标识人员类型
- MainActivity保存人脸数据时映射完整字段,使用personType优先判断用户类型
- NetViewModelV2中获取人脸数据时改用完整构造函数创建FaceEntity
- 累积更新lastFaceTimestamp为当前页最大时间戳,避免时间戳遗漏
- 优化时间戳更新逻辑,避免直接使用列表最后一条数据
This commit is contained in:
mazengfei
2026-07-15 10:56:40 +08:00
parent 16dba32eb7
commit 28a475ca43
5 changed files with 41 additions and 23 deletions
+2 -2
View File
@@ -37,9 +37,9 @@ class MyApp : App() {
if (!savedUrl.isNullOrEmpty()) { if (!savedUrl.isNullOrEmpty()) {
GlobalData.appBaseUrl = savedUrl GlobalData.appBaseUrl = savedUrl
} else { } else {
// 未保存过则使用默认逻辑:特定设备走测试环境,其余走 UAT // 未保存过则使用默认逻辑:特定设备走测试环境,其余走 UAT 测试档口机:2987f0c5-5754-33e9-b00a-251db5e2e55f
GlobalData.appBaseUrl = GlobalData.appBaseUrl =
if ("2987f0c5-5754-33e9-b00a-251db5e2e55f" == deviceId) GlobalData.LOCAL_BASE_URL else GlobalData.PROD_BASE_URL if ("2987f0c5-5754-33e9-b00a-251db5e2e55f" == deviceId) GlobalData.TEST_BASE_URL else GlobalData.PROD_BASE_URL
} }
} }
@@ -1236,14 +1236,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
FaceDatabase.getInstance(this@MainActivity).faceDao().deleteFaceById(vo.userId) FaceDatabase.getInstance(this@MainActivity).faceDao().deleteFaceById(vo.userId)
} }
} else { } else {
//保存数据 // 保存数据:使用完整构造函数,映射后端全部字段到数据库
val faceEntity = FaceEntity( val faceEntity = FaceEntity(
vo.userId, null, Base64.decode(vo.faceFeature) vo.userId, // userName
).also { Base64.decode(vo.faceFeature), // featureData
//1-会员、2-临时用户 vo.personType ?: if (vo.member == true) "1" else "2", // userType
it.userType = if (vo.member == true) "1" else "2" vo.cardNo ?: "", // cardNo
it.cardNo = vo.cardNo vo.userId ?: "", // userId
} vo.userFaceId ?: "", // userFaceId
vo.member ?: false, // member
vo.faceUpdateTimestamp?.toLongOrNull() ?: 0L // faceUpdateTimestamp
)
faceList.add(faceEntity) faceList.add(faceEntity)
} }
} }
@@ -5,15 +5,18 @@ import kotlinx.parcelize.Parcelize
/** /**
* 新系统人脸数据 VO * 新系统人脸数据 VO
* 对应接口:/neglect/booth/face/page 和 /neglect/booth/face/increment * 对应接口:/nutrition/neglect/common/face/page 和 /nutrition/neglect/common/face/increment
*/ */
@Parcelize @Parcelize
data class FaceVO( data class FaceVO(
val userFaceId: String?, val userFaceId: String?,
val userId: String?, val userId: String?,
val faceFeature: String?, val faceFeature: String?,
val faceUpdateTimestamp: Long?, /** 后端返回 String 类型(防止 JS 大数精度丢失),映射时自行转为 Long */
val faceUpdateTimestamp: String?,
val cardNo: String?, val cardNo: String?,
val member: Boolean?, val member: Boolean?,
val faceDeleted: Boolean? val faceDeleted: Boolean?,
/** 人员类型:由后端定义,如 "1"-会员、"2"-临时用户、"3"-其他等 */
val personType: String?
) : Parcelable ) : Parcelable
@@ -34,12 +34,18 @@ interface ApiServiceV2 {
@Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/serve/device/config" @Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/serve/device/config"
): ApiResponse<DeviceConfig?> ): ApiResponse<DeviceConfig?>
/**
* 获取全量人脸数据
*/
@POST @POST
suspend fun getFacePage( suspend fun getFacePage(
@Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/common/face/page", @Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/common/face/page",
@Body request: Map<String, Long> @Body request: Map<String, Long>
): ApiResponse<List<FaceVO>?> ): ApiResponse<List<FaceVO>?>
/**
* 获取增量人脸数据
*/
@POST @POST
suspend fun getFaceIncrement( suspend fun getFaceIncrement(
@Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/common/face/increment", @Url url: String = "${GlobalData.appBaseUrl}/nutrition/neglect/common/face/increment",
@@ -84,7 +84,9 @@ class NetViewModelV2 : BaseViewModel() {
Timber.tag(TAG).d("getFacePage index = $currentPageNum") Timber.tag(TAG).d("getFacePage index = $currentPageNum")
launch { launch {
_loadFaceResult.value = false _loadFaceResult.value = false
// 重置持久化时间戳和内存累加器
SpTool.lastFaceTimestamp = 0 SpTool.lastFaceTimestamp = 0
lastFaceTimestamp = 0L
FileUtil.saveLog("获取人脸全量数据开始,重置时间戳为0") FileUtil.saveLog("获取人脸全量数据开始,重置时间戳为0")
val response = ApiClient.repositoryV2.getFacePage(currentPageNum, pageSize) val response = ApiClient.repositoryV2.getFacePage(currentPageNum, pageSize)
if (!parseResponse(response)) { if (!parseResponse(response)) {
@@ -98,21 +100,26 @@ class NetViewModelV2 : BaseViewModel() {
return@withContext return@withContext
} }
val faceEntity = list.map { vo -> val faceEntity = list.map { vo ->
FaceEntity(vo.userId, null, Base64.decode(vo.faceFeature)).also { FaceEntity(
it.userType = if (vo.member == true) "1" else "2" vo.userId, // userName
it.cardNo = vo.cardNo Base64.decode(vo.faceFeature), // featureData
} vo.personType ?: if (vo.member == true) "1" else "2", // userType
vo.cardNo ?: "", // cardNo
vo.userId ?: "", // userId
vo.userFaceId ?: "", // userFaceId
vo.member ?: false, // member
vo.faceUpdateTimestamp?.toLongOrNull() ?: 0L // faceUpdateTimestamp
)
} }
faceApi.updateFaceData(currentPageNum.toInt(), faceEntity) faceApi.updateFaceData(currentPageNum.toInt(), faceEntity)
// 取当前页最大时间戳(后端返回 String 类型,需转为 Long 比较),跨页累加防止中间页有更大值被覆盖
val pageMaxTimestamp = list.maxOf { it.faceUpdateTimestamp?.toLongOrNull() ?: 0L }
lastFaceTimestamp = maxOf(lastFaceTimestamp, pageMaxTimestamp)
if (list.size >= pageSize) { if (list.size >= pageSize) {
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L
currentPageNum++ currentPageNum++
getFacePage(currentPageNum, pageSize, onSuccess, onFailure) getFacePage(currentPageNum, pageSize, onSuccess, onFailure)
return@withContext return@withContext
} }
if (list.isNotEmpty()) {
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L
}
SpTool.lastFaceTimestamp = lastFaceTimestamp SpTool.lastFaceTimestamp = lastFaceTimestamp
FileUtil.saveLog("获取人脸[全量]数据结束,时间戳为:$lastFaceTimestamp") FileUtil.saveLog("获取人脸[全量]数据结束,时间戳为:$lastFaceTimestamp")
_loadFaceResult.value = true _loadFaceResult.value = true
@@ -143,9 +150,8 @@ class NetViewModelV2 : BaseViewModel() {
return@withContext return@withContext
} }
onPageQueryFinished(list) onPageQueryFinished(list)
if (list.isNotEmpty()) { // 取列表中最大时间戳(后端返回 String 类型,需转为 Long),而非依赖列表最后一条
lastFaceTimestamp = list.last().faceUpdateTimestamp ?: 0L lastFaceTimestamp = list.maxOf { it.faceUpdateTimestamp?.toLongOrNull() ?: 0L }
}
SpTool.lastFaceTimestamp = lastFaceTimestamp SpTool.lastFaceTimestamp = lastFaceTimestamp
FileUtil.saveLog("获取人脸[增量]数据结束,时间戳为:$lastFaceTimestamp") FileUtil.saveLog("获取人脸[增量]数据结束,时间戳为:$lastFaceTimestamp")
onAllQueryFinished() onAllQueryFinished()