refactor(device): 重构设备信息模块,按面板拆分数据存储和接口

将原 SnDeviceSystemInfo 单一实体拆分为基本信息、硬件、网络、安全、其他信息五个独立子表和服务,重构 DeviceController 和 MobileController 接口以支持分面板查询和上传
This commit is contained in:
TongTongStudio
2026-08-05 02:09:38 +08:00
parent 537644ab2e
commit 3608c205b9
39 changed files with 2447 additions and 164 deletions

47
sql/sn_hardware_info.sql Normal file
View File

@@ -0,0 +1,47 @@
-- =============================================================================
-- 设备硬件信息表sys_sn_hardware_info
-- 说明:设备【硬件信息】面板独立分表,与基本信息表分离存储。
-- =============================================================================
CREATE TABLE IF NOT EXISTS `sys_sn_hardware_info`
(
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serialno` VARCHAR(64) NOT NULL COMMENT '设备序列号(关联 sys_sn.serialno',
-- ===================== 硬件信息面板 =====================
`cpu_abi` VARCHAR(128) DEFAULT NULL COMMENT 'CPU ABI 列表(逗号分隔)',
`cpu_abi2` VARCHAR(128) DEFAULT NULL COMMENT 'CPU ABI2',
`cpu_min` VARCHAR(64) DEFAULT NULL COMMENT '最小 CPU ABI',
`cpu_model` VARCHAR(128) DEFAULT NULL COMMENT 'CPU 型号',
`cpu_cores` INT DEFAULT NULL COMMENT 'CPU 核心数',
`cpu_max_freq` VARCHAR(32) DEFAULT NULL COMMENT 'CPU 最大频率',
`cpu_min_freq` VARCHAR(32) DEFAULT NULL COMMENT 'CPU 最小频率',
`total_ram` VARCHAR(32) DEFAULT NULL COMMENT '总内存',
`available_ram` VARCHAR(32) DEFAULT NULL COMMENT '可用内存',
`internal_storage` VARCHAR(32) DEFAULT NULL COMMENT '内部存储',
`available_storage` VARCHAR(32) DEFAULT NULL COMMENT '可用存储',
`external_storage` VARCHAR(32) DEFAULT NULL COMMENT '外部存储SD卡',
`battery_capacity` VARCHAR(32) DEFAULT NULL COMMENT '电池容量',
`battery_level` INT DEFAULT NULL COMMENT '电池电量0-100',
`battery_status` VARCHAR(32) DEFAULT NULL COMMENT '电池状态',
`battery_health` VARCHAR(32) DEFAULT NULL COMMENT '电池健康度',
`battery_temp` VARCHAR(32) DEFAULT NULL COMMENT '电池温度',
`battery_voltage` VARCHAR(32) DEFAULT NULL COMMENT '电池电压',
`battery_technology` VARCHAR(32) DEFAULT NULL COMMENT '电池技术',
`gpu_renderer` VARCHAR(128) DEFAULT NULL COMMENT 'GPU 渲染器',
`gpu_vendor` VARCHAR(64) DEFAULT NULL COMMENT 'GPU 厂商',
`gpu_version` VARCHAR(64) DEFAULT NULL COMMENT 'GPU 版本',
`sensors` TEXT DEFAULT NULL COMMENT '传感器列表JSON',
`support_abi` VARCHAR(128) DEFAULT NULL COMMENT '支持的应用二进制接口',
`support_abi64` VARCHAR(128) DEFAULT NULL COMMENT '支持的 64 位 ABI',
-- ===================== 通用字段 =====================
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除0未删 1已删',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_serialno` (`serialno`),
KEY `idx_is_deleted` (`is_deleted`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COMMENT = '设备硬件信息表';

47
sql/sn_network_info.sql Normal file
View File

@@ -0,0 +1,47 @@
-- =============================================================================
-- 设备网络信息表sys_sn_network_info
-- 说明:设备【网络信息】面板独立分表,与基本信息表分离存储。
-- =============================================================================
CREATE TABLE IF NOT EXISTS `sys_sn_network_info`
(
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serialno` VARCHAR(64) NOT NULL COMMENT '设备序列号(关联 sys_sn.serialno',
-- ===================== 网络信息面板 =====================
`network_type` VARCHAR(32) DEFAULT NULL COMMENT '网络类型WIFI/MOBILE/ETHERNET等',
`network_subtype` VARCHAR(32) DEFAULT NULL COMMENT '网络子类型',
`is_connected` TINYINT DEFAULT NULL COMMENT '是否联网0否 1是',
`wifi_ssid` VARCHAR(128) DEFAULT NULL COMMENT 'WiFi SSID',
`wifi_bssid` VARCHAR(64) DEFAULT NULL COMMENT 'WiFi BSSID',
`wifi_ip` VARCHAR(64) DEFAULT NULL COMMENT 'WiFi IP 地址',
`wifi_mac` VARCHAR(64) DEFAULT NULL COMMENT 'WiFi MAC 地址',
`wifi_gateway` VARCHAR(64) DEFAULT NULL COMMENT 'WiFi 网关',
`wifi_netmask` VARCHAR(64) DEFAULT NULL COMMENT 'WiFi 子网掩码',
`wifi_dns` VARCHAR(128) DEFAULT NULL COMMENT 'WiFi DNS',
`wifi_rssi` INT DEFAULT NULL COMMENT 'WiFi 信号强度',
`wifi_speed` VARCHAR(32) DEFAULT NULL COMMENT 'WiFi 连接速度',
`mobile_ip` VARCHAR(64) DEFAULT NULL COMMENT '移动网络 IP',
`mobile_mac` VARCHAR(64) DEFAULT NULL COMMENT '移动网络 MAC',
`mobile_imei` VARCHAR(64) DEFAULT NULL COMMENT 'IMEI',
`mobile_imsi` VARCHAR(64) DEFAULT NULL COMMENT 'IMSI',
`mobile_operator` VARCHAR(64) DEFAULT NULL COMMENT '运营商名称',
`mobile_sim_serial` VARCHAR(64) DEFAULT NULL COMMENT 'SIM 序列号',
`mobile_network_type` VARCHAR(32) DEFAULT NULL COMMENT '移动网络类型',
`bluetooth_mac` VARCHAR(64) DEFAULT NULL COMMENT '蓝牙 MAC 地址',
`bluetooth_name` VARCHAR(128) DEFAULT NULL COMMENT '蓝牙名称',
`is_vpn` TINYINT DEFAULT NULL COMMENT '是否 VPN0否 1是',
`is_proxy` TINYINT DEFAULT NULL COMMENT '是否代理0否 1是',
`proxy_host` VARCHAR(64) DEFAULT NULL COMMENT '代理主机',
`proxy_port` VARCHAR(16) DEFAULT NULL COMMENT '代理端口',
-- ===================== 通用字段 =====================
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除0未删 1已删',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_serialno` (`serialno`),
KEY `idx_is_deleted` (`is_deleted`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COMMENT = '设备网络信息表';

44
sql/sn_other_info.sql Normal file
View File

@@ -0,0 +1,44 @@
-- =============================================================================
-- 设备其他信息表sys_sn_other_info
-- 说明:设备【其他信息】面板独立分表,与基本信息表分离存储。
-- =============================================================================
CREATE TABLE IF NOT EXISTS `sys_sn_other_info`
(
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serialno` VARCHAR(64) NOT NULL COMMENT '设备序列号(关联 sys_sn.serialno',
-- ===================== 其他信息面板 =====================
`app_version` VARCHAR(32) DEFAULT NULL COMMENT 'App 版本',
`app_version_code` INT DEFAULT NULL COMMENT 'App 版本号',
`install_time` DATETIME DEFAULT NULL COMMENT 'App 安装时间',
`update_time_app` DATETIME DEFAULT NULL COMMENT 'App 更新时间',
`package_name` VARCHAR(128) DEFAULT NULL COMMENT '应用包名',
`channel` VARCHAR(64) DEFAULT NULL COMMENT '渠道',
`device_id` VARCHAR(64) DEFAULT NULL COMMENT '设备 ID应用层',
`gaid` VARCHAR(64) DEFAULT NULL COMMENT 'Google Advertising ID',
`oaid` VARCHAR(64) DEFAULT NULL COMMENT 'OAID',
`phone_number` VARCHAR(32) DEFAULT NULL COMMENT '手机号(脱敏)',
`iccid` VARCHAR(32) DEFAULT NULL COMMENT 'ICCID',
`imsi` VARCHAR(64) DEFAULT NULL COMMENT 'IMSI',
`camera_info` TEXT DEFAULT NULL COMMENT '摄像头信息JSON',
`sensor_count` INT DEFAULT NULL COMMENT '传感器数量',
`app_list_md5` VARCHAR(64) DEFAULT NULL COMMENT '应用列表 MD5',
`is_charging` TINYINT DEFAULT NULL COMMENT '是否充电中0否 1是',
`charging_type` VARCHAR(32) DEFAULT NULL COMMENT '充电类型',
`temperature` VARCHAR(32) DEFAULT NULL COMMENT '设备温度',
`free_storage` VARCHAR(32) DEFAULT NULL COMMENT '剩余存储',
`total_storage` VARCHAR(32) DEFAULT NULL COMMENT '总存储',
`free_ram` VARCHAR(32) DEFAULT NULL COMMENT '剩余内存',
`total_ram` VARCHAR(32) DEFAULT NULL COMMENT '总内存',
-- ===================== 通用字段 =====================
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除0未删 1已删',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_serialno` (`serialno`),
KEY `idx_is_deleted` (`is_deleted`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COMMENT = '设备其他信息表';

43
sql/sn_security_info.sql Normal file
View File

@@ -0,0 +1,43 @@
-- =============================================================================
-- 设备安全信息表sys_sn_security_info
-- 说明:设备【安全信息】面板独立分表,与基本信息表分离存储。
-- =============================================================================
CREATE TABLE IF NOT EXISTS `sys_sn_security_info`
(
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serialno` VARCHAR(64) NOT NULL COMMENT '设备序列号(关联 sys_sn.serialno',
-- ===================== 安全信息面板 =====================
`is_root` TINYINT DEFAULT NULL COMMENT '是否已 Root0否 1是',
`is_jailbreak` TINYINT DEFAULT NULL COMMENT '是否已越狱0否 1是',
`root_status` TINYINT DEFAULT NULL COMMENT 'Root/越狱状态0否 1是',
`has_su_binary` TINYINT DEFAULT NULL COMMENT '是否存在 su 二进制0否 1是',
`has_busybox` TINYINT DEFAULT NULL COMMENT '是否存在 BusyBox0否 1是',
`is_emulator` TINYINT DEFAULT NULL COMMENT '是否模拟器0否 1是',
`is_debuggable` TINYINT DEFAULT NULL COMMENT '是否可调试0否 1是',
`is_usb_debug` TINYINT DEFAULT NULL COMMENT '是否开启 USB 调试0否 1是',
`is_unknown_sources` TINYINT DEFAULT NULL COMMENT '是否允许未知来源0否 1是',
`is_verify_apps` TINYINT DEFAULT NULL COMMENT '是否验证应用0否 1是',
`is_encrypted` TINYINT DEFAULT NULL COMMENT '是否加密0否 1是',
`lock_screen_type` VARCHAR(32) DEFAULT NULL COMMENT '锁屏类型',
`has_password` TINYINT DEFAULT NULL COMMENT '是否设置密码0否 1是',
`password_type` VARCHAR(32) DEFAULT NULL COMMENT '密码类型',
`security_patch` VARCHAR(32) DEFAULT NULL COMMENT '安全补丁级别',
`google_play_protect` TINYINT DEFAULT NULL COMMENT 'Google Play 保护0否 1是',
`adb_status` TINYINT DEFAULT NULL COMMENT 'ADB 状态0关 1开',
`is_vpn_active` TINYINT DEFAULT NULL COMMENT 'VPN 是否激活0否 1是',
`is_device_owner` TINYINT DEFAULT NULL COMMENT '是否设备所有者0否 1是',
`android_version` VARCHAR(32) DEFAULT NULL COMMENT 'Android 版本(安全相关)',
`kernel_version` VARCHAR(128) DEFAULT NULL COMMENT '内核版本(安全相关)',
-- ===================== 通用字段 =====================
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除0未删 1已删',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_serialno` (`serialno`),
KEY `idx_is_deleted` (`is_deleted`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COMMENT = '设备安全信息表';

77
sql/sn_system_info.sql Normal file
View File

@@ -0,0 +1,77 @@
-- =============================================================================
-- 设备基本信息表sys_sn_system_info
-- 说明:仅存放设备【基本信息】面板数据;
-- 硬件信息 / 网络信息 / 安全信息 / 其他信息 已拆分至下列独立表。
-- 脚本遵循项目规范:不直连库,由 DBA 执行。
--
-- 重要:部署环境中若已存在【旧结构】的 sys_sn_system_info列名为 sn_model、
-- sn_brand 等CREATE TABLE IF NOT EXISTS 不会重建,会导致实体查询报
-- "Unknown column 'device_name'"。因此此处先 DROP 再 CREATE确保表结构与
-- 实体SnDeviceSystemInfo完全一致。
-- 注意DROP 会清空该表历史数据,设备数据可由端上重新上报补齐。
-- =============================================================================
DROP TABLE IF EXISTS `sys_sn_system_info`;
CREATE TABLE `sys_sn_system_info`
(
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`serialno` VARCHAR(64) NOT NULL COMMENT '设备序列号(关联 sys_sn.serialno',
-- ===================== 基本信息面板 =====================
`device_name` VARCHAR(128) DEFAULT NULL COMMENT '设备名称',
`device_brand` VARCHAR(64) DEFAULT NULL COMMENT '设备品牌',
`device_model` VARCHAR(64) DEFAULT NULL COMMENT '设备型号',
`device_board` VARCHAR(64) DEFAULT NULL COMMENT '主板名称',
`device_manufacturer` VARCHAR(64) DEFAULT NULL COMMENT '制造商',
`hardware` VARCHAR(64) DEFAULT NULL COMMENT '硬件信息',
`host` VARCHAR(64) DEFAULT NULL COMMENT '主机名',
`android_version` VARCHAR(32) DEFAULT NULL COMMENT 'Android 版本',
`android_api` INT DEFAULT NULL COMMENT 'Android API 级别',
`android_id` VARCHAR(64) DEFAULT NULL COMMENT 'Android ID',
`build_id` VARCHAR(64) DEFAULT NULL COMMENT 'Build ID',
`build_display_id` VARCHAR(128) DEFAULT NULL COMMENT 'Build Display ID',
`build_fingerprint` VARCHAR(255) DEFAULT NULL COMMENT 'Build 指纹',
`build_type` VARCHAR(32) DEFAULT NULL COMMENT 'Build 类型user/userdebug/eng',
`build_user` VARCHAR(64) DEFAULT NULL COMMENT 'Build 用户',
`build_host` VARCHAR(64) DEFAULT NULL COMMENT 'Build 主机',
`build_tags` VARCHAR(64) DEFAULT NULL COMMENT 'Build 标签',
`build_time` DATETIME DEFAULT NULL COMMENT 'Build 时间',
`language` VARCHAR(32) DEFAULT NULL COMMENT '系统语言',
`timezone` VARCHAR(64) DEFAULT NULL COMMENT '时区',
`boot_time` DATETIME DEFAULT NULL COMMENT '开机时间',
`screen_resolution` VARCHAR(32) DEFAULT NULL COMMENT '屏幕分辨率',
`screen_density` INT DEFAULT NULL COMMENT '屏幕密度',
`kernel_version` VARCHAR(128) DEFAULT NULL COMMENT '内核版本',
`rom_version` VARCHAR(128) DEFAULT NULL COMMENT 'ROM 版本',
-- ===================== 补充基本信息字段 =====================
`product_name` VARCHAR(128) DEFAULT NULL COMMENT '产品名称',
`product_model` VARCHAR(64) DEFAULT NULL COMMENT '产品型号',
`product_device` VARCHAR(64) DEFAULT NULL COMMENT '产品设备名',
`board_platform` VARCHAR(64) DEFAULT NULL COMMENT '主板平台',
`device_type` VARCHAR(32) DEFAULT NULL COMMENT '设备类型phone/tablet/tv等',
`is_tablet` TINYINT DEFAULT 0 COMMENT '是否平板0否 1是',
`release_version` VARCHAR(32) DEFAULT NULL COMMENT 'Android 发布版本号',
`display_version` VARCHAR(64) DEFAULT NULL COMMENT '显示版本号',
`bootloader` VARCHAR(64) DEFAULT NULL COMMENT 'Bootloader 版本',
`baseband_version` VARCHAR(64) DEFAULT NULL COMMENT '基带版本',
`radio_version` VARCHAR(64) DEFAULT NULL COMMENT 'Radio 版本',
`screen_size` VARCHAR(16) DEFAULT NULL COMMENT '屏幕尺寸(英寸,文本)',
`screen_inch` DECIMAL(4,2) DEFAULT NULL COMMENT '屏幕尺寸(数值,英寸)',
`refresh_rate` INT DEFAULT NULL COMMENT '屏幕刷新率Hz',
`os_type` VARCHAR(32) DEFAULT NULL COMMENT '操作系统类型',
`os_version` VARCHAR(32) DEFAULT NULL COMMENT '操作系统版本',
`firmware_version` VARCHAR(64) DEFAULT NULL COMMENT '固件版本',
-- ===================== 通用字段 =====================
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`is_deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除0未删 1已删',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_serialno` (`serialno`),
KEY `idx_is_deleted` (`is_deleted`)
) ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COMMENT = '设备基本信息表';

View File

@@ -1,150 +1,105 @@
package com.youlai.boot.device.controller;
import com.youlai.boot.common.annotation.Log;
import com.youlai.boot.common.enums.ActionTypeEnum;
import com.youlai.boot.common.enums.LogModuleEnum;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.boot.common.result.PageResult;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.device.model.entity.SnDeviceInfo;
import com.youlai.boot.device.model.form.DeveloperForm;
import com.youlai.boot.device.model.query.DeviceQuery;
import com.youlai.boot.device.model.vo.DeviceSystemInfoVO;
import com.youlai.boot.device.model.vo.DeviceHardwareInfoVO;
import com.youlai.boot.device.model.vo.DeviceNetworkInfoVO;
import com.youlai.boot.device.model.vo.DeviceOtherInfoVO;
import com.youlai.boot.device.model.vo.DevicePageVO;
import com.youlai.boot.device.model.vo.DeviceSecurityInfoVO;
import com.youlai.boot.device.model.vo.DeviceSystemInfoVO;
import com.youlai.boot.device.service.DeviceService;
import com.youlai.boot.device.service.HardwareInfoService;
import com.youlai.boot.device.service.NetworkInfoService;
import com.youlai.boot.device.service.OtherInfoService;
import com.youlai.boot.device.service.SecurityInfoService;
import com.youlai.boot.device.service.SystemInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 设备控制
* @author TTSTD
* @since 2026/04/05
* 设备管理控制
*
* @author Ray.Hao
* @since 2026-06-25
*/
@Tag(name = "15.SN管理")
@Tag(name = "设备管理")
@RestController
@RequestMapping("/api/v1/device")
@RequiredArgsConstructor
@Slf4j
public class DeviceController {
private final DeviceService deviceService;
@Operation(summary = "SN列表")
@GetMapping
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.LIST)
public PageResult<DevicePageVO> getSnList(@Valid DeviceQuery deviceQuery) {
return PageResult.success(deviceService.getSnPage(deviceQuery));
private final DeviceService deviceService;
private final SystemInfoService systemInfoService;
private final HardwareInfoService hardwareInfoService;
private final NetworkInfoService networkInfoService;
private final SecurityInfoService securityInfoService;
private final OtherInfoService otherInfoService;
@Operation(summary = "设备分页列表")
@GetMapping("/page")
public PageResult<DevicePageVO> getDevicePage(DeviceQuery query) {
IPage<DevicePageVO> page = deviceService.getSnPage(query);
return PageResult.success(page);
}
@Operation(summary = "获取SN绑定激活信息")
@GetMapping("/{sn}/info")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.VIEW)
// @PreAuthorize("@ss.hasPerm('sys:sn:view')")
public Result<DevicePageVO> getSnBindInfo(@PathVariable String sn) {
@Operation(summary = "设备详情")
@GetMapping("/{sn}/detail")
public Result<DevicePageVO> getDeviceDetail(
@Parameter(description = "设备序列号") @PathVariable("sn") String sn) {
DevicePageVO detail = deviceService.getSnBindInfo(sn);
return Result.success(detail);
}
@Operation(summary = "获取SN基础信息")
@GetMapping("/{sn}/system_info")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.VIEW)
// @PreAuthorize("@ss.hasPerm('sys:sn:view')")
public Result<DeviceSystemInfoVO> getSnSystemInfo(@PathVariable String sn) {
DeviceSystemInfoVO info = deviceService.getSnSystemInfo(sn);
return Result.success(info);
// ===================== 设备系统信息(分面板独立接口) =====================
@Operation(summary = "设备基本信息")
@GetMapping("/{sn}/basic_info")
public Result<DeviceSystemInfoVO> getBasicInfo(
@Parameter(description = "设备序列号") @PathVariable("sn") String sn) {
DeviceSystemInfoVO vo = deviceService.getDeviceBasicInfo(sn);
return Result.success(vo);
}
@Operation(summary = "新增SN")
@PostMapping("/add")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.INSERT)
// @PreAuthorize("@ss.hasPerm('sys:sn:create')")
public Result<Void> addSn(@RequestBody SnDeviceInfo snDeviceInfo) {
deviceService.addSn(snDeviceInfo);
return Result.success();
@Operation(summary = "设备硬件信息")
@GetMapping("/{sn}/hardware_info")
public Result<DeviceHardwareInfoVO> getHardwareInfo(
@Parameter(description = "设备序列号") @PathVariable("sn") String sn) {
DeviceHardwareInfoVO vo = deviceService.getDeviceHardwareInfo(sn);
return Result.success(vo);
}
@Operation(summary = "删除SN")
@DeleteMapping("/{sn}")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.DELETE)
@PreAuthorize("@ss.hasPerm('sys:sn:delete')")
public Result<Void> deleteSn(@PathVariable String sn) {
deviceService.deleteSn(sn);
return Result.success();
@Operation(summary = "设备网络信息")
@GetMapping("/{sn}/network_info")
public Result<DeviceNetworkInfoVO> getNetworkInfo(
@Parameter(description = "设备序列号") @PathVariable("sn") String sn) {
DeviceNetworkInfoVO vo = deviceService.getDeviceNetworkInfo(sn);
return Result.success(vo);
}
@Operation(summary = "设备刷新")
@PostMapping("/refresh")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.REFRESH)
public Result<?> devicerefresh(@RequestParam String sn) {
boolean result = deviceService.deviceRefresh(sn);
return Result.judge(result);
@Operation(summary = "设备安全信息")
@GetMapping("/{sn}/security_info")
public Result<DeviceSecurityInfoVO> getSecurityInfo(
@Parameter(description = "设备序列号") @PathVariable("sn") String sn) {
DeviceSecurityInfoVO vo = deviceService.getDeviceSecurityInfo(sn);
return Result.success(vo);
}
@Operation(summary = "设备截图")
@PostMapping("/screenshot")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.SCREENSHOT)
public Result<?> screenSnapshot(@RequestParam String sn) {
boolean result = deviceService.screenSnapshot(sn);
return Result.judge(result);
}
@Operation(summary = "设备重启")
@PostMapping("/reboot")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.REBOOT)
public Result<?> reboot(@RequestParam String sn) {
boolean result = deviceService.deviceReboot(sn);
return Result.judge(result);
}
@Operation(summary = "设备关机")
@PostMapping("/shutdown")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.SHUTDOWN)
public Result<?> shutdown(@RequestParam String sn) {
boolean result = deviceService.deviceShutdown(sn);
return Result.judge(result);
}
@Operation(summary = "设备定位")
@PostMapping("/locate")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.LOCATE)
public Result<?> deviceLocate(@RequestParam String sn) {
boolean result = deviceService.deviceLocate(sn);
return Result.judge(result);
}
@Operation(summary = "设备重置")
@PostMapping("/restore")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.RESTORE)
public Result<?> deviceRestore(@RequestParam String sn) {
boolean result = deviceService.restore(sn);
return Result.judge(result);
}
@Operation(summary = "开发者模式")
@PostMapping("/developer")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.DEVELOPER)
public Result<?> deviceDeveloper(@RequestParam String sn) {
boolean result = deviceService.setDeviceDeveloper(sn);
return Result.judge(result);
}
@Operation(summary = "新增开发者选项配置")
@PostMapping("/developer/config")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.INSERT)
public Result<Void> addDeveloperConfig(@Valid @RequestBody DeveloperForm developerForm) {
boolean result = deviceService.addDeveloperConfig(
developerForm.getSn(),
developerForm.getDeveloperOptions()
);
return Result.judge(result);
}
@Operation(summary = "删除开发者选项配置")
@DeleteMapping("/developer/config")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.DELETE)
public Result<Void> deleteDeveloperConfig(@RequestParam String sn) {
boolean result = deviceService.deleteDeveloperConfig(sn);
return Result.judge(result);
@Operation(summary = "设备其他信息")
@GetMapping("/{sn}/other_info")
public Result<DeviceOtherInfoVO> getOtherInfo(
@Parameter(description = "设备序列号") @PathVariable("sn") String sn) {
DeviceOtherInfoVO vo = deviceService.getDeviceOtherInfo(sn);
return Result.success(vo);
}
}

View File

@@ -0,0 +1,132 @@
package com.youlai.boot.device.controller;
import com.youlai.boot.common.annotation.Log;
import com.youlai.boot.common.enums.ActionTypeEnum;
import com.youlai.boot.common.enums.LogModuleEnum;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.device.model.entity.SnDeviceInfo;
import com.youlai.boot.device.model.form.DeveloperForm;
import com.youlai.boot.device.model.vo.DevicePageVO;
import com.youlai.boot.device.service.DeviceService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
/**
* 设备操作管理控制层(还原原 DeviceController 中的设备操作类接口)
* 与 DeviceController列表 + 分面板信息查询)分离,职责更清晰。
*
* @author TTSTD
* @since 2026/08/05
*/
@Tag(name = "15.SN管理-操作")
@RestController
@RequestMapping("/api/v1/device")
@RequiredArgsConstructor
public class DeviceOpsController {
private final DeviceService deviceService;
@Operation(summary = "获取SN绑定激活信息")
@GetMapping("/{sn}/info")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.VIEW)
public Result<DevicePageVO> getSnBindInfo(@PathVariable String sn) {
DevicePageVO detail = deviceService.getSnBindInfo(sn);
return Result.success(detail);
}
@Operation(summary = "新增SN")
@PostMapping("/add")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.INSERT)
public Result<Void> addSn(@RequestBody SnDeviceInfo snDeviceInfo) {
deviceService.addSn(snDeviceInfo);
return Result.success();
}
@Operation(summary = "删除SN")
@DeleteMapping("/{sn}")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.DELETE)
@PreAuthorize("@ss.hasPerm('sys:sn:delete')")
public Result<Void> deleteSn(@PathVariable String sn) {
deviceService.deleteSn(sn);
return Result.success();
}
@Operation(summary = "设备刷新")
@PostMapping("/refresh")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.REFRESH)
public Result<?> devicerefresh(@RequestParam String sn) {
boolean result = deviceService.deviceRefresh(sn);
return Result.judge(result);
}
@Operation(summary = "设备截图")
@PostMapping("/screenshot")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.SCREENSHOT)
public Result<?> screenSnapshot(@RequestParam String sn) {
boolean result = deviceService.screenSnapshot(sn);
return Result.judge(result);
}
@Operation(summary = "设备重启")
@PostMapping("/reboot")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.REBOOT)
public Result<?> reboot(@RequestParam String sn) {
boolean result = deviceService.deviceReboot(sn);
return Result.judge(result);
}
@Operation(summary = "设备关机")
@PostMapping("/shutdown")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.SHUTDOWN)
public Result<?> shutdown(@RequestParam String sn) {
boolean result = deviceService.deviceShutdown(sn);
return Result.judge(result);
}
@Operation(summary = "设备定位")
@PostMapping("/locate")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.LOCATE)
public Result<?> deviceLocate(@RequestParam String sn) {
boolean result = deviceService.deviceLocate(sn);
return Result.judge(result);
}
@Operation(summary = "设备重置")
@PostMapping("/restore")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.RESTORE)
public Result<?> deviceRestore(@RequestParam String sn) {
boolean result = deviceService.restore(sn);
return Result.judge(result);
}
@Operation(summary = "开发者模式")
@PostMapping("/developer")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.DEVELOPER)
public Result<?> deviceDeveloper(@RequestParam String sn) {
boolean result = deviceService.setDeviceDeveloper(sn);
return Result.judge(result);
}
@Operation(summary = "新增开发者选项配置")
@PostMapping("/developer/config")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.INSERT)
public Result<Void> addDeveloperConfig(@Valid @RequestBody DeveloperForm developerForm) {
boolean result = deviceService.addDeveloperConfig(
developerForm.getSn(),
developerForm.getDeveloperOptions()
);
return Result.judge(result);
}
@Operation(summary = "删除开发者选项配置")
@DeleteMapping("/developer/config")
@Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.DELETE)
public Result<Void> deleteDeveloperConfig(@RequestParam String sn) {
boolean result = deviceService.deleteDeveloperConfig(sn);
return Result.judge(result);
}
}

