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; + } +}