diff --git a/README.md b/README.md index 5d6a32b..da29594 100644 --- a/README.md +++ b/README.md @@ -121,9 +121,9 @@ pnpm dev ## gRPC 与 QUIC -原有机器人 gRPC 客户端与 proto 均保留,但业务调用只传永久 `robotId`。平台根据 `inspection_robot.robot_id` 查找 QUIC 最近同步的 `ip_address` 和 `port`,不再使用终端 ID 或终端配置解析 gRPC 地址。 +原有机器人 gRPC 客户端与 proto 均保留,但业务调用只传永久 `robotId`。平台根据 `iot_robot.robot_id` 查找 QUIC 最近同步的 `ip_address` 和 `port`,不再使用终端 ID 或终端配置解析 gRPC 地址。 -边缘端通过 QUIC 上报设备快照后,平台按 `robotId + deviceId` 写入 `inspection_robot_device`。前端选择机器人后只展示该机器人当前在线且启用的设备;单一匹配设备会自动选中并锁定。 +边缘端通过 QUIC 上报设备快照后,平台按 `robotId + deviceId` 写入 `iot_device`。前端选择机器人后只展示该机器人当前在线且启用的设备;单一匹配设备会自动选中并锁定。 QUIC 不是独立服务,`cmvr-iot-quic` 已作为 `cmvr-iot-admin` 的运行时依赖。启用时主应用同时启动: @@ -151,6 +151,6 @@ Windows 下也可以使用 `bin/package.bat`、`bin/run.bat` 和 `bin/clean.bat` ## 排查提示 - `ApplicationContext ... has been closed already`:彻底停止旧 Java 进程后重新启动,不要使用 DevTools 热重启。 -- 找不到机器人或机器人离线:确认机器人表已登记相同的永久 `robotId`,并检查 QUIC 注册日志、`inspection_robot` 的地址和连接状态。 +- 找不到机器人或机器人离线:确认资源中心已登记相同的永久 `robotId`,并检查 QUIC 注册日志、`iot_robot` 的地址和连接状态。 - QUIC 启动失败:检查证书、私钥、ALPN、UDP 端口占用和 native library 对应的操作系统架构。 - 数据库提示缺少字段:确认基础脚本版本及对应模块迁移脚本已经执行。 diff --git a/cmvr-iot-admin/pom.xml b/cmvr-iot-admin/pom.xml index 06ce377..4e264ef 100644 --- a/cmvr-iot-admin/pom.xml +++ b/cmvr-iot-admin/pom.xml @@ -86,6 +86,10 @@ com.cmvr cmvr-iot-aima + + com.cmvr + cmvr-iot-resource + com.cmvr cmvr-iot-tts diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/DeviceListController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/DeviceListController.java deleted file mode 100644 index da8509f..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/api/DeviceListController.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.cmvr.web.controller.api; - - -import com.cmvr.device.domain.DeDeviceRegistration; -import com.cmvr.device.service.IDeDeviceRegistrationService; -import com.cmvr.edge.client.service.EdgeSystemService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; - -@Api(tags = "边缘--设备信息获取") -@RestController -@RequestMapping("/api/deviceList") -@RequiredArgsConstructor -public class DeviceListController { - - private final EdgeSystemService systemService; - private final IDeDeviceRegistrationService registrationService; - - - @PreAuthorize("@ss.hasPermi('device:profile:list')") - @GetMapping("/addList") - @ApiOperation("同步设备信息列表") - public int addDeviceList(@RequestParam String robotId){ - - List list = systemService.deviceList(robotId); - - return registrationService.addDeviceList(list); - } - - - -} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceProfileController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceProfileController.java deleted file mode 100644 index 08e7ca8..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceProfileController.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.cmvr.web.controller.device; - -import java.util.List; - -import com.cmvr.device.domain.vo.ProfileVo; -import com.cmvr.device.domain.vo.TeMechanicalArmVo; -import com.cmvr.edge.client.service.EdgeSystemService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; -import com.cmvr.common.annotation.Log; -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.enums.BusinessType; -import com.cmvr.device.domain.DeDeviceProfile; -import com.cmvr.device.service.IDeDeviceProfileService; -import com.cmvr.common.core.page.TableDataInfo; - -/** - * 设备配置信息Controller - * - * @author cmvr-iot - * @date 2025-05-09 - */ -@RestController -@RequestMapping("/device/profile") -@RequiredArgsConstructor -@Api(tags = "设备--配置信息") -public class DeDeviceProfileController extends BaseController -{ - - private final IDeDeviceProfileService deDeviceProfileService; - - private final EdgeSystemService systemService; - - /** - * 查询设备配置信息列表 - */ - @PreAuthorize("@ss.hasPermi('device:profile:list')") - @GetMapping("/list") - @ApiOperation("查询设备信息列表") - public TableDataInfo list(DeDeviceProfile deDeviceProfile) - { - startPage(); - List list = deDeviceProfileService.selectDeDeviceProfileList(deDeviceProfile); - return getDataTable(list); - } - - - /** - * 根据设备id获取设备详细配置信息 - */ - @PreAuthorize("@ss.hasPermi('device:profile:query')") - @GetMapping("/{id}") - @ApiOperation("根据设备id获取当前设备配置信息") - public AjaxResult getInfo(@PathVariable String id) - { - return success(deDeviceProfileService.selectDeDeviceProfileById(id)); - } - - /** - * 根据设备id和备注获取设备详细配置信息 - */ - @PreAuthorize("@ss.hasPermi('device:profile:query')") - @GetMapping("/parameterInfo") - @ApiOperation("根据设备id获取当前设备配置信息") - public AjaxResult getParameterInfo(@RequestParam String id, @RequestParam String remark) - { - return success(deDeviceProfileService.selectProfileByIdAndRemark(id,remark)); - } - - /** - * 新增设备配置信息 - */ - @PreAuthorize("@ss.hasPermi('device:profile:add')") - @Log(title = "设备配置信息", businessType = BusinessType.INSERT) - @ApiOperation("新增设备信息") - @PostMapping - public AjaxResult add(@RequestBody List deDeviceProfiles) - { - - return toAjax(deDeviceProfileService.insertDeDeviceProfile(deDeviceProfiles)); - } - - /** - * 修改设备配置信息 - */ - @PreAuthorize("@ss.hasPermi('device:profile:edit')") - @Log(title = "设备配置信息", businessType = BusinessType.UPDATE) - @ApiOperation("修改设备信息") - @PutMapping - public AjaxResult edit(@RequestBody List deDeviceProfiles) - { - return toAjax(deDeviceProfileService.updateDeDeviceProfile(deDeviceProfiles)); - } - - /** - * 删除设备配置信息 - */ - @PreAuthorize("@ss.hasPermi('device:profile:remove')") - @Log(title = "设备配置信息", businessType = BusinessType.DELETE) - @ApiOperation("删除设备配置信息") - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { - return toAjax(deDeviceProfileService.deleteDeDeviceProfileByIds(ids)); - } - - - - - -} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java deleted file mode 100644 index 87ca10f..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceRegistrationController.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.cmvr.web.controller.device; - -import java.util.List; -import jakarta.servlet.http.HttpServletResponse; - -import com.cmvr.edge.client.service.EdgeSystemService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.cmvr.common.annotation.Log; -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.enums.BusinessType; -import com.cmvr.device.domain.DeDeviceRegistration; -import com.cmvr.device.service.IDeDeviceRegistrationService; -import com.cmvr.common.utils.poi.ExcelUtil; -import com.cmvr.common.core.page.TableDataInfo; - -/** - * 设备注册Controller - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@RestController -@RequestMapping("/device/register") -@RequiredArgsConstructor -@Api(tags = "设备--注册") -public class DeDeviceRegistrationController extends BaseController -{ - @Autowired - private IDeDeviceRegistrationService deDeviceRegistrationService; - - private final EdgeSystemService systemService; - - /** - * 查询设备注册列表 - */ - @ApiOperation("查询设备注册列表") - @PreAuthorize("@ss.hasPermi('device:register:list')") - @GetMapping("/list") - public TableDataInfo list(DeDeviceRegistration deDeviceRegistration) - { - startPage(); - List list = deDeviceRegistrationService.selectDeDeviceRegistrationList(deDeviceRegistration); - return getDataTable(list); - } - - /** - * 导出设备注册列表 - */ - @ApiOperation("导出设备注册列表") - @PreAuthorize("@ss.hasPermi('device:register:export')") - @Log(title = "设备注册", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, DeDeviceRegistration deDeviceRegistration) - { - List list = deDeviceRegistrationService.selectDeDeviceRegistrationList(deDeviceRegistration); - ExcelUtil util = new ExcelUtil(DeDeviceRegistration.class); - util.exportExcel(response, list, "设备注册数据"); - } - - /** - * 获取设备注册详细信息 - */ - @ApiOperation("获取设备注册详细信息") - @PreAuthorize("@ss.hasPermi('device:register:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") String id) - { - return success(deDeviceRegistrationService.selectDeDeviceRegistrationById(id)); - } - - /** - * 新增设备注册 - */ - @ApiOperation("新增设备注册") - @PreAuthorize("@ss.hasPermi('device:register:add')") - @Log(title = "设备注册", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody DeDeviceRegistration deDeviceRegistration) - { - return toAjax(deDeviceRegistrationService.insertDeDeviceRegistration(deDeviceRegistration)); - } - - /** - * 修改设备注册 - */ - @ApiOperation("修改设备注册") - @PreAuthorize("@ss.hasPermi('device:register:edit')") - @Log(title = "设备注册", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody DeDeviceRegistration deDeviceRegistration) - { - return toAjax(deDeviceRegistrationService.updateDeDeviceRegistration(deDeviceRegistration)); - } - - - - - /** - * 删除设备注册 - */ - @ApiOperation("删除设备注册") - @PreAuthorize("@ss.hasPermi('device:register:remove')") - @Log(title = "设备注册", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { - return toAjax(deDeviceRegistrationService.deleteDeDeviceRegistrationByIds(ids)); - } -} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java deleted file mode 100644 index 3612d08..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeDeviceTerminalConfigController.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.cmvr.web.controller.device; - -import com.cmvr.common.annotation.Log; -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.core.page.TableDataInfo; -import com.cmvr.common.enums.BusinessType; -import com.cmvr.common.utils.poi.ExcelUtil; -import com.cmvr.device.domain.DeDeviceTerminalConfig; -import com.cmvr.device.service.IDeDeviceTerminalConfigService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; - -import jakarta.servlet.http.HttpServletResponse; -import java.util.List; - -/** - * 设备终端配置Controller - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@RestController -@RequestMapping("/device/terminal") -@RequiredArgsConstructor -@Api(tags = "设备--终端配置") -public class DeDeviceTerminalConfigController extends BaseController { - @Autowired - private IDeDeviceTerminalConfigService deDeviceTerminalConfigService; - - /** - * 查询设备终端配置列表 - */ - @ApiOperation("查询设备终端配置列表") - @PreAuthorize("@ss.hasPermi('device:terminal:list')") - @GetMapping("/list") - public TableDataInfo list(DeDeviceTerminalConfig deDeviceTerminalConfig) { - startPage(); - List list = deDeviceTerminalConfigService.selectDeDeviceTerminalConfigList(deDeviceTerminalConfig); - return getDataTable(list); - } - - /** - * 导出设备终端配置列表 - */ - @ApiOperation("导出设备终端配置列表") - @PreAuthorize("@ss.hasPermi('device:terminal:export')") - @Log(title = "设备终端配置", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, DeDeviceTerminalConfig deDeviceTerminalConfig) { - List list = deDeviceTerminalConfigService.selectDeDeviceTerminalConfigList(deDeviceTerminalConfig); - ExcelUtil util = new ExcelUtil(DeDeviceTerminalConfig.class); - util.exportExcel(response, list, "设备终端配置数据"); - } - - /** - * 获取设备终端配置详细信息 - */ - @ApiOperation("获取设备终端配置详细信息") - @PreAuthorize("@ss.hasPermi('device:terminal:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") String id) { - return success(deDeviceTerminalConfigService.selectDeDeviceTerminalConfigById(id)); - } - - /** - * 新增设备终端配置 - */ - @ApiOperation("新增设备终端配置") - @PreAuthorize("@ss.hasPermi('device:terminal:add')") - @Log(title = "设备终端配置", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody DeDeviceTerminalConfig deDeviceTerminalConfig) { - return toAjax(deDeviceTerminalConfigService.insertDeDeviceTerminalConfig(deDeviceTerminalConfig)); - } - - /** - * 修改设备终端配置 - */ - @ApiOperation("修改设备终端数据") - @PreAuthorize("@ss.hasPermi('device:terminal:edit')") - @Log(title = "设备终端配置", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody DeDeviceTerminalConfig deDeviceTerminalConfig) { - return toAjax(deDeviceTerminalConfigService.updateDeDeviceTerminalConfig(deDeviceTerminalConfig)); - } - - /** - * 删除设备终端配置 - */ - @ApiOperation("删除设备终端配置") - @PreAuthorize("@ss.hasPermi('device:terminal:remove')") - @Log(title = "设备终端配置", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) { - return toAjax(deDeviceTerminalConfigService.deleteDeDeviceTerminalConfigByIds(ids)); - } -} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java deleted file mode 100644 index b486564..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/device/DeRobotConfigController.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.cmvr.web.controller.device; - -import java.util.List; -import jakarta.servlet.http.HttpServletResponse; - -import com.cmvr.common.annotation.Log; -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.enums.BusinessType; -import com.cmvr.common.utils.poi.ExcelUtil; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.cmvr.device.domain.DeRobotConfig; -import com.cmvr.device.service.IDeRobotConfigService; - -import static com.cmvr.common.core.domain.AjaxResult.success; - -/** - * 机器人配置Controller - * - * @author cmvr-iot - * @date 2025-09-09 - */ -@RestController -@RequestMapping("/device/robot") -public class DeRobotConfigController extends BaseController -{ - @Autowired - private IDeRobotConfigService deRobotConfigService; - - /** - * 查询机器人配置列表 - */ - @PreAuthorize("@ss.hasPermi('device:robot:list')") - @GetMapping("/list") - public AjaxResult list(DeRobotConfig deRobotConfig) - { - List list = deRobotConfigService.selectDeRobotConfigList(deRobotConfig); - return success(list); - } - - /** - * 导出机器人配置列表 - */ - @PreAuthorize("@ss.hasPermi('device:robot:export')") - @Log(title = "机器人配置", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, DeRobotConfig deRobotConfig) - { - List list = deRobotConfigService.selectDeRobotConfigList(deRobotConfig); - ExcelUtil util = new ExcelUtil(DeRobotConfig.class); - util.exportExcel(response, list, "机器人配置数据"); - } - - /** - * 获取机器人配置详细信息 - */ - @PreAuthorize("@ss.hasPermi('device:robot:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") String id) - { - return success(deRobotConfigService.selectDeRobotConfigById(id)); - } - - /** - * 新增机器人配置 - */ - @PreAuthorize("@ss.hasPermi('device:robot:add')") - @Log(title = "机器人配置", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody DeRobotConfig deRobotConfig) - { - return toAjax(deRobotConfigService.insertDeRobotConfig(deRobotConfig)); - } - - /** - * 修改机器人配置 - */ - @PreAuthorize("@ss.hasPermi('device:robot:edit')") - @Log(title = "机器人配置", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody DeRobotConfig deRobotConfig) - { - return toAjax(deRobotConfigService.updateDeRobotConfig(deRobotConfig)); - } - - /** - * 删除机器人配置 - */ - @PreAuthorize("@ss.hasPermi('device:robot:remove')") - @Log(title = "机器人配置", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { - return toAjax(deRobotConfigService.deleteDeRobotConfigByIds(ids)); - } -} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java deleted file mode 100644 index f0503ac..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionMapController.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.cmvr.web.controller.inspection; - -import java.util.List; -import jakarta.servlet.http.HttpServletResponse; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.cmvr.common.annotation.Log; -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.enums.BusinessType; -import com.cmvr.inspection.domain.InspectionMap; -import com.cmvr.inspection.domain.vo.InspectionMapVo; -import com.cmvr.inspection.service.IInspectionMapService; -import com.cmvr.common.utils.poi.ExcelUtil; -import com.cmvr.common.core.page.TableDataInfo; - -/** - * 巡检地图Controller - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@RestController -@RequestMapping("/inspection/map") -@Api(tags = "智能巡检--地图管理") -public class InspectionMapController extends BaseController -{ - @Autowired - private IInspectionMapService inspectionMapService; - - /** - * 查询巡检地图列表 - */ - @ApiOperation("查询巡检地图列表") - @PreAuthorize("@ss.hasPermi('inspection:map:list')") - @GetMapping("/list") - public TableDataInfo list(InspectionMap inspectionMap) - { - startPage(); - List list = inspectionMapService.selectInspectionMapList(inspectionMap); - return getDataTable(list); - } - - /** - * 导出巡检地图列表 - */ - @ApiOperation("导出巡检地图列表") - @PreAuthorize("@ss.hasPermi('inspection:map:export')") - @Log(title = "巡检地图", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, InspectionMap inspectionMap) - { - List list = inspectionMapService.selectInspectionMapList(inspectionMap); - ExcelUtil util = new ExcelUtil<>(InspectionMapVo.class); - util.exportExcel(response, list, "巡检地图数据"); - } - - /** - * 获取巡检地图详细信息 - */ - @ApiOperation("获取巡检地图详细信息") - @PreAuthorize("@ss.hasPermi('inspection:map:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") String id) - { - return success(inspectionMapService.selectInspectionMapById(id)); - } - - /** - * 新增巡检地图 - */ - @ApiOperation("新增巡检地图") - @PreAuthorize("@ss.hasPermi('inspection:map:add')") - @Log(title = "巡检地图", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody InspectionMap inspectionMap) - { - return toAjax(inspectionMapService.insertInspectionMap(inspectionMap)); - } - - /** - * 修改巡检地图 - */ - @ApiOperation("修改巡检地图") - @PreAuthorize("@ss.hasPermi('inspection:map:edit')") - @Log(title = "巡检地图", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody InspectionMap inspectionMap) - { - return toAjax(inspectionMapService.updateInspectionMap(inspectionMap)); - } - - /** - * 删除巡检地图 - */ - @ApiOperation("删除巡检地图") - @PreAuthorize("@ss.hasPermi('inspection:map:remove')") - @Log(title = "巡检地图", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { - return toAjax(inspectionMapService.deleteInspectionMapByIds(ids)); - } -} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java deleted file mode 100644 index 72461fc..0000000 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/inspection/InspectionRobotController.java +++ /dev/null @@ -1,260 +0,0 @@ -package com.cmvr.web.controller.inspection; - -import java.util.List; -import jakarta.servlet.http.HttpServletResponse; - -import cmvr.msgs.AgvUtils; -import com.cmvr.inspection.domain.vo.InspectionRobotVo; -import io.swagger.annotations.*; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; -import com.cmvr.common.annotation.Log; -import com.cmvr.common.core.controller.BaseController; -import com.cmvr.common.core.domain.AjaxResult; -import com.cmvr.common.enums.BusinessType; -import com.cmvr.inspection.domain.InspectionRobot; -import com.cmvr.inspection.service.IInspectionRobotService; -import com.cmvr.common.utils.poi.ExcelUtil; -import com.cmvr.common.core.page.TableDataInfo; - -/** - * 巡检机器人Controller - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@RestController -@RequestMapping("/inspection/robot") -@Api(tags = "智能巡检--机器人管理") -public class InspectionRobotController extends BaseController -{ - @Autowired - private IInspectionRobotService inspectionRobotService; - - /** - * 查询巡检机器人列表 - */ - @ApiOperation("查询巡检机器人列表") - @PreAuthorize("@ss.hasPermi('inspection:robot:list')") - @GetMapping("/list") - public TableDataInfo list(InspectionRobot inspectionRobot) - { - startPage(); - List list = inspectionRobotService.selectInspectionRobotList(inspectionRobot); - return getDataTable(list); - } - - /** - * 导出巡检机器人列表 - */ - @ApiOperation("导出巡检机器人列表") - @PreAuthorize("@ss.hasPermi('inspection:robot:export')") - @Log(title = "巡检机器人", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, InspectionRobot inspectionRobot) - { - List list = inspectionRobotService.selectInspectionRobotList(inspectionRobot); - ExcelUtil util = new ExcelUtil<>(InspectionRobotVo.class); - util.exportExcel(response, list, "巡检机器人数据"); - } - - /** - * 获取巡检机器人详细信息 - */ - @ApiOperation("获取巡检机器人详细信息") - @PreAuthorize("@ss.hasPermi('inspection:robot:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") String id) - { - return success(inspectionRobotService.selectInspectionRobotById(id)); - } - - @ApiOperation("查询机器人自动发现的设备") - @PreAuthorize("@ss.hasPermi('inspection:robot:query')") - @GetMapping("/{id}/devices") - public AjaxResult devices(@PathVariable("id") String id) - { - return success(inspectionRobotService.selectRobotDevices(id)); - } - - @ApiOperation("按机器人ID查询自动发现的设备") - @PreAuthorize("@ss.hasPermi('inspection:robot:query')") - @GetMapping("/devices") - public AjaxResult devicesByRobotId( - @RequestParam @ApiParam(value = "机器人永久唯一ID", required = true) String robotId, - @RequestParam(required = false) @ApiParam("设备类型") Integer deviceKind, - @RequestParam(defaultValue = "true") @ApiParam("是否只查询在线且启用的设备") boolean onlineOnly) - { - return success(inspectionRobotService.selectRobotDevicesByRobotId(robotId, deviceKind, onlineOnly)); - } - - /** - * 新增巡检机器人 - */ - @ApiOperation("新增巡检机器人") - @PreAuthorize("@ss.hasPermi('inspection:robot:add')") - @Log(title = "巡检机器人", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody InspectionRobot inspectionRobot) - { - return toAjax(inspectionRobotService.insertInspectionRobot(inspectionRobot)); - } - - /** - * 修改巡检机器人 - */ - @ApiOperation("修改巡检机器人") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "巡检机器人", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody InspectionRobot inspectionRobot) - { - return toAjax(inspectionRobotService.updateInspectionRobot(inspectionRobot)); - } - - /** - * 删除巡检机器人 - */ - @ApiOperation("删除巡检机器人") - @PreAuthorize("@ss.hasPermi('inspection:robot:remove')") - @Log(title = "巡检机器人", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable String[] ids) - { - return toAjax(inspectionRobotService.deleteInspectionRobotByIds(ids)); - } - - /** - * 获取机器人地图列表(从AGV获取) - */ - @ApiOperation("获取机器人地图列表") - @PreAuthorize("@ss.hasPermi('inspection:robot:query')") - @GetMapping("/{robotId}/maps") - public AjaxResult getRobotMapList(@PathVariable String robotId) - { - List robotMapList = inspectionRobotService.getRobotMapList(robotId); - return success(robotMapList); - } - - /** - * 绑定机器人地图 - */ - @ApiOperation("绑定机器人地图") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "绑定机器人地图", businessType = BusinessType.UPDATE) - @PostMapping("/{robotId}/bind-map/{mapId}") - public AjaxResult bindRobotMap(@PathVariable String robotId, - @PathVariable String mapId) - { - return toAjax(inspectionRobotService.bindRobotMap(robotId, mapId)); - } - - /** - * 从机器人下载地图 - */ - @ApiOperation("从机器人下载地图") - @PreAuthorize("@ss.hasPermi('inspection:robot:add')") - @Log(title = "从机器人下载地图", businessType = BusinessType.INSERT) - @GetMapping("/{robotId}/download-map") - public AjaxResult downloadMapFromRobot( - @PathVariable @ApiParam("机器人ID") String robotId, - @RequestParam(value = "mapName") @ApiParam("地图名称") String mapName - ) - { - Object mapId = inspectionRobotService.downloadMapFromRobot(robotId, mapName); - return success(mapId); - } - - /** - * 上传地图(从源机器人下载到目标机器人) - */ - @ApiOperation("上传地图到机器人") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "上传地图到机器人", businessType = BusinessType.OTHER) - @PostMapping("/{robotId}/upload-map-from-source") - public AjaxResult uploadMapFromSource(@PathVariable String robotId) - { - String result = inspectionRobotService.uploadMapFromSource(robotId); - return success(result); - } - - /** - * 同步机器人状态 - */ - @ApiOperation("同步机器人状态") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "同步机器人状态", businessType = BusinessType.UPDATE) - @PostMapping("/{robotId}/sync-status") - public AjaxResult syncRobotStatus(@PathVariable String robotId) - { - return success(inspectionRobotService.syncRobotStatus(robotId)); - } - - /** - * 获取机器人实时位置 - */ - @ApiOperation("获取机器人实时位置") - @PreAuthorize("@ss.hasPermi('inspection:robot:query')") - @GetMapping("/{robotId}/location") - public AjaxResult getRobotRealtimeLocation(@PathVariable String robotId) - { - AgvUtils.AgvPose2d location = inspectionRobotService.getRobotRealtimeLocation(robotId); - return success(location); - } - - /** - * 导航到指定位置(坐标) - */ - @ApiOperation("导航到指定位置") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "导航到指定位置", businessType = BusinessType.OTHER) - @PostMapping("/{robotId}/navigate-to-position") - public AjaxResult navigateToPosition( - @PathVariable @ApiParam("机器人ID") String robotId, - @RequestParam @ApiParam("X坐标(米)") Double x, - @RequestParam @ApiParam("Y坐标(米)") Double y, - @RequestParam(required = false) @ApiParam("朝向角(弧度)") Double theta - ) - { - inspectionRobotService.navigateToPosition( - robotId, x, y, theta - ); - return success(); - } - - /** - * 开始建图 - */ - @ApiOperation("开始建图") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "开始建图", businessType = BusinessType.OTHER) - @PostMapping("/{robotId}/start-mapping") - public AjaxResult startMapping( - @PathVariable @ApiParam("机器人ID") String robotId, - @RequestParam @ApiParam("建图维度(0:未指定 1:2D 2:3D 3:2D+3D)") int dimension, - @RequestParam(required = false) @ApiParam("地图名称(可选)") String mapName, - @RequestParam(defaultValue = "true") @ApiParam("是否实时建图") boolean realTime - ) - { - String sessionId = inspectionRobotService.startMapping(robotId, dimension, mapName, realTime); - java.util.Map result = new java.util.HashMap<>(); - result.put("sessionId", sessionId); - return success(result); - } - - /** - * 停止建图 - */ - @ApiOperation("停止建图") - @PreAuthorize("@ss.hasPermi('inspection:robot:edit')") - @Log(title = "停止建图", businessType = BusinessType.OTHER) - @PostMapping("/{robotId}/stop-mapping") - public AjaxResult stopMapping(@PathVariable @ApiParam("机器人ID") String robotId) - { - inspectionRobotService.stopMapping(robotId); - return success(); - } - -} - diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceDeviceController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceDeviceController.java new file mode 100644 index 0000000..de7b245 --- /dev/null +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceDeviceController.java @@ -0,0 +1,52 @@ +package com.cmvr.web.controller.resource; + +import com.cmvr.common.core.controller.BaseController; +import com.cmvr.common.core.domain.AjaxResult; +import com.cmvr.common.core.page.TableDataInfo; +import com.cmvr.resource.domain.ResourceDevice; +import com.cmvr.resource.service.ResourceDeviceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/resource/devices") +@Api(tags = "资源中心-设备管理") +public class ResourceDeviceController extends BaseController { + private final ResourceDeviceService deviceService; + + public ResourceDeviceController(ResourceDeviceService deviceService) { + this.deviceService = deviceService; + } + + @GetMapping + @ApiOperation("查询设备列表") + @PreAuthorize("@ss.hasPermi('resource:device:list')") + public TableDataInfo list(ResourceDevice query, + @RequestParam(defaultValue = "true") boolean onlineOnly) { + startPage(); + return getDataTable(deviceService.list(query, onlineOnly)); + } + + @GetMapping("/{id}") + @ApiOperation("查询设备详情") + @PreAuthorize("@ss.hasPermi('resource:device:list')") + public AjaxResult get(@PathVariable String id) { + return success(deviceService.get(id)); + } + + @PutMapping("/{id}") + @ApiOperation("修改设备名称、用途和启用状态") + @PreAuthorize("@ss.hasPermi('resource:device:edit')") + public AjaxResult update(@PathVariable String id, @RequestBody ResourceDevice device) { + device.setId(id); + return toAjax(deviceService.updateBusinessConfig(device)); + } +} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceMapController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceMapController.java new file mode 100644 index 0000000..0b4e917 --- /dev/null +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceMapController.java @@ -0,0 +1,73 @@ +package com.cmvr.web.controller.resource; + +import com.cmvr.common.core.controller.BaseController; +import com.cmvr.common.core.domain.AjaxResult; +import com.cmvr.common.core.page.TableDataInfo; +import com.cmvr.resource.domain.ResourceMap; +import com.cmvr.resource.service.ResourceMapService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +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; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestBody; +import java.util.Arrays; + +@RestController +@RequestMapping("/resource/maps") +@Api(tags = "资源中心-地图管理") +public class ResourceMapController extends BaseController { + private final ResourceMapService mapService; + + public ResourceMapController(ResourceMapService mapService) { + this.mapService = mapService; + } + + @GetMapping + @ApiOperation("查询地图列表") + @PreAuthorize("@ss.hasPermi('resource:map:list')") + public TableDataInfo list(ResourceMap query) { + startPage(); + return getDataTable(mapService.list(query)); + } + + @GetMapping("/robot/{robotId}") + @ApiOperation("查询机器人可用地图") + @PreAuthorize("@ss.hasPermi('resource:map:list')") + public AjaxResult listByRobot(@PathVariable String robotId) { + return success(mapService.listByRobotId(robotId)); + } + + @GetMapping("/{id}") + @ApiOperation("查询地图详情") + @PreAuthorize("@ss.hasPermi('resource:map:query')") + public AjaxResult get(@PathVariable String id) { + return success(mapService.get(id)); + } + + @PostMapping + @ApiOperation("新增地图") + @PreAuthorize("@ss.hasPermi('resource:map:add')") + public AjaxResult create(@RequestBody ResourceMap map) { + return toAjax(mapService.create(map)); + } + + @PutMapping + @ApiOperation("修改地图") + @PreAuthorize("@ss.hasPermi('resource:map:edit')") + public AjaxResult update(@RequestBody ResourceMap map) { + return toAjax(mapService.update(map)); + } + + @DeleteMapping("/{ids}") + @ApiOperation("删除地图") + @PreAuthorize("@ss.hasPermi('resource:map:remove')") + public AjaxResult remove(@PathVariable String[] ids) { + return toAjax(mapService.remove(Arrays.asList(ids))); + } +} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceRobotController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceRobotController.java new file mode 100644 index 0000000..f8f73b6 --- /dev/null +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceRobotController.java @@ -0,0 +1,188 @@ +package com.cmvr.web.controller.resource; + +import com.cmvr.common.core.controller.BaseController; +import com.cmvr.common.core.domain.AjaxResult; +import com.cmvr.common.core.page.TableDataInfo; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.service.ResourceRobotService; +import com.cmvr.resource.service.ResourceRobotMapService; +import com.cmvr.resource.service.ResourceRobotControlService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import org.springframework.security.access.prepost.PreAuthorize; +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.RequestParam; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/resource/robots") +@Api(tags = "资源中心-机器人管理") +public class ResourceRobotController extends BaseController { + private final ResourceRobotService resourceRobotService; + private final ResourceRobotMapService robotMapService; + private final ResourceRobotControlService controlService; + + public ResourceRobotController(ResourceRobotService resourceRobotService, + ResourceRobotMapService robotMapService, + ResourceRobotControlService controlService) { + this.resourceRobotService = resourceRobotService; + this.robotMapService = robotMapService; + this.controlService = controlService; + } + + @GetMapping + @ApiOperation("查询机器人列表") + @PreAuthorize("@ss.hasPermi('resource:robot:list')") + public TableDataInfo list(ResourceRobot query) { + startPage(); + return getDataTable(resourceRobotService.list(query)); + } + + @GetMapping("/{robotId}") + @ApiOperation("根据永久机器人ID查询机器人") + @PreAuthorize("@ss.hasPermi('resource:robot:query')") + public AjaxResult get(@PathVariable String robotId) { + ResourceRobot robot = resourceRobotService.getByRobotId(robotId); + return robot == null ? error("机器人不存在:" + robotId) : success(robot); + } + + @GetMapping("/{robotId}/devices") + @ApiOperation("查询机器人设备") + @PreAuthorize("@ss.hasPermi('resource:device:list')") + public AjaxResult devices(@PathVariable String robotId, + @RequestParam(required = false) Integer deviceKind, + @RequestParam(defaultValue = "true") @ApiParam("是否只返回在线且启用的设备") boolean onlineOnly) { + return success(resourceRobotService.listDevices(robotId, deviceKind, onlineOnly)); + } + + @GetMapping("/id/{id}") + @ApiOperation("根据数据主键查询机器人") + @PreAuthorize("@ss.hasPermi('resource:robot:query')") + public AjaxResult getById(@PathVariable String id) { + return success(resourceRobotService.getById(id)); + } + + @GetMapping("/id/{id}/devices") + @ApiOperation("根据机器人数据主键查询设备") + @PreAuthorize("@ss.hasPermi('resource:device:list')") + public AjaxResult devicesById(@PathVariable String id, + @RequestParam(required = false) Integer deviceKind, + @RequestParam(defaultValue = "false") boolean onlineOnly) { + return success(resourceRobotService.listDevicesByRobotRecord(id, deviceKind, onlineOnly)); + } + + @PostMapping + @ApiOperation("登记机器人") + @PreAuthorize("@ss.hasPermi('resource:robot:add')") + public AjaxResult create(@RequestBody ResourceRobot robot) { + return toAjax(resourceRobotService.create(robot)); + } + + @PutMapping + @ApiOperation("修改机器人") + @PreAuthorize("@ss.hasPermi('resource:robot:edit')") + public AjaxResult update(@RequestBody ResourceRobot robot) { + return toAjax(resourceRobotService.update(robot)); + } + + @DeleteMapping("/{ids}") + @ApiOperation("归档机器人") + @PreAuthorize("@ss.hasPermi('resource:robot:remove')") + public AjaxResult archive(@PathVariable String[] ids) { + return toAjax(resourceRobotService.archive(ids)); + } + + @GetMapping("/{robotId}/maps") + @ApiOperation("查询机器人绑定的地图") + @PreAuthorize("@ss.hasPermi('resource:map:list')") + public AjaxResult maps(@PathVariable String robotId) { + return success(robotMapService.listMaps(robotId)); + } + + @PostMapping("/{robotId}/maps/{mapId}") + @ApiOperation("绑定机器人地图") + @PreAuthorize("@ss.hasPermi('resource:robot:edit')") + public AjaxResult bindMap(@PathVariable String robotId, @PathVariable String mapId, + @RequestParam(defaultValue = "false") boolean makeDefault) { + return toAjax(robotMapService.bind(robotId, mapId, makeDefault)); + } + + @DeleteMapping("/{robotId}/maps/{mapId}") + @ApiOperation("解除机器人地图绑定") + @PreAuthorize("@ss.hasPermi('resource:robot:edit')") + public AjaxResult unbindMap(@PathVariable String robotId, @PathVariable String mapId) { + return toAjax(robotMapService.unbind(robotId, mapId)); + } + + @GetMapping("/{robotRef}/remote-maps") + @ApiOperation("查询边缘机器人地图列表") + @PreAuthorize("@ss.hasPermi('resource:map:list')") + public AjaxResult remoteMaps(@PathVariable String robotRef) { + return success(controlService.listRemoteMaps(robotRef)); + } + + @GetMapping("/{robotRef}/download-map") + @ApiOperation("下载边缘机器人地图") + @PreAuthorize("@ss.hasPermi('resource:map:add')") + public AjaxResult downloadMap(@PathVariable String robotRef, @RequestParam String mapName) { + return success(controlService.downloadMap(robotRef, mapName)); + } + + @PostMapping("/{robotRef}/upload-active-map") + @ApiOperation("上传当前地图到边缘机器人") + @PreAuthorize("@ss.hasPermi('resource:map:edit')") + public AjaxResult uploadActiveMap(@PathVariable String robotRef) { + return success(controlService.uploadActiveMap(robotRef)); + } + + @PostMapping("/{robotRef}/sync-runtime") + @ApiOperation("同步机器人实时状态") + @PreAuthorize("@ss.hasPermi('resource:robot:edit')") + public AjaxResult syncRuntime(@PathVariable String robotRef) { + return success(controlService.syncRuntimeState(robotRef)); + } + + @GetMapping("/{robotRef}/location") + @ApiOperation("查询机器人实时位置") + @PreAuthorize("@ss.hasPermi('resource:robot:query')") + public AjaxResult location(@PathVariable String robotRef) { + return success(controlService.getRealtimeLocation(robotRef)); + } + + @PostMapping("/{robotRef}/navigate-to-position") + @ApiOperation("控制机器人导航到坐标") + @PreAuthorize("@ss.hasPermi('resource:robot:edit')") + public AjaxResult navigateToPosition(@PathVariable String robotRef, + @RequestParam Double x, + @RequestParam Double y, + @RequestParam(required = false) Double theta) { + controlService.navigateToPosition(robotRef, x, y, theta); + return success(); + } + + @PostMapping("/{robotRef}/start-mapping") + @ApiOperation("控制机器人开始建图") + @PreAuthorize("@ss.hasPermi('resource:map:add')") + public AjaxResult startMapping(@PathVariable String robotRef, + @RequestParam int dimension, + @RequestParam(required = false) String mapName, + @RequestParam(defaultValue = "true") boolean realTime) { + return success(java.util.Map.of("sessionId", + controlService.startMapping(robotRef, dimension, mapName, realTime))); + } + + @PostMapping("/{robotRef}/stop-mapping") + @ApiOperation("控制机器人结束建图") + @PreAuthorize("@ss.hasPermi('resource:map:edit')") + public AjaxResult stopMapping(@PathVariable String robotRef) { + controlService.stopMapping(robotRef); + return success(); + } +} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceTerminalController.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceTerminalController.java new file mode 100644 index 0000000..45fc705 --- /dev/null +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/controller/resource/ResourceTerminalController.java @@ -0,0 +1,75 @@ +package com.cmvr.web.controller.resource; + +import com.cmvr.common.core.controller.BaseController; +import com.cmvr.common.core.domain.AjaxResult; +import com.cmvr.common.core.page.TableDataInfo; +import com.cmvr.resource.domain.ResourceTerminal; +import com.cmvr.resource.service.ResourceTerminalService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.DeleteMapping; +import java.util.List; + +@RestController +@RequestMapping("/resource/terminals") +@Api(tags = "资源中心-边缘终端") +public class ResourceTerminalController extends BaseController { + private final ResourceTerminalService terminalService; + + public ResourceTerminalController(ResourceTerminalService terminalService) { + this.terminalService = terminalService; + } + + @GetMapping + @ApiOperation("查询边缘终端列表") + @PreAuthorize("@ss.hasPermi('resource:terminal:list')") + public TableDataInfo list(ResourceTerminal query) { + startPage(); + return getDataTable(terminalService.list(query)); + } + + @GetMapping("/{id}") + @ApiOperation("查询边缘终端详情") + @PreAuthorize("@ss.hasPermi('resource:terminal:list')") + public AjaxResult get(@PathVariable String id) { return success(terminalService.get(id)); } + + @PostMapping + @ApiOperation("新增边缘终端") + @PreAuthorize("@ss.hasPermi('resource:terminal:add')") + public AjaxResult create(@RequestBody ResourceTerminal terminal) { + return toAjax(terminalService.create(terminal)); + } + + @PutMapping + @ApiOperation("修改边缘终端") + @PreAuthorize("@ss.hasPermi('resource:terminal:edit')") + public AjaxResult update(@RequestBody ResourceTerminal terminal) { + return toAjax(terminalService.update(terminal)); + } + + @GetMapping("/{id}/robots") + @ApiOperation("查询边缘终端关联的机器人") + @PreAuthorize("@ss.hasPermi('resource:terminal:list')") + public AjaxResult robots(@PathVariable String id) { return success(terminalService.listRobotIds(id)); } + + @PutMapping("/{id}/robots") + @ApiOperation("更新边缘终端关联的机器人") + @PreAuthorize("@ss.hasPermi('resource:terminal:edit')") + public AjaxResult replaceRobots(@PathVariable String id, @RequestBody List robotIds) { + terminalService.replaceRobots(id, robotIds); + return success(); + } + + @DeleteMapping("/{ids}") + @ApiOperation("删除边缘终端") + @PreAuthorize("@ss.hasPermi('resource:terminal:remove')") + public AjaxResult remove(@PathVariable String[] ids) { return toAjax(terminalService.remove(ids)); } +} diff --git a/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java b/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java index 139d788..e3ec706 100644 --- a/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java +++ b/cmvr-iot-admin/src/main/java/com/cmvr/web/core/config/OpenApiConfig.java @@ -57,6 +57,18 @@ public class OpenApiConfig return group("00-all", "全部接口", "/**"); } + @Bean + public GroupedOpenApi resourceCenterApi() + { + return GroupedOpenApi.builder() + .group("10-resource-center") + .displayName("资源中心") + .pathsToMatch("/resource/**") + .addOperationCustomizer(legacySwaggerOperationCustomizer()) + .addOpenApiCustomizer(legacyTagOrderCustomizer()) + .build(); + } + private GroupedOpenApi group(String id, String displayName, String... paths) { return GroupedOpenApi.builder() diff --git a/cmvr-iot-admin/src/main/resources/application-dev.yml b/cmvr-iot-admin/src/main/resources/application-dev.yml index 3ebc0e5..8b21a34 100644 --- a/cmvr-iot-admin/src/main/resources/application-dev.yml +++ b/cmvr-iot-admin/src/main/resources/application-dev.yml @@ -1,6 +1,6 @@ server: # 服务器的HTTP端口,默认为8080 - port: 13080 + port: 14080 # 数据源配置 spring: datasource: @@ -9,7 +9,7 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://192.168.28.10:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://192.168.28.10:3306/${CMVR_DB_NAME:cmvr-iot-resource-dev}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: cmvr2468 # 从库数据源 @@ -74,7 +74,7 @@ spring: # 端口,默认为6379 port: 6379 # 数据库索引 - database: 0 + database: ${CMVR_REDIS_DATABASE:1} # 密码 password: cmvr2468 # 连接超时时间 @@ -138,3 +138,11 @@ media-analysis: api-key: ${MEDIA_ANALYSIS_API_KEY:} connect-timeout-ms: 5000 read-timeout-ms: 600000 + +# Isolate the resource-center development instance from the currently running robot gateway. +cmvr: + resource: + robot-state: + enabled: false + quic: + enabled: false diff --git a/cmvr-iot-admin/src/main/resources/application-test.yml b/cmvr-iot-admin/src/main/resources/application-test.yml index dc27746..24dabeb 100644 --- a/cmvr-iot-admin/src/main/resources/application-test.yml +++ b/cmvr-iot-admin/src/main/resources/application-test.yml @@ -1,6 +1,6 @@ server: # 服务器的HTTP端口,默认为8080 - port: 13080 + port: 14080 # 数据源配置 spring: datasource: @@ -9,7 +9,7 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://192.168.28.10:3306/cmvr-iot-dev?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://192.168.28.10:3306/${CMVR_DB_NAME:cmvr-iot-resource-dev}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: cmvr2468 # 从库数据源 @@ -74,7 +74,7 @@ spring: # 端口,默认为6379 port: 6379 # 数据库索引 - database: 0 + database: ${CMVR_REDIS_DATABASE:1} # 密码 password: cmvr2468 # 连接超时时间 @@ -138,3 +138,11 @@ media-analysis: api-key: ${MEDIA_ANALYSIS_API_KEY:cmvr-analysis-2026-c65ec181d5ab4a49aef34e6fd1be6704} connect-timeout-ms: 5000 read-timeout-ms: 600000 + +# Isolate the resource-center development instance from the currently running robot gateway. +#cmvr: +# resource: +# robot-state: +# enabled: false +# quic: +# enabled: false diff --git a/cmvr-iot-admin/src/main/resources/application.yml b/cmvr-iot-admin/src/main/resources/application.yml index 814b7cd..c2db5cb 100644 --- a/cmvr-iot-admin/src/main/resources/application.yml +++ b/cmvr-iot-admin/src/main/resources/application.yml @@ -127,7 +127,7 @@ xss: # Integrated QUIC gateway and in-process node synchronization. cmvr: - inspection: + resource: robot-state: enabled: true initial-delay-ms: 3000 diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/EdgeSystemService.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/EdgeSystemService.java index 3448cd7..f912b82 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/EdgeSystemService.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/EdgeSystemService.java @@ -3,12 +3,10 @@ package com.cmvr.edge.client.service; import cmvr.api.Common; import cmvr.api.SafetyCommand; import cmvr.api.SystemCommand; -import com.cmvr.device.domain.DeDeviceRegistration; import com.cmvr.edge.client.model.system.EdgeSystemJsonCommandVO; import com.cmvr.edge.client.model.system.EdgeSystemUpdateParamsVO; import com.cmvr.edge.client.model.system.EdgeActionQueueVO; -import java.util.List; /** * 边缘系统服务接口 @@ -41,7 +39,5 @@ public interface EdgeSystemService { String robotId, String reason, Integer timeoutMs); - public List deviceList(String robotId); - public String stopAll(String robotId); } diff --git a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/impl/EdgeSystemServiceImpl.java b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/impl/EdgeSystemServiceImpl.java index 46ede02..dc33c5b 100644 --- a/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/impl/EdgeSystemServiceImpl.java +++ b/cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client/src/main/java/com/cmvr/edge/client/service/impl/EdgeSystemServiceImpl.java @@ -9,7 +9,6 @@ import cmvr.api.SystemCommand; import cmvr.api.SystemServiceGrpc; import cmvr.api.SafetyCommand; import com.alibaba.fastjson2.JSON; -import com.cmvr.device.domain.DeDeviceRegistration; import com.cmvr.edge.client.manage.GrpcServiceManager; import com.cmvr.edge.client.model.system.EdgeSystemJsonCommandVO; import com.cmvr.edge.client.model.system.EdgeSystemUpdateParamsVO; @@ -24,7 +23,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; -import java.util.ArrayList; import java.util.Base64; import java.util.List; import java.util.HashSet; @@ -373,72 +371,6 @@ public class EdgeSystemServiceImpl implements EdgeSystemService { } - @Override - public List deviceList(String robotId) { - try { - SystemServiceGrpc.SystemServiceBlockingStub stub = grpcServiceManager.getGrpcClient( - robotId, SystemServiceGrpc.SystemServiceBlockingStub.class); - SystemCommand.GetDeviceListCommand.Feedback response = stub.getDeviceList( - SystemCommand.GetDeviceListCommand.Request.newBuilder().build()); - - List deviceList = response.getDeviceListList(); - List devices = new ArrayList<>(deviceList.size()); - for (SystemCommand.SystemDeviceInfo device : deviceList) { - DeDeviceRegistration registration = new DeDeviceRegistration(); - registration.setDeviceCode(device.getDeviceId()); - registration.setDeviceModel(toDeviceModel(device)); - registration.setIdDeDeviceTerminalConfig(robotId); - devices.add(registration); - } - - logger.info("获取到设备列表,数量:{},设备管理器:{} {}", - devices.size(), response.getManagerName(), response.getManagerVersion()); - return devices; - } catch (Exception e) { - logger.error("调用设备列表接口异常", e); - throw new GlobalException("获取设备列表失败: " + e.getMessage()); - } - } - - private String toDeviceModel(SystemCommand.SystemDeviceInfo device) { - switch (device.getDeviceType()) { - case SYSTEM_DEVICE_TYPE_AGV: - return "AGV"; - case SYSTEM_DEVICE_TYPE_ARM: - return "ARM"; - case SYSTEM_DEVICE_TYPE_BATTERY: - return "Battery"; - case SYSTEM_DEVICE_TYPE_BIO_HEAD: - return "BioHead"; - case SYSTEM_DEVICE_TYPE_CAMERA: - return "Camera"; - case SYSTEM_DEVICE_TYPE_CAN_BUS: - return "CanBus"; - case SYSTEM_DEVICE_TYPE_DEX_HAND: - return "DexHand"; - case SYSTEM_DEVICE_TYPE_GRIPPER: - return "Gripper"; - case SYSTEM_DEVICE_TYPE_MICROPHONE: - return "Microphone"; - case SYSTEM_DEVICE_TYPE_MOTOR: - return "Motor"; - case SYSTEM_DEVICE_TYPE_MOTOR_SYSTEM: - return "MotorSystem"; - case SYSTEM_DEVICE_TYPE_MUJOCO_VIEWER: - return "MujocoViewer"; - case SYSTEM_DEVICE_TYPE_MUJOCO_WORLD: - return "MujocoWorld"; - case SYSTEM_DEVICE_TYPE_ROBOT: - return "Robot"; - case SYSTEM_DEVICE_TYPE_SPEAKER: - return "Speaker"; - case SYSTEM_DEVICE_TYPE_UNSPECIFIED: - case UNRECOGNIZED: - default: - return device.getTypeName().isEmpty() ? "Unknown" : device.getTypeName(); - } - } - @Override public String stopAll(String robotId) { SystemServiceGrpc.SystemServiceBlockingStub stub = grpcServiceManager.getGrpcClient( diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceProfile.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceProfile.java deleted file mode 100644 index ee61329..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceProfile.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.cmvr.device.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; - -/** - * 设备配置信息对象 de_device_profile - * - * @author cmvr-iot - * @since 2025-05-09 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel("设备配置类") -@EqualsAndHashCode(callSuper = false) -public class DeDeviceProfile extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** id */ - @ApiModelProperty("id") - @TableId(value = "id",type = IdType.ASSIGN_UUID) - private String id; - - /** 设备id */ - @Excel(name = "设备id") - @ApiModelProperty("设备id") - private String idDeDeviceRegistration; - - /** 设备终端id */ - @Excel(name = "设备终端id") - @ApiModelProperty("设备终端id") - private String id_de_device_terminal_config; - - /** 设备类型 */ - @Excel(name = "设备类型") - @ApiModelProperty("设备类型") - private String deviceModel; - - /** 参数名称 */ - @Excel(name = "参数名称") - @ApiModelProperty("参数名称") - private String paramName; - - - /** 参数默认值 */ - @Excel(name = "参数默认值") - @ApiModelProperty("参数默认值") - private String defaultValue; - - /** 参数类型 */ - @Excel(name = "参数类型") - @ApiModelProperty("参数类型") - private String paramType; - -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceRegistration.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceRegistration.java deleted file mode 100644 index ff91529..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceRegistration.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.cmvr.device.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; - -/** - * 设备注册对象 de_device_registration - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel("设备注册") -public class DeDeviceRegistration extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - - public DeDeviceRegistration(String deviceCode,String deviceModel){ - this.deviceCode=deviceCode; - this.deviceModel=deviceModel; - } - - /** id */ - @ApiModelProperty("id") - @TableId(value = "id",type = IdType.ASSIGN_UUID) - private String id; - - /** 备注 */ - @Excel(name = "备注") - @ApiModelProperty("备注") - private String remake; - - /** 设备终端配置id */ - @Excel(name = "设备终端配置id") - @ApiModelProperty("设备终端id") - private String idDeDeviceTerminalConfig; - - /** 设备编码 */ - @Excel(name = "设备编码") - @ApiModelProperty("设备编码") - private String deviceCode; - - /** 设备名称 */ - @Excel(name = "设备名称") - @ApiModelProperty("设备名称") - private String deviceName; - - - /** 设备型号 */ - @Excel(name = "设备型号") - @ApiModelProperty("设备型号") - private String deviceModel; - - /** 设备状态 */ - @Excel(name = "设备状态") - @ApiModelProperty(value = "设备状态 (0正常 1停用)") - private String status; - -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java deleted file mode 100644 index 5f41236..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeDeviceTerminalConfig.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.cmvr.device.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; - -import java.util.Date; - -/** - * 设备终端配置对象 de_device_terminal_config - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel("设备终端配置") -public class DeDeviceTerminalConfig extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** id */ - @ApiModelProperty("id") - @TableId(value = "id" , type = IdType.ASSIGN_UUID) - private String id; - - /** 备注 */ - @Excel(name = "备注") - @ApiModelProperty("备注") - private String remake; - - /** 终端名称 */ - @Excel(name = "终端名称") - @ApiModelProperty("终端名称") - private String name; - - /** 主机 */ - @Excel(name = "主机") - @ApiModelProperty("主机") - private String host; - - /** 端口号 */ - @Excel(name = "端口号") - @ApiModelProperty("端口号") - private Long port; - - /** 状态 */ - @Excel(name = "状态") - @ApiModelProperty("状态") - private String status; - - /** 说明 */ - @Excel(name = "说明") - @ApiModelProperty("说明") - private String description; - - /** QUIC终端主动注册时使用的稳定节点ID,人工绑定后不可与其他终端重复。 */ - @Excel(name = "QUIC节点ID") - @ApiModelProperty("QUIC节点ID") - private String quicNodeId; - - /** Gateway从已认证QUIC连接中观察到的源IP。 */ - @ApiModelProperty("QUIC连接源IP") - private String quicObservedIp; - - /** 当前QUIC注册会话ID。 */ - @ApiModelProperty("QUIC会话ID") - private String quicSessionId; - - /** 终端本次操作系统启动ID。 */ - @ApiModelProperty("QUIC终端启动ID") - private String quicBootId; - - /** cmvr-es上报的软件版本。 */ - @ApiModelProperty("终端软件版本") - private String quicSoftwareVersion; - - /** QUIC在线状态:0离线,1在线;与原有status启停字段相互独立。 */ - @ApiModelProperty("QUIC在线状态:0离线,1在线") - private String quicOnlineStatus; - - /** 最近一次收到有效QUIC心跳或注册事件的时间。 */ - @ApiModelProperty("最近QUIC心跳时间") - private Date quicLastHeartbeatTime; - -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeRobotConfig.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeRobotConfig.java deleted file mode 100644 index 1c76a2f..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/DeRobotConfig.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.cmvr.device.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -/** - * 机器人配置对象 de_robot_config - * - * @author cmvr-iot - * @date 2025-09-09 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel("机器人配置对象") -public class DeRobotConfig extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** 主键ID */ - @ApiModelProperty("id") - @TableId(value = "id" , type = IdType.ASSIGN_UUID) - private String id; - - /** 配置ID,32位的UUID,可以是设备ID或机器人ID。 */ - @Excel(name = "配置ID,32位的UUID,可以是设备ID或机器人ID。") - @ApiModelProperty("配置ID,32位的UUID,可以是设备ID或机器人ID。") - private String configId; - - /** 配置类型,区分是设备还是终端 */ - @Excel(name = "配置类型,区分是设备还是终端") - @ApiModelProperty(name = "配置类型,区分是设备还是终端") - private String configType; - - /** 父配置ID,用于构成树形结构。终端节点为root,设备节点指向其父终端的id */ - @Excel(name = "父配置ID,用于构成树形结构。终端节点为root,设备节点指向其父终端的id") - @ApiModelProperty(name = "父配置ID,用于构成树形结构。终端节点为root,设备节点指向其父终端的id") - private String pid; - - /** 节点名称,名称可以随意取,不强制唯一 */ - @Excel(name = "节点名称,名称可以随意取,不强制唯一") - @ApiModelProperty(name = "节点名称,名称可以随意取,不强制唯一") - private String nodeName; - -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/vo/ProfileVo.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/vo/ProfileVo.java deleted file mode 100644 index c8961c9..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/vo/ProfileVo.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.cmvr.device.domain.vo; - - -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel("参数视图类") -@EqualsAndHashCode(callSuper = false) -public class ProfileVo extends BaseEntity { - - - /** 设备类型 */ - @Excel(name = "设备类型") - @ApiModelProperty("设备类型") - private String deviceModel; - - /** 设备id */ - @Excel(name = "设备id") - @ApiModelProperty("设备id") - private String idDeDeviceRegistration; - - /** 设备终端id */ - @Excel(name = "设备终端id") - @ApiModelProperty("设备终端id") - private String id_de_device_terminal_config; - - /** 设备名称 */ - @Excel(name = "设备名称") - @ApiModelProperty("设备名称") - private String deviceName; - - /** 终端名称 */ - @Excel(name = "终端名称") - @ApiModelProperty("终端名称") - private String terminalName; - - @Excel(name = "参数列表") - @ApiModelProperty("参数列表") - private List parameters; - -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/vo/TeMechanicalArmVo.java b/cmvr-iot-device/src/main/java/com/cmvr/device/domain/vo/TeMechanicalArmVo.java deleted file mode 100644 index 360f0d7..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/domain/vo/TeMechanicalArmVo.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.cmvr.device.domain.vo; - -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -@ApiModel("机械臂相关参数") -public class TeMechanicalArmVo extends BaseEntity { - - @Excel(name = "设备id") - @ApiModelProperty("设备id") - private String idDeDeviceRegistration; - - @Excel(name = "工作模式") - @ApiModelProperty("工作模式") - private String workModule; - - @Excel(name = "位置步进") - @ApiModelProperty("位置步进") - private String posStep; - - @Excel(name = "姿态步进") - @ApiModelProperty("姿态步进") - private String postureStep; - - @Excel(name = "关节步进") - @ApiModelProperty("关节步进") - private String jointStep; - - @Excel(name = "关节1") - @ApiModelProperty("关节1") - private String joint1; - - @Excel(name = "关节2") - @ApiModelProperty("关节2") - private String joint2; - - @Excel(name = "关节3") - @ApiModelProperty("关节3") - private String joint3; - - @Excel(name = "关节4") - @ApiModelProperty("关节4") - private String joint4; - - @Excel(name = "关节5") - @ApiModelProperty("关节5") - private String joint5; - - @Excel(name = "关节6") - @ApiModelProperty("关节6") - private String joint6; - - @Excel(name = "x轴") - @ApiModelProperty("x轴") - private String x; - - @Excel(name = "y轴") - @ApiModelProperty("y轴") - private String y; - - @Excel(name = "z轴") - @ApiModelProperty("z轴") - private String z; - - @Excel(name = "rx轴") - @ApiModelProperty("rx轴") - private String rx; - - @Excel(name = "ry轴") - @ApiModelProperty("ry轴") - private String ry; - - @Excel(name = "rz轴") - @ApiModelProperty("rz轴") - private String rz; - - -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceProfileMapper.java b/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceProfileMapper.java deleted file mode 100644 index 755c001..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceProfileMapper.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.cmvr.device.mapper; - -import java.util.List; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.cmvr.device.domain.DeDeviceProfile; -import com.cmvr.device.domain.vo.ParameterVo; -import com.cmvr.device.domain.vo.ProfileVo; -import com.cmvr.device.domain.vo.TeMechanicalArmVo; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; -import org.springframework.context.annotation.Primary; - -/** - * 设备配置信息Mapper接口 - * - * @author cmvr-iot - * @date 2025-05-09 - */ -@Mapper -public interface DeDeviceProfileMapper extends BaseMapper -{ - /** - * 根据设备id查询当前设备的所有配置信息 - * - * @param id 设备配置信息主键 - * @return 设备配置信息 - */ - public List selectDeDeviceProfileById(String id); - - /** - * 根据id查询参数信息 - * @param id - * @return - */ - public DeDeviceProfile selectProfileById(String id); - - -// 查询所有设备配置列表信息 - public List selectAllProfilesVo(); - - - /** - * 根据设备id和备注查询相关参数信息 - * @param id 设备id - * @param remark 备注 - * @return 返回设备参数对象 - */ - public List selectProfileByIdAndRemark(@Param("id") String id,@Param("remark") String remark); - - - /** - * 根据设备id和备注查询相关参数信息 - * @param id 设备id - * @param remark 备注 - * @return 返回视图对象 - */ - public List selectParameterByIdAndRemark(@Param("id") String id, @Param("remark") String remark); - - - /** - * 根据设备参数id去修改参数默认值 - * @param id 设备id - * @return 结果 - */ - public int updateProfileByIdAndByName(@Param("id") String id, @Param("name") String name, @Param("value") String value); - - /** - * 查询设备配置信息列表 - * - * @param deDeviceProfile 设备配置信息 - * @return 设备配置信息集合 - */ - public List selectDeDeviceProfileList(DeDeviceProfile deDeviceProfile); - - - /** - * 新增设备配置信息 - * - * @param deDeviceProfile 设备配置信息 - * @return 结果 - */ - public int insertDeDeviceProfile(DeDeviceProfile deDeviceProfile); - - /** - * 修改设备配置信息 - * - * @param deDeviceProfile 设备配置信息 - * @return 结果 - */ - public int updateDeDeviceProfile(DeDeviceProfile deDeviceProfile); - - /** - * 删除设备配置信息 - * - * @param id 设备配置信息主键 - * @return 结果 - */ - public int deleteDeDeviceProfileById(String id); - - /** - * 批量删除设备配置信息 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteDeDeviceProfileByIds(String[] ids); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceRegistrationMapper.java b/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceRegistrationMapper.java deleted file mode 100644 index 68e8938..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceRegistrationMapper.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.cmvr.device.mapper; - -import java.util.List; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.cmvr.device.domain.DeDeviceRegistration; -import org.apache.ibatis.annotations.Mapper; - -/** - * 设备注册Mapper接口 - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@Mapper -public interface DeDeviceRegistrationMapper extends BaseMapper -{ - /** - * 查询设备注册 - * - * @param id 设备注册主键 - * @return 设备注册 - */ - public DeDeviceRegistration selectDeDeviceRegistrationById(String id); - - - /** - * 查询设备表中所有的设备编号 - * @return 设备编号集合 - */ - public List selectAllDeviceCode(); - - - public String selectDeviceModelById(String id); - - - /** - * 查询设备注册列表 - * - * @param deDeviceRegistration 设备注册 - * @return 设备注册集合 - */ - public List selectDeDeviceRegistrationList(DeDeviceRegistration deDeviceRegistration); - - /** - * 新增设备注册 - * - * @param deDeviceRegistration 设备注册 - * @return 结果 - */ - public int insertDeDeviceRegistration(DeDeviceRegistration deDeviceRegistration); - - /** - * 修改设备注册 - * - * @param deDeviceRegistration 设备注册 - * @return 结果 - */ - public int updateDeDeviceRegistration(DeDeviceRegistration deDeviceRegistration); - - /** - * 删除设备注册 - * - * @param id 设备注册主键 - * @return 结果 - */ - public int deleteDeDeviceRegistrationById(String id); - - /** - * 批量删除设备注册 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteDeDeviceRegistrationByIds(String[] ids); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java b/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java deleted file mode 100644 index 2a5437e..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeDeviceTerminalConfigMapper.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.cmvr.device.mapper; - -import java.util.List; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.cmvr.device.domain.DeDeviceTerminalConfig; -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; - -import java.util.Date; - -/** - * 设备终端配置Mapper接口 - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@Mapper -public interface DeDeviceTerminalConfigMapper extends BaseMapper -{ - /** - * 查询设备终端配置 - * - * @param id 设备终端配置主键 - * @return 设备终端配置 - */ - public DeDeviceTerminalConfig selectDeDeviceTerminalConfigById(String id); - - /** 根据QUIC节点ID查找已人工绑定的终端。 */ - DeDeviceTerminalConfig selectByQuicNodeId(@Param("quicNodeId") String quicNodeId); - - /** - * 更新QUIC运行态和终端gRPC地址,不覆盖终端名称、启停状态等人工配置。 - */ - int updateQuicRuntimeState(@Param("id") String id, - @Param("host") String host, - @Param("port") Long port, - @Param("observedIp") String observedIp, - @Param("sessionId") String sessionId, - @Param("bootId") String bootId, - @Param("softwareVersion") String softwareVersion, - @Param("onlineStatus") String onlineStatus, - @Param("lastHeartbeatTime") Date lastHeartbeatTime); - - /** - * 查询设备终端配置列表 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 设备终端配置集合 - */ - public List selectDeDeviceTerminalConfigList(DeDeviceTerminalConfig deDeviceTerminalConfig); - - /** - * 新增设备终端配置 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 结果 - */ - public int insertDeDeviceTerminalConfig(DeDeviceTerminalConfig deDeviceTerminalConfig); - - /** - * 修改设备终端配置 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 结果 - */ - public int updateDeDeviceTerminalConfig(DeDeviceTerminalConfig deDeviceTerminalConfig); - - /** - * 删除设备终端配置 - * - * @param id 设备终端配置主键 - * @return 结果 - */ - public int deleteDeDeviceTerminalConfigById(String id); - - /** - * 批量删除设备终端配置 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteDeDeviceTerminalConfigByIds(String[] ids); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeRobotConfigMapper.java b/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeRobotConfigMapper.java deleted file mode 100644 index 7a3fe82..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/mapper/DeRobotConfigMapper.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.cmvr.device.mapper; - -import java.util.List; -import com.cmvr.device.domain.DeRobotConfig; - -/** - * 机器人配置Mapper接口 - * - * @author cmvr-iot - * @date 2025-09-09 - */ -public interface DeRobotConfigMapper -{ - /** - * 查询机器人配置 - * - * @param id 机器人配置主键 - * @return 机器人配置 - */ - public DeRobotConfig selectDeRobotConfigById(String id); - - /** - * 查询机器人配置列表 - * - * @param deRobotConfig 机器人配置 - * @return 机器人配置集合 - */ - public List selectDeRobotConfigList(DeRobotConfig deRobotConfig); - - /** - * 新增机器人配置 - * - * @param deRobotConfig 机器人配置 - * @return 结果 - */ - public int insertDeRobotConfig(DeRobotConfig deRobotConfig); - - /** - * 修改机器人配置 - * - * @param deRobotConfig 机器人配置 - * @return 结果 - */ - public int updateDeRobotConfig(DeRobotConfig deRobotConfig); - - /** - * 删除机器人配置 - * - * @param id 机器人配置主键 - * @return 结果 - */ - public int deleteDeRobotConfigById(String id); - - /** - * 批量删除机器人配置 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteDeRobotConfigByIds(String[] ids); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceProfileService.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceProfileService.java deleted file mode 100644 index ada785c..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceProfileService.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.cmvr.device.service; - -import java.util.List; -import com.cmvr.device.domain.DeDeviceProfile; -import com.cmvr.device.domain.DeDeviceRegistration; -import com.cmvr.device.domain.vo.ProfileVo; -import com.cmvr.device.domain.vo.TeMechanicalArmVo; -import org.apache.ibatis.annotations.Param; - -/** - * 设备配置信息Service接口 - * - * @author cmvr-iot - * @date 2025-05-09 - */ -public interface IDeDeviceProfileService -{ - /** - * 根据设备id查询设备配置信息 - * - * @param id 设备id - * @return 设备配置信息 - */ - public List selectDeDeviceProfileById(String id); - - - /** - * 根据设备id和备注查询相关参数信息 - * @param id 设备id - * @param remark 备注 - * @return - */ - public List selectProfileByIdAndRemark(String id,String remark); - - - /** - * 根据设备id和参数名称,修改参数值 - * @param mechanicalArmVo 配置参数信息 - * @return 结果 - */ - public int updateProfileByIdAndByName(TeMechanicalArmVo mechanicalArmVo); - - - /** - * 查询设备配置信息列表 - * - * @param deDeviceProfile 设备配置信息 - * @return 设备配置信息集合 - */ - public List selectDeDeviceProfileList(DeDeviceProfile deDeviceProfile); - - /** - * 新增设备配置信息 - * - * @param deDeviceProfile 设备配置信息 - * @return 结果 - */ - public int insertDeDeviceProfile(List deDeviceProfile); - - /** - * 修改设备配置信息 - * - * @param deDeviceProfiles 设备配置信息 - * @return 结果 - */ - public int updateDeDeviceProfile(List deDeviceProfiles); - - /** - * 批量删除设备配置信息 - * - * @param ids 需要删除的设备配置信息主键集合 - * @return 结果 - */ - public int deleteDeDeviceProfileByIds(String[] ids); - - /** - * 删除设备配置信息信息 - * - * @param id 设备配置信息主键 - * @return 结果 - */ - public int deleteDeDeviceProfileById(String id); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceRegistrationService.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceRegistrationService.java deleted file mode 100644 index 283f0fb..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceRegistrationService.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.cmvr.device.service; - -import java.util.List; -import com.cmvr.device.domain.DeDeviceRegistration; -import com.cmvr.device.domain.vo.Device; - -/** - * 设备注册Service接口 - * - * @author cmvr-iot - * @date 2025-05-08 - */ -public interface IDeDeviceRegistrationService -{ - /** - * 查询设备注册 - * - * @param id 设备注册主键 - * @return 设备注册 - */ - public DeDeviceRegistration selectDeDeviceRegistrationById(String id); - - /** - * 新增获取到的 - * @param devices 设备列表 - * @return - */ - public int addDeviceList(List devices); - - /** - * 查询设备注册列表 - * - * @param deDeviceRegistration 设备注册 - * @return 设备注册集合 - */ - public List selectDeDeviceRegistrationList(DeDeviceRegistration deDeviceRegistration); - - /** - * 新增设备注册 - * - * @param deDeviceRegistration 设备注册 - * @return 结果 - */ - public int insertDeDeviceRegistration(DeDeviceRegistration deDeviceRegistration); - - /** - * 修改设备注册 - * - * @param deDeviceRegistration 设备注册 - * @return 结果 - */ - public int updateDeDeviceRegistration(DeDeviceRegistration deDeviceRegistration); - - /** - * 批量删除设备注册 - * - * @param ids 需要删除的设备注册主键集合 - * @return 结果 - */ - public int deleteDeDeviceRegistrationByIds(String[] ids); - - /** - * 删除设备注册信息 - * - * @param id 设备注册主键 - * @return 结果 - */ - public int deleteDeDeviceRegistrationById(String id); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceTerminalConfigService.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceTerminalConfigService.java deleted file mode 100644 index 9b870da..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeDeviceTerminalConfigService.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.cmvr.device.service; - -import java.util.List; -import java.util.Date; -import com.cmvr.device.domain.DeDeviceTerminalConfig; - -/** - * 设备终端配置Service接口 - * - * @author cmvr-iot - * @date 2025-05-08 - */ -public interface IDeDeviceTerminalConfigService -{ - /** - * 查询设备终端配置 - * - * @param id 设备终端配置主键 - * @return 设备终端配置 - */ - public DeDeviceTerminalConfig selectDeDeviceTerminalConfigById(String id); - - /** 根据QUIC节点ID查询已绑定终端。 */ - DeDeviceTerminalConfig selectByQuicNodeId(String quicNodeId); - - /** 更新QUIC运行态以及由终端主动上报的gRPC地址。 */ - int updateQuicRuntimeState(String id, String host, Long port, String observedIp, - String sessionId, String bootId, String softwareVersion, - String onlineStatus, Date lastHeartbeatTime); - - /** - * 查询设备终端配置列表 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 设备终端配置集合 - */ - public List selectDeDeviceTerminalConfigList(DeDeviceTerminalConfig deDeviceTerminalConfig); - - /** - * 新增设备终端配置 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 结果 - */ - public int insertDeDeviceTerminalConfig(DeDeviceTerminalConfig deDeviceTerminalConfig); - - /** - * 修改设备终端配置 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 结果 - */ - public int updateDeDeviceTerminalConfig(DeDeviceTerminalConfig deDeviceTerminalConfig); - - /** - * 批量删除设备终端配置 - * - * @param ids 需要删除的设备终端配置主键集合 - * @return 结果 - */ - public int deleteDeDeviceTerminalConfigByIds(String[] ids); - - /** - * 删除设备终端配置信息 - * - * @param id 设备终端配置主键 - * @return 结果 - */ - public int deleteDeDeviceTerminalConfigById(String id); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeRobotConfigService.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeRobotConfigService.java deleted file mode 100644 index a312f7c..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/IDeRobotConfigService.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.cmvr.device.service; - -import java.util.List; -import com.cmvr.device.domain.DeRobotConfig; - -/** - * 机器人配置Service接口 - * - * @author cmvr-iot - * @date 2025-09-09 - */ -public interface IDeRobotConfigService -{ - /** - * 查询机器人配置 - * - * @param id 机器人配置主键 - * @return 机器人配置 - */ - public DeRobotConfig selectDeRobotConfigById(String id); - - /** - * 查询机器人配置列表 - * - * @param deRobotConfig 机器人配置 - * @return 机器人配置集合 - */ - public List selectDeRobotConfigList(DeRobotConfig deRobotConfig); - - /** - * 新增机器人配置 - * - * @param deRobotConfig 机器人配置 - * @return 结果 - */ - public int insertDeRobotConfig(DeRobotConfig deRobotConfig); - - /** - * 修改机器人配置 - * - * @param deRobotConfig 机器人配置 - * @return 结果 - */ - public int updateDeRobotConfig(DeRobotConfig deRobotConfig); - - /** - * 批量删除机器人配置 - * - * @param ids 需要删除的机器人配置主键集合 - * @return 结果 - */ - public int deleteDeRobotConfigByIds(String[] ids); - - /** - * 删除机器人配置信息 - * - * @param id 机器人配置主键 - * @return 结果 - */ - public int deleteDeRobotConfigById(String id); -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceProfileServiceImpl.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceProfileServiceImpl.java deleted file mode 100644 index c351e14..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceProfileServiceImpl.java +++ /dev/null @@ -1,176 +0,0 @@ -package com.cmvr.device.service.impl; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import com.cmvr.common.utils.DateUtils; -import com.cmvr.device.domain.DeDeviceRegistration; -import com.cmvr.device.domain.vo.ParameterVo; -import com.cmvr.device.domain.vo.ProfileVo; -import com.cmvr.device.domain.vo.TeMechanicalArmVo; -import com.cmvr.device.mapper.DeDeviceRegistrationMapper; -import org.apache.commons.collections4.list.PredicatedList; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.cmvr.device.mapper.DeDeviceProfileMapper; -import com.cmvr.device.domain.DeDeviceProfile; -import com.cmvr.device.service.IDeDeviceProfileService; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -/** - * 设备配置信息Service业务层处理 - * - * @author cmvr-iot - * @date 2025-05-09 - */ -@Service -public class DeDeviceProfileServiceImpl implements IDeDeviceProfileService -{ - @Autowired - private DeDeviceProfileMapper deDeviceProfileMapper; - - @Autowired - private DeDeviceRegistrationMapper deviceRegistrationMapper; - - /** - * 根据设备id查询当前设备设备配置信息 - * - * @param id 设备id - * @return 设备配置信息 - */ - @Override - public List selectDeDeviceProfileById(String id) - { - //根据设备id查询设备配置信息 - DeDeviceProfile deviceProfile=deDeviceProfileMapper.selectProfileById(id); - //根据设备id和备注查询设备配置信息 - List deviceProfiles=deDeviceProfileMapper - .selectProfileByIdAndRemark( - deviceProfile.getIdDeDeviceRegistration(), - deviceProfile.getRemark() - ); - //打印设备配置信息 - System.out.println(deviceProfiles); - //返回设备配置信息 - return deviceProfiles; - - } - - @Override - public List selectProfileByIdAndRemark(String id, String remark) { - return deDeviceProfileMapper.selectProfileByIdAndRemark(id,remark); - } - - - /** - * 根据设备参数id去修改参数默认值 - * @param mechanicalArmVo 配置参数信息 - * @return 结果 - */ - @Override - public int updateProfileByIdAndByName(TeMechanicalArmVo mechanicalArmVo) { - if (mechanicalArmVo == null || StringUtils.isEmpty(mechanicalArmVo.getIdDeDeviceRegistration())) { - return 0; - } - int totalUpdated = 0; - String deviceId = mechanicalArmVo.getIdDeDeviceRegistration(); - // 使用 Map 收集非空属性 - Map fieldMap = new HashMap<>(); - if (mechanicalArmVo.getWorkModule() != null) fieldMap.put("workModule", mechanicalArmVo.getWorkModule()); - if (mechanicalArmVo.getPosStep() != null) fieldMap.put("posStep", mechanicalArmVo.getPosStep()); - if (mechanicalArmVo.getJointStep() != null) fieldMap.put("jointStep", mechanicalArmVo.getJointStep()); - if (mechanicalArmVo.getJoint1() != null) fieldMap.put("joint1", mechanicalArmVo.getJoint1()); - if (mechanicalArmVo.getJoint2() != null) fieldMap.put("joint2", mechanicalArmVo.getJoint2()); - if (mechanicalArmVo.getJoint3() != null) fieldMap.put("joint3", mechanicalArmVo.getJoint3()); - if (mechanicalArmVo.getJoint4() != null) fieldMap.put("joint4", mechanicalArmVo.getJoint4()); - if (mechanicalArmVo.getJoint5() != null) fieldMap.put("joint5", mechanicalArmVo.getJoint5()); - if (mechanicalArmVo.getJoint6() != null) fieldMap.put("joint6", mechanicalArmVo.getJoint6()); - if (mechanicalArmVo.getX() != null) fieldMap.put("x", mechanicalArmVo.getX()); - if (mechanicalArmVo.getY() != null) fieldMap.put("y", mechanicalArmVo.getY()); - if (mechanicalArmVo.getZ() != null) fieldMap.put("z", mechanicalArmVo.getZ()); - if (mechanicalArmVo.getRx() != null) fieldMap.put("rx", mechanicalArmVo.getRx()); - if (mechanicalArmVo.getRy() != null) fieldMap.put("ry", mechanicalArmVo.getRy()); - if (mechanicalArmVo.getRz() != null) fieldMap.put("rz", mechanicalArmVo.getRz()); - // 遍历 Map 执行更新 - for (Map.Entry entry : fieldMap.entrySet()) { - totalUpdated += deDeviceProfileMapper.updateProfileByIdAndByName( - deviceId, entry.getKey(), (String)entry.getValue()); - } - return totalUpdated; - } - - /** - * 查询设备配置信息列表 - * - * @param deDeviceProfile 设备配置信息 - * @return 设备配置信息 - */ - @Override - public List selectDeDeviceProfileList(DeDeviceProfile deDeviceProfile) - { - List profileVoList=deDeviceProfileMapper.selectAllProfilesVo(); - return profileVoList; - } - - /** - * 新增设备配置信息 - * - * @param deDeviceProfile 设备配置信息 - * @return 结果 - */ - @Override - public int insertDeDeviceProfile(List deDeviceProfile) - { - int i=0; - for (DeDeviceProfile profile : deDeviceProfile) { - i=deDeviceProfileMapper.insert(profile); - } - return i; - } - - /** - * 修改设备配置信息 - * - * @param deDeviceProfiles 设备配置信息 - * @return 结果 - */ - @Override - public int updateDeDeviceProfile(List deDeviceProfiles) - { - int i=0; - for (DeDeviceProfile profile : deDeviceProfiles) { - i=deDeviceProfileMapper.updateDeDeviceProfile(profile); - } - return i; - } - - /** - * 批量删除设备配置信息 - * - * @param ids 需要删除的设备配置信息主键 - * @return 结果 - */ - @Override - public int deleteDeDeviceProfileByIds(String[] ids) - { - return deDeviceProfileMapper.deleteDeDeviceProfileByIds(ids); - } - - /** - * 删除设备配置信息信息 - * - * @param id 设备配置信息主键 - * @return 结果 - */ - @Override - public int deleteDeDeviceProfileById(String id) - { - return deDeviceProfileMapper.deleteDeDeviceProfileById(id); - } -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceRegistrationServiceImpl.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceRegistrationServiceImpl.java deleted file mode 100644 index 19d076f..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceRegistrationServiceImpl.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.cmvr.device.service.impl; - -import java.util.List; - -import com.cmvr.common.utils.DateUtils; -import com.cmvr.common.utils.DateUtils; -import com.cmvr.device.domain.DeDeviceProfile; -import com.cmvr.device.domain.vo.Device; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.cmvr.device.mapper.DeDeviceRegistrationMapper; -import com.cmvr.device.domain.DeDeviceRegistration; -import com.cmvr.device.service.IDeDeviceRegistrationService; - -/** - * 设备注册Service业务层处理 - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@Service -public class DeDeviceRegistrationServiceImpl implements IDeDeviceRegistrationService -{ - @Autowired - private DeDeviceRegistrationMapper deDeviceRegistrationMapper; - - /** - * 查询设备注册 - * - * @param id 设备注册主键 - * @return 设备注册 - */ - @Override - public DeDeviceRegistration selectDeDeviceRegistrationById(String id) - { - return deDeviceRegistrationMapper.selectDeDeviceRegistrationById(id); - } - - - @Override - public int addDeviceList(List devices) { - - // 2. 获取数据库中已有设备 - List deviceCodes= deDeviceRegistrationMapper.selectAllDeviceCode(); - - int addedCount = 0; - - for (DeDeviceRegistration edgeDevice : devices) { - if (!deviceCodes.contains(edgeDevice.getDeviceCode())) { - - deDeviceRegistrationMapper.insert(edgeDevice); - addedCount++; - } - } - - return addedCount; - - } - - - - - /** - * 查询设备注册列表 - * - * @param deDeviceRegistration 设备注册 - * @return 设备注册 - */ - @Override - public List selectDeDeviceRegistrationList(DeDeviceRegistration deDeviceRegistration) - { - return deDeviceRegistrationMapper.selectDeDeviceRegistrationList(deDeviceRegistration); - } - - /** - * 新增设备注册 - * - * @param deDeviceRegistration 设备注册 - * @return 结果 - */ - @Override - public int insertDeDeviceRegistration(DeDeviceRegistration deDeviceRegistration) - { - deDeviceRegistration.setCreateTime(DateUtils.getNowDate()); - deDeviceRegistration.setStatus("1"); - return deDeviceRegistrationMapper.insert(deDeviceRegistration); - } - - /** - * 修改设备注册 - * - * @param deDeviceRegistration 设备注册 - * @return 结果 - */ - @Override - public int updateDeDeviceRegistration(DeDeviceRegistration deDeviceRegistration) - { - deDeviceRegistration.setUpdateTime(DateUtils.getNowDate()); - return deDeviceRegistrationMapper.updateDeDeviceRegistration(deDeviceRegistration); - } - - /** - * 批量删除设备注册 - * - * @param ids 需要删除的设备注册主键 - * @return 结果 - */ - @Override - public int deleteDeDeviceRegistrationByIds(String[] ids) - { - return deDeviceRegistrationMapper.deleteDeDeviceRegistrationByIds(ids); - } - - /** - * 删除设备注册信息 - * - * @param id 设备注册主键 - * @return 结果 - */ - @Override - public int deleteDeDeviceRegistrationById(String id) - { - return deDeviceRegistrationMapper.deleteDeDeviceRegistrationById(id); - } -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceTerminalConfigServiceImpl.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceTerminalConfigServiceImpl.java deleted file mode 100644 index e003eef..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeDeviceTerminalConfigServiceImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.cmvr.device.service.impl; - -import java.util.List; -import java.util.Date; -import com.cmvr.common.utils.DateUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Service; -import com.cmvr.device.mapper.DeDeviceTerminalConfigMapper; -import com.cmvr.device.domain.DeDeviceTerminalConfig; -import com.cmvr.device.service.IDeDeviceTerminalConfigService; - -/** - * 设备终端配置Service业务层处理 - * - * @author cmvr-iot - * @date 2025-05-08 - */ -@Service -public class DeDeviceTerminalConfigServiceImpl implements IDeDeviceTerminalConfigService -{ - @Autowired - private DeDeviceTerminalConfigMapper deDeviceTerminalConfigMapper; - - /** - * 查询设备终端配置 - * - * @param id 设备终端配置主键 - * @return 设备终端配置 - */ - @Override - public DeDeviceTerminalConfig selectDeDeviceTerminalConfigById(String id) - { - return deDeviceTerminalConfigMapper.selectDeDeviceTerminalConfigById(id); - } - - @Override - public DeDeviceTerminalConfig selectByQuicNodeId(String quicNodeId) - { - return deDeviceTerminalConfigMapper.selectByQuicNodeId(quicNodeId); - } - - @Override - public int updateQuicRuntimeState(String id, String host, Long port, String observedIp, - String sessionId, String bootId, String softwareVersion, - String onlineStatus, Date lastHeartbeatTime) - { - return deDeviceTerminalConfigMapper.updateQuicRuntimeState(id, host, port, observedIp, - sessionId, bootId, softwareVersion, onlineStatus, lastHeartbeatTime); - } - - /** - * 查询设备终端配置列表 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 设备终端配置 - */ - @Override - public List selectDeDeviceTerminalConfigList(DeDeviceTerminalConfig deDeviceTerminalConfig) - { - return deDeviceTerminalConfigMapper.selectDeDeviceTerminalConfigList(deDeviceTerminalConfig); - } - - /** - * 新增设备终端配置 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 结果 - */ - @Override - public int insertDeDeviceTerminalConfig(DeDeviceTerminalConfig deDeviceTerminalConfig) - { - deDeviceTerminalConfig.setCreateTime(DateUtils.getNowDate()); - deDeviceTerminalConfig.setStatus("1"); - return this.deDeviceTerminalConfigMapper.insert(deDeviceTerminalConfig); - } - - /** - * 修改设备终端配置 - * - * @param deDeviceTerminalConfig 设备终端配置 - * @return 结果 - */ - @Override - public int updateDeDeviceTerminalConfig(DeDeviceTerminalConfig deDeviceTerminalConfig) - { - deDeviceTerminalConfig.setUpdateTime(DateUtils.getNowDate()); - return deDeviceTerminalConfigMapper.updateDeDeviceTerminalConfig(deDeviceTerminalConfig); - } - - /** - * 批量删除设备终端配置 - * - * @param ids 需要删除的设备终端配置主键 - * @return 结果 - */ - @Override - public int deleteDeDeviceTerminalConfigByIds(String[] ids) - { - return deDeviceTerminalConfigMapper.deleteDeDeviceTerminalConfigByIds(ids); - } - - /** - * 删除设备终端配置信息 - * - * @param id 设备终端配置主键 - * @return 结果 - */ - @Override - public int deleteDeDeviceTerminalConfigById(String id) - { - return deDeviceTerminalConfigMapper.deleteDeDeviceTerminalConfigById(id); - } -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeRobotConfigServiceImpl.java b/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeRobotConfigServiceImpl.java deleted file mode 100644 index 34eecbb..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/service/impl/DeRobotConfigServiceImpl.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.cmvr.device.service.impl; - -import java.util.List; - -import com.cmvr.common.utils.DateUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.cmvr.device.mapper.DeRobotConfigMapper; -import com.cmvr.device.domain.DeRobotConfig; -import com.cmvr.device.service.IDeRobotConfigService; - -/** - * 机器人配置Service业务层处理 - * - * @author cmvr-iot - * @date 2025-09-09 - */ -@Service -public class DeRobotConfigServiceImpl implements IDeRobotConfigService -{ - @Autowired - private DeRobotConfigMapper deRobotConfigMapper; - - /** - * 查询机器人配置 - * - * @param id 机器人配置主键 - * @return 机器人配置 - */ - @Override - public DeRobotConfig selectDeRobotConfigById(String id) - { - return deRobotConfigMapper.selectDeRobotConfigById(id); - } - - /** - * 查询机器人配置列表 - * - * @param deRobotConfig 机器人配置 - * @return 机器人配置 - */ - @Override - public List selectDeRobotConfigList(DeRobotConfig deRobotConfig) - { - return deRobotConfigMapper.selectDeRobotConfigList(deRobotConfig); - } - - /** - * 新增机器人配置 - * - * @param deRobotConfig 机器人配置 - * @return 结果 - */ - @Override - public int insertDeRobotConfig(DeRobotConfig deRobotConfig) - { - deRobotConfig.setCreateTime(DateUtils.getNowDate()); - return deRobotConfigMapper.insertDeRobotConfig(deRobotConfig); - } - - /** - * 修改机器人配置 - * - * @param deRobotConfig 机器人配置 - * @return 结果 - */ - @Override - public int updateDeRobotConfig(DeRobotConfig deRobotConfig) - { - deRobotConfig.setUpdateTime(DateUtils.getNowDate()); - return deRobotConfigMapper.updateDeRobotConfig(deRobotConfig); - } - - /** - * 批量删除机器人配置 - * - * @param ids 需要删除的机器人配置主键 - * @return 结果 - */ - @Override - public int deleteDeRobotConfigByIds(String[] ids) - { - return deRobotConfigMapper.deleteDeRobotConfigByIds(ids); - } - - /** - * 删除机器人配置信息 - * - * @param id 机器人配置主键 - * @return 结果 - */ - @Override - public int deleteDeRobotConfigById(String id) - { - return deRobotConfigMapper.deleteDeRobotConfigById(id); - } -} diff --git a/cmvr-iot-device/src/main/java/com/cmvr/device/util/VoUtil.java b/cmvr-iot-device/src/main/java/com/cmvr/device/util/VoUtil.java deleted file mode 100644 index 84830d6..0000000 --- a/cmvr-iot-device/src/main/java/com/cmvr/device/util/VoUtil.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.cmvr.device.util; - -import com.cmvr.device.domain.vo.TeMechanicalArmVo; - -import java.lang.reflect.Field; - -public class VoUtil { - /** - * 获取TeMechanicalArmVo对象中除设备ID外的非空属性名 - * @param vo TeMechanicalArmVo对象 - * @return 非空属性名,如果没有则返回null - */ - public static String getNonNullPropertyName(TeMechanicalArmVo vo) { - if (vo == null) return null; - - try { - for (Field field : TeMechanicalArmVo.class.getDeclaredFields()) { - if ("idDeDeviceRegistration".equals(field.getName())) continue; - - field.setAccessible(true); - Object value = field.get(vo); - - // 排除null和空字符串 - if (value instanceof String) { - if (!((String) value).trim().isEmpty()) { - return field.getName(); - } - } else if (value != null) { - return field.getName(); - } - } - } catch (IllegalAccessException e) { - throw new RuntimeException("获取属性值失败", e); - } - - return null; - } -} \ No newline at end of file diff --git a/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceProfileMapper.xml b/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceProfileMapper.xml deleted file mode 100644 index ddd69f4..0000000 --- a/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceProfileMapper.xml +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - - - - - - - - - - - - select id, create_by, create_time, update_by, update_time, remark, device_model , id_de_device_terminal_config ,id_de_device_registration, param_name, default_value , param_type from de_device_profile - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - insert into de_device_profile - - id, - create_by, - create_time, - update_by, - update_time, - remark, - device_model, - id_de_device_registration, - param_name, - default_value, - param_type, - - - #{id}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - #{remark}, - #{deviceModel}, - #{idDeDeviceRegistration}, - #{paramName}, - #{defaultValue}, - #{paramType}, - - - - - update de_device_profile - - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - remark = #{remark}, - id_de_device_registration = #{idDeDeviceRegistration}, - param_name = #{paramName}, - default_value = #{defaultValue}, - param_type = #{paramType}, - - where id = #{id} - - - - - UPDATE de_device_profile set default_value=#{value} - WHERE id_de_device_registration = #{id} AND param_name = #{name} - - - - - - - - delete from de_device_profile where id = #{id} - - - - delete from de_device_profile where id in - - #{id} - - - \ No newline at end of file diff --git a/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceRegistrationMapper.xml b/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceRegistrationMapper.xml deleted file mode 100644 index 9c68ee5..0000000 --- a/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceRegistrationMapper.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - select id, create_by, create_time, update_by, update_time, remake, id_de_device_terminal_config, device_code, device_name, device_model, status from de_device_registration - - - - - - - - - - - - - insert into de_device_registration - - id, - create_by, - create_time, - update_by, - update_time, - remake, - id_de_device_terminal_config, - device_code, - device_name, - device_model, - status, - - - #{id}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - #{remake}, - #{idDeDeviceTerminalConfig}, - #{deviceCode}, - #{deviceName}, - #{deviceModel}, - #{status}, - - - - - update de_device_registration - - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - remake = #{remake}, - id_de_device_terminal_config = #{idDeDeviceTerminalConfig}, - device_code = #{deviceCode}, - device_name = #{deviceName}, - device_model = #{deviceModel}, - status = #{status}, - - where id = #{id} - - - - delete from de_device_registration where id = #{id} - - - - delete from de_device_registration where id in - - #{id} - - - \ No newline at end of file diff --git a/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceTerminalConfigMapper.xml b/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceTerminalConfigMapper.xml deleted file mode 100644 index cc4e6fd..0000000 --- a/cmvr-iot-device/src/main/resources/mapper/device/DeDeviceTerminalConfigMapper.xml +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - select id, create_by, create_time, update_by, update_time, remake, name, host, port, status, description, - quic_node_id, quic_observed_ip, quic_session_id, quic_boot_id, quic_software_version, - quic_online_status, quic_last_heartbeat_time - from de_device_terminal_config - - - - - - - - - - insert into de_device_terminal_config - - id, - create_by, - create_time, - update_by, - update_time, - remake, - name, - host, - port, - status, - description, - quic_node_id, - quic_online_status, - - - #{id}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - #{remake}, - #{name}, - #{host}, - #{port}, - #{status}, - #{description}, - #{quicNodeId}, - #{quicOnlineStatus}, - - - - - update de_device_terminal_config - - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - remake = #{remake}, - name = #{name}, - host = #{host}, - port = #{port}, - status = #{status}, - description = #{description}, - quic_node_id = #{quicNodeId}, - quic_online_status = #{quicOnlineStatus}, - - where id = #{id} - - - - update de_device_terminal_config - - host = #{host}, - port = #{port}, - quic_observed_ip = #{observedIp}, - quic_session_id = #{sessionId}, - quic_boot_id = #{bootId}, - quic_software_version = #{softwareVersion}, - quic_online_status = #{onlineStatus}, - quic_last_heartbeat_time = #{lastHeartbeatTime}, - update_time = now() - - where id = #{id} - - - - delete from de_device_terminal_config where id = #{id} - - - - delete from de_device_terminal_config where id in - - #{id} - - - diff --git a/cmvr-iot-device/src/main/resources/mapper/device/DeRobotConfigMapper.xml b/cmvr-iot-device/src/main/resources/mapper/device/DeRobotConfigMapper.xml deleted file mode 100644 index 8820946..0000000 --- a/cmvr-iot-device/src/main/resources/mapper/device/DeRobotConfigMapper.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - select id, config_id, config_type, pid, node_name, create_by, create_time, update_by, update_time, remark from de_robot_config - - - - - - - - insert into de_robot_config - - id, - config_id, - config_type, - pid, - node_name, - create_by, - create_time, - update_by, - update_time, - remark, - - - #{id}, - #{configId}, - #{configType}, - #{pid}, - #{nodeName}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - #{remark}, - - - - - update de_robot_config - - config_id = #{configId}, - config_type = #{configType}, - pid = #{pid}, - node_name = #{nodeName}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - remark = #{remark}, - - where id = #{id} - - - - delete from de_robot_config where id = #{id} - - - - delete from de_robot_config where id in - - #{id} - - - \ No newline at end of file diff --git a/cmvr-iot-inspection/pom.xml b/cmvr-iot-inspection/pom.xml index c666276..31ba220 100644 --- a/cmvr-iot-inspection/pom.xml +++ b/cmvr-iot-inspection/pom.xml @@ -35,5 +35,10 @@ cmvr-iot-device + + com.cmvr + cmvr-iot-resource + + diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionMap.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionMap.java deleted file mode 100644 index 0f869e5..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionMap.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.cmvr.inspection.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; - -/** - * 巡检地图对象 inspection_map - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -@ApiModel("巡检地图") -public class InspectionMap extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** id */ - @ApiModelProperty("id") - @TableId(value = "id", type = IdType.ASSIGN_UUID) - private String id; - - /** 地图名称 */ - @Excel(name = "地图名称") - @ApiModelProperty("地图名称") - private String mapName; - - /** 地图来源的机器人id */ - @Excel(name = "地图来源的机器人id") - @ApiModelProperty("地图来源的机器人id") - private String mapSourceRobotId; - - /** 地图来源的地图名称 */ - @Excel(name = "地图来源的地图名称") - @ApiModelProperty("地图来源的地图名称") - private String mapSourceName; - - /** 地图文件路径 */ - @Excel(name = "地图文件路径") - @ApiModelProperty("地图文件路径") - private String mapFilePath; - - /** 状态 */ - @Excel(name = "状态") - @ApiModelProperty("状态(0正常 1停用)") - private String status; - - /** 地图描述 */ - @Excel(name = "地图描述") - @ApiModelProperty("地图描述") - private String mapDesc; - -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionRobot.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionRobot.java deleted file mode 100644 index 30b95a2..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionRobot.java +++ /dev/null @@ -1,116 +0,0 @@ -package com.cmvr.inspection.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; - -import java.util.Date; - -/** - * 巡检机器人对象 inspection_robot - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -@ApiModel("巡检机器人") -public class InspectionRobot extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** id */ - @ApiModelProperty("id") - @TableId(value = "id", type = IdType.ASSIGN_UUID) - private String id; - - /** Permanent robot identity reported by QUIC. */ - @Excel(name = "机器人ID") - @ApiModelProperty("机器人永久唯一ID") - private String robotId; - - /** Business display code. It is not an edge device ID. */ - @Excel(name = "机器人业务编号") - @ApiModelProperty("机器人业务编号,仅用于业务展示,不作为设备ID") - private String robotCode; - - /** 机器人名称 */ - @Excel(name = "机器人名称") - @ApiModelProperty("机器人名称") - private String robotName; - - /** 机器人型号 */ - @Excel(name = "机器人型号") - @ApiModelProperty("机器人型号") - private String robotModel; - - /** 机器人类型 */ - @Excel(name = "机器人类型") - @ApiModelProperty("机器人类型") - private String robotType; - - /** IP地址 */ - @Excel(name = "IP地址") - @ApiModelProperty("IP地址") - private String ipAddress; - - /** 端口号 */ - @Excel(name = "端口号") - @ApiModelProperty("端口号") - private Long port; - - /** 当前地图 */ - @Excel(name = "当前地图") - @ApiModelProperty("当前地图") - private String currentMapId; - - /** 当前状态 */ - @Excel(name = "当前状态") - @ApiModelProperty("AGV运行模式(0未知 1断开 2空闲 3手动 4自动 5充电 6暂停 7停止 8故障 9急停)") - private String status; - - /** 电量百分比 */ - @Excel(name = "电量百分比") - @ApiModelProperty("电量百分比") - private Integer batteryLevel; - - /** 当前位置 */ - @Excel(name = "当前位置") - @ApiModelProperty("当前位置") - private String currentPosition; - - /** QUIC runtime state, independent from the robot business status. */ - @ApiModelProperty("连接状态:0离线,1在线") - private String connectStatus; - - @ApiModelProperty("当前QUIC节点ID") - private String quicNodeId; - - @ApiModelProperty("当前QUIC会话ID") - private String quicSessionId; - - @ApiModelProperty("边缘端启动ID") - private String quicBootId; - - @ApiModelProperty("QUIC连接来源IP") - private String observedIp; - - @ApiModelProperty("边缘端软件版本") - private String softwareVersion; - - @ApiModelProperty("最后心跳时间") - private Date lastHeartbeatTime; - - @ApiModelProperty("归档状态:0正常,1归档") - private String archivedStatus; - -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionRobotDevice.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionRobotDevice.java deleted file mode 100644 index 2a922bd..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/InspectionRobotDevice.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.cmvr.inspection.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.cmvr.common.core.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.util.Date; - -@Data -@EqualsAndHashCode(callSuper = true) -@ApiModel("机器人设备") -public class InspectionRobotDevice extends BaseEntity { - - private static final long serialVersionUID = 1L; - - @TableId(value = "id", type = IdType.ASSIGN_UUID) - private String id; - - @ApiModelProperty("机器人永久唯一ID") - private String robotId; - - @ApiModelProperty("边缘端设备ID") - private String deviceId; - - private String deviceName; - private Integer deviceKind; - private String typeName; - private String enabled; - private Integer managerState; - private Integer healthStatus; - private String onlineStatus; - private String hasError; - private String errorMessage; - private Date statusUpdatedTime; - private Date lastSeenTime; - private Date offlineTime; -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/vo/InspectionMapVo.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/vo/InspectionMapVo.java deleted file mode 100644 index f502e20..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/vo/InspectionMapVo.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.cmvr.inspection.domain.vo; - -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -/** - * 巡检地图视图对象(包含关联信息) - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -@ApiModel("巡检地图视图对象") -public class InspectionMapVo extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** id */ - @ApiModelProperty("id") - private String id; - - /** 地图名称 */ - @Excel(name = "地图名称") - @ApiModelProperty("地图名称") - private String mapName; - - /** 地图来源的机器人id */ - @Excel(name = "地图来源的机器人id") - @ApiModelProperty("地图来源的机器人id") - private String mapSourceRobotId; - - /** 地图来源的机器人名称(关联字段) */ - @Excel(name = "地图来源的机器人名称") - @ApiModelProperty("地图来源的机器人名称") - private String mapSourceRobotName; - - /** 地图来源的地图名称 */ - @Excel(name = "地图来源的地图名称") - @ApiModelProperty("地图来源的地图名称") - private String mapSourceName; - - /** 地图文件路径 */ - @Excel(name = "地图文件路径") - @ApiModelProperty("地图文件路径") - private String mapFilePath; - - /** 状态 */ - @Excel(name = "状态") - @ApiModelProperty("状态(0正常 1停用)") - private String status; - - /** 地图描述 */ - @Excel(name = "地图描述") - @ApiModelProperty("地图描述") - private String mapDesc; - - /** 创建人昵称 */ - @Excel(name = "创建人昵称") - @ApiModelProperty("创建人昵称") - private String createByName; - - /** 修改人昵称 */ - @Excel(name = "修改人昵称") - @ApiModelProperty("修改人昵称") - private String updateByName; - -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/vo/InspectionRobotVo.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/vo/InspectionRobotVo.java deleted file mode 100644 index d1d42ed..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/domain/vo/InspectionRobotVo.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.cmvr.inspection.domain.vo; - -import com.cmvr.common.annotation.Excel; -import com.cmvr.common.core.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.Date; - -/** - * 巡检机器人视图对象(包含关联信息) - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -@ApiModel("巡检机器人视图对象") -public class InspectionRobotVo extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** id */ - @ApiModelProperty("id") - private String id; - - @Excel(name = "机器人ID") - @ApiModelProperty("机器人永久唯一ID") - private String robotId; - - /** Business display code. It is not an edge device ID. */ - @Excel(name = "机器人业务编号") - @ApiModelProperty("机器人业务编号,仅用于业务展示,不作为设备ID") - private String robotCode; - - /** 机器人名称 */ - @Excel(name = "机器人名称") - @ApiModelProperty("机器人名称") - private String robotName; - - /** 机器人型号 */ - @Excel(name = "机器人型号") - @ApiModelProperty("机器人型号") - private String robotModel; - - /** 机器人类型 */ - @Excel(name = "机器人类型") - @ApiModelProperty("机器人类型") - private String robotType; - - /** IP地址 */ - @Excel(name = "IP地址") - @ApiModelProperty("IP地址") - private String ipAddress; - - /** 端口号 */ - @Excel(name = "端口号") - @ApiModelProperty("端口号") - private Integer port; - - /** 当前地图ID */ - @Excel(name = "当前地图ID") - @ApiModelProperty("当前地图ID") - private String currentMapId; - - /** 当前地图名称(关联字段) */ - @Excel(name = "当前地图名称") - @ApiModelProperty("当前地图名称") - private String currentMapName; - - /** 机器人中地图名称 */ - @Excel(name = "机器人中地图名称") - @ApiModelProperty("机器人中地图名称") - private String robotMapName; - - /** 当前状态 */ - @Excel(name = "当前状态") - @ApiModelProperty("AGV运行模式(0未知 1断开 2空闲 3手动 4自动 5充电 6暂停 7停止 8故障 9急停)") - private String status; - - /** 电量百分比 */ - @Excel(name = "电量百分比") - @ApiModelProperty("电量百分比") - private Integer batteryLevel; - - /** 当前位置 */ - @Excel(name = "当前位置") - @ApiModelProperty("当前位置") - private String currentPosition; - - /** 创建人昵称 */ - @Excel(name = "创建人昵称") - @ApiModelProperty("创建人昵称") - private String createByName; - - /** 修改人昵称 */ - @Excel(name = "修改人昵称") - @ApiModelProperty("修改人昵称") - private String updateByName; - - @ApiModelProperty("连接状态:0离线,1在线") - private String connectStatus; - - @ApiModelProperty("当前QUIC节点ID") - private String quicNodeId; - - @ApiModelProperty("当前QUIC会话ID") - private String quicSessionId; - - @ApiModelProperty("边缘端启动ID") - private String quicBootId; - - @ApiModelProperty("QUIC连接来源IP") - private String observedIp; - - @ApiModelProperty("边缘端软件版本") - private String softwareVersion; - - @ApiModelProperty("最后心跳时间") - private Date lastHeartbeatTime; - - @ApiModelProperty("设备总数") - private Integer deviceTotal; - - @ApiModelProperty("在线设备数") - private Integer onlineDeviceCount; - - @ApiModelProperty("故障设备数") - private Integer faultDeviceCount; - -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionMapMapper.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionMapMapper.java deleted file mode 100644 index 30b94e3..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionMapMapper.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.cmvr.inspection.mapper; - -import java.util.List; -import com.cmvr.inspection.domain.InspectionMap; -import com.cmvr.inspection.domain.vo.InspectionMapVo; -import com.github.yulichang.base.MPJBaseMapper; -import org.apache.ibatis.annotations.Param; - -/** - * 巡检地图Mapper接口 - * - * @author cmvr-iot - */ -public interface InspectionMapMapper extends MPJBaseMapper -{ - /** - * 查询巡检地图 - * - * @param id 巡检地图主键 - * @return 巡检地图 - */ - InspectionMap selectInspectionMapById(String id); - - /** - * 新增巡检地图 - * - * @param inspectionMap 巡检地图 - * @return 结果 - */ - int insertInspectionMap(InspectionMap inspectionMap); - - /** - * 修改巡检地图 - * - * @param inspectionMap 巡检地图 - * @return 结果 - */ - int updateInspectionMap(InspectionMap inspectionMap); - - /** - * 批量删除巡检地图 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteInspectionMapByIds(String[] ids); - - /** - * 查询巡检地图视图列表(包含关联信息) - * - * @param inspectionMap 巡检地图 - * @return 巡检地图视图集合 - */ - List selectInspectionMapVoList(InspectionMap inspectionMap); - - /** - * 根据机器人ID查询地图列表 - * - * @param robotId 机器人ID - * @return 地图列表 - */ - List selectMapsByRobotId(@Param("robotId") String robotId); -} - diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionRobotDeviceMapper.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionRobotDeviceMapper.java deleted file mode 100644 index 81b859d..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionRobotDeviceMapper.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.cmvr.inspection.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.cmvr.inspection.domain.InspectionRobotDevice; -import org.apache.ibatis.annotations.Param; - -import java.util.Date; -import java.util.List; - -public interface InspectionRobotDeviceMapper extends BaseMapper { - - List selectByRobotId(@Param("robotId") String robotId); - - List selectByRobotIdAndKind(@Param("robotId") String robotId, - @Param("deviceKind") Integer deviceKind, - @Param("onlineOnly") boolean onlineOnly); - - List selectByIdentity(@Param("robotId") String robotId, - @Param("deviceId") String deviceId); - - int updateRuntimeState(InspectionRobotDevice device); - - int markMissingOffline(@Param("robotId") String robotId, - @Param("deviceIds") List deviceIds, - @Param("offlineTime") Date offlineTime); - - int markAllOffline(@Param("robotId") String robotId, - @Param("offlineTime") Date offlineTime); -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionRobotMapper.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionRobotMapper.java deleted file mode 100644 index 5930801..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/mapper/InspectionRobotMapper.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.cmvr.inspection.mapper; - -import java.util.List; -import java.util.Date; -import com.cmvr.inspection.domain.InspectionRobot; -import com.cmvr.inspection.domain.vo.InspectionRobotVo; -import com.github.yulichang.base.MPJBaseMapper; -import org.apache.ibatis.annotations.Param; - -/** - * 巡检机器人Mapper接口 - * - * @author cmvr-iot - * @since 2026-05-29 - */ -public interface InspectionRobotMapper extends MPJBaseMapper -{ - /** - * 查询巡检机器人 - * - * @param id 巡检机器人主键 - * @return 巡检机器人 - */ - InspectionRobot selectInspectionRobotById(String id); - - List selectByRobotId(String robotId); - - int updateQuicRuntimeState(InspectionRobot robot); - - /** - * Update the AGV runtime snapshot without changing business audit fields. - */ - int updateRuntimeStatus(InspectionRobot robot); - - /** - * Select connected robots that currently report one online AGV device. - */ - List selectRuntimeSyncCandidates(@Param("heartbeatCutoff") Date heartbeatCutoff, - @Param("excludedRobotIds") List excludedRobotIds); - - List selectStaleConnectedRobots(@Param("heartbeatCutoff") Date heartbeatCutoff, - @Param("excludedRobotIds") List excludedRobotIds); - - int markHeartbeatExpiredOffline(@Param("id") String id, - @Param("heartbeatCutoff") Date heartbeatCutoff, - @Param("offlineTime") Date offlineTime); - - int archiveInspectionRobotByIds(@Param("ids") String[] ids, @Param("updateBy") String updateBy); - - /** - * 新增巡检机器人 - * - * @param inspectionRobot 巡检机器人 - * @return 结果 - */ - int insertInspectionRobot(InspectionRobot inspectionRobot); - - /** - * 修改巡检机器人 - * - * @param inspectionRobot 巡检机器人 - * @return 结果 - */ - int updateInspectionRobot(InspectionRobot inspectionRobot); - - /** - * 批量删除巡检机器人 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteInspectionRobotByIds(String[] ids); - - /** - * 查询巡检机器人视图列表(包含关联信息) - * - * @param inspectionRobot 巡检机器人 - * @return 巡检机器人视图集合 - */ - List selectInspectionRobotVoList(InspectionRobot inspectionRobot); -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/IInspectionMapService.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/IInspectionMapService.java deleted file mode 100644 index 084a00b..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/IInspectionMapService.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.cmvr.inspection.service; - -import java.util.List; - -import com.baomidou.mybatisplus.spring.service.IService; -import com.cmvr.inspection.domain.InspectionMap; -import com.cmvr.inspection.domain.vo.InspectionMapVo; - -/** - * 巡检地图Service接口 - * - * @author cmvr-iot - * @since 2026-05-29 - */ -public interface IInspectionMapService extends IService -{ - /** - * 查询巡检地图 - * - * @param id 巡检地图主键 - * @return 巡检地图 - */ - InspectionMap selectInspectionMapById(String id); - - /** - * 查询巡检地图列表 - * - * @param inspectionMap 巡检地图 - * @return 巡检地图集合 - */ - List selectInspectionMapList(InspectionMap inspectionMap); - - /** - * 新增巡检地图 - * - * @param inspectionMap 巡检地图 - * @return 结果 - */ - int insertInspectionMap(InspectionMap inspectionMap); - - /** - * 修改巡检地图 - * - * @param inspectionMap 巡检地图 - * @return 结果 - */ - int updateInspectionMap(InspectionMap inspectionMap); - - /** - * 批量删除巡检地图 - * - * @param ids 需要删除的巡检地图主键集合 - * @return 结果 - */ - int deleteInspectionMapByIds(String[] ids); - - /** - * 根据机器人ID查询地图列表 - * - * @param robotId 机器人ID - * @return 地图列表 - */ - List getMapsByRobotId(String robotId); - -} - diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/IInspectionRobotService.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/IInspectionRobotService.java deleted file mode 100644 index 75c09ca..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/IInspectionRobotService.java +++ /dev/null @@ -1,143 +0,0 @@ - -package com.cmvr.inspection.service; - -import java.util.List; - -import cmvr.msgs.AgvUtils; -import com.baomidou.mybatisplus.spring.service.IService; -import com.cmvr.inspection.domain.InspectionRobot; -import com.cmvr.inspection.domain.InspectionRobotDevice; -import com.cmvr.inspection.domain.vo.InspectionRobotVo; - -/** - * 巡检机器人Service接口 - * - * @author cmvr-iot - * @since 2026-05-29 - */ -public interface IInspectionRobotService extends IService -{ - /** - * 查询巡检机器人 - * - * @param id 巡检机器人主键 - * @return 巡检机器人 - */ - InspectionRobot selectInspectionRobotById(String id); - - /** - * 查询巡检机器人列表 - * - * @param inspectionRobot 巡检机器人 - * @return 巡检机器人集合 - */ - List selectInspectionRobotList(InspectionRobot inspectionRobot); - - /** - * 新增巡检机器人 - * - * @param inspectionRobot 巡检机器人 - * @return 结果 - */ - int insertInspectionRobot(InspectionRobot inspectionRobot); - - /** - * 修改巡检机器人 - * - * @param inspectionRobot 巡检机器人 - * @return 结果 - */ - int updateInspectionRobot(InspectionRobot inspectionRobot); - - /** - * 批量删除巡检机器人 - * - * @param ids 需要删除的巡检机器人主键集合 - * @return 结果 - */ - int deleteInspectionRobotByIds(String[] ids); - - List selectRobotDevices(String id); - - List selectRobotDevicesByRobotId(String robotId, Integer deviceKind, - boolean onlineOnly); - - /** - * 获取机器人地图列表(从AGV获取) - * - * @param robotId 机器人ID - * @return 地图列表 - */ - List getRobotMapList(String robotId); - - /** - * 绑定机器人地图 - * - * @param robotId 机器人ID - * @param mapId 地图ID - * @return 结果 - */ - int bindRobotMap(String robotId, String mapId); - - /** - * 从机器人下载地图 - * - * @param robotId 机器人ID - * @param mapName 地图名称 - * @return 地图内容 - */ - String downloadMapFromRobot(String robotId, String mapName); - - /** - * 上传地图(从源机器人下载到目标机器人) - * - * @param robotId 目标机器人ID - * @return 结果 - */ - String uploadMapFromSource(String robotId); - - /** - * 同步机器人状态(电量、位置等) - * - * @param robotId 机器人ID - * @return 更新后的机器人信息 - */ - InspectionRobot syncRobotStatus(String robotId); - - /** - * 获取机器人实时位置 - * - * @param robotId 机器人ID - * @return 机器人位置信息 - */ - AgvUtils.AgvPose2d getRobotRealtimeLocation(String robotId); - - /** - * 导航到指定位置(坐标) - * - * @param robotId 机器人ID - * @param x X坐标(米) - * @param y Y坐标(米) - * @param theta 朝向角(弧度) - */ - void navigateToPosition(String robotId, Double x, Double y, Double theta); - - /** - * 开始建图 - * - * @param robotId 机器人ID - * @param dimension 建图维度(0:未指定 1:2D 2:3D 3:2D+3D) - * @param mapName 地图名称(可选) - * @param realTime 是否实时建图 - * @return 会话ID - */ - String startMapping(String robotId, int dimension, String mapName, boolean realTime); - - /** - * 停止建图 - * - * @param robotId 机器人ID - */ - void stopMapping(String robotId); - -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionMapServiceImpl.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionMapServiceImpl.java deleted file mode 100644 index d83640f..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionMapServiceImpl.java +++ /dev/null @@ -1,109 +0,0 @@ - -package com.cmvr.inspection.service.impl; - -import java.util.List; -import java.util.UUID; - -import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; -import com.cmvr.common.utils.SecurityUtils; -import com.cmvr.inspection.domain.vo.InspectionMapVo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.cmvr.common.utils.DateUtils; -import com.cmvr.inspection.mapper.InspectionMapMapper; -import com.cmvr.inspection.domain.InspectionMap; -import com.cmvr.inspection.service.IInspectionMapService; - -/** - * 巡检地图Service业务层处理 - * - * @author cmvr-iot - * @since 2026-05-29 - */ -@Service -public class InspectionMapServiceImpl extends ServiceImpl implements IInspectionMapService -{ - @Autowired - private InspectionMapMapper inspectionMapMapper; - - /** - * 查询巡检地图 - * - * @param id 巡检地图主键 - * @return 巡检地图 - */ - @Override - public InspectionMap selectInspectionMapById(String id) - { - return inspectionMapMapper.selectInspectionMapById(id); - } - - /** - * 查询巡检地图列表 - * - * @param inspectionMap 巡检地图 - * @return 巡检地图 - */ - @Override - public List selectInspectionMapList(InspectionMap inspectionMap) - { - return inspectionMapMapper.selectInspectionMapVoList(inspectionMap); - } - - /** - * 新增巡检地图 - * - * @param inspectionMap 巡检地图 - * @return 结果 - */ - @Override - public int insertInspectionMap(InspectionMap inspectionMap) - { - // 生成UUID作为主键 - if (inspectionMap.getId() == null || inspectionMap.getId().isEmpty()) { - inspectionMap.setId(UUID.randomUUID().toString().replace("-", "")); - } - inspectionMap.setCreateTime(DateUtils.getNowDate()); - inspectionMap.setCreateBy(SecurityUtils.getUsername()); - return inspectionMapMapper.insertInspectionMap(inspectionMap); - } - - /** - * 修改巡检地图 - * - * @param inspectionMap 巡检地图 - * @return 结果 - */ - @Override - public int updateInspectionMap(InspectionMap inspectionMap) - { - inspectionMap.setUpdateTime(DateUtils.getNowDate()); - inspectionMap.setUpdateBy(SecurityUtils.getUsername()); - return inspectionMapMapper.updateInspectionMap(inspectionMap); - } - - /** - * 批量删除巡检地图 - * - * @param ids 需要删除的巡检地图主键 - * @return 结果 - */ - @Override - public int deleteInspectionMapByIds(String[] ids) - { - return inspectionMapMapper.deleteInspectionMapByIds(ids); - } - - /** - * 根据机器人ID查询地图列表 - * - * @param robotId 机器人ID - * @return 地图列表 - */ - @Override - public List getMapsByRobotId(String robotId) - { - return inspectionMapMapper.selectMapsByRobotId(robotId); - } - -} \ No newline at end of file diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionResultServiceImpl.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionResultServiceImpl.java index 033a4fc..05fd4af 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionResultServiceImpl.java +++ b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionResultServiceImpl.java @@ -15,7 +15,6 @@ import com.cmvr.inspection.domain.InspectionAlarm; import com.cmvr.inspection.domain.InspectionDetectionAlert; import com.cmvr.inspection.domain.InspectionResult; import com.cmvr.inspection.domain.InspectionResultMedia; -import com.cmvr.inspection.domain.InspectionRobot; import com.cmvr.inspection.domain.InspectionTask; import com.cmvr.inspection.domain.InspectionTaskInstance; import com.cmvr.inspection.domain.InspectionTaskLog; @@ -28,7 +27,8 @@ import com.cmvr.inspection.enums.TaskStatusEnum; import com.cmvr.inspection.mapper.InspectionAlarmMapper; import com.cmvr.inspection.mapper.InspectionResultMapper; import com.cmvr.inspection.mapper.InspectionResultMediaMapper; -import com.cmvr.inspection.mapper.InspectionRobotMapper; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import com.cmvr.resource.domain.ResourceRobot; import com.cmvr.inspection.mapper.InspectionTaskMapper; import com.cmvr.inspection.mapper.InspectionTaskInstanceMapper; import com.cmvr.inspection.service.IInspectionResultService; @@ -76,7 +76,7 @@ public class InspectionResultServiceImpl extends ServiceImpl implements IInspectionRobotService -{ - @Autowired - private InspectionRobotMapper inspectionRobotMapper; - - @Autowired - private InspectionMapMapper inspectionMapMapper; - - @Autowired - private EdgeAgvService edgeAgvService; - - @Autowired - private InspectionRobotDeviceMapper inspectionRobotDeviceMapper; - - /** - * 查询巡检机器人 - * - * @param id 巡检机器人主键 - * @return 巡检机器人 - */ - @Override - public InspectionRobot selectInspectionRobotById(String id) - { - return inspectionRobotMapper.selectInspectionRobotById(id); - } - - /** - * 查询巡检机器人列表 - * - * @param inspectionRobot 巡检机器人 - * @return 巡检机器人 - */ - @Override - public List selectInspectionRobotList(InspectionRobot inspectionRobot) - { - return inspectionRobotMapper.selectInspectionRobotVoList(inspectionRobot); - } - - /** - * 新增巡检机器人 - * - * @param inspectionRobot 巡检机器人 - * @return 结果 - */ - @Override - public synchronized int insertInspectionRobot(InspectionRobot inspectionRobot) - { - String robotId = normalizeRobotId(inspectionRobot.getRobotId()); - if (StrUtil.isBlank(robotId)) { - throw new GlobalException("机器人ID不能为空"); - } - if (!inspectionRobotMapper.selectByRobotId(robotId).isEmpty()) { - throw new GlobalException("机器人ID已存在:" + robotId); - } - inspectionRobot.setRobotId(robotId); - inspectionRobot.setIpAddress(null); - inspectionRobot.setPort(null); - inspectionRobot.setConnectStatus("0"); - inspectionRobot.setArchivedStatus("0"); - // 生成UUID作为主键 - if (inspectionRobot.getId() == null || inspectionRobot.getId().isEmpty()) { - inspectionRobot.setId(UUID.randomUUID().toString().replace("-", "")); - } - inspectionRobot.setCreateTime(DateUtils.getNowDate()); - inspectionRobot.setCreateBy(SecurityUtils.getUsername()); - return inspectionRobotMapper.insertInspectionRobot(inspectionRobot); - } - - /** - * 修改巡检机器人 - * - * @param inspectionRobot 巡检机器人 - * @return 结果 - */ - @Override - public int updateInspectionRobot(InspectionRobot inspectionRobot) - { - InspectionRobot existing = inspectionRobotMapper.selectInspectionRobotById(inspectionRobot.getId()); - if (existing == null) { - throw new GlobalException("机器人不存在"); - } - if (!java.util.Objects.equals(existing.getRobotId(), normalizeRobotId(inspectionRobot.getRobotId()))) { - throw new GlobalException("机器人ID是永久身份标识,不允许修改"); - } - inspectionRobot.setRobotId(null); - inspectionRobot.setIpAddress(null); - inspectionRobot.setPort(null); - inspectionRobot.setUpdateTime(DateUtils.getNowDate()); - inspectionRobot.setUpdateBy(SecurityUtils.getUsername()); - return inspectionRobotMapper.updateInspectionRobot(inspectionRobot); - } - - /** - * 批量删除巡检机器人 - * - * @param ids 需要删除的巡检机器人主键 - * @return 结果 - */ - @Override - public int deleteInspectionRobotByIds(String[] ids) - { - return inspectionRobotMapper.archiveInspectionRobotByIds(ids, SecurityUtils.getUsername()); - } - - @Override - public List selectRobotDevices(String id) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(id); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - if (StrUtil.isBlank(robot.getRobotId())) { - return java.util.Collections.emptyList(); - } - return inspectionRobotDeviceMapper.selectByRobotId(robot.getRobotId()); - } - - @Override - public List selectRobotDevicesByRobotId(String robotId, Integer deviceKind, - boolean onlineOnly) - { - String normalizedRobotId = normalizeRobotId(robotId); - if (StrUtil.isBlank(normalizedRobotId)) { - throw new GlobalException("机器人ID不能为空"); - } - if (inspectionRobotMapper.selectByRobotId(normalizedRobotId).isEmpty()) { - throw new GlobalException("机器人不存在:" + normalizedRobotId); - } - return inspectionRobotDeviceMapper.selectByRobotIdAndKind( - normalizedRobotId, deviceKind, onlineOnly); - } - - private static String normalizeRobotId(String robotId) - { - return robotId == null ? null : robotId.trim(); - } - - /** - * Build an AGV request from the device snapshot reported by this robot. - * robotCode is a business label and must never be used as an edge device ID. - */ - private EdgeCommonVO buildAgvRequest(InspectionRobot robot) - { - if (robot == null || StrUtil.isBlank(robot.getRobotId())) { - throw new GlobalException("机器人永久ID不能为空"); - } - List agvDevices = inspectionRobotDeviceMapper.selectByRobotIdAndKind( - robot.getRobotId(), QuicEdge.DeviceKind.DEVICE_KIND_AGV_VALUE, true); - if (agvDevices.isEmpty()) { - List onlineDevices = inspectionRobotDeviceMapper.selectByRobotIdAndKind( - robot.getRobotId(), null, true); - if (onlineDevices.isEmpty()) { - throw new GlobalException("机器人当前没有在线设备:" + robot.getRobotId()); - } - String deviceSummary = onlineDevices.stream() - .map(device -> device.getDeviceId() + "(" + deviceKindName(device.getDeviceKind()) + ")") - .collect(java.util.stream.Collectors.joining("、")); - throw new GlobalException("机器人在线设备中没有AGV,当前设备:" + deviceSummary); - } - if (agvDevices.size() > 1) { - String deviceIds = agvDevices.stream() - .map(InspectionRobotDevice::getDeviceId) - .collect(java.util.stream.Collectors.joining("、")); - throw new GlobalException("机器人存在多个在线AGV设备,无法确定默认设备:" + deviceIds); - } - - EdgeCommonVO request = new EdgeCommonVO(); - request.setRobotId(robot.getRobotId()); - request.setDeviceId(agvDevices.get(0).getDeviceId()); - return request; - } - - private String deviceKindName(Integer deviceKind) - { - if (deviceKind == null) { - return "未知类型"; - } - QuicEdge.DeviceKind kind = QuicEdge.DeviceKind.forNumber(deviceKind); - return kind == null ? "未知类型" + deviceKind : kind.name().replace("DEVICE_KIND_", ""); - } - - /** - * 获取机器人地图列表(从AGV获取) - * - * @param robotId 机器人ID - * @return 地图列表 - */ - @Override - public List getRobotMapList(String robotId) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - return edgeAgvService.listMaps(buildAgvRequest(robot)); - } - - /** - * 绑定机器人地图 - * - * @param robotId 机器人ID - * @param mapId 地图ID - * @return 结果 - */ - @Override - public int bindRobotMap(String robotId, String mapId) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - InspectionMap map = inspectionMapMapper.selectInspectionMapById(mapId); - if (map == null) { - throw new GlobalException("地图不存在"); - } - - robot.setCurrentMapId(mapId); - robot.setUpdateTime(DateUtils.getNowDate()); - robot.setUpdateBy(SecurityUtils.getUsername()); - - return inspectionRobotMapper.updateInspectionRobot(robot); - } - - /** - * 从机器人下载地图 - * - * @param robotId 机器人ID - * @param mapName 地图名称 - * @return 地图内容 - */ - @Override - public String downloadMapFromRobot(String robotId, String mapName) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - return edgeAgvService.downloadMap(buildAgvRequest(robot), mapName); - } - - /** - * 上传地图(从源机器人下载到目标机器人) - * - * @param robotId 目标机器人ID - * @return 结果 - */ - @Override - public String uploadMapFromSource(String robotId) - { - // 1. 获取目标机器人信息 - InspectionRobot targetRobot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (targetRobot == null) { - throw new GlobalException("目标机器人不存在"); - } - - // 2. 获取地图信息 - InspectionMap map = inspectionMapMapper.selectInspectionMapById(targetRobot.getCurrentMapId()); - if (map == null) { - throw new GlobalException("地图不存在"); - } - - // 3. 检查地图是否有来源机器人ID和地图名称 - if (StrUtil.isBlank(map.getMapSourceRobotId())) { - throw new GlobalException("地图未配置来源机器人ID"); - } - if (StrUtil.isBlank(map.getMapSourceName())) { - throw new GlobalException("地图未配置来源地图名称"); - } - - // 4. 获取来源机器人信息 - InspectionRobot sourceRobot = inspectionRobotMapper.selectInspectionRobotById(map.getMapSourceRobotId()); - if (sourceRobot == null) { - throw new GlobalException("来源机器人不存在"); - } - - // 5. 从来源机器人下载地图JSON - String mapContent = edgeAgvService.downloadMap( - buildAgvRequest(sourceRobot), map.getMapSourceName()); - - if (StrUtil.isBlank(mapContent)) { - throw new GlobalException("下载的地图内容为空"); - } - - // 6. 上传地图到目标机器人 - edgeAgvService.uploadMap( - buildAgvRequest(targetRobot), map.getMapSourceName(), mapContent); - - return "上传成功"; - } - - /** - * 同步机器人状态(电量、位置等) - * - * @param robotId 机器人ID - * @return 更新后的机器人信息 - */ - @Override - public InspectionRobot syncRobotStatus(String robotId) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - try { - AgvUtils.AgvRuntimeState runtimeState = edgeAgvService.getRuntimeState(buildAgvRequest(robot)); - if (runtimeState == null) { - throw new GlobalException("AGV未返回运行状态"); - } - - // 设置电池电量 - if (runtimeState.hasBattery()) { - int percentage = (int) Math.round(runtimeState.getBattery().getPercentage() * 100D); - robot.setBatteryLevel(Math.max(0, Math.min(100, percentage))); - } - - // 设置位置信息 - if (runtimeState.hasPose()) { - AgvUtils.AgvPose2d pose = runtimeState.getPose(); - robot.setCurrentPosition(String.format(Locale.ROOT, "%.3f,%.3f,%.3f", - pose.getX(), pose.getY(), pose.getTheta())); - } - - // Keep the platform status identical to the edge AgvMode value. - robot.setStatus(String.valueOf(runtimeState.getMode())); - - inspectionRobotMapper.updateRuntimeStatus(robot); - } catch (Exception e) { - if (e instanceof GlobalException) { - throw (GlobalException) e; - } - robot.setStatus("0"); - inspectionRobotMapper.updateRuntimeStatus(robot); - throw new GlobalException("获取机器人运行状态失败:" + - (StrUtil.isBlank(e.getMessage()) ? e.getClass().getSimpleName() : e.getMessage()), e); - } - - return robot; - } - - /** - * 获取机器人实时位置 - * - * @param robotId 机器人ID - * @return 机器人位置信息 - */ - @Override - public AgvUtils.AgvPose2d getRobotRealtimeLocation(String robotId) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - AgvUtils.AgvRuntimeState runtimeState = edgeAgvService.getRuntimeState(buildAgvRequest(robot)); - return runtimeState.hasPose() ? runtimeState.getPose() : null; - } - - /** - * 导航到指定位置(坐标) - * - * @param robotId 机器人ID - * @param x X坐标(米) - * @param y Y坐标(米) - * @param theta 朝向角(弧度) - */ - @Override - public void navigateToPosition(String robotId, Double x, Double y, Double theta) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - if (x == null || y == null) { - throw new GlobalException("X和Y坐标不能为空"); - } - - // 构建目标位姿 - AgvUtils.AgvPose2d pose = AgvUtils.AgvPose2d.newBuilder() - .setX(x) - .setY(y) - .setTheta(theta != null ? theta : 0.0) - .build(); - - // 调用边缘端接口进行导航 - edgeAgvService.navigateToPose(buildAgvRequest(robot), pose); - } - - /** - * 开始建图 - * - * @param robotId 机器人ID - * @param dimension 建图维度(0:未指定 1:2D 2:3D 3:2D+3D) - * @param mapName 地图名称(可选) - * @param realTime 是否实时建图 - * @return 会话ID - */ - @Override - public String startMapping(String robotId, int dimension, String mapName, boolean realTime) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - AgvUtils.AgvMapDimension mapDimension = AgvUtils.AgvMapDimension.forNumber(dimension); - return edgeAgvService.startMapping( - buildAgvRequest(robot), mapDimension, mapName, realTime); - } - - /** - * 停止建图 - * - * @param robotId 机器人ID - */ - @Override - public void stopMapping(String robotId) - { - InspectionRobot robot = inspectionRobotMapper.selectInspectionRobotById(robotId); - if (robot == null) { - throw new GlobalException("机器人不存在"); - } - - edgeAgvService.stopMapping(buildAgvRequest(robot)); - } - -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionTaskInstanceServiceImpl.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionTaskInstanceServiceImpl.java index 91237f1..a7477bf 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionTaskInstanceServiceImpl.java +++ b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/impl/InspectionTaskInstanceServiceImpl.java @@ -10,12 +10,12 @@ import com.baomidou.mybatisplus.spring.service.impl.ServiceImpl; import cn.hutool.core.util.StrUtil; import com.cmvr.common.exception.ServiceException; import com.cmvr.common.utils.SecurityUtils; -import com.cmvr.inspection.domain.InspectionRobot; import com.cmvr.inspection.domain.InspectionTask; import com.cmvr.inspection.domain.dto.InspectionTaskInstanceQuery; import com.cmvr.inspection.domain.vo.InspectionTaskInstanceVo; import com.cmvr.inspection.enums.TaskStatusEnum; -import com.cmvr.inspection.mapper.InspectionRobotMapper; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.mapper.ResourceRobotMapper; import com.cmvr.inspection.service.IInspectionTaskService; import com.cmvr.test.flow.control.FlowControlService; import com.cmvr.test.flow.runtime.engine.FlowTaskRuntimeService; @@ -50,7 +50,7 @@ public class InspectionTaskInstanceServiceImpl extends ServiceImpl robots = inspectionRobotMapper.selectByRobotId(robotId); - return robots == null || robots.isEmpty() ? null : robots.get(0); + return resourceRobotMapper.selectByRobotIdentity(robotId); } /** diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/task/RobotHeartbeatExpiryTask.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/task/RobotHeartbeatExpiryTask.java deleted file mode 100644 index aff4b34..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/task/RobotHeartbeatExpiryTask.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.cmvr.inspection.task; - -import com.cmvr.inspection.service.RobotQuicStateService; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -@ConditionalOnProperty(prefix = "cmvr.quic", name = "enabled", havingValue = "true") -public class RobotHeartbeatExpiryTask { - - private final RobotQuicStateService robotQuicStateService; - - @Scheduled(initialDelayString = "${cmvr.inspection.robot-state.initial-delay-ms:3000}", - fixedDelayString = "${cmvr.inspection.robot-state.heartbeat-check-ms:5000}") - public void expireStaleRobots() { - robotQuicStateService.expireStaleRobots(); - } -} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/task/RobotRuntimeStateRefreshTask.java b/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/task/RobotRuntimeStateRefreshTask.java deleted file mode 100644 index fa6fb51..0000000 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/task/RobotRuntimeStateRefreshTask.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.cmvr.inspection.task; - -import com.cmvr.inspection.domain.InspectionRobot; -import com.cmvr.inspection.config.RobotStateProperties; -import com.cmvr.inspection.mapper.InspectionRobotMapper; -import com.cmvr.inspection.service.IInspectionRobotService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.core.task.TaskExecutor; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import java.util.Set; -import java.util.Date; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Periodically persists AGV runtime snapshots for connected robots. - */ -@Component -@ConditionalOnProperty(prefix = "cmvr.inspection.robot-state", name = "enabled", - havingValue = "true", matchIfMissing = true) -public class RobotRuntimeStateRefreshTask -{ - private static final Logger log = LoggerFactory.getLogger(RobotRuntimeStateRefreshTask.class); - - private final InspectionRobotMapper inspectionRobotMapper; - private final IInspectionRobotService inspectionRobotService; - private final TaskExecutor taskExecutor; - private final RobotStateProperties robotStateProperties; - private final Set syncingRobotIds = ConcurrentHashMap.newKeySet(); - - public RobotRuntimeStateRefreshTask(InspectionRobotMapper inspectionRobotMapper, - IInspectionRobotService inspectionRobotService, - @Qualifier("threadPoolTaskExecutor") TaskExecutor taskExecutor, - RobotStateProperties robotStateProperties) - { - this.inspectionRobotMapper = inspectionRobotMapper; - this.inspectionRobotService = inspectionRobotService; - this.taskExecutor = taskExecutor; - this.robotStateProperties = robotStateProperties; - } - - @Scheduled(initialDelayString = "${cmvr.inspection.robot-state.initial-delay-ms:3000}", - fixedDelayString = "${cmvr.inspection.robot-state.refresh-ms:5000}") - public void refreshConnectedRobots() - { - Date cutoff = robotStateProperties.heartbeatCutoff(new Date()); - for (InspectionRobot robot : inspectionRobotMapper.selectRuntimeSyncCandidates( - cutoff, robotStateProperties.normalizedVirtualRobotIds())) { - if (robot.getId() == null || !syncingRobotIds.add(robot.getId())) { - continue; - } - taskExecutor.execute(() -> refreshRobot(robot)); - } - } - - private void refreshRobot(InspectionRobot robot) - { - try { - inspectionRobotService.syncRobotStatus(robot.getId()); - } catch (Exception e) { - log.debug("Failed to refresh AGV runtime state, robotId={}, reason={}", - robot.getRobotId(), e.getMessage()); - } finally { - syncingRobotIds.remove(robot.getId()); - } - } -} diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionAlarmMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionAlarmMapper.xml index c0750c2..4282081 100644 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionAlarmMapper.xml +++ b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionAlarmMapper.xml @@ -206,7 +206,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" u1.nick_name as create_by_name, u2.nick_name as update_by_name from inspection_alarm a left join inspection_task t on a.task_id = t.id - left join inspection_robot r on a.robot_id = r.id + left join iot_robot r on a.robot_id = r.id left join sys_user u1 on a.create_by = u1.user_name left join sys_user u2 on a.update_by = u2.user_name diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionMapMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionMapMapper.xml deleted file mode 100644 index f9c43e0..0000000 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionMapMapper.xml +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select id, create_by, create_time, update_by, update_time, remark, map_name, map_source_robot_id, map_source_name, map_file_path, status, map_desc from inspection_map - - - - - - - - insert into inspection_map - - id, - create_by, - create_time, - update_by, - update_time, - remark, - map_name, - map_source_robot_id, - map_source_name, - map_file_path, - status, - map_desc, - - - #{id}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - #{remark}, - #{mapName}, - #{mapSourceRobotId}, - #{mapSourceName}, - #{mapFilePath}, - #{status}, - #{mapDesc}, - - - - - update inspection_map - - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - remark = #{remark}, - map_name = #{mapName}, - map_source_robot_id = #{mapSourceRobotId}, - map_source_name = #{mapSourceName}, - map_file_path = #{mapFilePath}, - status = #{status}, - map_desc = #{mapDesc}, - - where id = #{id} - - - - delete from inspection_map where id = #{id} - - - - delete from inspection_map where id in - - #{id} - - - - - - - - - diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionRobotDeviceMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionRobotDeviceMapper.xml deleted file mode 100644 index 161f58f..0000000 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionRobotDeviceMapper.xml +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - id, robot_id, device_id, device_name, device_kind, type_name, enabled, - manager_state, health_status, online_status, has_error, error_message, - status_updated_time, last_seen_time, offline_time, create_by, create_time, - update_by, update_time, remark - - - - - - - - - update inspection_robot_device - set device_kind = #{deviceKind}, type_name = #{typeName}, enabled = #{enabled}, - manager_state = #{managerState}, health_status = #{healthStatus}, - online_status = #{onlineStatus}, has_error = #{hasError}, - error_message = #{errorMessage}, status_updated_time = #{statusUpdatedTime}, - last_seen_time = #{lastSeenTime}, offline_time = #{offlineTime}, - update_by = #{updateBy}, update_time = #{updateTime} - where id = #{id} - - - - update inspection_robot_device - set online_status = '0', offline_time = #{offlineTime}, - update_by = 'quic', update_time = #{offlineTime} - where robot_id = #{robotId} and online_status != '0' - - and device_id not in - - #{deviceId} - - - - - - update inspection_robot_device - set online_status = '0', offline_time = #{offlineTime}, - update_by = 'quic', update_time = #{offlineTime} - where robot_id = #{robotId} and online_status != '0' - - diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionRobotMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionRobotMapper.xml deleted file mode 100644 index 5ef7c75..0000000 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionRobotMapper.xml +++ /dev/null @@ -1,283 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select id, robot_id, create_by, create_time, update_by, update_time, remark, - robot_code, robot_name, robot_model, robot_type, ip_address, port, - current_map_id, status, battery_level, current_position, - connect_status, quic_node_id, quic_session_id, quic_boot_id, - observed_ip, software_version, last_heartbeat_time, archived_status - from inspection_robot - - - - - - - - - - insert into inspection_robot - - id, - robot_id, - create_by, - create_time, - update_by, - update_time, - remark, - robot_code, - robot_name, - robot_model, - robot_type, - ip_address, - port, - current_map_id, - status, - battery_level, - current_position, - connect_status, - archived_status, - - - #{id}, - #{robotId}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - #{remark}, - #{robotCode}, - #{robotName}, - #{robotModel}, - #{robotType}, - #{ipAddress}, - #{port}, - #{currentMapId}, - #{status}, - #{batteryLevel}, - #{currentPosition}, - #{connectStatus}, - #{archivedStatus}, - - - - - update inspection_robot - - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - remark = #{remark}, - robot_code = #{robotCode}, - robot_name = #{robotName}, - robot_model = #{robotModel}, - robot_type = #{robotType}, - ip_address = #{ipAddress}, - port = #{port}, - current_map_id = #{currentMapId}, - status = #{status}, - battery_level = #{batteryLevel}, - current_position = #{currentPosition}, - - where id = #{id} - - - - update inspection_robot - set ip_address = #{ipAddress}, port = #{port}, connect_status = #{connectStatus}, - status = coalesce(#{status}, status), - quic_node_id = #{quicNodeId}, quic_session_id = #{quicSessionId}, - quic_boot_id = #{quicBootId}, observed_ip = #{observedIp}, - software_version = #{softwareVersion}, last_heartbeat_time = #{lastHeartbeatTime}, - update_by = 'quic', update_time = #{updateTime} - where id = #{id} - - - - update inspection_robot - set status = coalesce(#{status}, status), - battery_level = coalesce(#{batteryLevel}, battery_level), - current_position = coalesce(#{currentPosition}, current_position) - where id = #{id} - - - - - - - - update inspection_robot - set connect_status = '0', status = '1', - update_by = 'heartbeat-timeout', update_time = #{offlineTime} - where id = #{id} - and connect_status = '1' - and (last_heartbeat_time is null or last_heartbeat_time < #{heartbeatCutoff}) - - - - update inspection_robot set archived_status = '1', connect_status = '0', - update_time = sysdate(), update_by = #{updateBy} - where id in - - #{id} - - - - - delete from inspection_robot where id = #{id} - - - - delete from inspection_robot where id in - - #{id} - - - - - diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskInstanceMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskInstanceMapper.xml index 3a00f5c..ec4c2bf 100644 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskInstanceMapper.xml +++ b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskInstanceMapper.xml @@ -131,13 +131,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select ti.id, ti.create_by, ti.create_time, ti.update_by, ti.update_time, ti.remark,ti.waypoint_count, ti.task_id, t.task_name, t.task_code, ti.robot_id, r.robot_name, r.robot_id as robot_identity, - r.current_map_id as robot_current_map_id, m.map_name, + r.active_map_id as robot_current_map_id, m.map_name, ti.status, ti.start_time, ti.end_time, ti.task_ins_id, u1.nick_name as create_by_name, u2.nick_name as update_by_name from inspection_task_instance ti left join inspection_task t on ti.task_id = t.id - left join inspection_robot r on ti.robot_id = r.id - left join inspection_map m on r.current_map_id = m.id + left join iot_robot r on ti.robot_id = r.id + left join iot_map m on r.active_map_id = m.id left join sys_user u1 on ti.create_by = u1.user_name left join sys_user u2 on ti.update_by = u2.user_name @@ -170,12 +170,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select ti.id, ti.create_by, ti.create_time, ti.update_by, ti.update_time, ti.remark, ti.task_id, t.task_name, t.task_code, ti.robot_id, r.robot_name, r.robot_id as robot_identity, - r.current_map_id as robot_current_map_id, m.map_name, + r.active_map_id as robot_current_map_id, m.map_name, ti.status, ti.start_time, ti.end_time, ti.task_ins_id from inspection_task_instance ti left join inspection_task t on ti.task_id = t.id - left join inspection_robot r on ti.robot_id = r.id - left join inspection_map m on r.current_map_id = m.id + left join iot_robot r on ti.robot_id = r.id + left join iot_map m on r.active_map_id = m.id where ti.id = #{id} diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskMapper.xml index 5392926..c03dc60 100644 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskMapper.xml +++ b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionTaskMapper.xml @@ -123,7 +123,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" left join sys_user u1 on t.create_by = u1.user_name left join sys_user u2 on t.update_by = u2.user_name - left join inspection_map m on t.map_id = m.id + left join iot_map m on t.map_id = m.id and t.task_code = #{taskCode} and t.task_name like concat('%', #{taskName}, '%') diff --git a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionWaypointMapper.xml b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionWaypointMapper.xml index 0a4d770..8cd02ce 100644 --- a/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionWaypointMapper.xml +++ b/cmvr-iot-inspection/src/main/resources/mapper/inspection/InspectionWaypointMapper.xml @@ -110,7 +110,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" u1.nick_name as create_by_name, u2.nick_name as update_by_name from inspection_waypoint w left join te_detection_item d on w.detect_item_id = d.id - left join inspection_map m on w.map_id = m.id + left join iot_map m on w.map_id = m.id left join sys_user u1 on w.create_by = u1.user_name left join sys_user u2 on w.update_by = u2.user_name diff --git a/cmvr-iot-quic/README.md b/cmvr-iot-quic/README.md index 9f3b693..e7a4cc7 100644 --- a/cmvr-iot-quic/README.md +++ b/cmvr-iot-quic/README.md @@ -15,7 +15,7 @@ cmvr-iot-admin |-- NodeEventBroker `-- RobotQuicEventSubscriber(进程内直接订阅) v -inspection_robot + inspection_robot_device + 原有机器人 gRPC 客户端 +iot_robot + iot_device + 原有机器人 gRPC 客户端 ``` QUIC 链路不启动内部 gRPC Server,也不经过本机 TCP 端口。QUIC 注册中的永久 `robotId` 是机器人唯一业务身份;平台据此同步机器人 gRPC endpoint、设备快照,并在地址变化时清理对应 channel。 @@ -80,14 +80,13 @@ Linux 部署时将证书路径换成实际绝对路径。对应配置也可以 首次使用前执行: ```text -sql/robot_quic_identity_migration.sql -sql/robot_id_only_migration.sql +sql/resource_center_v1.sql ``` 先在机器人管理页面新增机器人并填写边缘端上报的永久 `robotId`。机器人首次连接后,平台自动补全地址、端口、QUIC 会话信息和设备清单,无需绑定终端: ```sql -INSERT INTO inspection_robot (id, robot_name, robot_id, connect_status, archived_status) +INSERT INTO iot_robot (id, robot_name, robot_id, connect_status, archived_status) VALUES ('业务主键', '测试机器人', '边缘端永久机器人ID', '0', '0'); ``` diff --git a/cmvr-iot-resource/pom.xml b/cmvr-iot-resource/pom.xml new file mode 100644 index 0000000..0e15929 --- /dev/null +++ b/cmvr-iot-resource/pom.xml @@ -0,0 +1,33 @@ + + + 4.0.0 + + com.cmvr + cmvr-iot + 3.9.2 + + + cmvr-iot-resource + Platform robot, device, terminal and map resources + + + + com.cmvr + cmvr-iot-common + + + com.cmvr + cmvr-iot-test + + + com.cmvr + cmvr-iot-grpc-client + + + com.cmvr + cmvr-iot-quic-contract + + + diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/config/RobotStateProperties.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/config/ResourceRobotStateProperties.java similarity index 83% rename from cmvr-iot-inspection/src/main/java/com/cmvr/inspection/config/RobotStateProperties.java rename to cmvr-iot-resource/src/main/java/com/cmvr/resource/config/ResourceRobotStateProperties.java index d34010e..e28a694 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/config/RobotStateProperties.java +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/config/ResourceRobotStateProperties.java @@ -1,4 +1,4 @@ -package com.cmvr.inspection.config; +package com.cmvr.resource.config; import org.apache.commons.lang3.StringUtils; import org.springframework.boot.context.properties.ConfigurationProperties; @@ -10,9 +10,8 @@ import java.util.List; import java.util.Locale; @Component -@ConfigurationProperties(prefix = "cmvr.inspection.robot-state") -public class RobotStateProperties { - +@ConfigurationProperties(prefix = "cmvr.resource.robot-state") +public class ResourceRobotStateProperties { private long heartbeatTimeoutMs = 15_000L; private List virtualRobotIds = new ArrayList<>(); @@ -33,8 +32,7 @@ public class RobotStateProperties { } public Date heartbeatCutoff(Date now) { - long timeout = Math.max(1_000L, heartbeatTimeoutMs); - return new Date(now.getTime() - timeout); + return new Date(now.getTime() - Math.max(1_000L, heartbeatTimeoutMs)); } public boolean isVirtualRobot(String robotId) { @@ -44,7 +42,7 @@ public class RobotStateProperties { public List normalizedVirtualRobotIds() { return virtualRobotIds.stream() - .map(RobotStateProperties::normalize) + .map(ResourceRobotStateProperties::normalize) .filter(StringUtils::isNotBlank) .distinct() .toList(); diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceDevice.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceDevice.java new file mode 100644 index 0000000..f2bba2d --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceDevice.java @@ -0,0 +1,51 @@ +package com.cmvr.resource.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.cmvr.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** Device discovered under a platform robot. Identity is robotId + deviceId. */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("iot_device") +@ApiModel(value = "ResourceDevice", description = "机器人自动发现并上报的设备资源") +public class ResourceDevice extends BaseEntity { + @TableId + @ApiModelProperty("设备数据主键") + private String id; + @ApiModelProperty("所属机器人的永久robotId") + private String robotId; + @ApiModelProperty("边缘端设备ID,与robotId共同确定设备身份") + private String deviceId; + @ApiModelProperty("设备显示名称") + private String deviceName; + @ApiModelProperty("设备类型编码") + private Integer deviceKind; + @com.baomidou.mybatisplus.annotation.TableField("device_type") + @ApiModelProperty("边缘端设备实现类型") + private String typeName; + @ApiModelProperty("业务用途,例如前摄像头、左机械臂") + private String deviceRole; + private Integer deviceIndex; + private String terminalId; + @ApiModelProperty("是否启用:1启用,0停用") + private String enabled; + private Integer managerState; + private Integer healthStatus; + @ApiModelProperty("在线状态:1在线,0离线") + private String onlineStatus; + @ApiModelProperty("是否存在故障:1是,0否") + private String hasError; + @ApiModelProperty("边缘端上报的故障信息") + private String errorMessage; + private Date statusUpdatedTime; + @ApiModelProperty("最后发现时间") + private Date lastSeenTime; + private Date offlineTime; +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceMap.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceMap.java new file mode 100644 index 0000000..fb33b26 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceMap.java @@ -0,0 +1,43 @@ +package com.cmvr.resource.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.cmvr.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("iot_map") +@ApiModel(value = "ResourceMap", description = "可供AGV机器人和导航任务使用的地图") +public class ResourceMap extends BaseEntity { + @TableId + private String id; + @ApiModelProperty("地图名称") + private String mapName; + @ApiModelProperty("地图版本") + private String mapVersion; + @ApiModelProperty("地图类型,例如2D") + private String mapType; + @ApiModelProperty("坐标系,例如map") + private String coordinateSystem; + @ApiModelProperty("来源类型:ROBOT、UPLOAD或OTHER") + private String sourceType; + @ApiModelProperty("来源机器人的永久robotId") + private String sourceRobotId; + @ApiModelProperty("机器人侧原地图名称") + private String sourceMapName; + @ApiModelProperty("地图文件地址") + private String mapFilePath; + @ApiModelProperty("状态:0启用,1停用") + private String status; + @ApiModelProperty("地图描述") + private String mapDesc; + @TableField(exist = false) + private String mapSourceRobotId; + @TableField(exist = false) + private String mapSourceName; +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobot.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobot.java new file mode 100644 index 0000000..468dfb1 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobot.java @@ -0,0 +1,63 @@ +package com.cmvr.resource.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.cmvr.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** Platform robot identity. robotId is the identity reported by QUIC. */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("iot_robot") +@ApiModel(value = "ResourceRobot", description = "平台统一管理的机器人身份和运行状态") +public class ResourceRobot extends BaseEntity { + @TableId + private String id; + @ApiModelProperty("永久机器人ID,由QUIC上报且创建后不可修改") + private String robotId; + @ApiModelProperty("机器人业务编号") + private String robotCode; + @ApiModelProperty("机器人名称") + private String robotName; + @ApiModelProperty("机器人型号") + private String robotModel; + @ApiModelProperty("机器人类型") + private String robotType; + @ApiModelProperty("当前gRPC地址") + private String ipAddress; + @ApiModelProperty("当前gRPC端口") + private Long port; + @TableField("active_map_id") + @ApiModelProperty("当前地图ID,仅带AGV设备的机器人需要") + private String currentMapId; + @TableField("runtime_status") + @ApiModelProperty("机器人运行状态") + private String status; + @ApiModelProperty("电量百分比") + private Integer batteryLevel; + private String currentPosition; + @ApiModelProperty("连接状态:1在线,0离线") + private String connectStatus; + private String quicNodeId; + private String quicSessionId; + private String quicBootId; + private String observedIp; + private String softwareVersion; + @ApiModelProperty("最后心跳时间") + private Date lastHeartbeatTime; + private String archivedStatus; + @TableField(exist = false) + private String currentMapName; + @TableField(exist = false) + private Integer deviceTotal; + @TableField(exist = false) + private Integer onlineDeviceCount; + @TableField(exist = false) + private Integer faultDeviceCount; +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobotMap.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobotMap.java new file mode 100644 index 0000000..e2290e1 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobotMap.java @@ -0,0 +1,24 @@ +package com.cmvr.resource.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.cmvr.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("iot_robot_map") +public class ResourceRobotMap extends BaseEntity { + @TableId + private String id; + private String robotId; + private String mapId; + private String enabled; + private String isDefault; + private String loadedStatus; + private String compatibilityStatus; + private Date lastLoadedTime; +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobotTerminal.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobotTerminal.java new file mode 100644 index 0000000..ffa1451 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceRobotTerminal.java @@ -0,0 +1,21 @@ +package com.cmvr.resource.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.util.Date; + +@Data +@TableName("iot_robot_terminal") +public class ResourceRobotTerminal { + @TableId + private String id; + private String robotId; + private String terminalId; + private String active; + private Date bindTime; + private Date unbindTime; + private Date createTime; + private Date updateTime; +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceTerminal.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceTerminal.java new file mode 100644 index 0000000..8727feb --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/domain/ResourceTerminal.java @@ -0,0 +1,41 @@ +package com.cmvr.resource.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.cmvr.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; +import com.baomidou.mybatisplus.annotation.TableField; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("iot_terminal") +@ApiModel(value = "ResourceTerminal", description = "通过QUIC接入平台的边缘运行终端") +public class ResourceTerminal extends BaseEntity { + @TableId + private String id; + @ApiModelProperty("终端编码,对应QUIC节点身份") + private String terminalCode; + @ApiModelProperty("终端显示名称") + private String terminalName; + @ApiModelProperty("终端网络地址") + private String ipAddress; + @ApiModelProperty("终端gRPC端口") + private Long port; + @ApiModelProperty("边缘软件版本") + private String softwareVersion; + @ApiModelProperty("连接状态:1在线,0离线") + private String connectStatus; + @ApiModelProperty("最后心跳时间") + private Date lastHeartbeatTime; + @ApiModelProperty("终端状态") + private String status; + @TableField(exist = false) + private String robotIdsCsv; + @TableField(exist = false) + private Integer robotCount; +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceDeviceMapper.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceDeviceMapper.java new file mode 100644 index 0000000..285b4d3 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceDeviceMapper.java @@ -0,0 +1,28 @@ +package com.cmvr.resource.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cmvr.resource.domain.ResourceDevice; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Date; + +public interface ResourceDeviceMapper extends BaseMapper { + List selectResourceDevices(ResourceDevice query, + @Param("onlineOnly") boolean onlineOnly); + + List selectByRobotId(@Param("robotId") String robotId, + @Param("deviceKind") Integer deviceKind, + @Param("onlineOnly") boolean onlineOnly); + + List selectByIdentity(@Param("robotId") String robotId, + @Param("deviceId") String deviceId); + + int updateRuntimeState(ResourceDevice device); + + int markMissingOffline(@Param("robotId") String robotId, + @Param("deviceIds") List deviceIds, + @Param("offlineTime") Date offlineTime); + + int markAllOffline(@Param("robotId") String robotId, @Param("offlineTime") Date offlineTime); +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceMapMapper.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceMapMapper.java new file mode 100644 index 0000000..394750b --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceMapMapper.java @@ -0,0 +1,12 @@ +package com.cmvr.resource.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cmvr.resource.domain.ResourceMap; + +import java.util.List; + +public interface ResourceMapMapper extends BaseMapper { + List selectResourceMaps(ResourceMap query); + + List selectByRobotId(String robotId); +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotMapMapper.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotMapMapper.java new file mode 100644 index 0000000..530f2de --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotMapMapper.java @@ -0,0 +1,14 @@ +package com.cmvr.resource.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cmvr.resource.domain.ResourceRobotMap; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +public interface ResourceRobotMapMapper extends BaseMapper { + int clearDefault(@Param("robotId") String robotId, @Param("exceptMapId") String exceptMapId); + + int deleteBinding(@Param("robotId") String robotId, @Param("mapId") String mapId); + + int countByMapIds(@Param("mapIds") List mapIds); +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotMapper.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotMapper.java new file mode 100644 index 0000000..1554473 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotMapper.java @@ -0,0 +1,37 @@ +package com.cmvr.resource.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cmvr.resource.domain.ResourceRobot; + +import java.util.List; +import java.util.Date; +import org.apache.ibatis.annotations.Param; + +public interface ResourceRobotMapper extends BaseMapper { + List selectResourceRobots(ResourceRobot query); + + ResourceRobot selectByRobotIdentity(String robotId); + + ResourceRobot selectById(String id); + + int archiveByIds(@Param("ids") String[] ids, @Param("updateBy") String updateBy); + + int clearActiveMap(@Param("id") String id, @Param("mapId") String mapId, + @Param("updateBy") String updateBy); + + int updateQuicRuntimeState(ResourceRobot robot); + + List selectStaleConnected(@Param("heartbeatCutoff") Date heartbeatCutoff, + @Param("excludedRobotIds") List excludedRobotIds); + + List selectRuntimeSyncCandidates(@Param("heartbeatCutoff") Date heartbeatCutoff, + @Param("excludedRobotIds") List excludedRobotIds); + + int updateAgvRuntimeStatus(ResourceRobot robot); + + List lockByRobotIds(@Param("robotIds") List robotIds); + + int markHeartbeatExpiredOffline(@Param("id") String id, + @Param("heartbeatCutoff") Date heartbeatCutoff, + @Param("offlineTime") Date offlineTime); +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotTerminalMapper.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotTerminalMapper.java new file mode 100644 index 0000000..0a13858 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceRobotTerminalMapper.java @@ -0,0 +1,19 @@ +package com.cmvr.resource.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cmvr.resource.domain.ResourceRobotTerminal; +import org.apache.ibatis.annotations.Param; +import java.util.List; + +public interface ResourceRobotTerminalMapper extends BaseMapper { + int deactivateOtherBindings(@Param("robotId") String robotId, @Param("terminalId") String terminalId); + + List selectActiveRobotIds(@Param("terminalId") String terminalId); + + int deactivateTerminalBindings(@Param("terminalId") String terminalId); + + int deleteTerminalBindings(@Param("terminalId") String terminalId); + + int activateBinding(@Param("id") String id, @Param("robotId") String robotId, + @Param("terminalId") String terminalId); +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceTerminalMapper.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceTerminalMapper.java new file mode 100644 index 0000000..e2a0367 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/mapper/ResourceTerminalMapper.java @@ -0,0 +1,12 @@ +package com.cmvr.resource.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.cmvr.resource.domain.ResourceTerminal; + +import java.util.List; + +public interface ResourceTerminalMapper extends BaseMapper { + List selectResourceTerminals(ResourceTerminal query); + + ResourceTerminal selectByCode(String terminalCode); +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceDeviceService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceDeviceService.java new file mode 100644 index 0000000..dcb9b3f --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceDeviceService.java @@ -0,0 +1,44 @@ +package com.cmvr.resource.service; + +import com.cmvr.common.exception.GlobalException; +import com.cmvr.common.utils.DateUtils; +import com.cmvr.common.utils.SecurityUtils; +import com.cmvr.resource.domain.ResourceDevice; +import com.cmvr.resource.mapper.ResourceDeviceMapper; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.List; + +@Service +public class ResourceDeviceService { + private final ResourceDeviceMapper deviceMapper; + + public ResourceDeviceService(ResourceDeviceMapper deviceMapper) { + this.deviceMapper = deviceMapper; + } + + public List list(ResourceDevice query, boolean onlineOnly) { + return deviceMapper.selectResourceDevices(query, onlineOnly); + } + + public ResourceDevice get(String id) { + return StringUtils.hasText(id) ? deviceMapper.selectById(id.trim()) : null; + } + + public int updateBusinessConfig(ResourceDevice input) { + ResourceDevice existing = get(input.getId()); + if (existing == null) { + throw new GlobalException("设备不存在"); + } + ResourceDevice update = new ResourceDevice(); + update.setId(existing.getId()); + update.setDeviceName(input.getDeviceName()); + update.setDeviceRole(input.getDeviceRole()); + update.setEnabled("0".equals(input.getEnabled()) ? "0" : "1"); + update.setRemark(input.getRemark()); + update.setUpdateBy(SecurityUtils.getUsername()); + update.setUpdateTime(DateUtils.getNowDate()); + return deviceMapper.updateById(update); + } +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceMapService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceMapService.java new file mode 100644 index 0000000..76e3ca2 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceMapService.java @@ -0,0 +1,69 @@ +package com.cmvr.resource.service; + +import com.cmvr.resource.domain.ResourceMap; +import com.cmvr.resource.mapper.ResourceMapMapper; +import com.cmvr.resource.mapper.ResourceRobotMapMapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import com.cmvr.common.exception.GlobalException; +import com.cmvr.common.utils.DateUtils; +import com.cmvr.common.utils.SecurityUtils; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +@Service +public class ResourceMapService { + private final ResourceMapMapper mapMapper; + private final ResourceRobotMapMapper robotMapMapper; + + public ResourceMapService(ResourceMapMapper mapMapper, ResourceRobotMapMapper robotMapMapper) { + this.mapMapper = mapMapper; + this.robotMapMapper = robotMapMapper; + } + + public List list(ResourceMap query) { + return mapMapper.selectResourceMaps(query); + } + + public List listByRobotId(String robotId) { + return StringUtils.hasText(robotId) + ? mapMapper.selectByRobotId(robotId.trim()) + : Collections.emptyList(); + } + + public ResourceMap get(String id) { + return mapMapper.selectById(id); + } + + public int create(ResourceMap map) { + if (!StringUtils.hasText(map.getMapName())) { + throw new GlobalException("地图名称不能为空"); + } + map.setId(UUID.randomUUID().toString().replace("-", "")); + map.setStatus(StringUtils.hasText(map.getStatus()) ? map.getStatus() : "0"); + map.setCreateBy(SecurityUtils.getUsername()); + map.setCreateTime(DateUtils.getNowDate()); + return mapMapper.insert(map); + } + + public int update(ResourceMap map) { + if (!StringUtils.hasText(map.getId()) || mapMapper.selectById(map.getId()) == null) { + throw new GlobalException("地图不存在"); + } + map.setUpdateBy(SecurityUtils.getUsername()); + map.setUpdateTime(DateUtils.getNowDate()); + return mapMapper.updateById(map); + } + + @Transactional(rollbackFor = Exception.class) + public int remove(List ids) { + if (ids == null || ids.isEmpty()) return 0; + if (robotMapMapper.countByMapIds(ids) > 0) { + throw new GlobalException("地图仍被机器人绑定,请先解除机器人地图关系"); + } + return mapMapper.deleteByIds(ids); + } +} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/RobotQuicEventSubscriber.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceQuicEventSubscriber.java similarity index 62% rename from cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/RobotQuicEventSubscriber.java rename to cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceQuicEventSubscriber.java index 05e8d48..b063e3d 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/RobotQuicEventSubscriber.java +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceQuicEventSubscriber.java @@ -1,4 +1,4 @@ -package com.cmvr.inspection.service; +package com.cmvr.resource.service; import com.cmvr.quic.contract.QuicEventBus; import com.cmvr.quic.gateway.v1.NodeEvent; @@ -17,12 +17,11 @@ import java.util.concurrent.TimeUnit; @Service @RequiredArgsConstructor -public class RobotQuicEventSubscriber { - - private static final Logger log = LoggerFactory.getLogger(RobotQuicEventSubscriber.class); +public class ResourceQuicEventSubscriber { + private static final Logger log = LoggerFactory.getLogger(ResourceQuicEventSubscriber.class); private final QuicEventBus eventBus; - private final RobotQuicStateService stateService; + private final ResourceQuicStateSynchronizer synchronizer; @Value("${cmvr.quic.enabled:false}") private boolean enabled; @@ -36,27 +35,26 @@ public class RobotQuicEventSubscriber { return; } executor = Executors.newSingleThreadExecutor(runnable -> { - Thread thread = new Thread(runnable, "quic-robot-sync"); + Thread thread = new Thread(runnable, "quic-resource-sync"); thread.setDaemon(true); return thread; }); subscription = eventBus.watchNodes(true, this::enqueue); - log.info("已启动QUIC机器人身份和设备同步"); + log.info("QUIC resource synchronization started"); } private void enqueue(NodeEvent event) { try { executor.execute(() -> { try { - stateService.synchronize(event); + synchronizer.synchronize(event); } catch (RuntimeException error) { - log.error("同步QUIC机器人失败,robotId={},nodeId={},eventType={}", - event.getNode().getRobotId(), event.getNode().getNodeId(), - event.getType(), error); + log.error("Failed to synchronize QUIC resource, robotId={}, nodeId={}, eventType={}", + event.getNode().getRobotId(), event.getNode().getNodeId(), event.getType(), error); } }); } catch (RejectedExecutionException ignored) { - log.debug("QUIC机器人同步线程已停止"); + log.debug("QUIC resource synchronization executor is stopped"); } } @@ -65,16 +63,17 @@ public class RobotQuicEventSubscriber { if (subscription != null) { subscription.close(); } - if (executor != null) { - executor.shutdown(); - try { - if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { - executor.shutdownNow(); - } - } catch (InterruptedException error) { + if (executor == null) { + return; + } + executor.shutdown(); + try { + if (!executor.awaitTermination(5, TimeUnit.SECONDS)) { executor.shutdownNow(); - Thread.currentThread().interrupt(); } + } catch (InterruptedException error) { + executor.shutdownNow(); + Thread.currentThread().interrupt(); } } } diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/RobotQuicStateService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceQuicStateSynchronizer.java similarity index 53% rename from cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/RobotQuicStateService.java rename to cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceQuicStateSynchronizer.java index 7ee2ff9..fea6740 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/RobotQuicStateService.java +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceQuicStateSynchronizer.java @@ -1,16 +1,21 @@ -package com.cmvr.inspection.service; +package com.cmvr.resource.service; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.cmvr.common.utils.DateUtils; import com.cmvr.edge.client.manage.GrpcServiceManager; -import com.cmvr.inspection.config.RobotStateProperties; -import com.cmvr.inspection.domain.InspectionRobot; -import com.cmvr.inspection.domain.InspectionRobotDevice; -import com.cmvr.inspection.mapper.InspectionRobotDeviceMapper; -import com.cmvr.inspection.mapper.InspectionRobotMapper; import com.cmvr.quic.gateway.v1.ManagedDeviceStatus; import com.cmvr.quic.gateway.v1.NodeEvent; import com.cmvr.quic.gateway.v1.NodeEventType; import com.cmvr.quic.gateway.v1.NodeSnapshot; +import com.cmvr.resource.config.ResourceRobotStateProperties; +import com.cmvr.resource.domain.ResourceDevice; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.domain.ResourceRobotTerminal; +import com.cmvr.resource.domain.ResourceTerminal; +import com.cmvr.resource.mapper.ResourceDeviceMapper; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import com.cmvr.resource.mapper.ResourceRobotTerminalMapper; +import com.cmvr.resource.mapper.ResourceTerminalMapper; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -23,72 +28,53 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Objects; +import java.util.UUID; @Service @RequiredArgsConstructor -public class RobotQuicStateService { - - private static final Logger log = LoggerFactory.getLogger(RobotQuicStateService.class); +public class ResourceQuicStateSynchronizer { + private static final Logger log = LoggerFactory.getLogger(ResourceQuicStateSynchronizer.class); private static final int AGV_DEVICE_KIND = 1; - private final InspectionRobotMapper robotMapper; - private final InspectionRobotDeviceMapper deviceMapper; + private final ResourceRobotMapper robotMapper; + private final ResourceDeviceMapper deviceMapper; + private final ResourceTerminalMapper terminalMapper; + private final ResourceRobotTerminalMapper robotTerminalMapper; + private final ResourceRobotStateProperties stateProperties; private final GrpcServiceManager grpcServiceManager; - private final RobotStateProperties robotStateProperties; @Value("${cmvr.quic.grpc-host-source:observed-source}") private String grpcHostSource; @Transactional(rollbackFor = Exception.class) - public void synchronize(NodeEvent event) { + public boolean synchronize(NodeEvent event) { NodeSnapshot node = event.getNode(); String robotId = StringUtils.trimToNull(node.getRobotId()); - if (robotId == null) { - log.warn("忽略未携带机器人ID的QUIC事件,nodeId={},eventType={}", - node.getNodeId(), event.getType()); - return; + if (robotId == null || stateProperties.isVirtualRobot(robotId)) { + return false; } - if (robotStateProperties.isVirtualRobot(robotId)) { - log.debug("Ignoring QUIC state for virtual robot, robotId={}, eventType={}", robotId, event.getType()); - return; - } - - List matches = robotMapper.selectByRobotId(robotId); - if (matches.isEmpty()) { - log.warn("QUIC机器人尚未在平台登记,robotId={},nodeId={}", robotId, node.getNodeId()); - return; - } - if (matches.size() != 1) { - log.error("机器人ID存在{}条重复记录,拒绝同步,robotId={}", matches.size(), robotId); - return; - } - - InspectionRobot robot = matches.get(0); - if ("1".equals(robot.getArchivedStatus())) { - log.warn("已归档机器人尝试连接,拒绝同步,robotId={}", robotId); - return; + ResourceRobot robot = robotMapper.selectByRobotIdentity(robotId); + if (robot == null || "1".equals(robot.getArchivedStatus())) { + log.warn("QUIC robot is not registered in resource center, robotId={}, nodeId={}", + robotId, node.getNodeId()); + return false; } boolean offline = event.getType() == NodeEventType.NODE_EVENT_TYPE_OFFLINE || !node.getOnline(); if (offline && StringUtils.isNotBlank(robot.getQuicSessionId()) && !robot.getQuicSessionId().equals(node.getSessionId())) { - log.info("忽略旧QUIC会话的离线事件,robotId={},activeSession={},eventSession={}", - robotId, robot.getQuicSessionId(), node.getSessionId()); - return; + return true; } - Date eventTime = new Date(event.getEventTimeUnixMs() == 0 - ? System.currentTimeMillis() : event.getEventTimeUnixMs()); String oldHost = robot.getIpAddress(); Long oldPort = robot.getPort(); + Date eventTime = new Date(event.getEventTimeUnixMs() == 0 + ? System.currentTimeMillis() : event.getEventTimeUnixMs()); if (!offline) { - String host = resolveGrpcHost(node); - Long port = node.getGrpcEndpoint().getPort() == 0 - ? null : Long.valueOf(node.getGrpcEndpoint().getPort()); - robot.setIpAddress(host); - robot.setPort(port); + robot.setIpAddress(resolveGrpcHost(node)); + robot.setPort(node.getGrpcEndpoint().getPort() == 0 + ? null : (long) node.getGrpcEndpoint().getPort()); } - robot.setConnectStatus(offline ? "0" : "1"); robot.setQuicNodeId(node.getNodeId()); robot.setQuicSessionId(node.getSessionId()); @@ -99,50 +85,40 @@ public class RobotQuicStateService { || event.getType() == NodeEventType.NODE_EVENT_TYPE_HEARTBEAT) { robot.setLastHeartbeatTime(eventTime); } - robot.setUpdateTime(DateUtils.getNowDate()); if (offline || !hasEnabledAgv(node)) { robot.setStatus("1"); } + robot.setUpdateTime(DateUtils.getNowDate()); robotMapper.updateQuicRuntimeState(robot); + synchronizeTerminal(robotId, node, eventTime, offline); if (offline) { deviceMapper.markAllOffline(robotId, eventTime); } else { synchronizeDevices(robotId, node, eventTime); } - if (offline || !Objects.equals(oldHost, robot.getIpAddress()) || !Objects.equals(oldPort, robot.getPort())) { grpcServiceManager.invalidateRobot(robotId); } - if (event.getType() == NodeEventType.NODE_EVENT_TYPE_HEARTBEAT) { - log.debug("QUIC机器人心跳已同步,robotId={},nodeId={},grpc={}:{},devices={}", - robotId, node.getNodeId(), robot.getIpAddress(), robot.getPort(), - node.getDeviceManager().getDevicesCount()); - } else { - log.info("QUIC机器人状态已同步,robotId={},nodeId={},online={},grpc={}:{},devices={}", - robotId, node.getNodeId(), !offline, robot.getIpAddress(), robot.getPort(), - node.getDeviceManager().getDevicesCount()); - } + return true; } @Transactional(rollbackFor = Exception.class) public int expireStaleRobots() { Date now = DateUtils.getNowDate(); - Date cutoff = robotStateProperties.heartbeatCutoff(now); - List excludedRobotIds = robotStateProperties.normalizedVirtualRobotIds(); - int expired = 0; - for (InspectionRobot robot : robotMapper.selectStaleConnectedRobots(cutoff, excludedRobotIds)) { + Date cutoff = stateProperties.heartbeatCutoff(now); + int count = 0; + for (ResourceRobot robot : robotMapper.selectStaleConnected( + cutoff, stateProperties.normalizedVirtualRobotIds())) { if (robotMapper.markHeartbeatExpiredOffline(robot.getId(), cutoff, now) == 0) { continue; } deviceMapper.markAllOffline(robot.getRobotId(), now); grpcServiceManager.invalidateRobot(robot.getRobotId()); - expired++; - log.warn("Robot heartbeat expired and was marked offline, robotId={}, lastHeartbeatTime={}, timeoutMs={}", - robot.getRobotId(), robot.getLastHeartbeatTime(), robotStateProperties.getHeartbeatTimeoutMs()); + count++; } - return expired; + return count; } private void synchronizeDevices(String robotId, NodeSnapshot node, Date eventTime) { @@ -153,13 +129,12 @@ public class RobotQuicStateService { continue; } reportedIds.add(deviceId); - List matches = deviceMapper.selectByIdentity(robotId, deviceId); + List matches = deviceMapper.selectByIdentity(robotId, deviceId); if (matches.size() > 1) { - log.error("机器人设备存在重复记录,跳过更新,robotId={},deviceId={},count={}", - robotId, deviceId, matches.size()); + log.error("Duplicate resource device identity, robotId={}, deviceId={}", robotId, deviceId); continue; } - InspectionRobotDevice device = matches.isEmpty() + ResourceDevice device = matches.isEmpty() ? createDevice(robotId, deviceId, eventTime) : matches.get(0); device.setDeviceKind(status.getKind()); device.setTypeName(status.getTypeName()); @@ -184,8 +159,9 @@ public class RobotQuicStateService { deviceMapper.markMissingOffline(robotId, reportedIds, eventTime); } - private InspectionRobotDevice createDevice(String robotId, String deviceId, Date now) { - InspectionRobotDevice device = new InspectionRobotDevice(); + private ResourceDevice createDevice(String robotId, String deviceId, Date now) { + ResourceDevice device = new ResourceDevice(); + device.setId(UUID.randomUUID().toString().replace("-", "")); device.setRobotId(robotId); device.setDeviceId(deviceId); device.setDeviceName(deviceId); @@ -194,6 +170,60 @@ public class RobotQuicStateService { return device; } + private void synchronizeTerminal(String robotId, NodeSnapshot node, Date eventTime, boolean offline) { + String terminalCode = StringUtils.trimToNull(node.getNodeId()); + if (terminalCode == null) { + return; + } + ResourceTerminal terminal = terminalMapper.selectByCode(terminalCode); + boolean newTerminal = terminal == null; + if (newTerminal) { + terminal = new ResourceTerminal(); + terminal.setId(UUID.randomUUID().toString().replace("-", "")); + terminal.setTerminalCode(terminalCode); + terminal.setTerminalName(terminalCode); + terminal.setCreateBy("quic"); + terminal.setCreateTime(eventTime); + } + terminal.setIpAddress(StringUtils.trimToNull(node.getObservedSourceIp())); + terminal.setPort(node.getGrpcEndpoint().getPort() == 0 + ? null : (long) node.getGrpcEndpoint().getPort()); + terminal.setSoftwareVersion(node.getSoftwareVersion()); + terminal.setConnectStatus(offline ? "0" : "1"); + terminal.setLastHeartbeatTime(eventTime); + terminal.setStatus(offline ? "OFFLINE" : "ONLINE"); + terminal.setUpdateBy("quic"); + terminal.setUpdateTime(eventTime); + if (newTerminal) { + terminalMapper.insert(terminal); + } else { + terminalMapper.updateById(terminal); + } + + ResourceRobotTerminal binding = robotTerminalMapper.selectOne( + new LambdaQueryWrapper() + .eq(ResourceRobotTerminal::getRobotId, robotId) + .eq(ResourceRobotTerminal::getTerminalId, terminal.getId())); + if (binding == null) { + binding = new ResourceRobotTerminal(); + binding.setId(UUID.randomUUID().toString().replace("-", "")); + binding.setRobotId(robotId); + binding.setTerminalId(terminal.getId()); + binding.setBindTime(eventTime); + binding.setCreateTime(eventTime); + binding.setActive(offline ? "0" : "1"); + robotTerminalMapper.insert(binding); + } else { + binding.setActive(offline ? "0" : "1"); + binding.setUnbindTime(offline ? eventTime : null); + binding.setUpdateTime(eventTime); + robotTerminalMapper.updateById(binding); + } + if (!offline) { + robotTerminalMapper.deactivateOtherBindings(robotId, terminal.getId()); + } + } + private boolean hasEnabledAgv(NodeSnapshot node) { return node.getDeviceManager().getDevicesList().stream() .anyMatch(device -> device.getKind() == AGV_DEVICE_KIND && device.getEnabled()); diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotControlService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotControlService.java new file mode 100644 index 0000000..6afc8f8 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotControlService.java @@ -0,0 +1,174 @@ +package com.cmvr.resource.service; + +import cmvr.msgs.AgvUtils; +import cmvr.quic_edge.v1.QuicEdge; +import com.cmvr.common.exception.GlobalException; +import com.cmvr.edge.client.model.EdgeCommonVO; +import com.cmvr.edge.client.service.EdgeAgvService; +import com.cmvr.resource.domain.ResourceDevice; +import com.cmvr.resource.domain.ResourceMap; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.mapper.ResourceDeviceMapper; +import com.cmvr.resource.mapper.ResourceMapMapper; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class ResourceRobotControlService { + private final ResourceRobotMapper robotMapper; + private final ResourceDeviceMapper deviceMapper; + private final ResourceMapMapper mapMapper; + private final ResourceRobotMapService robotMapService; + private final EdgeAgvService edgeAgvService; + + public List listRemoteMaps(String robotRef) { + return edgeAgvService.listMaps(buildAgvRequest(requireRobot(robotRef))); + } + + public int bindMap(String robotRef, String mapId) { + ResourceRobot robot = requireRobot(robotRef); + if (mapMapper.selectById(mapId) == null) { + throw new GlobalException("地图不存在:" + mapId); + } + return robotMapService.bind(robot.getRobotId(), mapId, true); + } + + public String downloadMap(String robotRef, String mapName) { + return edgeAgvService.downloadMap(buildAgvRequest(requireRobot(robotRef)), mapName); + } + + public String uploadActiveMap(String robotRef) { + ResourceRobot target = requireRobot(robotRef); + ResourceMap map = mapMapper.selectById(target.getCurrentMapId()); + if (map == null) { + throw new GlobalException("机器人未绑定有效地图"); + } + String sourceRobotId = StringUtils.trimToNull(map.getSourceRobotId()); + String sourceMapName = StringUtils.trimToNull(map.getSourceMapName()); + if (sourceRobotId == null || sourceMapName == null) { + throw new GlobalException("地图未配置来源机器人或来源地图名称"); + } + ResourceRobot source = requireRobot(sourceRobotId); + String content = edgeAgvService.downloadMap(buildAgvRequest(source), sourceMapName); + if (StringUtils.isBlank(content)) { + throw new GlobalException("下载的地图内容为空"); + } + edgeAgvService.uploadMap(buildAgvRequest(target), sourceMapName, content); + return "上传成功"; + } + + public ResourceRobot syncRuntimeState(String robotRef) { + ResourceRobot robot = requireRobot(robotRef); + try { + AgvUtils.AgvRuntimeState runtime = edgeAgvService.getRuntimeState(buildAgvRequest(robot)); + if (runtime == null) { + throw new GlobalException("AGV未返回运行状态"); + } + if (runtime.hasBattery()) { + int percentage = (int) Math.round(runtime.getBattery().getPercentage() * 100D); + robot.setBatteryLevel(Math.max(0, Math.min(100, percentage))); + } + if (runtime.hasPose()) { + AgvUtils.AgvPose2d pose = runtime.getPose(); + robot.setCurrentPosition(String.format(Locale.ROOT, "%.3f,%.3f,%.3f", + pose.getX(), pose.getY(), pose.getTheta())); + } + robot.setStatus(String.valueOf(runtime.getMode())); + robotMapper.updateAgvRuntimeStatus(robot); + return robot; + } catch (GlobalException error) { + throw error; + } catch (Exception error) { + robot.setStatus("0"); + robotMapper.updateAgvRuntimeStatus(robot); + String detail = StringUtils.isBlank(error.getMessage()) + ? error.getClass().getSimpleName() : error.getMessage(); + throw new GlobalException("获取机器人运行状态失败:" + detail, error); + } + } + + public AgvUtils.AgvPose2d getRealtimeLocation(String robotRef) { + AgvUtils.AgvRuntimeState runtime = edgeAgvService.getRuntimeState( + buildAgvRequest(requireRobot(robotRef))); + return runtime.hasPose() ? runtime.getPose() : null; + } + + public void navigateToPosition(String robotRef, Double x, Double y, Double theta) { + if (x == null || y == null) { + throw new GlobalException("X和Y坐标不能为空"); + } + AgvUtils.AgvPose2d pose = AgvUtils.AgvPose2d.newBuilder() + .setX(x) + .setY(y) + .setTheta(theta == null ? 0D : theta) + .build(); + edgeAgvService.navigateToPose(buildAgvRequest(requireRobot(robotRef)), pose); + } + + public String startMapping(String robotRef, int dimension, String mapName, boolean realTime) { + AgvUtils.AgvMapDimension mapDimension = AgvUtils.AgvMapDimension.forNumber(dimension); + if (mapDimension == null) { + throw new GlobalException("无效的建图维度:" + dimension); + } + return edgeAgvService.startMapping( + buildAgvRequest(requireRobot(robotRef)), mapDimension, mapName, realTime); + } + + public void stopMapping(String robotRef) { + edgeAgvService.stopMapping(buildAgvRequest(requireRobot(robotRef))); + } + + private ResourceRobot requireRobot(String robotRef) { + String normalized = StringUtils.trimToNull(robotRef); + if (normalized == null) { + throw new GlobalException("机器人标识不能为空"); + } + ResourceRobot robot = robotMapper.selectById(normalized); + if (robot == null) { + robot = robotMapper.selectByRobotIdentity(normalized); + } + if (robot == null || "1".equals(robot.getArchivedStatus())) { + throw new GlobalException("机器人不存在:" + normalized); + } + return robot; + } + + private EdgeCommonVO buildAgvRequest(ResourceRobot robot) { + List agvDevices = deviceMapper.selectByRobotId( + robot.getRobotId(), QuicEdge.DeviceKind.DEVICE_KIND_AGV_VALUE, true); + if (agvDevices.isEmpty()) { + List onlineDevices = deviceMapper.selectByRobotId(robot.getRobotId(), null, true); + if (onlineDevices.isEmpty()) { + throw new GlobalException("机器人当前没有在线设备:" + robot.getRobotId()); + } + String summary = onlineDevices.stream() + .map(device -> device.getDeviceId() + "(" + deviceKindName(device.getDeviceKind()) + ")") + .collect(Collectors.joining("、")); + throw new GlobalException("机器人在线设备中没有AGV,当前设备:" + summary); + } + if (agvDevices.size() > 1) { + String ids = agvDevices.stream().map(ResourceDevice::getDeviceId) + .collect(Collectors.joining("、")); + throw new GlobalException("机器人存在多个在线AGV,无法确定默认设备:" + ids); + } + EdgeCommonVO request = new EdgeCommonVO(); + request.setRobotId(robot.getRobotId()); + request.setDeviceId(agvDevices.get(0).getDeviceId()); + return request; + } + + private String deviceKindName(Integer deviceKind) { + if (deviceKind == null) { + return "未知类型"; + } + QuicEdge.DeviceKind kind = QuicEdge.DeviceKind.forNumber(deviceKind); + return kind == null ? "未知类型" + deviceKind : kind.name().replace("DEVICE_KIND_", ""); + } +} diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotDeviceAssignmentValidator.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotDeviceAssignmentValidator.java similarity index 67% rename from cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotDeviceAssignmentValidator.java rename to cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotDeviceAssignmentValidator.java index 8ed9448..14e9a91 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotDeviceAssignmentValidator.java +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotDeviceAssignmentValidator.java @@ -1,35 +1,43 @@ -package com.cmvr.inspection.service; +package com.cmvr.resource.service; import com.cmvr.common.exception.GlobalException; -import com.cmvr.inspection.mapper.InspectionRobotDeviceMapper; -import com.cmvr.inspection.config.RobotStateProperties; +import com.cmvr.resource.config.ResourceRobotStateProperties; +import com.cmvr.resource.domain.ResourceDevice; +import com.cmvr.resource.mapper.ResourceDeviceMapper; import com.cmvr.test.flow.runtime.engine.RobotDeviceAssignmentValidator; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.util.List; import java.util.Locale; @Service @RequiredArgsConstructor -public class InspectionRobotDeviceAssignmentValidator implements RobotDeviceAssignmentValidator { - +public class ResourceRobotDeviceAssignmentValidator implements RobotDeviceAssignmentValidator { private static final int MICROPHONE_DEVICE_KIND = 9; private static final String RECORDING_STREAM_CONFLICT = "cannot start streaming while microphone recording is active"; - private final InspectionRobotDeviceMapper deviceMapper; - private final RobotStateProperties robotStateProperties; + private final ResourceDeviceMapper deviceMapper; + private final ResourceRobotStateProperties stateProperties; @Override public void validate(String robotId, String deviceId, Integer expectedDeviceKind) { - if (robotStateProperties.isVirtualRobot(robotId)) { + validateAndGet(robotId, deviceId, expectedDeviceKind); + } + + private ResourceDevice validateAndGet(String robotId, String deviceId, Integer expectedDeviceKind) { + if (stateProperties.isVirtualRobot(robotId)) { throw new GlobalException("虚拟机器人不能绑定边缘设备:" + robotId); } - var devices = deviceMapper.selectByIdentity(robotId, deviceId); + List devices = deviceMapper.selectByIdentity(robotId, deviceId); if (devices.isEmpty()) { throw new GlobalException("设备[" + deviceId + "]不属于机器人[" + robotId + "]"); } - var device = devices.get(0); + if (devices.size() > 1) { + throw new GlobalException("设备身份存在重复记录:" + robotId + "/" + deviceId); + } + ResourceDevice device = devices.get(0); Integer actualKind = device.getDeviceKind(); if (expectedDeviceKind != null && !expectedDeviceKind.equals(actualKind)) { throw new GlobalException("设备[" + deviceId + "]的类型与流程设备用途不匹配"); @@ -45,12 +53,12 @@ public class InspectionRobotDeviceAssignmentValidator implements RobotDeviceAssi && device.getErrorMessage().toLowerCase(Locale.ROOT).contains(RECORDING_STREAM_CONFLICT); if ("1".equals(device.getHasError()) && !recoverableMicrophoneConflict) { String detail = device.getErrorMessage() == null || device.getErrorMessage().isBlank() - ? "设备上报异常" - : device.getErrorMessage(); + ? "设备上报异常" : device.getErrorMessage(); throw new GlobalException("设备[" + deviceId + "]当前异常: " + detail); } if (Integer.valueOf(3).equals(device.getHealthStatus()) && !recoverableMicrophoneConflict) { throw new GlobalException("设备[" + deviceId + "]当前处于故障状态"); } + return device; } } diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotEndpointResolver.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotEndpointResolver.java similarity index 62% rename from cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotEndpointResolver.java rename to cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotEndpointResolver.java index 56cb5a4..de47441 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotEndpointResolver.java +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotEndpointResolver.java @@ -1,24 +1,22 @@ -package com.cmvr.inspection.service; +package com.cmvr.resource.service; import com.cmvr.common.exception.GlobalException; import com.cmvr.common.robot.RobotEndpoint; import com.cmvr.common.robot.RobotEndpointResolver; -import com.cmvr.inspection.domain.InspectionRobot; -import com.cmvr.inspection.config.RobotStateProperties; -import com.cmvr.inspection.mapper.InspectionRobotMapper; +import com.cmvr.resource.config.ResourceRobotStateProperties; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.mapper.ResourceRobotMapper; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import java.util.List; import java.util.Date; @Service @RequiredArgsConstructor -public class InspectionRobotEndpointResolver implements RobotEndpointResolver { - - private final InspectionRobotMapper robotMapper; - private final RobotStateProperties robotStateProperties; +public class ResourceRobotEndpointResolver implements RobotEndpointResolver { + private final ResourceRobotMapper robotMapper; + private final ResourceRobotStateProperties stateProperties; @Override public RobotEndpoint resolve(String robotId) { @@ -26,25 +24,21 @@ public class InspectionRobotEndpointResolver implements RobotEndpointResolver { if (normalized == null) { throw new GlobalException("机器人ID不能为空"); } - if (robotStateProperties.isVirtualRobot(normalized)) { + if (stateProperties.isVirtualRobot(normalized)) { throw new GlobalException("虚拟机器人不能调用边缘设备服务:" + normalized); } - List robots = robotMapper.selectByRobotId(normalized); - if (robots.isEmpty()) { + ResourceRobot robot = robotMapper.selectByRobotIdentity(normalized); + if (robot == null) { throw new GlobalException("机器人不存在:" + normalized); } - if (robots.size() > 1) { - throw new GlobalException("机器人ID存在重复数据:" + normalized); - } - InspectionRobot robot = robots.get(0); if ("1".equals(robot.getArchivedStatus())) { throw new GlobalException("机器人已归档:" + normalized); } if (!"1".equals(robot.getConnectStatus())) { throw new GlobalException("机器人当前离线:" + normalized); } - Date heartbeatCutoff = robotStateProperties.heartbeatCutoff(new Date()); - if (robot.getLastHeartbeatTime() == null || robot.getLastHeartbeatTime().before(heartbeatCutoff)) { + Date cutoff = stateProperties.heartbeatCutoff(new Date()); + if (robot.getLastHeartbeatTime() == null || robot.getLastHeartbeatTime().before(cutoff)) { throw new GlobalException("机器人QUIC心跳已超时:" + normalized); } if (StringUtils.isBlank(robot.getIpAddress()) || robot.getPort() == null) { diff --git a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotExecutionTargetResolver.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotExecutionTargetResolver.java similarity index 59% rename from cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotExecutionTargetResolver.java rename to cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotExecutionTargetResolver.java index 183fbfd..a4ee289 100644 --- a/cmvr-iot-inspection/src/main/java/com/cmvr/inspection/service/InspectionRobotExecutionTargetResolver.java +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotExecutionTargetResolver.java @@ -1,23 +1,22 @@ -package com.cmvr.inspection.service; +package com.cmvr.resource.service; +import com.cmvr.resource.config.ResourceRobotStateProperties; import com.cmvr.test.flow.runtime.engine.RobotExecutionTarget; import com.cmvr.test.flow.runtime.engine.RobotExecutionTargetResolver; -import com.cmvr.inspection.config.RobotStateProperties; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @Service @RequiredArgsConstructor -public class InspectionRobotExecutionTargetResolver implements RobotExecutionTargetResolver { - - private final InspectionRobotEndpointResolver endpointResolver; - private final RobotStateProperties robotStateProperties; +public class ResourceRobotExecutionTargetResolver implements RobotExecutionTargetResolver { + private final ResourceRobotEndpointResolver endpointResolver; + private final ResourceRobotStateProperties stateProperties; @Override public RobotExecutionTarget resolve(String robotId) { String normalized = StringUtils.trimToNull(robotId); - if (!robotStateProperties.isVirtualRobot(normalized)) { + if (!stateProperties.isVirtualRobot(normalized)) { endpointResolver.resolve(normalized); } return new RobotExecutionTarget(normalized); diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotMapService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotMapService.java new file mode 100644 index 0000000..8b4ab95 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotMapService.java @@ -0,0 +1,86 @@ +package com.cmvr.resource.service; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.cmvr.common.exception.GlobalException; +import com.cmvr.common.utils.DateUtils; +import com.cmvr.common.utils.SecurityUtils; +import com.cmvr.resource.domain.ResourceMap; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.domain.ResourceRobotMap; +import com.cmvr.resource.mapper.ResourceMapMapper; +import com.cmvr.resource.mapper.ResourceRobotMapMapper; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.UUID; + +@Service +public class ResourceRobotMapService { + private final ResourceRobotMapper robotMapper; + private final ResourceMapMapper mapMapper; + private final ResourceRobotMapMapper bindingMapper; + + public ResourceRobotMapService(ResourceRobotMapper robotMapper, ResourceMapMapper mapMapper, + ResourceRobotMapMapper bindingMapper) { + this.robotMapper = robotMapper; + this.mapMapper = mapMapper; + this.bindingMapper = bindingMapper; + } + + public List listMaps(String robotId) { + return mapMapper.selectByRobotId(robotId); + } + + @Transactional(rollbackFor = Exception.class) + public int bind(String robotId, String mapId, boolean makeDefault) { + ResourceRobot robot = robotMapper.selectByRobotIdentity(robotId); + if (robot == null) throw new GlobalException("机器人不存在:" + robotId); + if (mapMapper.selectById(mapId) == null) throw new GlobalException("地图不存在:" + mapId); + + ResourceRobotMap binding = bindingMapper.selectOne(new LambdaQueryWrapper() + .eq(ResourceRobotMap::getRobotId, robotId) + .eq(ResourceRobotMap::getMapId, mapId)); + if (binding == null) { + binding = new ResourceRobotMap(); + binding.setId(UUID.randomUUID().toString().replace("-", "")); + binding.setRobotId(robotId); + binding.setMapId(mapId); + binding.setEnabled("1"); + binding.setIsDefault(makeDefault ? "1" : "0"); + binding.setLoadedStatus("NOT_LOADED"); + binding.setCompatibilityStatus("UNKNOWN"); + binding.setCreateBy(SecurityUtils.getUsername()); + binding.setCreateTime(DateUtils.getNowDate()); + bindingMapper.insert(binding); + } else { + binding.setEnabled("1"); + if (makeDefault) binding.setIsDefault("1"); + binding.setUpdateBy(SecurityUtils.getUsername()); + binding.setUpdateTime(DateUtils.getNowDate()); + bindingMapper.updateById(binding); + } + if (makeDefault) { + bindingMapper.clearDefault(robotId, mapId); + ResourceRobot update = new ResourceRobot(); + update.setId(robot.getId()); + update.setCurrentMapId(mapId); + update.setUpdateBy(SecurityUtils.getUsername()); + update.setUpdateTime(DateUtils.getNowDate()); + robotMapper.updateById(update); + } + return 1; + } + + @Transactional(rollbackFor = Exception.class) + public int unbind(String robotId, String mapId) { + ResourceRobot robot = robotMapper.selectByRobotIdentity(robotId); + if (robot == null) throw new GlobalException("机器人不存在:" + robotId); + int rows = bindingMapper.deleteBinding(robotId, mapId); + if (mapId.equals(robot.getCurrentMapId())) { + robotMapper.clearActiveMap(robot.getId(), mapId, SecurityUtils.getUsername()); + } + return rows; + } +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotService.java new file mode 100644 index 0000000..466906f --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceRobotService.java @@ -0,0 +1,111 @@ +package com.cmvr.resource.service; + +import com.cmvr.resource.domain.ResourceDevice; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.mapper.ResourceDeviceMapper; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; +import com.cmvr.common.exception.GlobalException; +import com.cmvr.common.utils.DateUtils; +import com.cmvr.common.utils.SecurityUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import org.springframework.transaction.annotation.Transactional; + +/** Shared resource lookup used by Aima, inspection and workflow modules. */ +@Service +public class ResourceRobotService { + private final ResourceRobotMapper robotMapper; + private final ResourceDeviceMapper deviceMapper; + + public ResourceRobotService(ResourceRobotMapper robotMapper, ResourceDeviceMapper deviceMapper) { + this.robotMapper = robotMapper; + this.deviceMapper = deviceMapper; + } + + public List list(ResourceRobot query) { + return robotMapper.selectResourceRobots(query); + } + + public ResourceRobot getByRobotId(String robotId) { + if (!StringUtils.hasText(robotId)) { + return null; + } + return robotMapper.selectByRobotIdentity(robotId.trim()); + } + + public ResourceRobot getById(String id) { + return StringUtils.hasText(id) ? robotMapper.selectById(id.trim()) : null; + } + + public List listDevices(String robotId, Integer deviceKind, boolean onlineOnly) { + if (!StringUtils.hasText(robotId)) { + return Collections.emptyList(); + } + return deviceMapper.selectByRobotId(robotId.trim(), deviceKind, onlineOnly); + } + + public List listDevicesByRobotRecord(String id, Integer deviceKind, boolean onlineOnly) { + ResourceRobot robot = getById(id); + if (robot == null) { + throw new GlobalException("机器人不存在"); + } + return listDevices(robot.getRobotId(), deviceKind, onlineOnly); + } + + @Transactional(rollbackFor = Exception.class) + public synchronized int create(ResourceRobot robot) { + String robotId = normalize(robot.getRobotId()); + if (!StringUtils.hasText(robotId)) { + throw new GlobalException("机器人ID不能为空"); + } + if (robotMapper.selectByRobotIdentity(robotId) != null) { + throw new GlobalException("机器人ID已存在:" + robotId); + } + robot.setId(UUID.randomUUID().toString().replace("-", "")); + robot.setRobotId(robotId); + robot.setIpAddress(null); + robot.setPort(null); + robot.setConnectStatus("0"); + robot.setArchivedStatus("0"); + robot.setCreateBy(SecurityUtils.getUsername()); + robot.setCreateTime(DateUtils.getNowDate()); + return robotMapper.insert(robot); + } + + @Transactional(rollbackFor = Exception.class) + public int update(ResourceRobot robot) { + ResourceRobot existing = getById(robot.getId()); + if (existing == null) { + throw new GlobalException("机器人不存在"); + } + if (!Objects.equals(existing.getRobotId(), normalize(robot.getRobotId()))) { + throw new GlobalException("机器人ID是永久身份标识,不允许修改"); + } + ResourceRobot update = new ResourceRobot(); + update.setId(existing.getId()); + update.setRobotName(robot.getRobotName()); + update.setRobotCode(robot.getRobotCode()); + update.setRobotModel(robot.getRobotModel()); + update.setRobotType(robot.getRobotType()); + update.setCurrentMapId(robot.getCurrentMapId()); + update.setRemark(robot.getRemark()); + update.setUpdateBy(SecurityUtils.getUsername()); + update.setUpdateTime(DateUtils.getNowDate()); + return robotMapper.updateById(update); + } + + @Transactional(rollbackFor = Exception.class) + public int archive(String[] ids) { + String username = SecurityUtils.getUsername(); + return robotMapper.archiveByIds(ids, username); + } + + private String normalize(String value) { + return value == null ? null : value.trim(); + } +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceTerminalService.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceTerminalService.java new file mode 100644 index 0000000..5611e91 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/service/ResourceTerminalService.java @@ -0,0 +1,108 @@ +package com.cmvr.resource.service; + +import com.cmvr.common.exception.GlobalException; +import com.cmvr.common.utils.DateUtils; +import com.cmvr.common.utils.SecurityUtils; +import com.cmvr.resource.domain.ResourceTerminal; +import com.cmvr.resource.mapper.ResourceTerminalMapper; +import com.cmvr.resource.mapper.ResourceRobotTerminalMapper; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.util.List; +import java.util.UUID; +import java.util.LinkedHashSet; + +@Service +public class ResourceTerminalService { + private final ResourceTerminalMapper terminalMapper; + private final ResourceRobotTerminalMapper bindingMapper; + private final ResourceRobotMapper robotMapper; + + public ResourceTerminalService(ResourceTerminalMapper terminalMapper, + ResourceRobotTerminalMapper bindingMapper, + ResourceRobotMapper robotMapper) { + this.terminalMapper = terminalMapper; + this.bindingMapper = bindingMapper; + this.robotMapper = robotMapper; + } + + public List list(ResourceTerminal query) { + return terminalMapper.selectResourceTerminals(query); + } + + public ResourceTerminal get(String id) { + ResourceTerminal terminal = StringUtils.hasText(id) ? terminalMapper.selectById(id) : null; + if (terminal == null) throw new GlobalException("终端不存在"); + List robotIds = bindingMapper.selectActiveRobotIds(id); + terminal.setRobotIdsCsv(String.join(",", robotIds)); + terminal.setRobotCount(robotIds.size()); + return terminal; + } + + public List listRobotIds(String id) { + get(id); + return bindingMapper.selectActiveRobotIds(id); + } + + public int create(ResourceTerminal terminal) { + if (!StringUtils.hasText(terminal.getTerminalCode())) throw new GlobalException("终端编码不能为空"); + if (terminalMapper.selectByCode(terminal.getTerminalCode().trim()) != null) { + throw new GlobalException("终端编码已存在:" + terminal.getTerminalCode()); + } + terminal.setId(UUID.randomUUID().toString().replace("-", "")); + terminal.setTerminalCode(terminal.getTerminalCode().trim()); + terminal.setConnectStatus("0"); + terminal.setCreateBy(SecurityUtils.getUsername()); + terminal.setCreateTime(DateUtils.getNowDate()); + return terminalMapper.insert(terminal); + } + + public int update(ResourceTerminal terminal) { + ResourceTerminal existing = terminalMapper.selectById(terminal.getId()); + if (existing == null) throw new GlobalException("终端不存在"); + terminal.setTerminalCode(null); + terminal.setIpAddress(null); + terminal.setPort(null); + terminal.setConnectStatus(null); + terminal.setLastHeartbeatTime(null); + terminal.setUpdateBy(SecurityUtils.getUsername()); + terminal.setUpdateTime(DateUtils.getNowDate()); + return terminalMapper.updateById(terminal); + } + + @Transactional(rollbackFor = Exception.class) + public int replaceRobots(String terminalId, List robotIds) { + get(terminalId); + LinkedHashSet normalized = new LinkedHashSet<>(); + if (robotIds != null) { + robotIds.stream().filter(StringUtils::hasText).map(String::trim).forEach(normalized::add); + } + for (String robotId : normalized) { + if (robotMapper.selectByRobotIdentity(robotId) == null) { + throw new GlobalException("机器人不存在:" + robotId); + } + } + if (!normalized.isEmpty()) robotMapper.lockByRobotIds(new java.util.ArrayList<>(normalized)); + int changed = bindingMapper.deactivateTerminalBindings(terminalId); + for (String robotId : normalized) { + bindingMapper.deactivateOtherBindings(robotId, terminalId); + changed += bindingMapper.activateBinding(UUID.randomUUID().toString().replace("-", ""), robotId, terminalId); + } + return changed; + } + + @Transactional(rollbackFor = Exception.class) + public int remove(String[] ids) { + int changed = 0; + for (String id : ids == null ? new String[0] : ids) { + ResourceTerminal terminal = get(id); + if ("1".equals(terminal.getConnectStatus())) throw new GlobalException("在线终端不能删除:" + terminal.getTerminalCode()); + bindingMapper.deleteTerminalBindings(id); + changed += terminalMapper.deleteById(id); + } + return changed; + } +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/task/ResourceRobotHeartbeatExpiryTask.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/task/ResourceRobotHeartbeatExpiryTask.java new file mode 100644 index 0000000..9789538 --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/task/ResourceRobotHeartbeatExpiryTask.java @@ -0,0 +1,20 @@ +package com.cmvr.resource.task; + +import com.cmvr.resource.service.ResourceQuicStateSynchronizer; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@ConditionalOnProperty(prefix = "cmvr.quic", name = "enabled", havingValue = "true") +public class ResourceRobotHeartbeatExpiryTask { + private final ResourceQuicStateSynchronizer synchronizer; + + @Scheduled(initialDelayString = "${cmvr.resource.robot-state.initial-delay-ms:3000}", + fixedDelayString = "${cmvr.resource.robot-state.heartbeat-check-ms:5000}") + public void expireStaleRobots() { + synchronizer.expireStaleRobots(); + } +} diff --git a/cmvr-iot-resource/src/main/java/com/cmvr/resource/task/ResourceRobotRuntimeRefreshTask.java b/cmvr-iot-resource/src/main/java/com/cmvr/resource/task/ResourceRobotRuntimeRefreshTask.java new file mode 100644 index 0000000..42cdedf --- /dev/null +++ b/cmvr-iot-resource/src/main/java/com/cmvr/resource/task/ResourceRobotRuntimeRefreshTask.java @@ -0,0 +1,64 @@ +package com.cmvr.resource.task; + +import com.cmvr.resource.config.ResourceRobotStateProperties; +import com.cmvr.resource.domain.ResourceRobot; +import com.cmvr.resource.mapper.ResourceRobotMapper; +import com.cmvr.resource.service.ResourceRobotControlService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.core.task.TaskExecutor; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +@Component +@ConditionalOnProperty(prefix = "cmvr.resource.robot-state", name = "enabled", + havingValue = "true", matchIfMissing = true) +public class ResourceRobotRuntimeRefreshTask { + private static final Logger log = LoggerFactory.getLogger(ResourceRobotRuntimeRefreshTask.class); + + private final ResourceRobotMapper robotMapper; + private final ResourceRobotControlService controlService; + private final TaskExecutor taskExecutor; + private final ResourceRobotStateProperties stateProperties; + private final Set syncingRobotIds = ConcurrentHashMap.newKeySet(); + + public ResourceRobotRuntimeRefreshTask(ResourceRobotMapper robotMapper, + ResourceRobotControlService controlService, + @Qualifier("threadPoolTaskExecutor") TaskExecutor taskExecutor, + ResourceRobotStateProperties stateProperties) { + this.robotMapper = robotMapper; + this.controlService = controlService; + this.taskExecutor = taskExecutor; + this.stateProperties = stateProperties; + } + + @Scheduled(initialDelayString = "${cmvr.resource.robot-state.initial-delay-ms:3000}", + fixedDelayString = "${cmvr.resource.robot-state.refresh-ms:5000}") + public void refreshConnectedRobots() { + Date cutoff = stateProperties.heartbeatCutoff(new Date()); + for (ResourceRobot robot : robotMapper.selectRuntimeSyncCandidates( + cutoff, stateProperties.normalizedVirtualRobotIds())) { + if (robot.getId() == null || !syncingRobotIds.add(robot.getId())) { + continue; + } + taskExecutor.execute(() -> refreshRobot(robot)); + } + } + + private void refreshRobot(ResourceRobot robot) { + try { + controlService.syncRuntimeState(robot.getRobotId()); + } catch (Exception error) { + log.debug("Failed to refresh AGV runtime state, robotId={}, reason={}", + robot.getRobotId(), error.getMessage()); + } finally { + syncingRobotIds.remove(robot.getId()); + } + } +} diff --git a/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceDeviceMapper.xml b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceDeviceMapper.xml new file mode 100644 index 0000000..574f40d --- /dev/null +++ b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceDeviceMapper.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, robot_id, device_id, device_name, device_kind, device_type, device_role, + device_index, terminal_id, enabled, manager_state, health_status, online_status, + has_error, error_message, status_updated_time, last_seen_time, + offline_time, create_by, create_time, update_by, update_time, remark + + + + + + + + + update iot_device + set device_kind = #{deviceKind}, device_type = #{typeName}, enabled = #{enabled}, + manager_state = #{managerState}, health_status = #{healthStatus}, + online_status = #{onlineStatus}, has_error = #{hasError}, error_message = #{errorMessage}, + status_updated_time = #{statusUpdatedTime}, last_seen_time = #{lastSeenTime}, + offline_time = #{offlineTime}, update_by = #{updateBy}, update_time = #{updateTime} + where id = #{id} + + + + update iot_device set online_status = '0', offline_time = #{offlineTime}, + update_by = 'quic', update_time = #{offlineTime} + where robot_id = #{robotId} and online_status != '0' + + and device_id not in + #{deviceId} + + + + + update iot_device set online_status = '0', offline_time = #{offlineTime}, + update_by = 'quic', update_time = #{offlineTime} + where robot_id = #{robotId} and online_status != '0' + + diff --git a/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceMapMapper.xml b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceMapMapper.xml new file mode 100644 index 0000000..d71308d --- /dev/null +++ b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceMapMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + id, map_name, map_version, map_type, coordinate_system, source_type, + source_robot_id, source_map_name, map_file_path, status, map_desc, create_by, create_time, + update_by, update_time, remark + + + + + diff --git a/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotMapMapper.xml b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotMapMapper.xml new file mode 100644 index 0000000..b02f86a --- /dev/null +++ b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotMapMapper.xml @@ -0,0 +1,15 @@ + + + + + update iot_robot_map set is_default = '0', update_time = now() + where robot_id = #{robotId} and map_id != #{exceptMapId} + + + delete from iot_robot_map where robot_id = #{robotId} and map_id = #{mapId} + + + diff --git a/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotMapper.xml b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotMapper.xml new file mode 100644 index 0000000..4b470a6 --- /dev/null +++ b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotMapper.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id, robot_id, robot_code, robot_name, robot_model, robot_type, ip_address, port, + active_map_id, runtime_status, battery_level, current_position, connect_status, + quic_node_id, quic_session_id, quic_boot_id, observed_ip, software_version, + last_heartbeat_time, archived_status, create_by, create_time, update_by, update_time, remark + + + + + + + + + update iot_robot set archived_status = '1', connect_status = '0', update_by = #{updateBy}, update_time = now() + where id in + #{id} + + + + update iot_robot set active_map_id = null, update_by = #{updateBy}, update_time = now() + where id = #{id} and active_map_id = #{mapId} + + + + update iot_robot + set ip_address = #{ipAddress}, port = #{port}, connect_status = #{connectStatus}, + runtime_status = coalesce(#{status}, runtime_status), + quic_node_id = #{quicNodeId}, quic_session_id = #{quicSessionId}, + quic_boot_id = #{quicBootId}, observed_ip = #{observedIp}, + software_version = #{softwareVersion}, last_heartbeat_time = #{lastHeartbeatTime}, + update_by = 'quic', update_time = #{updateTime} + where id = #{id} + + + + + + + + update iot_robot set runtime_status=#{status}, battery_level=#{batteryLevel}, + current_position=#{currentPosition}, update_by='agv-status', update_time=now() + where id=#{id} + + + + + + update iot_robot set connect_status = '0', runtime_status = '1', + update_by = 'heartbeat-timeout', update_time = #{offlineTime} + where id = #{id} and connect_status = '1' + and (last_heartbeat_time is null or last_heartbeat_time < #{heartbeatCutoff}) + + diff --git a/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotTerminalMapper.xml b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotTerminalMapper.xml new file mode 100644 index 0000000..3a208e2 --- /dev/null +++ b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceRobotTerminalMapper.xml @@ -0,0 +1,23 @@ + + + + + update iot_robot_terminal set active = '0', unbind_time = now(), update_time = now() + where robot_id = #{robotId} and terminal_id != #{terminalId} and active = '1' + + + + update iot_robot_terminal set active = '0', unbind_time = now(), update_time = now() + where terminal_id = #{terminalId} and active = '1' + + + delete from iot_robot_terminal where terminal_id = #{terminalId} + + + insert into iot_robot_terminal(id, robot_id, terminal_id, active, bind_time, create_time, update_time) + values(#{id}, #{robotId}, #{terminalId}, '1', now(), now(), now()) + on duplicate key update active = '1', bind_time = now(), unbind_time = null, update_time = now() + + diff --git a/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceTerminalMapper.xml b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceTerminalMapper.xml new file mode 100644 index 0000000..0f40659 --- /dev/null +++ b/cmvr-iot-resource/src/main/resources/mapper/resource/ResourceTerminalMapper.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + id, terminal_code, terminal_name, ip_address, port, software_version, + connect_status, last_heartbeat_time, status, create_by, create_time, update_by, update_time, remark + + + diff --git a/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/engine/RobotDeviceAssignmentValidator.java b/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/engine/RobotDeviceAssignmentValidator.java index f4fdf2f..9fa8689 100644 --- a/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/engine/RobotDeviceAssignmentValidator.java +++ b/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/engine/RobotDeviceAssignmentValidator.java @@ -4,4 +4,5 @@ package com.cmvr.test.flow.runtime.engine; public interface RobotDeviceAssignmentValidator { void validate(String robotId, String deviceId, Integer expectedDeviceKind); + } diff --git a/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateService.java b/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateService.java index 241011b..30364b4 100644 --- a/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateService.java +++ b/cmvr-iot-test/src/main/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateService.java @@ -19,6 +19,7 @@ import java.util.UUID; public class LLMMediaAnalysisOperateService implements LLMOperateService { private static final Set VIDEO_ANALYSIS_MODES = Set.of("AUTO", "FAST", "ACCURATE"); + private static final String ANY_VEHICLE_SOUND = "ANY_VEHICLE_SOUND"; private final MediaAnalysisClient mediaAnalysisClient; private final AsyncMediaAnalysisCoordinator asyncCoordinator; @@ -177,15 +178,25 @@ public class LLMMediaAnalysisOperateService implements LLMOperateService { } String actualLabel = StringUtils.trimToEmpty(output.getString("label")); String actualLabelName = StringUtils.trimToEmpty(output.getString("labelName")); - boolean passed = classified && (expectedLabel.equalsIgnoreCase(actualLabel) + boolean anyVehicleSound = ANY_VEHICLE_SOUND.equalsIgnoreCase(expectedLabel); + boolean vehicleSoundDetected = output.containsKey("vehicleSoundDetected") + ? Boolean.TRUE.equals(output.getBoolean("vehicleSoundDetected")) + : classified; + boolean passed = anyVehicleSound + ? vehicleSoundDetected + : classified && (expectedLabel.equalsIgnoreCase(actualLabel) || expectedLabel.equalsIgnoreCase(actualLabelName)); String displayName = StringUtils.defaultIfBlank(expectedLabelName, expectedLabel); output.put("expectedLabel", expectedLabel); output.put("expectedLabelName", displayName); output.put("passed", passed); - output.put("decisionReason", passed - ? "检测到目标声音:" + displayName - : "未检测到目标声音:" + displayName); + if (anyVehicleSound) { + output.put("decisionReason", passed ? "检测到车机发声" : "未检测到车机发声"); + } else { + output.put("decisionReason", passed + ? "检测到目标声音:" + displayName + : "未检测到目标声音:" + displayName); + } } private JSONObject buildVideoTuning(JSONObject source) { diff --git a/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateServiceTest.java b/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateServiceTest.java index 4089608..c941ea9 100644 --- a/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateServiceTest.java +++ b/cmvr-iot-test/src/test/java/com/cmvr/test/flow/runtime/operator/llm/LLMMediaAnalysisOperateServiceTest.java @@ -78,6 +78,29 @@ public class LLMMediaAnalysisOperateServiceTest { assertEquals(false, result.getOutputParams().getBooleanValue("passed")); } + @Test + public void passesBroadVehicleSoundTargetWhenConcreteLabelIsAmbiguous() { + MediaAnalysisClient client = request -> new JSONObject() + .fluentPut("status", "SUCCEEDED") + .fluentPut("analysisType", "AUDIO_CLASSIFICATION") + .fluentPut("profileCode", "aima.power_state.v1") + .fluentPut("result", new JSONObject() + .fluentPut("label", "UNKNOWN") + .fluentPut("matched", false) + .fluentPut("vehicleSoundDetected", true)); + LLMMediaAnalysisOperateService service = new LLMMediaAnalysisOperateService(client); + JSONObject input = new JSONObject() + .fluentPut("profileCode", "aima.power_state.v1") + .fluentPut("expectedLabel", "ANY_VEHICLE_SOUND") + .fluentPut("expectedLabelName", "车机发声(不限类型)") + .fluentPut("audioUrl", "https://files.example/audio.wav"); + + TaskNodeExecuteResult result = service.execute(message(ActionEnum.AUDIO_EVENT_CLASSIFY, input)); + + assertTrue(result.getOutputParams().getBooleanValue("passed")); + assertEquals("检测到车机发声", result.getOutputParams().getString("decisionReason")); + } + @Test public void forwardsVideoInstruction() { AtomicReference captured = new AtomicReference<>(); diff --git a/pom.xml b/pom.xml index 39e087f..45cb90f 100644 --- a/pom.xml +++ b/pom.xml @@ -267,6 +267,11 @@ cmvr-iot-aima ${cmvr-iot.version} + + com.cmvr + cmvr-iot-resource + ${cmvr-iot.version} + com.cmvr cmvr-iot-tts @@ -324,6 +329,7 @@ cmvr-iot-evaluation cmvr-iot-inspection cmvr-iot-aima + cmvr-iot-resource cmvr-iot-tts cmvr-iot-quic-contract cmvr-iot-quic diff --git a/sql/inspection_module.sql b/sql/inspection_module.sql index 6ed404c..aa4b328 100644 --- a/sql/inspection_module.sql +++ b/sql/inspection_module.sql @@ -2,86 +2,7 @@ -- 智能巡检模块数据库表结构 -- ---------------------------- --- 1. 巡检机器人表 -DROP TABLE IF EXISTS `inspection_robot`; -CREATE TABLE `inspection_robot` ( - `id` varchar(64) NOT NULL COMMENT '主键ID', - `robot_id` varchar(128) DEFAULT NULL COMMENT 'QUIC上报的永久机器人ID', - `create_by` varchar(64) DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `update_by` varchar(64) DEFAULT '' COMMENT '更新者', - `update_time` datetime DEFAULT NULL COMMENT '更新时间', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `robot_code` varchar(64) DEFAULT NULL COMMENT '机器人编码', - `robot_name` varchar(100) NOT NULL COMMENT '机器人名称', - `robot_model` varchar(100) DEFAULT NULL COMMENT '机器人型号', - `robot_type` varchar(50) DEFAULT NULL COMMENT '机器人类型', - `ip_address` varchar(50) DEFAULT NULL COMMENT 'IP地址', - `port` int(11) DEFAULT NULL COMMENT '端口号', - `current_map_id` varchar(64) DEFAULT NULL COMMENT '当前地图ID', - `status` char(1) DEFAULT '0' COMMENT 'AGV运行模式(0未知 1断开 2空闲 3手动 4自动 5充电 6暂停 7停止 8故障 9急停)', - `battery_level` int(3) DEFAULT NULL COMMENT '电量百分比', - `current_position` varchar(200) DEFAULT NULL COMMENT '当前位置', - `connect_status` char(1) NOT NULL DEFAULT '0' COMMENT '连接状态(0离线 1在线)', - `quic_node_id` varchar(128) DEFAULT NULL COMMENT '当前QUIC节点实例', - `quic_session_id` varchar(128) DEFAULT NULL COMMENT '当前QUIC会话', - `quic_boot_id` varchar(128) DEFAULT NULL COMMENT '边缘端启动ID', - `observed_ip` varchar(64) DEFAULT NULL COMMENT 'QUIC连接来源IP', - `software_version` varchar(64) DEFAULT NULL COMMENT '边缘端软件版本', - `last_heartbeat_time` datetime(3) DEFAULT NULL COMMENT '最后心跳时间', - `archived_status` char(1) NOT NULL DEFAULT '0' COMMENT '归档状态(0正常 1归档)', - PRIMARY KEY (`id`), - UNIQUE KEY `uk_robot_code` (`robot_code`), - KEY `idx_inspection_robot_robot_id` (`robot_id`), - KEY `idx_inspection_robot_connect_status` (`connect_status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检机器人表'; - --- 1.1 QUIC自动发现的机器人设备表(逻辑唯一性由后端校验) -DROP TABLE IF EXISTS `inspection_robot_device`; -CREATE TABLE `inspection_robot_device` ( - `id` varchar(64) NOT NULL COMMENT '主键ID', - `robot_id` varchar(128) NOT NULL COMMENT '永久机器人ID', - `device_id` varchar(128) NOT NULL COMMENT '边缘端设备ID', - `device_name` varchar(128) DEFAULT NULL COMMENT '设备显示名称', - `device_kind` int DEFAULT NULL COMMENT '设备类型', - `type_name` varchar(128) DEFAULT NULL COMMENT '设备实现类型', - `enabled` char(1) NOT NULL DEFAULT '1' COMMENT '是否启用', - `manager_state` int DEFAULT NULL COMMENT '设备管理状态', - `health_status` int DEFAULT NULL COMMENT '健康状态', - `online_status` char(1) NOT NULL DEFAULT '0' COMMENT '在线状态', - `has_error` char(1) NOT NULL DEFAULT '0' COMMENT '是否有错误', - `error_message` varchar(1000) DEFAULT NULL COMMENT '错误信息', - `status_updated_time` datetime(3) DEFAULT NULL COMMENT '边缘端状态更新时间', - `last_seen_time` datetime(3) DEFAULT NULL COMMENT '最后发现时间', - `offline_time` datetime(3) DEFAULT NULL COMMENT '离线时间', - `create_by` varchar(64) DEFAULT NULL, - `create_time` datetime DEFAULT NULL, - `update_by` varchar(64) DEFAULT NULL, - `update_time` datetime DEFAULT NULL, - `remark` varchar(500) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `idx_robot_device_robot_id` (`robot_id`), - UNIQUE KEY `uk_robot_device_identity` (`robot_id`, `device_id`), - KEY `idx_robot_device_online` (`robot_id`, `online_status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机器人自动发现设备'; - --- 2. 巡检地图表 -DROP TABLE IF EXISTS `inspection_map`; -CREATE TABLE `inspection_map` ( - `id` varchar(64) NOT NULL COMMENT '主键ID', - `create_by` varchar(64) DEFAULT '' COMMENT '创建者', - `create_time` datetime DEFAULT NULL COMMENT '创建时间', - `update_by` varchar(64) DEFAULT '' COMMENT '更新者', - `update_time` datetime DEFAULT NULL COMMENT '更新时间', - `remark` varchar(500) DEFAULT NULL COMMENT '备注', - `map_name` varchar(100) NOT NULL COMMENT '地图名称', - `map_source_robot_id` varchar(64) DEFAULT NULL COMMENT '地图来源的机器人id', - `map_source_name` varchar(100) DEFAULT NULL COMMENT '地图来源的地图名称', - `map_file_path` varchar(500) DEFAULT NULL COMMENT '地图文件路径', - `status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)', - `map_desc` varchar(500) DEFAULT NULL COMMENT '地图描述', - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检地图表'; +-- 机器人、设备和地图由资源中心统一管理,先执行 sql/resource_center_v1.sql。 -- 3. 巡检任务表(不再包含机器人信息) DROP TABLE IF EXISTS `inspection_task`; diff --git a/sql/quic_gateway_terminal_migration.sql b/sql/quic_gateway_terminal_migration.sql deleted file mode 100644 index ff4b3e3..0000000 --- a/sql/quic_gateway_terminal_migration.sql +++ /dev/null @@ -1,11 +0,0 @@ --- QUIC节点采用稳定node_id与平台终端人工绑定,禁止同一节点绑定多个终端。 -ALTER TABLE de_device_terminal_config - ADD COLUMN quic_node_id varchar(128) NULL COMMENT 'QUIC稳定节点ID' AFTER description, - ADD COLUMN quic_observed_ip varchar(128) NULL COMMENT 'Gateway观察到的QUIC源IP' AFTER quic_node_id, - ADD COLUMN quic_session_id varchar(64) NULL COMMENT '当前QUIC注册会话ID' AFTER quic_observed_ip, - ADD COLUMN quic_boot_id varchar(128) NULL COMMENT '终端操作系统启动ID' AFTER quic_session_id, - ADD COLUMN quic_software_version varchar(64) NULL COMMENT 'cmvr-es软件版本' AFTER quic_boot_id, - ADD COLUMN quic_online_status char(1) NOT NULL DEFAULT '0' COMMENT 'QUIC在线状态:0离线,1在线' AFTER quic_software_version, - ADD COLUMN quic_last_heartbeat_time datetime(3) NULL COMMENT '最近QUIC心跳时间' AFTER quic_online_status, - ADD UNIQUE KEY uk_terminal_quic_node_id (quic_node_id), - ADD KEY idx_terminal_quic_online (quic_online_status, quic_last_heartbeat_time); diff --git a/sql/resource_center_menu.sql b/sql/resource_center_menu.sql new file mode 100644 index 0000000..d04a3f2 --- /dev/null +++ b/sql/resource_center_menu.sql @@ -0,0 +1,75 @@ +-- Resource center menus. Idempotent; obsolete resource-management routes are removed. +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query, route_name, + is_frame, is_cache, menu_type, visible, status, perms, icon, + create_by, create_time, update_by, update_time, remark) +VALUES + (2200, '资源中心', 0, 4, 'resource', NULL, '', 'ResourceCenter', 1, 0, 'M', '0', '0', '', 'component', 'admin', NOW(), '', NULL, '通用机器人、设备、地图和终端资源'), + (2201, '机器人', 2200, 1, 'robot', 'resource/robot/index', '', 'ResourceRobot', 1, 0, 'C', '0', '0', 'resource:robot:list', 'monitor', 'admin', NOW(), '', NULL, '平台机器人身份与运行状态'), + (2202, '设备', 2200, 2, 'device', 'resource/device/index', '', 'ResourceDevice', 1, 0, 'C', '0', '0', 'resource:device:list', 'list', 'admin', NOW(), '', NULL, '机器人设备发现与用途配置'), + (2203, '地图', 2200, 3, 'map', 'resource/map/index', '', 'ResourceMap', 1, 0, 'C', '0', '0', 'resource:map:list', 'map', 'admin', NOW(), '', NULL, '仅有AGV能力的机器人需要绑定地图'), + (2204, '边缘终端', 2200, 4, 'terminal', 'resource/terminal/index', '', 'ResourceTerminal', 1, 0, 'C', '0', '0', 'resource:terminal:list', 'server', 'admin', NOW(), '', NULL, 'QUIC边缘终端运行状态') +ON DUPLICATE KEY UPDATE menu_name = VALUES(menu_name), parent_id = VALUES(parent_id), order_num = VALUES(order_num), + path = VALUES(path), component = VALUES(component), route_name = VALUES(route_name), visible = VALUES(visible), status = VALUES(status), + perms = VALUES(perms), icon = VALUES(icon), update_by = 'admin', update_time = NOW(), remark = VALUES(remark); + +INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, query, route_name, + is_frame, is_cache, menu_type, visible, status, perms, icon, + create_by, create_time, update_by, update_time, remark) +VALUES + (2210, '查询', 2201, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:robot:query', '#', 'admin', NOW(), '', NULL, ''), + (2211, '新增', 2201, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:robot:add', '#', 'admin', NOW(), '', NULL, ''), + (2212, '修改', 2201, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:robot:edit', '#', 'admin', NOW(), '', NULL, ''), + (2213, '删除', 2201, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:robot:remove', '#', 'admin', NOW(), '', NULL, ''), + (2220, '修改', 2202, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:device:edit', '#', 'admin', NOW(), '', NULL, ''), + (2230, '查询', 2203, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:map:query', '#', 'admin', NOW(), '', NULL, ''), + (2231, '新增', 2203, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:map:add', '#', 'admin', NOW(), '', NULL, ''), + (2232, '修改', 2203, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:map:edit', '#', 'admin', NOW(), '', NULL, ''), + (2233, '删除', 2203, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:map:remove', '#', 'admin', NOW(), '', NULL, ''), + (2241, '新增', 2204, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:terminal:add', '#', 'admin', NOW(), '', NULL, ''), + (2242, '修改', 2204, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:terminal:edit', '#', 'admin', NOW(), '', NULL, ''), + (2243, '删除', 2204, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'resource:terminal:remove', '#', 'admin', NOW(), '', NULL, '') +ON DUPLICATE KEY UPDATE menu_name=VALUES(menu_name), parent_id=VALUES(parent_id), order_num=VALUES(order_num), + status=VALUES(status), perms=VALUES(perms), update_by='admin', update_time=NOW(); + +-- Preserve each role's existing business access while exposing the unified resource pages. +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2200 FROM sys_role_menu rm WHERE rm.menu_id IN (2109, 2105, 2006); +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2201 FROM sys_role_menu rm WHERE rm.menu_id = 2109; +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2202 FROM sys_role_menu rm WHERE rm.menu_id = 2109; +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2203 FROM sys_role_menu rm WHERE rm.menu_id = 2105; +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2204 FROM sys_role_menu rm WHERE rm.menu_id = 2006; +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2200 FROM sys_role_menu rm WHERE rm.menu_id IN (2004, 2006, 2007, 2008, 2051); +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2201 FROM sys_role_menu rm WHERE rm.menu_id = 2051; +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT DISTINCT rm.role_id, 2202 FROM sys_role_menu rm WHERE rm.menu_id IN (2007, 2008, 2051); + +INSERT IGNORE INTO sys_role_menu(role_id, menu_id) +SELECT rm.role_id, f.menu_id +FROM sys_role_menu rm +JOIN ( + SELECT 2201 parent_id, 2210 menu_id UNION ALL SELECT 2201, 2211 UNION ALL SELECT 2201, 2212 UNION ALL SELECT 2201, 2213 + UNION ALL SELECT 2202, 2220 + UNION ALL SELECT 2203, 2230 UNION ALL SELECT 2203, 2231 UNION ALL SELECT 2203, 2232 UNION ALL SELECT 2203, 2233 + UNION ALL SELECT 2204, 2241 UNION ALL SELECT 2204, 2242 UNION ALL SELECT 2204, 2243 +) f ON f.parent_id = rm.menu_id; + +DELETE FROM sys_role_menu WHERE menu_id IN (2205, 2251, 2252, 2253); +DELETE FROM sys_menu WHERE menu_id IN (2251, 2252, 2253, 2205); + +-- Remove old device CRUD and inspection resource menus after permissions have been migrated. +DELETE FROM sys_role_menu +WHERE menu_id IN (2004, 2006, 2007, 2008, 2009, 2051, 2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2105, 2109); + +DELETE FROM sys_menu +WHERE menu_id IN (2064, 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2072, 2073, 2006, 2007, 2008, 2009, 2051, 2105, 2109, 2004); + +-- Route names are global in Vue Router. These legacy group names collided with +-- existing leaf pages even before the resource center was introduced. +UPDATE sys_menu SET route_name = 'SystemLogGroup', update_by = 'admin', update_time = NOW() WHERE menu_id = 108; +UPDATE sys_menu SET route_name = 'ViCorpusGroup', update_by = 'admin', update_time = NOW() WHERE menu_id = 2053; diff --git a/sql/resource_center_v1.sql b/sql/resource_center_v1.sql new file mode 100644 index 0000000..99a99a3 --- /dev/null +++ b/sql/resource_center_v1.sql @@ -0,0 +1,150 @@ +-- Resource center foundation. Safe to run repeatedly on the isolated development database. + +CREATE TABLE IF NOT EXISTS iot_robot ( + id varchar(64) NOT NULL, + robot_id varchar(128) NOT NULL, + robot_code varchar(128) DEFAULT NULL, + robot_name varchar(255) DEFAULT NULL, + robot_model varchar(128) DEFAULT NULL, + robot_type varchar(64) DEFAULT NULL, + ip_address varchar(128) DEFAULT NULL, + port bigint DEFAULT NULL, + active_map_id varchar(64) DEFAULT NULL, + runtime_status varchar(32) DEFAULT NULL, + battery_level int DEFAULT NULL, + current_position text, + connect_status varchar(16) DEFAULT NULL, + quic_node_id varchar(128) DEFAULT NULL, + quic_session_id varchar(128) DEFAULT NULL, + quic_boot_id varchar(128) DEFAULT NULL, + observed_ip varchar(128) DEFAULT NULL, + software_version varchar(128) DEFAULT NULL, + last_heartbeat_time datetime DEFAULT NULL, + archived_status varchar(16) DEFAULT '0', + create_by varchar(64) DEFAULT NULL, + create_time datetime DEFAULT NULL, + update_by varchar(64) DEFAULT NULL, + update_time datetime DEFAULT NULL, + remark varchar(500) DEFAULT NULL, + PRIMARY KEY (id), + UNIQUE KEY uk_iot_robot_robot_id (robot_id), + KEY idx_iot_robot_connect_status (connect_status), + KEY idx_iot_robot_active_map (active_map_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Platform robots'; + +CREATE TABLE IF NOT EXISTS iot_device ( + id varchar(64) NOT NULL, + robot_id varchar(128) NOT NULL, + device_id varchar(128) NOT NULL, + device_name varchar(255) DEFAULT NULL, + device_kind int DEFAULT NULL, + device_type varchar(64) DEFAULT NULL, + device_role varchar(128) DEFAULT NULL, + device_index int DEFAULT NULL, + terminal_id varchar(64) DEFAULT NULL, + enabled varchar(16) DEFAULT '1', + manager_state int DEFAULT NULL, + health_status int DEFAULT NULL, + online_status varchar(16) DEFAULT NULL, + has_error varchar(16) DEFAULT NULL, + error_message varchar(1000) DEFAULT NULL, + status_updated_time datetime DEFAULT NULL, + last_seen_time datetime DEFAULT NULL, + offline_time datetime DEFAULT NULL, + create_by varchar(64) DEFAULT NULL, + create_time datetime DEFAULT NULL, + update_by varchar(64) DEFAULT NULL, + update_time datetime DEFAULT NULL, + remark varchar(500) DEFAULT NULL, + PRIMARY KEY (id), + UNIQUE KEY uk_iot_device_identity (robot_id, device_id), + KEY idx_iot_device_robot (robot_id), + KEY idx_iot_device_kind_status (device_kind, online_status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Platform robot devices'; + +CREATE TABLE IF NOT EXISTS iot_terminal ( + id varchar(64) NOT NULL, + terminal_code varchar(128) NOT NULL, + terminal_name varchar(255) DEFAULT NULL, + ip_address varchar(128) DEFAULT NULL, + port bigint DEFAULT NULL, + software_version varchar(128) DEFAULT NULL, + connect_status varchar(16) DEFAULT NULL, + last_heartbeat_time datetime DEFAULT NULL, + status varchar(16) DEFAULT NULL, + create_by varchar(64) DEFAULT NULL, + create_time datetime DEFAULT NULL, + update_by varchar(64) DEFAULT NULL, + update_time datetime DEFAULT NULL, + remark varchar(500) DEFAULT NULL, + PRIMARY KEY (id), + UNIQUE KEY uk_iot_terminal_code (terminal_code) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Edge terminals'; + +CREATE TABLE IF NOT EXISTS iot_robot_terminal ( + id varchar(64) NOT NULL, + robot_id varchar(128) NOT NULL, + terminal_id varchar(64) NOT NULL, + active varchar(16) DEFAULT '1', + bind_time datetime DEFAULT NULL, + unbind_time datetime DEFAULT NULL, + create_time datetime DEFAULT NULL, + update_time datetime DEFAULT NULL, + PRIMARY KEY (id), + UNIQUE KEY uk_iot_robot_terminal (robot_id, terminal_id), + KEY idx_iot_robot_terminal_active (robot_id, active) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Robot terminal bindings'; + +CREATE TABLE IF NOT EXISTS iot_map ( + id varchar(64) NOT NULL, + map_name varchar(255) NOT NULL, + map_version varchar(64) DEFAULT NULL, + map_type varchar(64) DEFAULT NULL, + coordinate_system varchar(128) DEFAULT NULL, + source_type varchar(32) DEFAULT NULL, + source_robot_id varchar(128) DEFAULT NULL, + source_map_name varchar(255) DEFAULT NULL, + map_file_path varchar(1000) DEFAULT NULL, + status varchar(16) DEFAULT '0', + map_desc varchar(1000) DEFAULT NULL, + create_by varchar(64) DEFAULT NULL, + create_time datetime DEFAULT NULL, + update_by varchar(64) DEFAULT NULL, + update_time datetime DEFAULT NULL, + remark varchar(500) DEFAULT NULL, + PRIMARY KEY (id), + KEY idx_iot_map_source_robot (source_robot_id), + KEY idx_iot_map_status (status) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Platform maps'; + +SET @source_map_name_exists = ( + SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema = DATABASE() AND table_name = 'iot_map' AND column_name = 'source_map_name' +); +SET @source_map_name_sql = IF( + @source_map_name_exists = 0, + 'ALTER TABLE iot_map ADD COLUMN source_map_name varchar(255) DEFAULT NULL AFTER source_robot_id', + 'SELECT 1' +); +PREPARE source_map_name_stmt FROM @source_map_name_sql; +EXECUTE source_map_name_stmt; +DEALLOCATE PREPARE source_map_name_stmt; + +CREATE TABLE IF NOT EXISTS iot_robot_map ( + id varchar(64) NOT NULL, + robot_id varchar(128) NOT NULL, + map_id varchar(64) NOT NULL, + enabled varchar(16) DEFAULT '1', + is_default varchar(16) DEFAULT '0', + loaded_status varchar(32) DEFAULT 'NOT_LOADED', + compatibility_status varchar(32) DEFAULT 'UNKNOWN', + last_loaded_time datetime DEFAULT NULL, + remark varchar(500) DEFAULT NULL, + create_by varchar(64) DEFAULT NULL, + create_time datetime DEFAULT NULL, + update_by varchar(64) DEFAULT NULL, + update_time datetime DEFAULT NULL, + PRIMARY KEY (id), + UNIQUE KEY uk_iot_robot_map (robot_id, map_id), + KEY idx_iot_robot_map_default (robot_id, is_default) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Robot map bindings'; diff --git a/sql/robot_id_only_migration.sql b/sql/robot_id_only_migration.sql deleted file mode 100644 index 9989e32..0000000 --- a/sql/robot_id_only_migration.sql +++ /dev/null @@ -1,4 +0,0 @@ --- The permanent robot_id is the only edge routing identity. --- Historical data is intentionally not migrated. -alter table inspection_robot drop column terminal_id; -alter table te_task_inst drop column terminal_id; diff --git a/sql/robot_quic_identity_migration.sql b/sql/robot_quic_identity_migration.sql deleted file mode 100644 index cea8d44..0000000 --- a/sql/robot_quic_identity_migration.sql +++ /dev/null @@ -1,45 +0,0 @@ --- Existing robot rows are intentionally left with robot_id = NULL. -alter table inspection_robot - add column robot_id varchar(128) null comment 'Permanent robot identity reported by QUIC' after id, - add column connect_status char(1) not null default '0' comment '0 offline, 1 online' after robot_id, - add column quic_node_id varchar(128) null comment 'Current QUIC node instance' after connect_status, - add column quic_session_id varchar(128) null comment 'Current QUIC session' after quic_node_id, - add column quic_boot_id varchar(128) null comment 'Current edge boot id' after quic_session_id, - add column observed_ip varchar(64) null comment 'Observed QUIC source IP' after quic_boot_id, - add column software_version varchar(64) null comment 'Edge software version' after observed_ip, - add column last_heartbeat_time datetime(3) null comment 'Last accepted heartbeat time' after software_version, - add column archived_status char(1) not null default '0' comment '0 active, 1 archived' after last_heartbeat_time, - add index idx_inspection_robot_robot_id (robot_id), - add index idx_inspection_robot_connect_status (connect_status); - -create table inspection_robot_device ( - id varchar(64) not null, - robot_id varchar(128) not null, - device_id varchar(128) not null, - device_name varchar(128) null, - device_kind int null, - type_name varchar(128) null, - enabled char(1) not null default '1', - manager_state int null, - health_status int null, - online_status char(1) not null default '0', - has_error char(1) not null default '0', - error_message varchar(1000) null, - status_updated_time datetime(3) null, - last_seen_time datetime(3) null, - offline_time datetime(3) null, - create_by varchar(64) null, - create_time datetime null, - update_by varchar(64) null, - update_time datetime null, - remark varchar(500) null, - primary key (id), - index idx_robot_device_robot_id (robot_id), - unique index uk_robot_device_identity (robot_id, device_id), - index idx_robot_device_online (robot_id, online_status) -) comment='Devices discovered from robot QUIC heartbeat'; - --- New task instances record the permanent identity. Legacy instances remain NULL. -alter table te_task_inst - add column robot_id varchar(128) null comment 'Permanent robot identity' after task_id, - add index idx_te_task_inst_robot_id (robot_id); diff --git a/sql/workflow_resource_role_v2.sql b/sql/workflow_resource_role_v2.sql deleted file mode 100644 index dc4901d..0000000 --- a/sql/workflow_resource_role_v2.sql +++ /dev/null @@ -1,10 +0,0 @@ --- Workflow resource role V2 prerequisite. --- Resolve any rows returned by this query before applying the unique constraint. -select robot_id, device_id, count(*) as duplicate_count -from inspection_robot_device -group by robot_id, device_id -having count(*) > 1; - -alter table inspection_robot_device - drop index idx_robot_device_identity, - add unique key uk_robot_device_identity (robot_id, device_id);