View File

@@ -8,8 +8,16 @@ import com.youlai.boot.common.enums.LogModuleEnum;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.common.util.HashUtils;
import com.youlai.boot.device.model.entity.SnDeviceSystemInfo;
import com.youlai.boot.device.model.entity.SnDeviceHardwareInfo;
import com.youlai.boot.device.model.entity.SnDeviceNetworkInfo;
import com.youlai.boot.device.model.entity.SnDeviceSecurityInfo;
import com.youlai.boot.device.model.entity.SnDeviceOtherInfo;
import com.youlai.boot.device.model.req.ApkInstallInfoReq;
import com.youlai.boot.device.model.req.SnSystemInfoReq;
import com.youlai.boot.device.model.req.SnHardwareInfoReq;
import com.youlai.boot.device.model.req.SnNetworkInfoReq;
import com.youlai.boot.device.model.req.SnSecurityInfoReq;
import com.youlai.boot.device.model.req.SnOtherInfoReq;
import com.youlai.boot.device.model.req.SnLocationReq;
import com.youlai.boot.device.model.entity.SnLocation;
import com.youlai.boot.device.model.entity.SnScreenshot;
@@ -52,6 +60,10 @@ public class MobileController {
private final DeveloperService developerService;
private final ApkInstallService apkInstallService;
private final SystemInfoService systemInfoService;
private final HardwareInfoService hardwareInfoService;
private final NetworkInfoService networkInfoService;
private final SecurityInfoService securityInfoService;
private final OtherInfoService otherInfoService;
private final Logger logger = LoggerFactory.getLogger(MobileController.class);
@@ -122,6 +134,194 @@ public class MobileController {
}
}
@Operation(summary = "上传设备其他信息")
@PostMapping("/update_other_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
public Result<Void> updateOtherInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnOtherInfoReq snOtherInfoReq
) {
try {
if (sn == null || sn.trim().isEmpty()) {
return Result.failed("设备序列号不能为空");
}
if (snOtherInfoReq == null) {
return Result.failed("其他信息不能为空");
}
SnDeviceOtherInfo otherInfo = new SnDeviceOtherInfo();
BeanUtils.copyProperties(snOtherInfoReq, otherInfo);
otherInfo.setSerialno(sn);
otherInfo.setUpdateTime(LocalDateTime.now());
SnDeviceOtherInfo existingOtherInfo = otherInfoService.lambdaQuery()
.eq(SnDeviceOtherInfo::getSerialno, sn)
.one();
boolean saved;
if (existingOtherInfo != null) {
otherInfo.setId(existingOtherInfo.getId());
saved = otherInfoService.updateById(otherInfo);
} else {
otherInfo.setCreateTime(LocalDateTime.now());
saved = otherInfoService.save(otherInfo);
}
if (!saved) {
return Result.failed("保存其他信息失败");
}
logger.info("其他信息上传成功, sn: {}", sn);
return Result.success();
} catch (Exception e) {
logger.error("updateOtherInfo error, sn: {}", sn, e);
return Result.failed("上传其他信息失败: " + e.getMessage());
}
}
@Operation(summary = "上传设备硬件信息")
@PostMapping("/update_hardware_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
public Result<Void> updateHardwareInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnHardwareInfoReq snHardwareInfoReq
) {
try {
if (sn == null || sn.trim().isEmpty()) {
return Result.failed("设备序列号不能为空");
}
if (snHardwareInfoReq == null) {
return Result.failed("硬件信息不能为空");
}
SnDeviceHardwareInfo hardwareInfo = new SnDeviceHardwareInfo();
BeanUtils.copyProperties(snHardwareInfoReq, hardwareInfo);
hardwareInfo.setSerialno(sn);
hardwareInfo.setUpdateTime(LocalDateTime.now());
SnDeviceHardwareInfo existingHardwareInfo = hardwareInfoService.lambdaQuery()
.eq(SnDeviceHardwareInfo::getSerialno, sn)
.one();
boolean saved;
if (existingHardwareInfo != null) {
hardwareInfo.setId(existingHardwareInfo.getId());
saved = hardwareInfoService.updateById(hardwareInfo);
} else {
hardwareInfo.setCreateTime(LocalDateTime.now());
saved = hardwareInfoService.save(hardwareInfo);
}
if (!saved) {
return Result.failed("保存硬件信息失败");
}
logger.info("硬件信息上传成功, sn: {}", sn);
return Result.success();
} catch (Exception e) {
logger.error("updateHardwareInfo error, sn: {}", sn, e);
return Result.failed("上传硬件信息失败: " + e.getMessage());
}
}
@Operation(summary = "上传设备网络信息")
@PostMapping("/update_network_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
public Result<Void> updateNetworkInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnNetworkInfoReq snNetworkInfoReq
) {
try {
if (sn == null || sn.trim().isEmpty()) {
return Result.failed("设备序列号不能为空");
}
if (snNetworkInfoReq == null) {
return Result.failed("网络信息不能为空");
}
SnDeviceNetworkInfo networkInfo = new SnDeviceNetworkInfo();
BeanUtils.copyProperties(snNetworkInfoReq, networkInfo);
networkInfo.setSerialno(sn);
networkInfo.setUpdateTime(LocalDateTime.now());
SnDeviceNetworkInfo existingNetworkInfo = networkInfoService.lambdaQuery()
.eq(SnDeviceNetworkInfo::getSerialno, sn)
.one();
boolean saved;
if (existingNetworkInfo != null) {
networkInfo.setId(existingNetworkInfo.getId());
saved = networkInfoService.updateById(networkInfo);
} else {
networkInfo.setCreateTime(LocalDateTime.now());
saved = networkInfoService.save(networkInfo);
}
if (!saved) {
return Result.failed("保存网络信息失败");
}
logger.info("网络信息上传成功, sn: {}", sn);
return Result.success();
} catch (Exception e) {
logger.error("updateNetworkInfo error, sn: {}", sn, e);
return Result.failed("上传网络信息失败: " + e.getMessage());
}
}
@Operation(summary = "上传设备安全信息")
@PostMapping("/update_security_info")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.DEVELOPER)
public Result<Void> updateSecurityInfo(
@RequestHeader(value = "X-Device-SN") String sn,
@RequestBody SnSecurityInfoReq snSecurityInfoReq
) {
try {
if (sn == null || sn.trim().isEmpty()) {
return Result.failed("设备序列号不能为空");
}
if (snSecurityInfoReq == null) {
return Result.failed("安全信息不能为空");
}
SnDeviceSecurityInfo securityInfo = new SnDeviceSecurityInfo();
BeanUtils.copyProperties(snSecurityInfoReq, securityInfo);
securityInfo.setSerialno(sn);
securityInfo.setUpdateTime(LocalDateTime.now());
SnDeviceSecurityInfo existingSecurityInfo = securityInfoService.lambdaQuery()
.eq(SnDeviceSecurityInfo::getSerialno, sn)
.one();
boolean saved;
if (existingSecurityInfo != null) {
securityInfo.setId(existingSecurityInfo.getId());
saved = securityInfoService.updateById(securityInfo);
} else {
securityInfo.setCreateTime(LocalDateTime.now());
saved = securityInfoService.save(securityInfo);
}
if (!saved) {
return Result.failed("保存安全信息失败");
}
logger.info("安全信息上传成功, sn: {}", sn);
return Result.success();
} catch (Exception e) {
logger.error("updateSecurityInfo error, sn: {}", sn, e);
return Result.failed("上传安全信息失败: " + e.getMessage());
}
}
@Operation(summary = "上传设备截图")
@PostMapping("/upload_screenshot")
@Log(module = LogModuleEnum.MOBILE, value = ActionTypeEnum.SCREENSHOT)

