From 9d6498872f4de8ddd8a46b3933617f7dde0b9345 Mon Sep 17 00:00:00 2001 From: TongTongStudio Date: Wed, 5 Aug 2026 23:15:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(device):=20=E6=96=B0=E5=A2=9E=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E5=AE=9A=E4=BD=8D=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=B9=B6=E4=BF=AE=E5=A4=8D=E5=AE=9A=E4=BD=8D=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=AD=98=E5=82=A8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 GET /{sn}/location 接口,支持网页端查询设备最新定位信息 - 新增 DeviceLocationVO 视图对象用于返回定位数据 - 在 LocationService 中实现 getLatestBySn 方法 - 修复 map_error 字段类型错误:从 INT 改为 VARCHAR(255) - 修复移动端上报定位时 lastSuccessfulTime 缺失问题,由服务端统一写入 --- sql/sys_sn_location_fix_map_error.sql | 9 +++ .../controller/DeviceOpsController.java | 11 +++ .../device/controller/MobileController.java | 2 + .../device/model/vo/DeviceLocationVO.java | 69 +++++++++++++++++++ .../boot/device/service/LocationService.java | 10 ++- .../service/impl/LocationServiceImpl.java | 21 +++++- 6 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 sql/sys_sn_location_fix_map_error.sql create mode 100644 src/main/java/com/youlai/boot/device/model/vo/DeviceLocationVO.java diff --git a/sql/sys_sn_location_fix_map_error.sql b/sql/sys_sn_location_fix_map_error.sql new file mode 100644 index 00000000..a3eb38c5 --- /dev/null +++ b/sql/sys_sn_location_fix_map_error.sql @@ -0,0 +1,9 @@ +-- 修复 sys_sn_location.map_error 列类型 +-- 问题:代码中 map_error 为 String(存 '-' 表示成功,或真实错误信息), +-- 但数据库列当前为 INT,导致写入 '-' 时报错: +-- "Incorrect integer value: '-' for column 'map_error'" +-- 解决:将 map_error 改为 VARCHAR,使其可同时保存成功标记与失败原因。 + +ALTER TABLE sys_sn_location + MODIFY COLUMN map_error VARCHAR(255) NULL DEFAULT NULL + COMMENT '定位失败原因,成功时为 -'; diff --git a/src/main/java/com/youlai/boot/device/controller/DeviceOpsController.java b/src/main/java/com/youlai/boot/device/controller/DeviceOpsController.java index 6ce0fee1..7529225b 100644 --- a/src/main/java/com/youlai/boot/device/controller/DeviceOpsController.java +++ b/src/main/java/com/youlai/boot/device/controller/DeviceOpsController.java @@ -7,9 +7,12 @@ import com.youlai.boot.common.result.Result; import com.youlai.boot.device.model.entity.SnDeviceInfo; import com.youlai.boot.device.model.form.AppActionForm; import com.youlai.boot.device.model.form.DeveloperForm; +import com.youlai.boot.device.model.vo.DeviceLocationVO; import com.youlai.boot.device.model.vo.DevicePageVO; import com.youlai.boot.device.service.DeviceService; +import com.youlai.boot.device.service.LocationService; 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; @@ -30,6 +33,7 @@ import org.springframework.web.bind.annotation.*; public class DeviceOpsController { private final DeviceService deviceService; + private final LocationService locationService; @Operation(summary = "获取SN绑定激活信息") @GetMapping("/{sn}/info") @@ -96,6 +100,13 @@ public class DeviceOpsController { return Result.judge(result); } + @Operation(summary = "获取设备最新定位信息", description = "返回设备最近一次上报的定位信息,用于网页端展示百度地图") + @GetMapping("/{sn}/location") + public Result getLocation(@Parameter(description = "设备序列号", required = true) @PathVariable String sn) { + DeviceLocationVO location = locationService.getLatestBySn(sn); + return Result.success(location); + } + @Operation(summary = "设备重置") @PostMapping("/restore") @Log(module = LogModuleEnum.DEVICE, value = ActionTypeEnum.RESTORE) diff --git a/src/main/java/com/youlai/boot/device/controller/MobileController.java b/src/main/java/com/youlai/boot/device/controller/MobileController.java index b2c9f84f..4e587723 100644 --- a/src/main/java/com/youlai/boot/device/controller/MobileController.java +++ b/src/main/java/com/youlai/boot/device/controller/MobileController.java @@ -406,6 +406,8 @@ public class MobileController { SnLocation location = new SnLocation(); BeanUtils.copyProperties(locationReq, location); location.setSn(sn); + // 上次定位成功时间由服务端统一写入,避免移动端时间不准或 LocalDateTime 序列化格式不一致导致为空 + location.setLastSuccessfulTime(LocalDateTime.now()); SnLocation existingLocation = locationService.lambdaQuery() .eq(SnLocation::getSn, sn) diff --git a/src/main/java/com/youlai/boot/device/model/vo/DeviceLocationVO.java b/src/main/java/com/youlai/boot/device/model/vo/DeviceLocationVO.java new file mode 100644 index 00000000..08e04264 --- /dev/null +++ b/src/main/java/com/youlai/boot/device/model/vo/DeviceLocationVO.java @@ -0,0 +1,69 @@ +package com.youlai.boot.device.model.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 设备定位信息视图对象 + */ +@Schema(description = "设备定位信息") +@Data +public class DeviceLocationVO implements Serializable { + + @Schema(description = "设备序列号") + private String sn; + + @Schema(description = "国家") + private String country; + + @Schema(description = "国家代码") + private String countryCode; + + @Schema(description = "省") + private String province; + + @Schema(description = "市") + private String city; + + @Schema(description = "城市代码") + private String cityCode; + + @Schema(description = "区/县") + private String district; + + @Schema(description = "街道") + private String street; + + @Schema(description = "门牌号") + private String streetNumber; + + @Schema(description = "详细地址") + private String address; + + @Schema(description = "区域编码") + private String adCode; + + @Schema(description = "镇") + private String town; + + @Schema(description = "镇级行政区划编码") + private String townCode; + + @Schema(description = "位置描述(百度周边语义化描述)") + private String locationDescribe; + + @Schema(description = "经度") + private String longitude; + + @Schema(description = "纬度") + private String latitude; + + @Schema(description = "定位失败原因,成功时为 '-'") + private String mapError; + + @Schema(description = "上次定位成功时间") + private LocalDateTime lastSuccessfulTime; +} diff --git a/src/main/java/com/youlai/boot/device/service/LocationService.java b/src/main/java/com/youlai/boot/device/service/LocationService.java index 44b87f52..6a2d7ab4 100644 --- a/src/main/java/com/youlai/boot/device/service/LocationService.java +++ b/src/main/java/com/youlai/boot/device/service/LocationService.java @@ -2,10 +2,18 @@ package com.youlai.boot.device.service; import com.baomidou.mybatisplus.extension.service.IService; import com.youlai.boot.device.model.entity.SnLocation; +import com.youlai.boot.device.model.vo.DeviceLocationVO; /** * 设备定位服务接口 */ public interface LocationService extends IService { -} \ No newline at end of file + /** + * 根据设备 SN 获取最新一条定位信息 + * + * @param sn 设备序列号 + * @return 最新定位信息视图对象,不存在时返回 null + */ + DeviceLocationVO getLatestBySn(String sn); +} diff --git a/src/main/java/com/youlai/boot/device/service/impl/LocationServiceImpl.java b/src/main/java/com/youlai/boot/device/service/impl/LocationServiceImpl.java index 63386693..ce5ed713 100644 --- a/src/main/java/com/youlai/boot/device/service/impl/LocationServiceImpl.java +++ b/src/main/java/com/youlai/boot/device/service/impl/LocationServiceImpl.java @@ -1,10 +1,13 @@ 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.LocationMapper; import com.youlai.boot.device.model.entity.SnLocation; +import com.youlai.boot.device.model.vo.DeviceLocationVO; import com.youlai.boot.device.service.LocationService; import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; /** @@ -13,4 +16,20 @@ import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor public class LocationServiceImpl extends ServiceImpl implements LocationService { -} \ No newline at end of file + + @Override + public DeviceLocationVO getLatestBySn(String sn) { + SnLocation location = this.getOne( + new LambdaQueryWrapper() + .eq(SnLocation::getSn, sn) + .orderByDesc(SnLocation::getLastSuccessfulTime) + .last("LIMIT 1") + ); + if (location == null) { + return null; + } + DeviceLocationVO vo = new DeviceLocationVO(); + BeanUtils.copyProperties(location, vo); + return vo; + } +}