充电和脱离

This commit is contained in:
2026-09-18 16:51:03 +08:00
parent 0bf52a5d55
commit fe56a8ba6d
7 changed files with 768 additions and 13 deletions

View File

@@ -11,7 +11,10 @@ import {
getCurrentRosInspection,
getRosCarList,
getRosInspectionTaskDetail,
startRosCharging,
stopDispatchRosInspectionTask,
undockRosCharging,
type RosChargingResult,
} from "@/api/rosCar";
import { getToken } from "@/utils/auth";
import { parseRosMapYaml } from "@/utils/rosMapYaml";
@@ -42,6 +45,8 @@ interface RosCarRecord {
cameraWebrtcUrl2?: string;
liftHeight?: number;
liftDeviceStatusDescription?: string;
dockStatus?: string;
dockActive?: boolean;
}
interface RosCarListResult {
@@ -69,6 +74,8 @@ interface CarStatusPushData {
mapYamlUrl?: string;
status?: number;
signal?: string;
dockStatus?: string;
dockActive?: boolean;
}
interface CarVelocityPushData {
@@ -115,6 +122,8 @@ interface DeviceItem {
mapYamlUrl: string;
whiteLightUrl: string;
infraredUrl: string;
dockStatus?: string;
dockActive?: boolean;
}
interface ProjectItem {
@@ -195,6 +204,11 @@ interface RosDispatchResultResponse {
msg?: string;
}
interface RosChargingResultResponse {
data?: RosChargingResult;
msg?: string;
}
interface AlertItem {
id: string;
title: string;
@@ -286,6 +300,8 @@ function normalizeDeviceRecord(car: RosCarRecord, index: number): DeviceItem {
mapYamlUrl: car.mapYamlUrl || "",
whiteLightUrl: car.cameraWebrtcUrl || "",
infraredUrl: car.cameraWebrtcUrl2 || "",
dockStatus: car.dockStatus,
dockActive: car.dockActive ?? false,
};
}
@@ -494,6 +510,8 @@ const inspectionTaskId = ref("");
const currentInspection = ref<RosInspectionRecord | null>(null);
const inspectionLoading = ref(false);
const inspectionActionLoading = ref(false);
const chargingActionLoading = ref(false);
const undockingActionLoading = ref(false);
const lastDispatchTime = ref("");
const alertLoading = ref(false);
const alertError = ref("");
@@ -614,6 +632,27 @@ const currentScenario = computed(() => navScenario);
const hasRobotPose = computed(
() => typeof currentRobot.value.poseX === "number" && typeof currentRobot.value.poseY === "number",
);
// 回充状态文案:由 charging_dock 节点的 /dock_status 上报,未上报时给出中性提示
const chargingStatusText = computed(() => {
const device = currentRobot.value;
if (device.dockActive) {
return device.dockStatus || "自动回充进行中";
}
return device.dockStatus || "回充状态未上报";
});
const chargingButtonText = computed(() => {
if (currentRobot.value.dockActive) {
return "回充中...";
}
return chargingActionLoading.value ? "处理中..." : "自动回充";
});
const undockingButtonText = computed(() => {
if (currentRobot.value.dockActive) {
return "处理中...";
}
return undockingActionLoading.value ? "处理中..." : "充电脱离";
});
// 将 ROS 米制坐标转换成地图图片像素坐标,路线和机器人定位共用同一套转换
function rosPoseToMapPoint(poseX: number, poseY: number, poseYaw = 0): RobotMapPoint | null {
@@ -861,6 +900,74 @@ function confirmStopInspection() {
showConfirmDialog("停止巡检", "确认停止当前巡检任务吗?", () => runInspectionAction("stop"));
}
// 手动触发一次自动回充;需要小车在线且车端已启动回充节点
async function runStartCharging() {
const carId = currentRobot.value.carId;
if (!carId) {
window.$message.warning("未获取到小车ID,请先在设备管理中确认小车已保存");
return;
}
chargingActionLoading.value = true;
try {
const response = (await startRosCharging(carId)) as RosChargingResultResponse;
const accepted = response.data?.accepted ?? false;
const message = response.data?.message
|| response.msg
|| (accepted ? "已触发自动回充" : "触发自动回充失败");
if (accepted) {
window.$message.success(message);
} else {
window.$message.warning(message);
}
} catch (error) {
console.error(error);
} finally {
chargingActionLoading.value = false;
}
}
function confirmStartCharging() {
showConfirmDialog("自动回充", "确认让小车执行自动回充吗?", () => runStartCharging());
}
// 手动触发一次脱离充电桩;用于充电完成后手动让小车离开充电桩
async function runUndockCharging() {
const carId = currentRobot.value.carId;
if (!carId) {
window.$message.warning("未获取到小车ID,请先在设备管理中确认小车已保存");
return;
}
undockingActionLoading.value = true;
try {
const response = (await undockRosCharging(carId)) as RosChargingResultResponse;
const accepted = response.data?.accepted ?? false;
const message = response.data?.message
|| response.msg
|| (accepted ? "已触发脱离充电桩" : "触发脱离充电桩失败");
if (accepted) {
window.$message.success(message);
} else {
window.$message.warning(message);
}
} catch (error) {
console.error(error);
} finally {
undockingActionLoading.value = false;
}
}
function confirmUndockCharging() {
showConfirmDialog("充电脱离", "确认让小车脱离充电桩吗?", () => runUndockCharging());
}
// 切换设备时将当前设备已有升降柱高度回显到目标高度输入框
function syncLiftTargetFromDevice(device?: DeviceItem) {
if (!device || device.liftHeight === "--") {
@@ -921,6 +1028,8 @@ function applyCarStatusPush(data: CarStatusPushData) {
poseYaw: typeof data.poseYaw === "number" ? data.poseYaw : currentDevice.poseYaw,
mapPgmUrl: data.mapPgmUrl || currentDevice.mapPgmUrl,
mapYamlUrl: data.mapYamlUrl || currentDevice.mapYamlUrl,
dockStatus: typeof data.dockStatus === "string" ? data.dockStatus : currentDevice.dockStatus,
dockActive: typeof data.dockActive === "boolean" ? data.dockActive : currentDevice.dockActive,
};
projectDevices.value[0].devices.splice(deviceIndex, 1, nextDevice);
@@ -1868,6 +1977,26 @@ function getStatusClass(status: DeviceItem["status"]) {
>
{{ inspectionActionLoading ? "处理中..." : "下发巡检" }}
</button>
<div class="charging-status-row">
<span :class="['charging-status-dot', { active: currentRobot.dockActive }]"></span>
<span class="charging-status-text">{{ chargingStatusText }}</span>
</div>
<button
class="inspection-action-btn charging"
type="button"
:disabled="chargingActionLoading || currentRobot.dockActive"
@click="confirmStartCharging"
>
{{ chargingButtonText }}
</button>
<button
class="inspection-action-btn undock"
type="button"
:disabled="undockingActionLoading || currentRobot.dockActive"
@click="confirmUndockCharging"
>
{{ undockingButtonText }}
</button>
</div>
</div>
</div>