View File

@@ -0,0 +1,52 @@
package com.youlai.boot.device.converter;
import com.youlai.boot.device.model.entity.SnDeviceHardwareInfo;
import com.youlai.boot.device.model.entity.SnDeviceNetworkInfo;
import com.youlai.boot.device.model.entity.SnDeviceOtherInfo;
import com.youlai.boot.device.model.entity.SnDeviceSecurityInfo;
import com.youlai.boot.device.model.entity.SnDeviceSystemInfo;
import com.youlai.boot.device.model.vo.DeviceHardwareInfoVO;
import com.youlai.boot.device.model.vo.DeviceNetworkInfoVO;
import com.youlai.boot.device.model.vo.DeviceOtherInfoVO;
import com.youlai.boot.device.model.vo.DeviceSecurityInfoVO;
import com.youlai.boot.device.model.vo.DeviceSystemInfoVO;
import org.mapstruct.Mapper;
/**
* 设备系统信息 实体与 VO 转换器
* <p>
* 基本信息 / 硬件 / 网络 / 安全 / 其他 分面板独立映射。
* 使用 {@code source = "."} 将整个实体映射到目标对象,
* 规避 MapStruct 依赖编译期 -parameters 参数名的情况。
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Mapper(componentModel = "spring")
public interface SystemInfoConverter {
/**
* 基本信息实体 → 基本信息 VO
*/
DeviceSystemInfoVO toVo(SnDeviceSystemInfo entity);
/**
* 硬件信息实体 → 硬件信息 VO
*/
DeviceHardwareInfoVO toHardwareVo(SnDeviceHardwareInfo entity);
/**
* 网络信息实体 → 网络信息 VO
*/
DeviceNetworkInfoVO toNetworkVo(SnDeviceNetworkInfo entity);
/**
* 安全信息实体 → 安全信息 VO
*/
DeviceSecurityInfoVO toSecurityVo(SnDeviceSecurityInfo entity);
/**
* 其他信息实体 → 其他信息 VO
*/
DeviceOtherInfoVO toOtherVo(SnDeviceOtherInfo entity);
}

