Skip to content

Commit 60c87d2

Browse files
committed
feat(menu): 新增菜单结构迁移 SQL 脚本
配合前端菜单重构,新增数据库迁移脚本: - v3.0_nav_restructure.sql: 初始菜单结构(部署/运维/运营分析) - v3.2_ops_grouping.sql: 运维管理子目录(已标记废弃) - v3.3_fix_ops_nesting.sql: 修复运维管理双层嵌套 - v3.4_system_restructure.sql: 系统管理/系统监控子目录 - v3.5_component_paths.sql: 组件路径更新(配合前端目录重构)
1 parent c8dcad4 commit 60c87d2

12 files changed

Lines changed: 524 additions & 1 deletion

opentcs-applications/opentcs-vehicle/src/main/java/org/opentcs/vehicle/application/VehicleApplicationService.java

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77
import org.opentcs.driver.api.dto.VehicleStatus;
88
import org.opentcs.driver.registry.DriverRegistry;
99
import org.opentcs.kernel.api.OrderLifecycleApi;
10-
import org.opentcs.kernel.api.dto.OrderStateDTO;
1110
import org.opentcs.kernel.api.dto.PositionDTO;
1211
import org.opentcs.kernel.api.dto.TransportOrderDTO;
1312
import org.opentcs.kernel.api.dto.VehicleDTO;
1413
import org.opentcs.vehicle.application.bo.VehicleBO;
1514
import org.opentcs.vehicle.application.bo.VehicleCrudBO;
15+
import org.opentcs.vehicle.application.bo.OpsActionResultBO;
1616
import org.opentcs.kernel.application.TransportOrderRegistry;
1717
import org.opentcs.kernel.application.VehicleRegistry;
1818
import org.opentcs.kernel.domain.order.TransportOrder;
1919
import org.opentcs.kernel.domain.vehicle.Vehicle;
2020
import org.opentcs.kernel.domain.vehicle.VehiclePosition;
2121
import org.opentcs.kernel.domain.vehicle.VehicleState;
22+
import org.opentcs.vehicle.controller.req.GoChargeRequest;
23+
import org.opentcs.vehicle.controller.req.MapSwitchRequest;
24+
import org.opentcs.vehicle.controller.req.ModeSwitchRequest;
25+
import org.opentcs.vehicle.controller.req.MoveRequest;
2226
import org.opentcs.vehicle.persistence.entity.VehicleEntity;
2327
import org.opentcs.vehicle.persistence.service.VehicleRepository;
2428

@@ -28,10 +32,13 @@
2832
import org.springframework.transaction.annotation.Transactional;
2933

3034
import jakarta.annotation.PostConstruct;
35+
import java.time.LocalDateTime;
3136
import java.util.ArrayList;
3237
import java.util.HashMap;
3338
import java.util.List;
3439
import java.util.Map;
40+
import java.util.UUID;
41+
import java.util.concurrent.CopyOnWriteArrayList;
3542
import java.util.stream.Collectors;
3643

