feat:apk自动更新

This commit is contained in:
dzc committed 2026-07-30 17:06:48 +08:00
1 parent 06330260e5
commit 7d1e9a01f8
18 files changed
+653 -84

No files matched your search

@@ -0,0 +1,19 @@
package com.bsd.pjcloud.hard.api.constant;
/**
* 终端心跳场景。
*
* <p>枚举名称是终端与服务端之间的固定接口编码,不得随展示文案调整。</p>
*/
public enum TerminalHeartbeatSceneEnum {
/**
* 普通在线心跳;收到后清除之前的计划更新断开原因。
*/
ONLINE,
/**
* 自动更新安装前心跳;用于在应用重启期间保留可解释的离线原因。
*/
AUTO_UPDATE
}
@@ -0,0 +1,85 @@
package com.bsd.pjcloud.hard.api.dto.hard;
import com.bsd.pjcloud.hard.api.constant.TerminalHeartbeatSceneEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import java.util.Map;
/**
* 食堂、超市 Android 终端心跳请求。
*/
@Data
@Schema(description = "终端心跳请求")
public class TerminalHeartbeatDto {
/**
* APK 展示版本号,来源于终端当前安装包;取不到时允许为空。
*/
@Schema(description = "APK展示版本号")
private String apkVersionName;
/**
* APK 内部版本码,来源于终端当前安装包;取不到时允许为空。
*/
@Schema(description = "APK内部版本码")
private Long apkVersionCode;
/**
* 本次上报场景,使用 {@link TerminalHeartbeatSceneEnum} 的固定接口名称。
*/
@NotNull(message = "心跳场景不能为空")
@Schema(description = "心跳场景", requiredMode = Schema.RequiredMode.REQUIRED)
private TerminalHeartbeatSceneEnum scene;
/**
* Android 系统本次启动后的运行秒数,用于区分整机重启与应用进程重启。
*/
@Schema(description = "Android系统运行秒数")
private Long systemUptimeSeconds;
/**
* 当前应用进程运行秒数,用于识别应用崩溃或被系统重新拉起。
*/
@Schema(description = "应用进程运行秒数")
private Long appUptimeSeconds;
/**
* 最近上报时使用的网络类型,例如 ethernet、wifi、4g 或 offline。
*/
@Schema(description = "网络类型")
private String networkType;
/**
* 应用私有目录所在存储卷的可用空间,单位为字节。
*/
@Schema(description = "可用存储空间,单位字节")
private Long availableStorageBytes;
/**
* Root 最近检测状态,持久化值固定为 unknown、available 或 unavailable。
*/
@Pattern(regexp = "unknown|available|unavailable", message = "Root状态不正确")
@Schema(description = "Root状态")
private String rootStatus;
/**
* 当前应用是否已被 Android 配置为 Device Owner;无法读取时为空。
*/
@Schema(description = "是否为Device Owner")
private Boolean deviceOwner;
/**
* 最近上报时是否处于 Kiosk 锁定任务模式;无法读取时为空。
*/
@Schema(description = "是否处于Kiosk模式")
private Boolean kioskActive;
/**
* 可选外围硬件状态,以稳定功能编码映射布尔值,例如 printer、steelyard、cardReader、subScreen。
*/
@Schema(description = "可选外围硬件状态")
private Map<String, Boolean> deviceStatus;
}
@@ -0,0 +1,146 @@
package com.bsd.pjcloud.hard.api.entity.manager;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.bsd.pjcloud.common.core.util.TenantTable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 食堂、超市 Android 终端的最新心跳状态。
*
* <p>每台设备只保留一条最新记录,在线布尔值由服务端按时间阈值实时计算。</p>
*/
@Data
@TenantTable
@TableName("hard_terminal_status")
@EqualsAndHashCode(callSuper = true)
@Schema(description = "终端最新心跳状态")
public class HardTerminalStatusEntity extends Model<HardTerminalStatusEntity> {
/**
* 设备 ID,同时作为主键,对应 {@code hard_manager.id}。
*/
@TableId(type = IdType.INPUT)
@Schema(description = "设备ID")
private Long hardId;
/**
* 服务端最近收到心跳的时间,在线计算以此时间为准。
*/
@Schema(description = "最后在线时间")
private LocalDateTime lastOnlineTime;
/**
* 最近一次心跳场景,保存 {@code ONLINE} 或 {@code AUTO_UPDATE} 接口编码。
*/
@Schema(description = "最近心跳场景")
private String heartbeatScene;
/**
* 计划内断开原因;普通在线心跳会清空,当前仅保留“自动更新重启”。
*/
@Schema(description = "计划内断开原因")
private String disconnectReason;
/**
* 终端上报的 APK 展示版本号,无法读取时为空。
*/
@Schema(description = "APK展示版本号")
private String apkVersionName;
/**
* 终端上报的 APK 内部版本码,无法读取时为空。
*/
@Schema(description = "APK内部版本码")
private Long apkVersionCode;
/**
* Android 系统本次启动后的运行时长,单位为秒;终端无法读取时为空。
*/
@Schema(description = "Android系统运行秒数")
private Long systemUptimeSeconds;
/**
* 当前应用进程运行时长,单位为秒;终端无法读取时为空。
*/
@Schema(description = "应用进程运行秒数")
private Long appUptimeSeconds;
/**
* 最近一次心跳的网络类型,例如 ethernet、wifi、4g 或 offline。
*/
@Schema(description = "网络类型")
private String networkType;
/**
* 应用私有目录所在存储卷的可用空间,单位为字节。
*/
@Schema(description = "可用存储空间,单位字节")
private Long availableStorageBytes;
/**
* Root 最近检测状态,固定为 unknown、available 或 unavailable。
*/
@Schema(description = "Root状态")
private String rootStatus;
/**
* 最近一次心跳时当前应用是否为 Device Owner;无法读取时为空。
*/
@Schema(description = "是否为Device Owner")
private Boolean deviceOwner;
/**
* 最近一次心跳时是否处于 Kiosk 锁定任务模式;无法读取时为空。
*/
@Schema(description = "是否处于Kiosk模式")
private Boolean kioskActive;
/**
* 打印机、电子秤、读卡器和副屏等可选硬件状态 JSON 快照。
*/
@Schema(description = "可选外围硬件状态JSON")
private String deviceStatusJson;
/**
* 创建人;设备心跳没有后台用户上下文时为空。
*/
@TableField(fill = FieldFill.INSERT)
@Schema(description = "创建人")
private String createBy;
/**
* 首次收到该设备心跳的服务端时间。
*/
@TableField(fill = FieldFill.INSERT)
@Schema(description = "创建时间")
private LocalDateTime createTime;
/**
* 修改人;设备心跳没有后台用户上下文时为空。
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
@Schema(description = "修改人")
private String updateBy;
/**
* 最近一次心跳写入的服务端时间。
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
@Schema(description = "修改时间")
private LocalDateTime updateTime;
/**
* 数据所属租户 ID,取自已通过当前租户校验的设备记录。
*/
@Schema(description = "租户ID")
private Long tenantId;
}
@@ -6,6 +6,11 @@ import com.bsd.pjcloud.hard.api.vo.base.BaseHardGroupInterface;
import com.bsd.pjcloud.wallet.api.vo.base.BaseMchInterface;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 设备管理视图,包含设备基础资料及仅用于接口返回的关联、运行状态信息。
*/
@Data
public class HardManagerVo extends HardManagerEntity implements BaseDeptInterface, BaseMchInterface, BaseHardGroupInterface {
@@ -29,4 +34,29 @@ public class HardManagerVo extends HardManagerEntity implements BaseDeptInterfac
private String hardGroupName;
/**
* 终端是否在线;超市、食堂设备返回布尔值,其他设备类型返回 {@code null} 表示暂不支持。
*/
private Boolean online;
/**
* 服务端最近收到终端心跳的时间;尚未上报或设备类型不支持时为空。
*/
private LocalDateTime lastOnlineTime;
/**
* 当前 APK 展示版本号,来源于终端最近一次心跳;未上报时为空。
*/
private String apkVersionName;
/**
* 当前 APK 内部版本码,来源于终端最近一次心跳;未上报时为空。
*/
private Long apkVersionCode;
/**
* 断开连接的可解释原因;除主动自动更新外均为基于心跳超时的推断结果。
*/
private String disconnectReason;
}