View File

@@ -0,0 +1,9 @@
package com.youlai.boot.device.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.boot.device.model.entity.SnDeviceHardwareInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface HardwareInfoMapper extends BaseMapper<SnDeviceHardwareInfo> {
}

View File

@@ -0,0 +1,9 @@
package com.youlai.boot.device.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.boot.device.model.entity.SnDeviceNetworkInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface NetworkInfoMapper extends BaseMapper<SnDeviceNetworkInfo> {
}

View File

@@ -0,0 +1,9 @@
package com.youlai.boot.device.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.boot.device.model.entity.SnDeviceOtherInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OtherInfoMapper extends BaseMapper<SnDeviceOtherInfo> {
}

View File

@@ -0,0 +1,9 @@
package com.youlai.boot.device.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.boot.device.model.entity.SnDeviceSecurityInfo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SecurityInfoMapper extends BaseMapper<SnDeviceSecurityInfo> {
}

View File

@@ -0,0 +1,51 @@
package com.youlai.boot.device.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.youlai.boot.common.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
/**
* 设备硬件信息实体(硬件信息面板,独立分表)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Getter
@Setter
@TableName("sys_sn_hardware_info")
public class SnDeviceHardwareInfo extends BaseEntity {
/**
* 设备序列号(关联 sys_sn.serialno
*/
private String serialno;
// ===================== 硬件信息面板 =====================
private String cpuAbi;
private String cpuAbi2;
private String cpuMin;
private String cpuModel;
private Integer cpuCores;
private String cpuMaxFreq;
private String cpuMinFreq;
private String totalRam;
private String availableRam;
private String internalStorage;
private String availableStorage;
private String externalStorage;
private String batteryCapacity;
private Integer batteryLevel;
private String batteryStatus;
private String batteryHealth;
private String batteryTemp;
private String batteryVoltage;
private String batteryTechnology;
private String gpuRenderer;
private String gpuVendor;
private String gpuVersion;
private String sensors;
private String supportAbi;
private String supportAbi64;
}

