diff --git a/admin/src/main/java/com/multictrl/common/constant/BusinessConstant.java b/admin/src/main/java/com/multictrl/common/constant/BusinessConstant.java index 65c526a..42fab3f 100644 --- a/admin/src/main/java/com/multictrl/common/constant/BusinessConstant.java +++ b/admin/src/main/java/com/multictrl/common/constant/BusinessConstant.java @@ -53,6 +53,11 @@ public interface BusinessConstant { String FLY_TO_POINT_PROGRESS = "fly_to_point_progress"; String FILE_UPLOAD_CALLBACK = "file_upload_callback"; String FILEUPLOAD_PROGRESS = "fileupload_progress"; + String FLIGHTTASK_READY = "flighttask_ready"; + String RETURN_HOME_INFO = "return_home_info"; + String DEVICE_EXIT_HOMING_NOTIFY = "device_exit_homing_notify"; + String IN_FLIGHT_WAYLINE_PROGRESS = "in_flight_wayline_progress"; + String OBSTACLE_AVOIDANCE_NOTIFY = "obstacle_avoidance_notify"; String OTA_PROGRESS = "ota_progress"; String HMS = "hms"; //********************************* dj status topic method *********************************// diff --git a/admin/src/main/java/com/multictrl/modules/business/controller/FlightTaskController.java b/admin/src/main/java/com/multictrl/modules/business/controller/FlightTaskController.java index 369abaf..fad708a 100644 --- a/admin/src/main/java/com/multictrl/modules/business/controller/FlightTaskController.java +++ b/admin/src/main/java/com/multictrl/modules/business/controller/FlightTaskController.java @@ -83,6 +83,15 @@ public class FlightTaskController { return new Result>().ok(data); } + @GetMapping("/getFlightLog/{taskId}") + @Operation(summary = "飞行日志") + @RequiresPermissions("bus:task:flightLog") + public Result> getFlightLog(@PathVariable("taskId") String taskId) { + List data = flightTaskService.getFlightLog(taskId); + + return new Result>().ok(data); + } + @GetMapping("/getTaskMedia/{taskId}") @Operation(summary = "媒体文件") @RequiresPermissions("bus:task:taskMedia") diff --git a/admin/src/main/java/com/multictrl/modules/business/handler/EventsHandler.java b/admin/src/main/java/com/multictrl/modules/business/handler/EventsHandler.java index 5eb2dc9..7a6d3f4 100644 --- a/admin/src/main/java/com/multictrl/modules/business/handler/EventsHandler.java +++ b/admin/src/main/java/com/multictrl/modules/business/handler/EventsHandler.java @@ -6,15 +6,14 @@ import cn.hutool.json.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.multictrl.common.config.MinioConfig; import com.multictrl.common.constant.BusinessConstant; -import com.multictrl.common.utils.CacheUtils; -import com.multictrl.common.utils.FfmpegUtils; -import com.multictrl.common.utils.JsonUtils; -import com.multictrl.common.utils.Utils; +import com.multictrl.common.utils.*; import com.multictrl.modules.business.dao.HmsDao; import com.multictrl.modules.business.dto.MediaFileDTO; import com.multictrl.modules.business.entity.HmsEntity; import com.multictrl.modules.business.entity.RemoteLogEntity; +import com.multictrl.modules.business.influxdb.FlightLog; import com.multictrl.modules.business.service.CommandService; +import com.multictrl.modules.business.service.InfluxService; import com.multictrl.modules.business.service.MediaFileService; import com.multictrl.modules.business.service.MqttPushService; import com.multictrl.modules.business.service.RemoteLogService; @@ -22,6 +21,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +import java.time.Instant; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Date; @@ -43,6 +43,7 @@ public class EventsHandler implements MessageHandler { private final RemoteLogService remoteLogService; private final MinioConfig minioConfig; private final HmsDao hmsDao; + private final InfluxService influxService; @Override public void handleMessage(String topic, String payload, String gateway) { @@ -89,6 +90,8 @@ public class EventsHandler implements MessageHandler { CacheUtils.set(BusinessConstant.FLIGHT_TASK_PROGRESS_FLIGHT_ID + gateway, ext.getStr("flight_id")); } } + //飞行日志 + saveFlightTaskProgressLog(message, data, gateway); } else if (BusinessConstant.TAKEOFF_TO_POINT_PROGRESS.equals(method)) { log.debug("events --> 一键起飞结果上报: {}", payload); JSONObject data = message.getJSONObject(BusinessConstant.DATA); @@ -193,6 +196,22 @@ public class EventsHandler implements MessageHandler { hmsList.add(hmsEntity); } hmsDao.insert(hmsList); + //飞行日志 + for (HmsEntity hmsEntity : hmsList) { + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(hmsEntity.getDockSn()); + flightLog.setTime(hmsEntity.getReportDate().toInstant()); + flightLog.setMethod("健康告警\n" + BusinessConstant.HMS); + flightLog.setLevel(hmsEntity.getLevel()); + flightLog.setMessage( + "模块: " + hmsEntity.getModule() + "\n" + + "告警码: " + hmsEntity.getCode() + "\n" + + "告警信息: " + HmsUtils.getHmsText(hmsEntity.getCode()) + "\n" + + "设备类型: " + hmsEntity.getDeviceType() + "\n" + + "即时性: " + hmsEntity.getImminent() + "\n" + + "飞行状态: " + hmsEntity.getInTheSky()); + influxService.addRecord(flightLog); + } } } } else if (BusinessConstant.FILEUPLOAD_PROGRESS.equals(method)) { @@ -241,9 +260,368 @@ public class EventsHandler implements MessageHandler { } } else if (BusinessConstant.OTA_PROGRESS.equals(method)) { log.debug("events --> 固件升级进度: {}", payload); + } else if (BusinessConstant.FLIGHTTASK_READY.equals(method)) { + log.debug("events --> 航线任务准备就绪: {}", payload); + JSONObject data = message.getJSONObject(BusinessConstant.DATA); + if (data != null) { + JSONArray flightIds = data.getJSONArray("flight_ids"); + //飞行日志 + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(gateway); + flightLog.setLevel(0); + flightLog.setMethod("任务准备就绪\n" + BusinessConstant.FLIGHTTASK_READY); + flightLog.setTime(Instant.ofEpochMilli(message.getLong("timestamp"))); + flightLog.setMessage("航线任务准备就绪:" + flightIds.toString()); + influxService.addRecord(flightLog); + } + } else if (BusinessConstant.RETURN_HOME_INFO.equals(method)) { + log.debug("events --> 返航信息: {}", payload); + //飞行日志 + JSONObject data = message.getJSONObject(BusinessConstant.DATA); + if (data != null) { + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(gateway); + flightLog.setTime(Instant.ofEpochMilli(message.getLong("timestamp"))); + flightLog.setMethod("返航信息\n" + BusinessConstant.RETURN_HOME_INFO); + flightLog.setLevel(0); + + int lastPointType = data.getInt("last_point_type", -1); + String lastPointTypeCn = lastPointType == 0 ? "轨迹最后一个点在返航点的上空" + : lastPointType == 1 ? "轨迹最后一个点不在返航点上空" : String.valueOf(lastPointType); + + StringBuilder msg = new StringBuilder(); + msg.append("任务ID: ").append(data.getStr("flight_id", "")).append("\n"); + msg.append("最后轨迹点类型: ").append(lastPointTypeCn).append("\n"); + if (data.containsKey("home_dock_sn")) { + msg.append("Home点机场SN: ").append(data.getStr("home_dock_sn")).append("\n"); + } + JSONArray points = data.getJSONArray("planned_path_points"); + if (points != null && !points.isEmpty()) { + msg.append("规划轨迹点(").append(points.size()).append("个):\n"); + for (int i = 0; i < points.size(); i++) { + JSONObject point = points.getJSONObject(i); + msg.append(i + 1).append(". 纬度: ").append(point.getDouble("latitude", 0d)) + .append(" 经度: ").append(point.getDouble("longitude", 0d)) + .append(" 高度: ").append(point.getDouble("height", 0d)).append("m\n"); + } + } + JSONArray homeInfo = data.getJSONArray("multi_dock_home_info"); + if (homeInfo != null && !homeInfo.isEmpty()) { + msg.append("蛙跳任务返航信息:\n"); + for (int i = 0; i < homeInfo.size(); i++) { + JSONObject info = homeInfo.getJSONObject(i); + int planStatus = info.getInt("plan_status", -1); + String planStatusCn = planStatus == 0 ? "规划失败或正在规划中" + : planStatus == 1 ? "规划路径不可达" + : planStatus == 2 ? "规划路径因电量不可达" + : planStatus == 3 ? "目标可达" : String.valueOf(planStatus); + msg.append(" 机场SN: ").append(info.getStr("sn", "")).append("\n"); + msg.append(" 路径规划状态: ").append(planStatusCn).append("\n"); + msg.append(" 预估电量消耗: ").append(info.getInt("estimated_battery_consumption", 0)).append("%\n"); + msg.append(" Home点距离: ").append(info.getDouble("home_distance", 0d)).append("m\n"); + } + } + flightLog.setMessage(msg.toString()); + influxService.addRecord(flightLog); + } + } else if (BusinessConstant.DEVICE_EXIT_HOMING_NOTIFY.equals(method)) { + log.debug("events --> 设备返航退出状态通知: {}", payload); + JSONObject data = message.getJSONObject(BusinessConstant.DATA); + //飞行日志 + if (data != null) { + Long timestamp = message.getLong("timestamp"); + String dockSn = data.getStr("sn"); + String action = data.getInt("action") == 0 ? "退出返航退出状态" : "进入返航退出状态"; + Integer reason = data.getInt("reason"); + String reasonCn = switch (reason) { + case 0 -> "操纵杆油门添加"; + case 1 -> "操纵杆间距添加"; + case 2 -> "行为树初始化失败"; + case 3 -> "被障碍物包围"; + case 4 -> "触发限飞限制"; + case 5 -> "障碍物距离太近"; + case 6 -> "无 GPS 信号"; + case 7 -> "GPS 和 VIO 位置输出标志为 false"; + case 8 -> "GPS 和 VIO 融合位置误差太大"; + case 9 -> "短距离回溯"; + case 10 -> "近距离触发返航"; + default -> reason + ""; + }; + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(dockSn); + flightLog.setLevel(0); + flightLog.setTime(Instant.ofEpochMilli(timestamp)); + flightLog.setMethod("设备返航退出状态通知\n" + BusinessConstant.DEVICE_EXIT_HOMING_NOTIFY); + flightLog.setMessage( + "消息类型: " + action + "\n" + + "退出返航原因: " + reasonCn + ); + } + } else if (BusinessConstant.IN_FLIGHT_WAYLINE_PROGRESS.equals(method)) { + log.debug("events --> 空中下发航线状态上报: {}", payload); + String inFlightWaylineId = message.getStr("in_flight_wayline_id"); + Integer percent = null; + JSONObject progress = message.getJSONObject("progress"); + if (progress != null) { + percent = progress.getInt("percent"); + } + Integer status = message.getInt("status"); + String statusCn = switch (status) { + case 1 -> "上传文件中"; + case 2 -> "文件上传成功"; + case 3 -> "执行任务中"; + case 4 -> "任务暂停"; + case 5 -> "任务取消"; + case 6 -> "任务成功"; + case 7 -> "任务失败"; + case 8 -> "任务超时"; + default -> status + ""; + }; + Integer result = message.getInt("result"); + Integer wayPointIndex = message.getInt("way_point_index"); + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(gateway); + flightLog.setLevel(0); + flightLog.setMethod("空中下发航线状态上报\n" + BusinessConstant.IN_FLIGHT_WAYLINE_PROGRESS); + flightLog.setMessage( + "航线任务ID: " + inFlightWaylineId + "\n" + + "任务进度: " + percent + "\n" + + "任务状态: " + statusCn + "\n" + + "错误原因码: " + result + "\n" + + "当前航点索引: " + wayPointIndex + ); + influxService.addRecord(flightLog); + }else if(BusinessConstant.OBSTACLE_AVOIDANCE_NOTIFY.equals(method)){ + log.debug("events --> 避障记录上报事件通知: {}", payload); + //飞行日志 + JSONObject data = message.getJSONObject(BusinessConstant.DATA); + if (data != null) { + String waylineUuid = data.getStr("wayline_uuid", ""); + String flightId = data.getStr("flight_id", ""); + boolean isFinalReport = data.getBool("is_final_report", false); + JSONArray obstacles = data.getJSONArray("obstacles"); + StringBuilder msg = new StringBuilder(); + msg.append("航线ID: ").append(waylineUuid).append("\n"); + msg.append("任务ID: ").append(flightId).append("\n"); + if (obstacles != null && !obstacles.isEmpty()) { + msg.append("避障记录(").append(obstacles.size()).append("条):\n"); + for (int i = 0; i < obstacles.size(); i++) { + JSONObject obstacle = obstacles.getJSONObject(i); + int type = obstacle.getInt("type", -1); + String typeCn = switch (type) { + case 0 -> "绕行开始(飞控映射到航线上)"; + case 1 -> "绕行结束(飞控映射到航线上)"; + case 2 -> "避障刹停(真实物理坐标)"; + default -> String.valueOf(type); + }; + msg.append(i + 1).append(". 障碍物ID: ").append(obstacle.getInt("id", -1)) + .append(" 类型: ").append(typeCn) + .append(" 时间戳: ").append(obstacle.getLong("timestamp", 0L)) + .append("\n 纬度: ").append(obstacle.getDouble("latitude", 0d)) + .append(" 经度: ").append(obstacle.getDouble("longitude", 0d)) + .append(" 高度: ").append(obstacle.getDouble("height", 0d)).append("m") + .append("\n 航段ID: ").append(obstacle.getInt("wayline_id", -1)) + .append(" 航点索引: ").append(obstacle.getInt("waypoint_index", -1)) + .append("\n"); + } + } + msg.append("是否最后一条: ").append(isFinalReport ? "是" : "否"); + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(gateway); + flightLog.setLevel(0); + flightLog.setMethod("避障记录上报\n" + BusinessConstant.OBSTACLE_AVOIDANCE_NOTIFY); + flightLog.setTime(Instant.ofEpochMilli(message.getLong("timestamp"))); + flightLog.setMessage(msg.toString()); + influxService.addRecord(flightLog); + } } } else { log.debug("events --> payload解析失败,解析后为null"); } } + + /** + * 保存航线任务进度飞行日志 + */ + private void saveFlightTaskProgressLog(JSONObject message, JSONObject data, String gateway) { + if (data == null || !data.containsKey("output")) { + return; + } + JSONObject output = data.getJSONObject("output"); + FlightLog flightLog = new FlightLog(); + flightLog.setDockSn(gateway); + flightLog.setTime(Instant.ofEpochMilli(message.getLong("timestamp"))); + flightLog.setMethod("航线任务进度\n" + BusinessConstant.FLIGHTTASK_PROGRESS); + flightLog.setLevel(0); + + String status = output.getStr("status", ""); + String statusCn = switch (status) { + case "canceled" -> "取消或终止"; + case "failed" -> "失败"; + case "in_progress" -> "执行中"; + case "ok" -> "执行成功"; + case "partially_done" -> "部分完成"; + case "paused" -> "暂停"; + case "rejected" -> "拒绝"; + case "sent" -> "已下发"; + case "timeout" -> "超时"; + default -> status; + }; + int currentStep = -1, percent = -1; + if (output.containsKey("progress")) { + JSONObject progress = output.getJSONObject("progress"); + currentStep = progress.getInt("current_step", -1); + percent = progress.getInt("percent", -1); + } + String[] stepCn = { + "初始状态", "启动前检查,飞行器是否在执行航线中", "启动前检查,机场是否退出工作模式", + "启动前检查,航线执行中", "启动前检查,返航中", "航线执行进入准备状态,开始等待任务下发", + "机场进入工作状态", "进入开机检查准备工作和开盖准备工作", "图传远程对频", + "等待飞行系统准备就绪,推送连接建立", "等待 RTK 源监听有值上报", + "检查 RTK 源是否是机场源,如果不是要重新设置", "等待飞行控制权通知", + "机场无控制权,抢夺飞行器控制权", "自定义飞行区一致性检查", "离线地图一致性检查", + "获取最新 KMZ URL", "下载 KMZ", "KMZ 上传中", "染色配置", + "飞行器起飞参数设置,备降点设置,起飞高度设置,染色设置", + "飞行器 flyto 起飞参数设置", "起飞机场检查降落机场准备状态", "Home 点设置", + "触发执行航线", "航线执行中", "进入返航的检查准备工作", "飞行器降落机场", + "降落以后的关盖", "机场退出工作模式", "机场异常恢复", "机场上传飞行系统日志", + "相机录像状态检查", "获取媒体文件数量", "机场起飞开盖的异常恢复", "通知任务结果", + "日志列表拉取 - 飞行器列表", "日志列表拉取 - 拉取机场列表", + "日志列表拉取 - 上传日志列表结果", "日志拉取-拉取飞行器日志", + "日志拉取-拉取机场日志", "日志拉取-压缩飞行器日志", "日志拉取-压缩机场日志", + "日志拉取-上传飞行器日志", "日志拉取-上传机场日志", "日志拉取-通知结果", + "自定义飞行区文件更新准备中", "自定义飞行区更新中", "离线地图更新准备中", "离线地图更新中" + }; + String stepStr = currentStep >= 0 && currentStep < stepCn.length ? stepCn[currentStep] : String.valueOf(currentStep); + + StringBuilder msg = new StringBuilder(); + msg.append("任务状态: ").append(statusCn).append("\n"); + msg.append("执行步骤: ").append(stepStr).append("\n"); + msg.append("进度: ").append(percent).append("%\n"); + if (output.containsKey("ext")) { + JSONObject ext = output.getJSONObject("ext"); + int missionState = ext.getInt("wayline_mission_state", -1); + String[] missionStateCn = {"断连", "不支持该航点", "航线准备状态", "航线文件上传中", + "触发开始命令", "进入航线", "航线执行", "航线中断", "航线恢复", "航线停止"}; + msg.append("航线任务状态: ").append(missionState >= 0 && missionState < missionStateCn.length ? missionStateCn[missionState] : missionState).append("\n"); + msg.append("当前航点: ").append(ext.getInt("current_waypoint_index", -1)).append("\n"); + msg.append("航线ID: ").append(ext.getInt("wayline_id", -1)).append("\n"); + msg.append("任务ID: ").append(ext.getStr("flight_id", "")).append("\n"); + msg.append("航迹ID: ").append(ext.getStr("track_id", "")).append("\n"); + msg.append("媒体文件数: ").append(ext.getInt("media_count", 0)).append("\n"); + if (ext.containsKey("break_point")) { + appendBreakPointInfo(msg, ext.getJSONObject("break_point")); + } + } + flightLog.setMessage(msg.toString()); + influxService.addRecord(flightLog); + } + + /** + * 拼接断点信息 + */ + private void appendBreakPointInfo(StringBuilder msg, JSONObject bp) { + int bpState = bp.getInt("state", -1); + int breakReason = bp.getInt("break_reason", 0); + msg.append("断点信息:\n"); + msg.append(" 断点序号: ").append(bp.getInt("index", -1)).append("\n"); + msg.append(" 断点状态: ").append(bpState == 0 ? "在航段上" : bpState == 1 ? "在航点上" : bpState).append("\n"); + msg.append(" 航段进度: ").append(bp.getDouble("progress", 0d)).append("\n"); + msg.append(" 航线ID: ").append(bp.getInt("wayline_id", -1)).append("\n"); + msg.append(" 中断原因: ").append(getBreakReasonCn(breakReason)).append("\n"); + msg.append(" 纬度: ").append(bp.getDouble("latitude", 0d)).append("\n"); + msg.append(" 经度: ").append(bp.getDouble("longitude", 0d)).append("\n"); + msg.append(" 高度: ").append(bp.getDouble("height", 0d)).append("m\n"); + msg.append(" 偏航角: ").append(bp.getDouble("attitude_head", 0d)); + } + + /** + * 中断原因枚举转中文 + */ + private static String getBreakReasonCn(int breakReason) { + return switch (breakReason) { + case 0 -> "无异常"; + case 1 -> "Mission ID 不存在,该航线任务未执行"; + case 2 -> "不常见错误,建议联系技术支持"; + case 4 -> "请求开始/恢复航线任务时,航线文件加载出错,请重新尝试上传文件开始或联系技术支持"; + case 5 -> "请求查询断点信息时,查询断点文件失败。请求恢复航线任务时,解析断点类型失败"; + case 6 -> "请求开始/结束航线任务时,cmd参数有误,协议请求的指令有误。请求恢复航线任务时,解析断点类型失败"; + case 7 -> "请求开始/恢复航线任务时,解析 wpmz 文件超时,请重试"; + case 257 -> "航线已经开始,不能再次开始"; + case 258 -> "此状态下无法中断航线,只允许在航线执行状态时暂停航线"; + case 259 -> "航线未开始,不能结束航线"; + case 261 -> "飞行任务冲突,无法获取飞行器控制权,不允许在降落和返航中开始航线"; + case 262 -> "该状态下无法恢复航线,只允许在航线暂停状态时恢复航线"; + case 513 -> "飞行器超过限高高度"; + case 514 -> "飞行器超过限远距离"; + case 515 -> "航线穿过限飞区,机场无法执行飞行任务"; + case 516 -> "飞行器触发限低"; + case 517 -> "飞行器触发避障"; + case 518 -> "RTK 信号差"; + case 519 -> "接近禁飞区边界"; + case 521 -> "超过机场限飞区限高"; + case 522 -> "航线请求起飞失败"; + case 523 -> "起飞任务执行失败"; + case 524 -> "请求航线任务失败"; + case 526 -> "请求航线 RTK 收敛任务失败"; + case 527 -> "航线 RTK 收敛任务运行失败"; + case 769 -> "GPS 信号弱"; + case 770 -> "遥控器档位不在 N 档"; + case 771 -> "返航点未刷新"; + case 772 -> "当前电量过低无法开始任务"; + case 773 -> "低电量返航导致航线中断"; + case 775 -> "遥控器与飞行器失联"; + case 778 -> "飞行器在地面起桨,不允许开始航线"; + case 779 -> "实时仿地过程中,相机状态异常(如过亮,过暗,两侧亮度不一致)"; + case 780 -> "实时仿地用户设置的仿地高度不合法(大于 200 m 或者小于 30 m)"; + case 781 -> "实时仿地过程中全局地图计算出错"; + case 784 -> "大风返航导致航线中断"; + case 1281 -> "用户退出"; + case 1282 -> "用户中断"; + case 1283 -> "用户触发返航"; + case 1539 -> "开始信息(航点 index 或者 progress)错误"; + case 1540 -> "使用不支持的坐标系"; + case 1541 -> "使用不支持的高度模式"; + case 1542 -> "使用不支持的过渡航线模式"; + case 1543 -> "使用不支持的 yaw 模式"; + case 1544 -> "使用不支持的 yaw 方向调转模式"; + case 1545 -> "使用不支持的航点类型"; + case 1546 -> "首尾点不能使用协调转弯类型"; + case 1547 -> "航线全局速度超过合理范围"; + case 1548 -> "航点数量异常"; + case 1549 -> "经纬度数据异常"; + case 1550 -> "转弯截距异常"; + case 1551 -> "航段最大速度超过合理范围"; + case 1552 -> "航段目标速度超过合理范围"; + case 1553 -> "航点 yaw 角度超过合理范围"; + case 1555 -> "断点续飞的 mission_id 输入错误"; + case 1556 -> "断点续飞的 progress 信息输入错误"; + case 1557 -> "断点续飞的任务状态异常"; + case 1558 -> "断点续飞的航点 index 信息输入错误"; + case 1559 -> "断点续飞的经纬度信息输入错误"; + case 1560 -> "断点续飞的航点 yaw 输入错误"; + case 1561 -> "断点续飞的标志位设置错误"; + case 1563 -> "航线生成失败"; + case 1564 -> "航线运行失败"; + case 1565 -> "航线避障紧急刹停"; + case 1588 -> "无法识别的动作类型"; + case 1595 -> "动作 ID 不能重复"; + case 1598 -> "动作 ID 值不能为 65535"; + case 1602 -> "动作组数量超过合理范围"; + case 1603 -> "动作组生效范围错误"; + case 1606 -> "断点续飞中动作 index 超过合理范围"; + case 1608 -> "断点信息中触发器运行结果异常"; + case 1609 -> "断点续飞中动作组 ID 信息不能重复"; + case 1610 -> "断点续飞中动作组位置不能重复"; + case 1611 -> "断点续飞中动作组位置超过合理范围"; + case 1612 -> "续飞中动作 ID 不在断点信息中"; + case 1613 -> "断点续飞中不能修改动作状态为中断"; + case 1614 -> "断点信息错误导致续飞失败"; + case 1634 -> "无法识别的动作类型"; + case 1649 -> "无法识别的触发器类型"; + case 65534 -> "未知内部错误"; + case 65535 -> "未知内部错误"; + default -> String.valueOf(breakReason); + }; + } } diff --git a/admin/src/main/java/com/multictrl/modules/business/influxdb/FlightLog.java b/admin/src/main/java/com/multictrl/modules/business/influxdb/FlightLog.java new file mode 100644 index 0000000..1a894c9 --- /dev/null +++ b/admin/src/main/java/com/multictrl/modules/business/influxdb/FlightLog.java @@ -0,0 +1,51 @@ +package com.multictrl.modules.business.influxdb; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.influxdb.annotations.Column; +import com.influxdb.annotations.Measurement; +import com.multictrl.common.utils.DateUtils; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.Instant; + +/** + * 飞行日志 + * + * @author Sdy + * @since 1.0.0 2026/6/1 + */ +@Data +@Schema(name = "飞行日志") +@Measurement(name = "flight_log") +public class FlightLog { + + @Schema(description = "主控sn") + @Column(tag = true) + private String dockSn; + + @Schema(hidden = true) + @Column(timestamp = true) + @JsonProperty("_time") + private Instant time; + + @Column + private String method; + + //{"0":"通知","1":"提醒","2":"警告"} + @Column + private Integer level; + + @Column + private String message; + + /** + * 时间字符串 + */ + private String timeStr; + + public void setTime(Instant time) { + this.time = time; + this.timeStr = DateUtils.utcToTime(time); + } +} diff --git a/admin/src/main/java/com/multictrl/modules/business/service/FlightTaskService.java b/admin/src/main/java/com/multictrl/modules/business/service/FlightTaskService.java index 946ac9f..ba51bda 100644 --- a/admin/src/main/java/com/multictrl/modules/business/service/FlightTaskService.java +++ b/admin/src/main/java/com/multictrl/modules/business/service/FlightTaskService.java @@ -39,6 +39,9 @@ public interface FlightTaskService extends CrudService getFlightTrack(String taskId); + //获取飞行日志 + List getFlightLog(String taskId); + //获取架次媒体 List getTaskMedia(String taskId); diff --git a/admin/src/main/java/com/multictrl/modules/business/service/impl/FlightTaskServiceImpl.java b/admin/src/main/java/com/multictrl/modules/business/service/impl/FlightTaskServiceImpl.java index e54ec9c..e9fce75 100644 --- a/admin/src/main/java/com/multictrl/modules/business/service/impl/FlightTaskServiceImpl.java +++ b/admin/src/main/java/com/multictrl/modules/business/service/impl/FlightTaskServiceImpl.java @@ -273,6 +273,26 @@ public class FlightTaskServiceImpl extends CrudServiceImpl getFlightLog(String taskId) { + FlightTaskEntity entity = selectById(taskId); + if (entity == null) { + throw new RenException(ErrorCode.ROUTE_TASK_NOT_EXIST); + } + Date outboundDate = entity.getOutboundDate(); + Date inboundDate = entity.getInboundDate(); + String dockSn = entity.getDockSn(); + if (outboundDate == null || inboundDate == null || StrUtil.isBlank(dockSn)) { + return List.of(); + } + HashMap condition = Maps.newHashMap(); + condition.put("dockSn", dockSn); + + return influxService.queryData(DateUtils.format(outboundDate, DateUtils.DATE_TIME_PATTERN), + DateUtils.format(inboundDate, DateUtils.DATE_TIME_PATTERN), "flight_log", condition, JSONObject.class, + "dockSn", "_time", "method", "level", "message"); + } + @Override public List getTaskMedia(String taskId) { Map params = new HashMap<>();