3744
/**
@@ -48,6 +55,7 @@ public class VehicleApplicationService {
4855
private final TransportOrderRegistry orderRegistry;
4956
private final OrderLifecycleApi orderLifecycleApi;
5057
private final DriverRegistry driverRegistry;
58+
private final List<Map<String, Object>> opsActionRecords = new CopyOnWriteArrayList<>();
5159

5260
/**
5361
* 启动时向驱动层注册状态监听器,自动检测订单完成事件。
@@ -242,6 +250,121 @@ public void sendInstantAction(String vehicleId, InstantAction action) {
242250
log.info("即时动作已发送到车辆 {}: {}", vehicleId, action.getActionType());
243251
}
244252

253+
public OpsActionResultBO switchMode(String vehicleName, ModeSwitchRequest request) {
254+
String targetMode = request.getTargetMode() == null ? "AUTOMATIC" : request.getTargetMode().toUpperCase();
255+
String actionType = "AUTOMATIC".equals(targetMode) ? "RESUME" : "PAUSE";
256+
257+
Map<String, String> params = new HashMap<>();
258+
params.put("targetMode", targetMode);
259+
params.put("executePolicy", nvl(request.getExecutePolicy(), "REJECT_IF_BUSY"));
260+
params.put("reason", nvl(request.getReason(), ""));
261+
return executeOpsAction(vehicleName, "MODE_SWITCH", actionType, params);
262+
}
263+
264+
public OpsActionResultBO switchMap(String vehicleName, MapSwitchRequest request) {
265+
Map<String, String> params = new HashMap<>();
266+
params.put("targetMapId", nvl(request.getTargetMapId(), ""));
267+
params.put("targetMapVersion", nvl(request.getTargetMapVersion(), ""));
268+
params.put("initPosition", nvl(request.getInitPosition(), ""));
269+
params.put("fallbackMapId", nvl(request.getFallbackMapId(), ""));
270+
return executeOpsAction(vehicleName, "MAP_SWITCH", "enableMap", params);
271+
}
272+
273+
public OpsActionResultBO goCharge(String vehicleName, GoChargeRequest request) {
274+
Map<String, String> params = new HashMap<>();
275+
params.put("chargePolicy", nvl(request.getChargePolicy(), "NEAREST"));
276+
params.put("stationId", nvl(request.getStationId(), ""));
277+
params.put("interruptPolicy", nvl(request.getInterruptPolicy(), "WAIT_CURRENT_TASK"));
278+
if (request.getMinSocThreshold() != null) {
279+
params.put("minSocThreshold", String.valueOf(request.getMinSocThreshold()));
280+
}
281+
return executeOpsAction(vehicleName, "GO_CHARGE", "CHARGE", params);
282+
}
283+
284+
public OpsActionResultBO moveVehicle(String vehicleName, MoveRequest request) {
285+
String moveType = nvl(request.getMoveType(), "MOVE_TO_NODE");
286+
Map<String, String> params = new HashMap<>();
287+
params.put("moveType", moveType);
288+
params.put("targetNodeId", nvl(request.getTargetNodeId(), ""));
289+
params.put("mapId", nvl(request.getMapId(), ""));
290+
params.put("confirmRisk", String.valueOf(Boolean.TRUE.equals(request.getConfirmRisk())));
291+
if (request.getX() != null) {
292+
params.put("x", String.valueOf(request.getX()));
293+
}
294+
if (request.getY() != null) {
295+
params.put("y", String.valueOf(request.getY()));
296+
}
297+
if (request.getTheta() != null) {
298+
params.put("theta", String.valueOf(request.getTheta()));
299+
}
300+
301+
String actionType = "INIT_POSITION".equalsIgnoreCase(moveType) ? "initPosition" : "MOVE";
302+
return executeOpsAction(vehicleName, "MOVE", actionType, params);
303+
}
304+
305+
public Map<String, Object> precheck(String vehicleName, String actionType) {
306+
Map<String, Object> result = new HashMap<>();
307+
boolean online = vehicleRegistry.isOnline(vehicleName);
308+
Vehicle vehicle = vehicleRegistry.getVehicleDomain(vehicleName);
309+
310+
result.put("vehicleName", vehicleName);
311+
result.put("actionType", actionType);
312+
result.put("online", online);
313+
result.put("state", vehicle == null ? "UNKNOWN" : vehicle.getState().name());
314+
result.put("allow", online);
315+
result.put("reasonCode", online ? null : "OPS_AMR_001");
316+
result.put("reasonMessage", online ? null : "车辆离线,禁止执行运维动作");
317+
return result;
318+
}
319+
320+
public List<Map<String, Object>> listOpsActionRecords(String vehicleName) {
321+
if (vehicleName == null || vehicleName.isBlank()) {
322+
return new ArrayList<>(opsActionRecords);
323+
}
324+
return opsActionRecords.stream()
325+
.filter(record -> vehicleName.equals(record.get("vehicleName")))
326+
.collect(Collectors.toList());
327+
}
328+
329+
private OpsActionResultBO executeOpsAction(String vehicleName,
330+
String actionCategory,
331+
String actionType,
332+
Map<String, String> parameters) {
333+
if (!vehicleRegistry.isOnline(vehicleName)) {
334+
throw new RuntimeException("车辆离线: " + vehicleName);
335+
}
336+
337+
String actionId = "OPS-" + System.currentTimeMillis();
338+
String traceId = UUID.randomUUID().toString().replace("-", "");
339+
340+
InstantAction action = new InstantAction(actionId, actionType);
341+
action.setParameters(parameters);
342+
driverRegistry.sendInstantAction(vehicleName, action);
343+
344+
Map<String, Object> record = new HashMap<>();
345+
record.put("actionId", actionId);
346+
record.put("traceId", traceId);
347+
record.put("vehicleName", vehicleName);
348+
record.put("actionCategory", actionCategory);
349+
record.put("actionType", actionType);
350+
record.put("requestPayload", parameters);
351+
record.put("executeStatus", "ACCEPTED");
352+
record.put("operatedAt", LocalDateTime.now().toString());
353+
opsActionRecords.add(0, record);
354+
355+
OpsActionResultBO result = new OpsActionResultBO();
356+
result.setActionId(actionId);
357+
result.setAccepted(true);
358+
result.setStatus("PENDING");
359+
result.setTraceId(traceId);
360+
result.setEstimatedFinishTime(LocalDateTime.now().plusMinutes(1).toString());
361+
return result;
362+
}
363+
364+
private String nvl(String value, String defaultValue) {
365+
return value == null || value.isBlank() ? defaultValue : value;
366+
}
367+
245368
/**
246369
* 处理车辆状态变更(从驱动层回调)
247370
*/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.opentcs.vehicle.application.bo;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class OpsActionResultBO {
7+
8+
private String actionId;
9+
private Boolean accepted;
10+
private String status;
11+
private String reasonCode;
12+
private String reasonMessage;
13+
private String traceId;
14+
private String estimatedFinishTime;
15+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package org.opentcs.vehicle.controller;
2+
3+
import lombok.RequiredArgsConstructor;
4+
import org.opentcs.common.core.domain.R;
5+
import org.opentcs.vehicle.application.VehicleApplicationService;
6+
import org.opentcs.vehicle.application.bo.OpsActionResultBO;
7+
import org.opentcs.vehicle.controller.req.GoChargeRequest;
8+
import org.opentcs.vehicle.controller.req.MapSwitchRequest;
9+
import org.opentcs.vehicle.controller.req.ModeSwitchRequest;
10+
import org.opentcs.vehicle.controller.req.MoveRequest;
11+
import org.springframework.web.bind.annotation.*;
12+
13+
import java.util.List;
14+
import java.util.Map;
15+
16+
@RestController
17+
@RequestMapping("/ops/amr")
18+
@RequiredArgsConstructor
19+
public class OpsAmrController {
20+
21+
private final VehicleApplicationService vehicleApplicationService;
22+
23+
@PostMapping("/{vehicleName}/mode/switch")
24+
public R<OpsActionResultBO> switchMode(@PathVariable String vehicleName, @RequestBody ModeSwitchRequest request) {
25+
return R.ok(vehicleApplicationService.switchMode(vehicleName, request));
26+
}
27+
28+
@PostMapping("/{vehicleName}/map/switch")
29+
public R<OpsActionResultBO> switchMap(@PathVariable String vehicleName, @RequestBody MapSwitchRequest request) {
30+
return R.ok(vehicleApplicationService.switchMap(vehicleName, request));
31+
}
32+
33+
@PostMapping("/{vehicleName}/charge/go")
34+
public R<OpsActionResultBO> goCharge(@PathVariable String vehicleName, @RequestBody GoChargeRequest request) {
35+
return R.ok(vehicleApplicationService.goCharge(vehicleName, request));
36+
}
37+
38+
@PostMapping("/{vehicleName}/move")
39+
public R<OpsActionResultBO> moveVehicle(@PathVariable String vehicleName, @RequestBody MoveRequest request) {
40+
return R.ok(vehicleApplicationService.moveVehicle(vehicleName, request));
41+
}
42+
43+
@GetMapping("/{vehicleName}/precheck")
44+
public R<Map<String, Object>> precheck(@PathVariable String vehicleName, @RequestParam String actionType) {
45+
return R.ok(vehicleApplicationService.precheck(vehicleName, actionType));
46+
}
47+
48+
@GetMapping("/actions")
49+
public R<List<Map<String, Object>>> listActionRecords(@RequestParam(required = false) String vehicleName) {
50+
return R.ok(vehicleApplicationService.listOpsActionRecords(vehicleName));
51+
}
52+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.opentcs.vehicle.controller.req;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class GoChargeRequest {
7+
8+
private String chargePolicy;
9+
private String stationId;
10+
private String interruptPolicy;
11+
private Integer minSocThreshold;
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.opentcs.vehicle.controller.req;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class MapSwitchRequest {
7+
8+
private String targetMapId;
9+
private String targetMapVersion;
10+
private String initPosition;
11+
private String fallbackMapId;
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.opentcs.vehicle.controller.req;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class ModeSwitchRequest {
7+
8+
private String targetMode;
9+
private String executePolicy;
10+
private String reason;
11+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.opentcs.vehicle.controller.req;
2+
3+
import lombok.Data;
4+
5+
@Data
6+
public class MoveRequest {
7+
8+
private String moveType;
9+
private String targetNodeId;
10+
private String mapId;
11+
private Double x;
12+
private Double y;
13+
private Double theta;
14+
private Boolean confirmRisk;
15+
}

0 commit comments

Comments
 (0)