View File

@@ -0,0 +1,51 @@
package com.youlai.boot.device.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.youlai.boot.common.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
/**
* 设备网络信息实体(网络信息面板,独立分表)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Getter
@Setter
@TableName("sys_sn_network_info")
public class SnDeviceNetworkInfo extends BaseEntity {
/**
* 设备序列号(关联 sys_sn.serialno
*/
private String serialno;
// ===================== 网络信息面板 =====================
private String networkType;
private String networkSubtype;
private Integer isConnected;
private String wifiSsid;
private String wifiBssid;
private String wifiIp;
private String wifiMac;
private String wifiGateway;
private String wifiNetmask;
private String wifiDns;
private Integer wifiRssi;
private String wifiSpeed;
private String mobileIp;
private String mobileMac;
private String mobileImei;
private String mobileImsi;
private String mobileOperator;
private String mobileSimSerial;
private String mobileNetworkType;
private String bluetoothMac;
private String bluetoothName;
private Integer isVpn;
private Integer isProxy;
private String proxyHost;
private String proxyPort;
}

View File

@@ -0,0 +1,50 @@
package com.youlai.boot.device.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.youlai.boot.common.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* 设备其他信息实体(其他信息面板,独立分表)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Getter
@Setter
@TableName("sys_sn_other_info")
public class SnDeviceOtherInfo extends BaseEntity {
/**
* 设备序列号(关联 sys_sn.serialno
*/
private String serialno;
// ===================== 其他信息面板 =====================
private String appVersion;
private Integer appVersionCode;
private LocalDateTime installTime;
private LocalDateTime updateTimeApp;
private String packageName;
private String channel;
private String deviceId;
private String gaid;
private String oaid;
private String phoneNumber;
private String iccid;
private String imsi;
private String cameraInfo;
private Integer sensorCount;
private String appListMd5;
private Integer isCharging;
private String chargingType;
private String temperature;
private String freeStorage;
private String totalStorage;
private String freeRam;
private String totalRam;
}

View File

@@ -0,0 +1,47 @@
package com.youlai.boot.device.model.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.youlai.boot.common.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
/**
* 设备安全信息实体(安全信息面板,独立分表)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Getter
@Setter
@TableName("sys_sn_security_info")
public class SnDeviceSecurityInfo extends BaseEntity {
/**
* 设备序列号(关联 sys_sn.serialno
*/
private String serialno;
// ===================== 安全信息面板 =====================
private Integer isRoot;
private Integer isJailbreak;
private Integer rootStatus;
private Integer hasSuBinary;
private Integer hasBusybox;
private Integer isEmulator;
private Integer isDebuggable;
private Integer isUsbDebug;
private Integer isUnknownSources;
private Integer isVerifyApps;
private Integer isEncrypted;
private String lockScreenType;
private Integer hasPassword;
private String passwordType;
private String securityPatch;
private Integer googlePlayProtect;
private Integer adbStatus;
private Integer isVpnActive;
private Integer isDeviceOwner;
private String androidVersion;
private String kernelVersion;
}

View File

@@ -5,28 +5,239 @@ import com.youlai.boot.common.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
/**
* 用户实体
* 设备基本信息实体(仅基本信息面板)
* <p>
* 硬件 / 网络 / 安全 / 其他 面板数据分别独立分表存储,
* 见 {@code SnDeviceHardwareInfo} / {@code SnDeviceNetworkInfo} /
* {@code SnDeviceSecurityInfo} / {@code SnDeviceOtherInfo}。
*
* @author Ray.Hao
* @since 2026-08-04
*/
@TableName("sys_sn_system_info")
@Getter
@Setter
@TableName("sys_sn_system_info")
public class SnDeviceSystemInfo extends BaseEntity {
/**
* 设备序列号
* 设备序列号(关联 sys_sn.serialno
*/
private String serialno;
private String snImei;
private String snImsi;
private String snWlanMac;
private String snDeviceMac;
private String snBluetoothMac;
private String snModel;
private String snBrand;
private String snBoard;
private String snAndroidVersion;
private int snAndroidApi;
private String snBuildId;
private String snBuildDisplayId;
// ===================== 基本信息面板 =====================
/**
* 设备名称
*/
private String deviceName;
/**
* 设备品牌
*/
private String deviceBrand;
/**
* 设备型号
*/
private String deviceModel;
/**
* 主板名称
*/
private String deviceBoard;
/**
* 制造商
*/
private String deviceManufacturer;
/**
* 硬件信息
*/
private String hardware;
/**
* 主机名
*/
private String host;
/**
* Android 版本
*/
private String androidVersion;
/**
* Android API 级别
*/
private Integer androidApi;
/**
* Android ID
*/
private String androidId;
/**
* Build ID
*/
private String buildId;
/**
* Build Display ID
*/
private String buildDisplayId;
/**
* Build 指纹
*/
private String buildFingerprint;
/**
* Build 类型user/userdebug/eng
*/
private String buildType;
/**
* Build 用户
*/
private String buildUser;
/**
* Build 主机
*/
private String buildHost;
/**
* Build 标签
*/
private String buildTags;
/**
* Build 时间
*/
private LocalDateTime buildTime;
/**
* 系统语言
*/
private String language;
/**
* 时区
*/
private String timezone;
/**
* 开机时间
*/
private LocalDateTime bootTime;
/**
* 屏幕分辨率
*/
private String screenResolution;
/**
* 屏幕密度
*/
private Integer screenDensity;
/**
* 内核版本
*/
private String kernelVersion;
/**
* ROM 版本
*/
private String romVersion;
// ===================== 补充基本信息字段 =====================
/**
* 产品名称
*/
private String productName;
/**
* 产品型号
*/
private String productModel;
/**
* 产品设备名
*/
private String productDevice;
/**
* 主板平台
*/
private String boardPlatform;
/**
* 设备类型phone/tablet/tv 等)
*/
private String deviceType;
/**
* 是否平板0否 1是
*/
private Integer isTablet;
/**
* Android 发布版本号
*/
private String releaseVersion;
/**
* 显示版本号
*/
private String displayVersion;
/**
* Bootloader 版本
*/
private String bootloader;
/**
* 基带版本
*/
private String basebandVersion;
/**
* Radio 版本
*/
private String radioVersion;
/**
* 屏幕尺寸(英寸,文本)
*/
private String screenSize;
/**
* 屏幕尺寸(数值,英寸)
*/
private java.math.BigDecimal screenInch;
/**
* 屏幕刷新率Hz
*/
private Integer refreshRate;
/**
* 操作系统类型
*/
private String osType;
/**
* 操作系统版本
*/
private String osVersion;
/**
* 固件版本
*/
private String firmwareVersion;
}

View File

@@ -0,0 +1,118 @@
package com.youlai.boot.device.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 设备硬件信息上传请求
*
* @author TTSTD
* @since 2026/08/05
*/
@Schema(description = "设备硬件信息")
@Data
public class SnHardwareInfoReq {
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "CPU ABI")
@JsonProperty("cpu_abi")
private String cpuAbi;
@Schema(description = "CPU ABI2")
@JsonProperty("cpu_abi2")
private String cpuAbi2;
@Schema(description = "CPU 最小信息")
@JsonProperty("cpu_min")
private String cpuMin;
@Schema(description = "CPU 型号")
@JsonProperty("cpu_model")
private String cpuModel;
@Schema(description = "CPU 核心数")
@JsonProperty("cpu_cores")
private Integer cpuCores;
@Schema(description = "CPU 最大频率")
@JsonProperty("cpu_max_freq")
private String cpuMaxFreq;
@Schema(description = "CPU 最小频率")
@JsonProperty("cpu_min_freq")
private String cpuMinFreq;
@Schema(description = "总内存")
@JsonProperty("total_ram")
private String totalRam;
@Schema(description = "可用内存")
@JsonProperty("available_ram")
private String availableRam;
@Schema(description = "内部存储")
@JsonProperty("internal_storage")
private String internalStorage;
@Schema(description = "可用存储")
@JsonProperty("available_storage")
private String availableStorage;
@Schema(description = "外部存储")
@JsonProperty("external_storage")
private String externalStorage;
@Schema(description = "电池容量")
@JsonProperty("battery_capacity")
private String batteryCapacity;
@Schema(description = "电池电量")
@JsonProperty("battery_level")
private Integer batteryLevel;
@Schema(description = "电池状态")
@JsonProperty("battery_status")
private String batteryStatus;
@Schema(description = "电池健康")
@JsonProperty("battery_health")
private String batteryHealth;
@Schema(description = "电池温度")
@JsonProperty("battery_temp")
private String batteryTemp;
@Schema(description = "电池电压")
@JsonProperty("battery_voltage")
private String batteryVoltage;
@Schema(description = "电池技术")
@JsonProperty("battery_technology")
private String batteryTechnology;
@Schema(description = "GPU 渲染器")
@JsonProperty("gpu_renderer")
private String gpuRenderer;
@Schema(description = "GPU 厂商")
@JsonProperty("gpu_vendor")
private String gpuVendor;
@Schema(description = "GPU 版本")
@JsonProperty("gpu_version")
private String gpuVersion;
@Schema(description = "传感器信息")
private String sensors;
@Schema(description = "支持的 ABI")
@JsonProperty("support_abi")
private String supportAbi;
@Schema(description = "支持的 64 位 ABI")
@JsonProperty("support_abi64")
private String supportAbi64;
}

View File

