package com.ruoyi.envaccess.controller; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.databind.ObjectMapper; import com.ruoyi.common.handler.CustomTenantLineHandler; import com.ruoyi.framework.aspectj.lang.annotation.Anonymous; import com.ruoyi.framework.aspectj.lang.annotation.Log; import com.ruoyi.framework.aspectj.lang.enums.BusinessType; import com.ruoyi.framework.web.domain.AjaxResult; import com.ruoyi.envaccess.pojo.EnvInspection; import com.ruoyi.envaccess.service.IEnvInspectionService; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * 环保门禁--智能巡检台账(含路径规划/AI视频分析/报告/无人机机器人,AI与无人机字段预留) */ @RestController @RequestMapping("/environmentAccess/inspection") public class EnvInspectionController { @Resource private IEnvInspectionService envInspectionService; @GetMapping("/page") public AjaxResult page(Page page, EnvInspection req) { return AjaxResult.success(envInspectionService.listPage(page, req)); } @GetMapping("/{id}") public AjaxResult detail(@PathVariable Long id) { return AjaxResult.success(envInspectionService.getById(id)); } @PostMapping("/add") @Log(title = "智能巡检-新增", businessType = BusinessType.INSERT) public AjaxResult add(@RequestBody EnvInspection inspection) { inspection.setId(null); if (inspection.getStatus() == null) { inspection.setStatus(0); } return envInspectionService.save(inspection) ? AjaxResult.success() : AjaxResult.error("新增失败"); } @PostMapping("/update") @Log(title = "智能巡检-修改", businessType = BusinessType.UPDATE) public AjaxResult update(@RequestBody EnvInspection inspection) { return envInspectionService.updateById(inspection) ? AjaxResult.success() : AjaxResult.error("修改失败"); } @DeleteMapping("/delete") @Log(title = "智能巡检-删除", businessType = BusinessType.DELETE) public AjaxResult delete(@RequestBody List ids) { return envInspectionService.removeByIds(ids) ? AjaxResult.success() : AjaxResult.error("删除失败"); } /** * 自动生成巡检报告 */ @GetMapping("/report/{id}") @Log(title = "智能巡检-生成报告", businessType = BusinessType.OTHER) public AjaxResult generateReport(@PathVariable Long id) { return AjaxResult.success((Object) envInspectionService.generateReport(id)); } @PostMapping("/export") public void export(HttpServletResponse response, EnvInspection req) { envInspectionService.export(response, req); } @Value("${envaccess.callback.secret:hbmjxt-callback-2026}") private String callbackSecret; private static final ObjectMapper CALLBACK_MAPPER = new ObjectMapper(); /** * 无人机 / 机器人 / AI 摄像头 巡检数据回传(对外开放接口,供第三方设备调用) * * 请求示例(POST JSON): * { * "secret": "hbmjxt-callback-2026", * "tenantId": 222, * "inspectionId": 3, // 可选,不传则按 area 匹配最近一条未取消任务,再没有就新建 * "area": "东门区域", * "deviceType": "UAV", // UAV 无人机 / ROBOT 机器人 / CAMERA 摄像头 * "deviceCode": "UAV-M350-001", * "collectedAt": "2026-10-24 09:12:35", * "aiSummary": "共识别 5 类目标,发现 1 处未佩戴安全帽", * "aiObjects": [{"object":"人员未佩戴安全帽","conclusion":"未按要求佩戴","confidence":0.93,"frameTime":"2026-10-24 09:12:35"}], * "longitude": 120.382145, "latitude": 31.298512, "altitude": 45.6, "battery": 78, * "photos": ["/profile/upload/uav_east_01.jpg"], * "track": [{"t":"09:12:10","lng":120.3821,"lat":31.2985}] * } */ @Anonymous @PostMapping("/callback") public AjaxResult callback(@RequestBody Map payload) { if (payload == null || payload.isEmpty()) { return AjaxResult.error("回传数据不能为空"); } if (!callbackSecret.equals(String.valueOf(payload.get("secret")))) { return AjaxResult.error("secret 校验失败,请在请求体中携带正确的 secret"); } Long tenantId = toLong(payload.get("tenantId")); if (tenantId == null) { return AjaxResult.error("tenantId 不能为空"); } String area = payload.get("area") == null ? "未指定区域" : String.valueOf(payload.get("area")); String deviceType = payload.get("deviceType") == null ? "UAV" : String.valueOf(payload.get("deviceType")); String deviceCode = payload.get("deviceCode") == null ? deviceType + "-UNKNOWN" : String.valueOf(payload.get("deviceCode")); Map ai = new LinkedHashMap<>(); ai.put("summary", payload.get("aiSummary") == null ? "本次回传未附带 AI 识别结论" : payload.get("aiSummary")); ai.put("objects", payload.get("aiObjects") == null ? new ArrayList<>() : payload.get("aiObjects")); Map uav = new LinkedHashMap<>(); uav.put("deviceType", deviceType); uav.put("deviceCode", deviceCode); uav.put("area", area); uav.put("collectedAt", payload.get("collectedAt") == null ? "" : payload.get("collectedAt")); uav.put("longitude", payload.get("longitude")); uav.put("latitude", payload.get("latitude")); uav.put("altitude", payload.get("altitude")); uav.put("battery", payload.get("battery")); uav.put("photos", payload.get("photos") == null ? new ArrayList<>() : payload.get("photos")); uav.put("track", payload.get("track") == null ? new ArrayList<>() : payload.get("track")); uav.put("receivedAt", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); String aiJson; String uavJson; try { aiJson = CALLBACK_MAPPER.writeValueAsString(ai); uavJson = CALLBACK_MAPPER.writeValueAsString(uav); } catch (Exception e) { return AjaxResult.error("回传数据序列化失败:" + e.getMessage()); } EnvInspection target = null; Long inspectionId = toLong(payload.get("inspectionId")); if (inspectionId != null) { target = envInspectionService.getById(inspectionId); } if (target == null) { com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper w = new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>(); w.eq(EnvInspection::getArea, area).ne(EnvInspection::getStatus, 3) .orderByDesc(EnvInspection::getId).last("limit 1"); target = envInspectionService.getOne(w, false); } boolean created = false; if (target == null) { target = new EnvInspection(); target.setInspectionName(area + " 智能巡检(设备回传)"); target.setInspectionType(2); target.setArea(area); target.setStatus(2); target.setPlanStartTime(new Date()); target.setPlanEndTime(new Date()); target.setActualStartTime(new Date()); target.setActualEndTime(new Date()); target.setInspector(deviceCode); target.setRoutePlan("由 " + deviceType + " 自动规划并执行"); target.setInspectionResult("设备自动巡检已完成,识别结果详见回传数据。"); target.setTenantId(tenantId); created = true; } target.setAiAnalysis(aiJson); target.setUavData(uavJson); if (target.getStatus() != null && target.getStatus() == 0) { target.setStatus(2); } if (target.getTenantId() == null) { target.setTenantId(tenantId); } // 设备回调没有登录上下文,临时跳过租户插件,tenant_id 已在上面显式写入 CustomTenantLineHandler.TEMP_IGNORE.set(Boolean.TRUE); try { if (created) { envInspectionService.save(target); } else { envInspectionService.updateById(target); } } catch (Exception e) { return AjaxResult.error("回传数据落库失败:" + e.getMessage()); } finally { CustomTenantLineHandler.TEMP_IGNORE.remove(); } Map result = new LinkedHashMap<>(); result.put("inspectionId", target.getId()); result.put("created", created); result.put("deviceCode", deviceCode); result.put("deviceType", deviceType); result.put("area", area); return AjaxResult.success("巡检数据回传成功", result); } private Long toLong(Object v) { if (v == null) { return null; } try { return Long.valueOf(String.valueOf(v).trim()); } catch (NumberFormatException e) { return null; } } }