@@ -0,0 +1,119 @@
package com.youlai.boot.device.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 设备网络信息上传请求
*
* @author TTSTD
* @since 2026/08/05
*/
@Schema(description = "设备网络信息")
@Data
public class SnNetworkInfoReq {
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "网络类型")
@JsonProperty("network_type")
private String networkType;
@Schema(description = "网络子类型")
@JsonProperty("network_subtype")
private String networkSubtype;
@Schema(description = "是否连接")
@JsonProperty("is_connected")
private Integer isConnected;
@Schema(description = "WiFi SSID")
@JsonProperty("wifi_ssid")
private String wifiSsid;
@Schema(description = "WiFi BSSID")
@JsonProperty("wifi_bssid")
private String wifiBssid;
@Schema(description = "WiFi IP")
@JsonProperty("wifi_ip")
private String wifiIp;
@Schema(description = "WiFi MAC")
@JsonProperty("wifi_mac")
private String wifiMac;
@Schema(description = "WiFi 网关")
@JsonProperty("wifi_gateway")
private String wifiGateway;
@Schema(description = "WiFi 子网掩码")
@JsonProperty("wifi_netmask")
private String wifiNetmask;
@Schema(description = "WiFi DNS")
@JsonProperty("wifi_dns")
private String wifiDns;
@Schema(description = "WiFi 信号强度")
@JsonProperty("wifi_rssi")
private Integer wifiRssi;
@Schema(description = "WiFi 速度")
@JsonProperty("wifi_speed")
private String wifiSpeed;
@Schema(description = "移动网络 IP")
@JsonProperty("mobile_ip")
private String mobileIp;
@Schema(description = "移动网络 MAC")
@JsonProperty("mobile_mac")
private String mobileMac;
@Schema(description = "移动网络 IMEI")
@JsonProperty("mobile_imei")
private String mobileImei;
@Schema(description = "移动网络 IMSI")
@JsonProperty("mobile_imsi")
private String mobileImsi;
@Schema(description = "运营商")
@JsonProperty("mobile_operator")
private String mobileOperator;
@Schema(description = "SIM 序列号")
@JsonProperty("mobile_sim_serial")
private String mobileSimSerial;
@Schema(description = "移动网络类型")
@JsonProperty("mobile_network_type")
private String mobileNetworkType;
@Schema(description = "蓝牙 MAC")
@JsonProperty("bluetooth_mac")
private String bluetoothMac;
@Schema(description = "蓝牙名称")
@JsonProperty("bluetooth_name")
private String bluetoothName;
@Schema(description = "是否 VPN")
@JsonProperty("is_vpn")
private Integer isVpn;
@Schema(description = "是否代理")
@JsonProperty("is_proxy")
private Integer isProxy;
@Schema(description = "代理主机")
@JsonProperty("proxy_host")
private String proxyHost;
@Schema(description = "代理端口")
@JsonProperty("proxy_port")
private String proxyPort;
}

View File

@@ -0,0 +1,103 @@
package com.youlai.boot.device.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 设备其他信息上传请求
*
* @author TTSTD
* @since 2026/08/05
*/
@Schema(description = "设备其他信息")
@Data
public class SnOtherInfoReq {
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "App版本")
@JsonProperty("app_version")
private String appVersion;
@Schema(description = "App版本号")
@JsonProperty("app_version_code")
private Integer appVersionCode;
@Schema(description = "安装时间")
@JsonProperty("install_time")
private LocalDateTime installTime;
@Schema(description = "App更新时间")
@JsonProperty("update_time_app")
private LocalDateTime updateTimeApp;
@Schema(description = "包名")
@JsonProperty("package_name")
private String packageName;
@Schema(description = "渠道")
private String channel;
@Schema(description = "设备ID")
@JsonProperty("device_id")
private String deviceId;
@Schema(description = "GAID")
private String gaid;
@Schema(description = "OAID")
private String oaid;
@Schema(description = "手机号")
@JsonProperty("phone_number")
private String phoneNumber;
@Schema(description = "ICCID")
private String iccid;
@Schema(description = "IMSI")
private String imsi;
@Schema(description = "相机信息")
@JsonProperty("camera_info")
private String cameraInfo;
@Schema(description = "传感器数量")
@JsonProperty("sensor_count")
private Integer sensorCount;
@Schema(description = "应用列表MD5")
@JsonProperty("app_list_md5")
private String appListMd5;
@Schema(description = "是否充电中0否 1是")
@JsonProperty("is_charging")
private Integer isCharging;
@Schema(description = "充电类型")
@JsonProperty("charging_type")
private String chargingType;
@Schema(description = "温度")
private String temperature;
@Schema(description = "可用存储")
@JsonProperty("free_storage")
private String freeStorage;
@Schema(description = "总存储")
@JsonProperty("total_storage")
private String totalStorage;
@Schema(description = "可用内存")
@JsonProperty("free_ram")
private String freeRam;
@Schema(description = "总内存")
@JsonProperty("total_ram")
private String totalRam;
}

View File

@@ -0,0 +1,103 @@
package com.youlai.boot.device.model.req;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 设备安全信息上传请求
*
* @author TTSTD
* @since 2026/08/05
*/
@Schema(description = "设备安全信息")
@Data
public class SnSecurityInfoReq {
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "是否 Root")
@JsonProperty("is_root")
private Integer isRoot;
@Schema(description = "是否越狱")
@JsonProperty("is_jailbreak")
private Integer isJailbreak;
@Schema(description = "Root 状态")
@JsonProperty("root_status")
private Integer rootStatus;
@Schema(description = "是否有 su 二进制")
@JsonProperty("has_su_binary")
private Integer hasSuBinary;
@Schema(description = "是否有 busybox")
@JsonProperty("has_busybox")
private Integer hasBusybox;
@Schema(description = "是否模拟器")
@JsonProperty("is_emulator")
private Integer isEmulator;
@Schema(description = "是否可调试")
@JsonProperty("is_debuggable")
private Integer isDebuggable;
@Schema(description = "是否 USB 调试")
@JsonProperty("is_usb_debug")
private Integer isUsbDebug;
@Schema(description = "是否未知来源")
@JsonProperty("is_unknown_sources")
private Integer isUnknownSources;
@Schema(description = "是否验证应用")
@JsonProperty("is_verify_apps")
private Integer isVerifyApps;
@Schema(description = "是否加密")
@JsonProperty("is_encrypted")
private Integer isEncrypted;
@Schema(description = "锁屏类型")
@JsonProperty("lock_screen_type")
private String lockScreenType;
@Schema(description = "是否有密码")
@JsonProperty("has_password")
private Integer hasPassword;
@Schema(description = "密码类型")
@JsonProperty("password_type")
private String passwordType;
@Schema(description = "安全补丁")
@JsonProperty("security_patch")
private String securityPatch;
@Schema(description = "Google Play 保护")
@JsonProperty("google_play_protect")
private Integer googlePlayProtect;
@Schema(description = "ADB 状态")
@JsonProperty("adb_status")
private Integer adbStatus;
@Schema(description = "是否 VPN 活跃")
@JsonProperty("is_vpn_active")
private Integer isVpnActive;
@Schema(description = "是否设备所有者")
@JsonProperty("is_device_owner")
private Integer isDeviceOwner;
@Schema(description = "Android 版本")
@JsonProperty("android_version")
private String androidVersion;
@Schema(description = "内核版本")
@JsonProperty("kernel_version")
private String kernelVersion;
}

View File

@@ -0,0 +1,96 @@
package com.youlai.boot.device.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 设备硬件信息视图对象(硬件信息面板)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Schema(description = "设备硬件信息视图对象")
@Data
public class DeviceHardwareInfoVO {
@Schema(description = "ID")
private Long id;
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "CPU ABI 列表")
private String cpuAbi;
@Schema(description = "CPU ABI2")
private String cpuAbi2;
@Schema(description = "最小 CPU ABI")
private String cpuMin;
@Schema(description = "CPU 型号")
private String cpuModel;
@Schema(description = "CPU 核心数")
private Integer cpuCores;
@Schema(description = "CPU 最大频率")
private String cpuMaxFreq;
@Schema(description = "CPU 最小频率")
private String cpuMinFreq;
@Schema(description = "总内存")
private String totalRam;
@Schema(description = "可用内存")
private String availableRam;
@Schema(description = "内部存储")
private String internalStorage;
@Schema(description = "可用存储")
private String availableStorage;
@Schema(description = "外部存储")
private String externalStorage;
@Schema(description = "电池容量")
private String batteryCapacity;
@Schema(description = "电池电量")
private Integer batteryLevel;
@Schema(description = "电池状态")
private String batteryStatus;
@Schema(description = "电池健康度")
private String batteryHealth;
@Schema(description = "电池温度")
private String batteryTemp;
@Schema(description = "电池电压")
private String batteryVoltage;
@Schema(description = "电池技术")
private String batteryTechnology;
@Schema(description = "GPU 渲染器")
private String gpuRenderer;
@Schema(description = "GPU 厂商")
private String gpuVendor;
@Schema(description = "GPU 版本")
private String gpuVersion;
@Schema(description = "传感器列表")
private String sensors;
@Schema(description = "支持的应用二进制接口")
private String supportAbi;
@Schema(description = "支持的 64 位 ABI")
private String supportAbi64;
}

View File

@@ -0,0 +1,96 @@
package com.youlai.boot.device.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 设备网络信息视图对象(网络信息面板)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Schema(description = "设备网络信息视图对象")
@Data
public class DeviceNetworkInfoVO {
@Schema(description = "ID")
private Long id;
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "网络类型")
private String networkType;
@Schema(description = "网络子类型")
private String networkSubtype;
@Schema(description = "是否联网0否 1是")
private Integer isConnected;
@Schema(description = "WiFi SSID")
private String wifiSsid;
@Schema(description = "WiFi BSSID")
private String wifiBssid;
@Schema(description = "WiFi IP 地址")
private String wifiIp;
@Schema(description = "WiFi MAC 地址")
private String wifiMac;
@Schema(description = "WiFi 网关")
private String wifiGateway;
@Schema(description = "WiFi 子网掩码")
private String wifiNetmask;
@Schema(description = "WiFi DNS")
private String wifiDns;
@Schema(description = "WiFi 信号强度")
private Integer wifiRssi;
@Schema(description = "WiFi 连接速度")
private String wifiSpeed;
@Schema(description = "移动网络 IP")
private String mobileIp;
@Schema(description = "移动网络 MAC")
private String mobileMac;
@Schema(description = "IMEI")
private String mobileImei;
@Schema(description = "IMSI")
private String mobileImsi;
@Schema(description = "运营商名称")
private String mobileOperator;
@Schema(description = "SIM 序列号")
private String mobileSimSerial;
@Schema(description = "移动网络类型")
private String mobileNetworkType;
@Schema(description = "蓝牙 MAC 地址")
private String bluetoothMac;
@Schema(description = "蓝牙名称")
private String bluetoothName;
@Schema(description = "是否 VPN0否 1是")
private Integer isVpn;
@Schema(description = "是否代理0否 1是")
private Integer isProxy;
@Schema(description = "代理主机")
private String proxyHost;
@Schema(description = "代理端口")
private String proxyPort;
}

View File

@@ -0,0 +1,89 @@
package com.youlai.boot.device.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 设备其他信息视图对象(其他信息面板)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Schema(description = "设备其他信息视图对象")
@Data
public class DeviceOtherInfoVO {
@Schema(description = "ID")
private Long id;
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "App 版本")
private String appVersion;
@Schema(description = "App 版本号")
private Integer appVersionCode;
@Schema(description = "App 安装时间")
private LocalDateTime installTime;
@Schema(description = "App 更新时间")
private LocalDateTime updateTimeApp;
@Schema(description = "应用包名")
private String packageName;
@Schema(description = "渠道")
private String channel;
@Schema(description = "设备 ID应用层")
private String deviceId;
@Schema(description = "Google Advertising ID")
private String gaid;
@Schema(description = "OAID")
private String oaid;
@Schema(description = "手机号(脱敏)")
private String phoneNumber;
@Schema(description = "ICCID")
private String iccid;
@Schema(description = "IMSI")
private String imsi;
@Schema(description = "摄像头信息")
private String cameraInfo;
@Schema(description = "传感器数量")
private Integer sensorCount;
@Schema(description = "应用列表 MD5")
private String appListMd5;
@Schema(description = "是否充电中0否 1是")
private Integer isCharging;
@Schema(description = "充电类型")
private String chargingType;
@Schema(description = "设备温度")
private String temperature;
@Schema(description = "剩余存储")
private String freeStorage;
@Schema(description = "总存储")
private String totalStorage;
@Schema(description = "剩余内存")
private String freeRam;
@Schema(description = "总内存")
private String totalRam;
}

View File

@@ -0,0 +1,84 @@
package com.youlai.boot.device.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 设备安全信息视图对象(安全信息面板)
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Schema(description = "设备安全信息视图对象")
@Data
public class DeviceSecurityInfoVO {
@Schema(description = "ID")
private Long id;
@Schema(description = "设备序列号")
private String serialno;
@Schema(description = "是否已 Root0否 1是")
private Integer isRoot;
@Schema(description = "是否已越狱0否 1是")
private Integer isJailbreak;
@Schema(description = "Root/越狱状态0否 1是")
private Integer rootStatus;
@Schema(description = "是否存在 su 二进制0否 1是")
private Integer hasSuBinary;
@Schema(description = "是否存在 BusyBox0否 1是")
private Integer hasBusybox;
@Schema(description = "是否模拟器0否 1是")
private Integer isEmulator;
@Schema(description = "是否可调试0否 1是")
private Integer isDebuggable;
@Schema(description = "是否开启 USB 调试0否 1是")
private Integer isUsbDebug;
@Schema(description = "是否允许未知来源0否 1是")
private Integer isUnknownSources;
@Schema(description = "是否验证应用0否 1是")
private Integer isVerifyApps;
@Schema(description = "是否加密0否 1是")
private Integer isEncrypted;
@Schema(description = "锁屏类型")
private String lockScreenType;
@Schema(description = "是否设置密码0否 1是")
private Integer hasPassword;
@Schema(description = "密码类型")
private String passwordType;
@Schema(description = "安全补丁级别")
private String securityPatch;
@Schema(description = "Google Play 保护0否 1是")
private Integer googlePlayProtect;
@Schema(description = "ADB 状态0关 1开")
private Integer adbStatus;
@Schema(description = "VPN 是否激活0否 1是")
private Integer isVpnActive;
@Schema(description = "是否设备所有者0否 1是")
private Integer isDeviceOwner;
@Schema(description = "Android 版本")
private String androidVersion;
@Schema(description = "内核版本")
private String kernelVersion;
}

View File

@@ -3,55 +3,155 @@ package com.youlai.boot.device.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 设备硬件对象
* 设备基本信息视图对象(仅基本信息面板)
* <p>
* 硬件 / 网络 / 安全 / 其他 面板分别使用独立 VO
* {@link DeviceHardwareInfoVO} / {@link DeviceNetworkInfoVO} /
* {@link DeviceSecurityInfoVO} / {@link DeviceOtherInfoVO}。
*
* @author haoxr
* @since 2022/1/15 9:41
* @author Ray.Hao
* @since 2026-08-04
*/
@Schema(description ="设备硬件对象")
@Schema(description = "设备基本信息视图对象")
@Data
public class DeviceSystemInfoVO {
@Schema(description="设备ID")
@Schema(description = "ID")
private Long id;
@Schema(description="SN")
@Schema(description = "设备序列号")
private String serialno;
@Schema(description="WLAN MAC地址")
private String snWlanMac;
// ===================== 基本信息面板 =====================
@Schema(description="设备MAC地址")
private String snDeviceMac;
@Schema(description = "设备名称")
private String deviceName;
@Schema(description="蓝牙MAC地址")
private String snBluetoothMac;
@Schema(description = "设备品牌")
private String deviceBrand;
@Schema(description="设备IMEI")
private String snImei;
@Schema(description = "设备型号")
private String deviceModel;
@Schema(description="设备型号")
private String snModel;
@Schema(description = "主板名称")
private String deviceBoard;
@Schema(description="设备品牌")
private String snBrand;
@Schema(description = "制造商")
private String deviceManufacturer;
@Schema(description="设备主板")
private String snBoard;
@Schema(description = "硬件信息")
private String hardware;
@Schema(description="设备Android版本")
private String snAndroidVersion;
@Schema(description = "主机名")
private String host;
@Schema(description="设备Android API")
private int snAndroidApi;
@Schema(description = "Android 版本")
private String androidVersion;
@Schema(description="设备构建ID")
private String snBuildId;
@Schema(description = "Android API 级别")
private Integer androidApi;
@Schema(description="设备显示ID")
private String snBuildDisplayId;
@Schema(description = "Android ID")
private String androidId;
@Schema(description = "Build ID")
private String buildId;
@Schema(description = "Build Display ID")
private String buildDisplayId;
@Schema(description = "Build 指纹")
private String buildFingerprint;
@Schema(description = "Build 类型")
private String buildType;
@Schema(description = "Build 用户")
private String buildUser;
@Schema(description = "Build 主机")
private String buildHost;
@Schema(description = "Build 标签")
private String buildTags;
@Schema(description = "Build 时间")
private LocalDateTime buildTime;
@Schema(description = "系统语言")
private String language;
@Schema(description = "时区")
private String timezone;
@Schema(description = "开机时间")
private LocalDateTime bootTime;
@Schema(description = "屏幕分辨率")
private String screenResolution;
@Schema(description = "屏幕密度")
private Integer screenDensity;
@Schema(description = "内核版本")
private String kernelVersion;
@Schema(description = "ROM 版本")
private String romVersion;
// ===================== 补充基本信息字段 =====================
@Schema(description = "产品名称")
private String productName;
@Schema(description = "产品型号")
private String productModel;
@Schema(description = "产品设备名")
private String productDevice;
@Schema(description = "主板平台")
private String boardPlatform;
@Schema(description = "设备类型phone/tablet/tv等")
private String deviceType;
@Schema(description = "是否平板0否 1是")
private Integer isTablet;
@Schema(description = "Android 发布版本号")
private String releaseVersion;
@Schema(description = "显示版本号")
private String displayVersion;
@Schema(description = "Bootloader 版本")
private String bootloader;
@Schema(description = "基带版本")
private String basebandVersion;
@Schema(description = "Radio 版本")
private String radioVersion;
@Schema(description = "屏幕尺寸(英寸,文本)")
private String screenSize;
@Schema(description = "屏幕尺寸(数值,英寸)")
private java.math.BigDecimal screenInch;
@Schema(description = "屏幕刷新率Hz")
private Integer refreshRate;
@Schema(description = "操作系统类型")
private String osType;
@Schema(description = "操作系统版本")
private String osVersion;
@Schema(description = "固件版本")
private String firmwareVersion;
}

View File

@@ -4,6 +4,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.device.model.entity.SnDeviceInfo;
import com.youlai.boot.device.model.query.DeviceQuery;
import com.youlai.boot.device.model.vo.DeviceHardwareInfoVO;
import com.youlai.boot.device.model.vo.DeviceNetworkInfoVO;
import com.youlai.boot.device.model.vo.DeviceOtherInfoVO;
import com.youlai.boot.device.model.vo.DeviceSecurityInfoVO;
import com.youlai.boot.device.model.vo.DeviceSystemInfoVO;
import com.youlai.boot.device.model.vo.DevicePageVO;
@@ -24,13 +28,45 @@ public interface DeviceService extends IService<SnDeviceInfo> {
* @return 设备详情信息
*/
DevicePageVO getSnBindInfo(String sn);
/**
* 获取设备基本信息
*
* @param sn 设备序列号
* @return 设备基本信息(无则返回 null
*/
DeviceSystemInfoVO getDeviceBasicInfo(String sn);
/**
* 获取设备硬件信息
*
* @param sn 设备序列号
* @return 设备硬件信息
* @return 设备硬件信息(无则返回 null
*/
DeviceSystemInfoVO getSnSystemInfo(String sn);
DeviceHardwareInfoVO getDeviceHardwareInfo(String sn);
/**
* 获取设备网络信息
*
* @param sn 设备序列号
* @return 设备网络信息(无则返回 null
*/
DeviceNetworkInfoVO getDeviceNetworkInfo(String sn);
/**
* 获取设备安全信息
*
* @param sn 设备序列号
* @return 设备安全信息(无则返回 null
*/
DeviceSecurityInfoVO getDeviceSecurityInfo(String sn);
/**
* 获取设备其他信息
*
* @param sn 设备序列号
* @return 设备其他信息(无则返回 null
*/
DeviceOtherInfoVO getDeviceOtherInfo(String sn);
/**
* 添加设备

View File

@@ -0,0 +1,21 @@
package com.youlai.boot.device.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.device.model.entity.SnDeviceHardwareInfo;
/**
* 设备硬件信息服务
*
* @author Ray.Hao
* @since 2026-08-04
*/
public interface HardwareInfoService extends IService<SnDeviceHardwareInfo> {
/**
* 根据序列号查询设备硬件信息
*
* @param sn 设备序列号
* @return 硬件信息实体(无则返回 null
*/
SnDeviceHardwareInfo getBySn(String sn);
}

View File

@@ -0,0 +1,21 @@
package com.youlai.boot.device.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.device.model.entity.SnDeviceNetworkInfo;
/**
* 设备网络信息服务
*
* @author Ray.Hao
* @since 2026-08-04
*/
public interface NetworkInfoService extends IService<SnDeviceNetworkInfo> {
/**
* 根据序列号查询设备网络信息
*
* @param sn 设备序列号
* @return 网络信息实体(无则返回 null
*/
SnDeviceNetworkInfo getBySn(String sn);
}

View File

@@ -0,0 +1,21 @@
package com.youlai.boot.device.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.device.model.entity.SnDeviceOtherInfo;
/**
* 设备其他信息服务
*
* @author Ray.Hao
* @since 2026-08-04
*/
public interface OtherInfoService extends IService<SnDeviceOtherInfo> {
/**
* 根据序列号查询设备其他信息
*
* @param sn 设备序列号
* @return 其他信息实体(无则返回 null
*/
SnDeviceOtherInfo getBySn(String sn);
}

View File

@@ -0,0 +1,21 @@
package com.youlai.boot.device.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.device.model.entity.SnDeviceSecurityInfo;
/**
* 设备安全信息服务
*
* @author Ray.Hao
* @since 2026-08-04
*/
public interface SecurityInfoService extends IService<SnDeviceSecurityInfo> {
/**
* 根据序列号查询设备安全信息
*
* @param sn 设备序列号
* @return 安全信息实体(无则返回 null
*/
SnDeviceSecurityInfo getBySn(String sn);
}

View File

@@ -4,4 +4,12 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.device.model.entity.SnDeviceSystemInfo;
public interface SystemInfoService extends IService<SnDeviceSystemInfo> {
/**
* 根据设备序列号获取设备系统信息
*
* @param sn 设备序列号
* @return 设备系统信息实体,不存在时返回 null
*/
SnDeviceSystemInfo getBySn(String sn);
}

View File

@@ -10,13 +10,28 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.framework.security.util.SecurityUtils;
import com.youlai.boot.device.converter.SystemInfoConverter;
import com.youlai.boot.device.mapper.DeviceMapper;
import com.youlai.boot.device.model.entity.SnDeviceHardwareInfo;
import com.youlai.boot.device.model.entity.SnDeviceInfo;
import com.youlai.boot.device.model.entity.SnDeviceNetworkInfo;
import com.youlai.boot.device.model.entity.SnDeviceOtherInfo;
import com.youlai.boot.device.model.entity.SnDeviceSecurityInfo;
import com.youlai.boot.device.model.entity.SnDeviceSystemInfo;
import com.youlai.boot.device.model.query.DeviceQuery;
import com.youlai.boot.device.model.vo.DeviceHardwareInfoVO;
import com.youlai.boot.device.model.vo.DeviceNetworkInfoVO;
import com.youlai.boot.device.model.vo.DeviceOtherInfoVO;
import com.youlai.boot.device.model.vo.DeviceSecurityInfoVO;
import com.youlai.boot.device.model.vo.DeviceSystemInfoVO;
import com.youlai.boot.device.model.vo.DevicePageVO;
import com.youlai.boot.device.service.DeveloperService;
import com.youlai.boot.device.service.DeviceService;
import com.youlai.boot.device.service.HardwareInfoService;
import com.youlai.boot.device.service.NetworkInfoService;
import com.youlai.boot.device.service.OtherInfoService;
import com.youlai.boot.device.service.SecurityInfoService;
import com.youlai.boot.device.service.SystemInfoService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
@@ -43,6 +58,14 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, SnDeviceInfo> i
private final DeveloperService developerService;
private final SystemInfoService systemInfoService;
private final HardwareInfoService hardwareInfoService;
private final NetworkInfoService networkInfoService;
private final SecurityInfoService securityInfoService;
private final OtherInfoService otherInfoService;
private final SystemInfoConverter systemInfoConverter;
@Override
public IPage<DevicePageVO> getSnPage(DeviceQuery queryParams) {
// 参数构建
@@ -76,8 +99,48 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, SnDeviceInfo> i
}
@Override
public DeviceSystemInfoVO getSnSystemInfo(String sn) {
return null;
public DeviceSystemInfoVO getDeviceBasicInfo(String sn) {
SnDeviceSystemInfo entity = systemInfoService.getBySn(sn);
if (entity == null) {
return null;
}
return systemInfoConverter.toVo(entity);
}
@Override
public DeviceHardwareInfoVO getDeviceHardwareInfo(String sn) {
SnDeviceHardwareInfo entity = hardwareInfoService.getBySn(sn);
if (entity == null) {
return null;
}
return systemInfoConverter.toHardwareVo(entity);
}
@Override
public DeviceNetworkInfoVO getDeviceNetworkInfo(String sn) {
SnDeviceNetworkInfo entity = networkInfoService.getBySn(sn);
if (entity == null) {
return null;
}
return systemInfoConverter.toNetworkVo(entity);
}
@Override
public DeviceSecurityInfoVO getDeviceSecurityInfo(String sn) {
SnDeviceSecurityInfo entity = securityInfoService.getBySn(sn);
if (entity == null) {
return null;
}
return systemInfoConverter.toSecurityVo(entity);
}
@Override
public DeviceOtherInfoVO getDeviceOtherInfo(String sn) {
SnDeviceOtherInfo entity = otherInfoService.getBySn(sn);
if (entity == null) {
return null;
}
return systemInfoConverter.toOtherVo(entity);
}
@Override

View File

@@ -0,0 +1,32 @@
package com.youlai.boot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.device.mapper.HardwareInfoMapper;
import com.youlai.boot.device.model.entity.SnDeviceHardwareInfo;
import com.youlai.boot.device.service.HardwareInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
/**
* 设备硬件信息服务实现
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Slf4j
@Service
public class HardwareInfoServiceImpl extends ServiceImpl<HardwareInfoMapper, SnDeviceHardwareInfo>
implements HardwareInfoService {
@Override
public SnDeviceHardwareInfo getBySn(String sn) {
if (StringUtils.isBlank(sn)) {
return null;
}
LambdaQueryWrapper<SnDeviceHardwareInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SnDeviceHardwareInfo::getSerialno, sn).last("LIMIT 1");
return this.getOne(wrapper);
}
}

View File

@@ -0,0 +1,32 @@
package com.youlai.boot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.device.mapper.NetworkInfoMapper;
import com.youlai.boot.device.model.entity.SnDeviceNetworkInfo;
import com.youlai.boot.device.service.NetworkInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
/**
* 设备网络信息服务实现
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Slf4j
@Service
public class NetworkInfoServiceImpl extends ServiceImpl<NetworkInfoMapper, SnDeviceNetworkInfo>
implements NetworkInfoService {
@Override
public SnDeviceNetworkInfo getBySn(String sn) {
if (StringUtils.isBlank(sn)) {
return null;
}
LambdaQueryWrapper<SnDeviceNetworkInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SnDeviceNetworkInfo::getSerialno, sn).last("LIMIT 1");
return this.getOne(wrapper);
}
}

View File

@@ -0,0 +1,32 @@
package com.youlai.boot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.device.mapper.OtherInfoMapper;
import com.youlai.boot.device.model.entity.SnDeviceOtherInfo;
import com.youlai.boot.device.service.OtherInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
/**
* 设备其他信息服务实现
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Slf4j
@Service
public class OtherInfoServiceImpl extends ServiceImpl<OtherInfoMapper, SnDeviceOtherInfo>
implements OtherInfoService {
@Override
public SnDeviceOtherInfo getBySn(String sn) {
if (StringUtils.isBlank(sn)) {
return null;
}
LambdaQueryWrapper<SnDeviceOtherInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SnDeviceOtherInfo::getSerialno, sn).last("LIMIT 1");
return this.getOne(wrapper);
}
}

View File

@@ -0,0 +1,32 @@
package com.youlai.boot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.device.mapper.SecurityInfoMapper;
import com.youlai.boot.device.model.entity.SnDeviceSecurityInfo;
import com.youlai.boot.device.service.SecurityInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
/**
* 设备安全信息服务实现
*
* @author Ray.Hao
* @since 2026-08-04
*/
@Slf4j
@Service
public class SecurityInfoServiceImpl extends ServiceImpl<SecurityInfoMapper, SnDeviceSecurityInfo>
implements SecurityInfoService {
@Override
public SnDeviceSecurityInfo getBySn(String sn) {
if (StringUtils.isBlank(sn)) {
return null;
}
LambdaQueryWrapper<SnDeviceSecurityInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SnDeviceSecurityInfo::getSerialno, sn).last("LIMIT 1");
return this.getOne(wrapper);
}
}

View File

@@ -1,13 +1,26 @@
package com.youlai.boot.device.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.device.mapper.SystemInfoMapper;
import com.youlai.boot.device.model.entity.SnDeviceSystemInfo;
import com.youlai.boot.device.service.SystemInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@Service
@RequiredArgsConstructor
public class SystemInfoServiceImpl extends ServiceImpl<SystemInfoMapper, SnDeviceSystemInfo> implements SystemInfoService {
@Override
public SnDeviceSystemInfo getBySn(String sn) {
if (!StringUtils.hasText(sn)) {
return null;
}
LambdaQueryWrapper<SnDeviceSystemInfo> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SnDeviceSystemInfo::getSerialno, sn)
.last("LIMIT 1");
return this.getOne(wrapper);
}
}