From 8d2e7e1ceeb09d366d2590d7cb29963075aadb22 Mon Sep 17 00:00:00 2001 From: wanxiaoli Date: Wed, 8 Jul 2026 16:14:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E8=AE=BE=E5=A4=87=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=88=A0=E9=99=A4=E4=B8=B4=E7=95=8C=E6=95=B0=E6=8D=AE?= =?UTF-8?q?,bug=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yfd/business/css/build/SimBuilder.java | 2 +- .../controller/CriticalDataController.java | 20 ++++++ .../css/controller/EventController.java | 14 +++++ .../css/controller/SimController.java | 62 ++++++++++++++++++- .../css/service/CriticalDataService.java | 2 + .../service/impl/CriticalDataServiceImpl.java | 8 +++ .../css/service/impl/ProjectServiceImpl.java | 4 +- 7 files changed, 108 insertions(+), 4 deletions(-) diff --git a/business-css/src/main/java/com/yfd/business/css/build/SimBuilder.java b/business-css/src/main/java/com/yfd/business/css/build/SimBuilder.java index 8c9ff1e..3f067a6 100644 --- a/business-css/src/main/java/com/yfd/business/css/build/SimBuilder.java +++ b/business-css/src/main/java/com/yfd/business/css/build/SimBuilder.java @@ -272,7 +272,7 @@ public class SimBuilder { // 简化起见,假设 Event 表中 device_id 有值,或者我们在 buildEvents 时传入 devToMat 映射关系? // Event 表有 device_id 字段,可以直接用。 if ("material".equals(entityType)) { - if (ev.getDeviceId() != null) targetUnitId = ev.getDeviceId(); + if (ev.getDeviceId() != null && !ev.getDeviceId().isBlank()) targetUnitId = ev.getDeviceId().trim(); } SimPropertyKey key = SimPropertyKey.of(targetUnitId, property); diff --git a/business-css/src/main/java/com/yfd/business/css/controller/CriticalDataController.java b/business-css/src/main/java/com/yfd/business/css/controller/CriticalDataController.java index 6ceab11..2e845f6 100644 --- a/business-css/src/main/java/com/yfd/business/css/controller/CriticalDataController.java +++ b/business-css/src/main/java/com/yfd/business/css/controller/CriticalDataController.java @@ -113,6 +113,26 @@ public class CriticalDataController { return criticalDataService.removeByIds(ids); } + @PreAuthorize("hasAuthority('criticalData:del')") + @Log(value = "按设备类型清空临界数据", module = "临界数据管理") + @DeleteMapping("/by-device-type") + public ResponseEntity> deleteByDeviceType(@RequestParam String deviceType, + @RequestParam(defaultValue = "false") boolean confirm) { + if (deviceType == null || deviceType.isBlank()) { + return ResponseEntity.badRequest().body(Map.of("code", 1, "msg", "deviceType不能为空")); + } + if (!confirm) { + return ResponseEntity.badRequest().body(Map.of("code", 1, "msg", "请确认删除:confirm=true")); + } + String dt = deviceType.trim(); + int deleted = criticalDataService.deleteByDeviceType(dt); + return ResponseEntity.ok(Map.of( + "code", 0, + "msg", "清空成功", + "data", Map.of("deviceType", dt, "deleted", deleted) + )); + } + /** * 4. 导入临界数据(Excel) * 输入参数:表单文件字段 file diff --git a/business-css/src/main/java/com/yfd/business/css/controller/EventController.java b/business-css/src/main/java/com/yfd/business/css/controller/EventController.java index a8262d5..4da1003 100644 --- a/business-css/src/main/java/com/yfd/business/css/controller/EventController.java +++ b/business-css/src/main/java/com/yfd/business/css/controller/EventController.java @@ -56,6 +56,8 @@ public class EventController { @PostMapping public ResponseEntity> addEvent(@RequestBody Event event) { assertCanWriteByScenarioId(event.getScenarioId()); + event.setDeviceId(normalizeBlankToNull(event.getDeviceId())); + event.setMaterialId(normalizeBlankToNull(event.getMaterialId())); event.setModifier(currentUsername()); eventService.save(event); Event savedEvent = event; @@ -89,6 +91,8 @@ public class EventController { } assertCanWriteByScenarioId(db.getScenarioId()); } + event.setDeviceId(normalizeBlankToNull(event.getDeviceId())); + event.setMaterialId(normalizeBlankToNull(event.getMaterialId())); event.setModifier(currentUsername()); event.setUpdatedAt(LocalDateTime.now()); return eventService.updateById(event); @@ -133,12 +137,16 @@ public class EventController { } if (event.getEventId() != null && !event.getEventId().isBlank() && exists != null) { // 更新逻辑 + event.setDeviceId(normalizeBlankToNull(event.getDeviceId())); + event.setMaterialId(normalizeBlankToNull(event.getMaterialId())); event.setModifier(currentUser); event.setUpdatedAt(now); eventService.updateById(event); savedEvents.add(event); } else { // 新增逻辑 + event.setDeviceId(normalizeBlankToNull(event.getDeviceId())); + event.setMaterialId(normalizeBlankToNull(event.getMaterialId())); event.setCreatedAt(now); event.setModifier(currentUser); event.setUpdatedAt(now); @@ -440,6 +448,12 @@ public class EventController { return 0.0; } + private String normalizeBlankToNull(String s) { + if (s == null) return null; + String v = s.trim(); + return v.isEmpty() ? null : v; + } + private void assertCanReadByScenarioId(String scenarioId) { if (scenarioId == null || scenarioId.isBlank()) { throw new RuntimeException("scenarioId不能为空"); diff --git a/business-css/src/main/java/com/yfd/business/css/controller/SimController.java b/business-css/src/main/java/com/yfd/business/css/controller/SimController.java index b8d3272..376f466 100644 --- a/business-css/src/main/java/com/yfd/business/css/controller/SimController.java +++ b/business-css/src/main/java/com/yfd/business/css/controller/SimController.java @@ -1,6 +1,7 @@ package com.yfd.business.css.controller; import com.yfd.business.css.build.SimBuilder; +import com.yfd.business.css.domain.Event; import com.yfd.business.css.domain.Scenario; import com.yfd.business.css.domain.ScenarioResult; import com.yfd.business.css.facade.SimDataFacade; @@ -12,6 +13,7 @@ import com.yfd.business.css.service.SimService; import com.yfd.business.css.service.SimInferService; import com.yfd.platform.config.ResponseResult; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factory.annotation.Autowired; import com.yfd.platform.annotation.Log; @@ -39,6 +41,9 @@ public class SimController { @Autowired private ScenarioResultService scenarioResultService; @Autowired private ObjectMapper objectMapper; + private static final int DEFAULT_STEPS = 10; + private static final int MAX_STEPS = 10000; + /** * 执行仿真计算 * @@ -50,7 +55,7 @@ public class SimController { public ResponseResult run(@RequestBody Map req) { String projectId = (String) req.get("projectId"); String scenarioId = (String) req.get("scenarioId"); - int steps = req.containsKey("steps") ? (int) req.get("steps") : 10; + Integer requestedSteps = parseSteps(req.get("steps")); boolean clearResult = Boolean.TRUE.equals(req.get("clearResult")); Scenario sc = scenarioService.getById(scenarioId); @@ -76,6 +81,8 @@ public class SimController { try { // 1. Load Data: 获取项目、设备和事件数据 SimDataPackage data = simDataFacade.loadSimulationData(projectId, scenarioId); + + int steps = resolveSteps(requestedSteps, data.getEvents()); // 2. Build Model: 将原始数据转换为仿真模型 (Units, Events, Nodes) List units = simBuilder.buildUnits(data, materialService); @@ -90,6 +97,7 @@ public class SimController { // 6. Convert Result: 将仿真结果转换为前端友好的格式,包含静态属性补全和元数据 Map resultData = SimResultConverter.toFrames(ctx, units, projectId, scenarioId); + resultData.put("steps", steps); // 为了让前端明确感知推理是否启动成功,这里增加一个状态提示 // 但因为是异步的,我们只能保证“已提交”。真正的成败由 asyncInferAndSave 决定。 @@ -118,6 +126,58 @@ public class SimController { } } + private int resolveSteps(Integer requestedSteps, List events) { + int steps; + if (requestedSteps != null) { + steps = requestedSteps; + } else { + int derived = deriveStepsFromEvents(events); + steps = Math.max(DEFAULT_STEPS, derived); + } + if (steps < 0) steps = DEFAULT_STEPS; + if (steps > MAX_STEPS) steps = MAX_STEPS; + return steps; + } + + private Integer parseSteps(Object raw) { + if (raw == null) return null; + if (raw instanceof Number n) return n.intValue(); + String s = String.valueOf(raw).trim(); + if (s.isEmpty()) return null; + try { + return Integer.parseInt(s); + } catch (Exception e) { + return null; + } + } + + private int deriveStepsFromEvents(List events) { + if (events == null || events.isEmpty()) return 0; + double maxT = 0.0; + for (Event ev : events) { + String json = ev.getAttrChanges(); + if (json == null || json.isBlank()) continue; + double base = ev.getTriggerTime() == null ? 0.0 : ev.getTriggerTime(); + try { + JsonNode root = objectMapper.readTree(json); + JsonNode segments = root.path("segments"); + if (!segments.isArray()) continue; + for (JsonNode seg : segments) { + JsonNode timeline = seg.path("timeline"); + if (!timeline.isArray()) continue; + for (JsonNode p : timeline) { + double t = p.path("t").asDouble(Double.NaN); + if (!Double.isFinite(t)) continue; + maxT = Math.max(maxT, base + t); + } + } + } catch (Exception ignored) { + } + } + if (maxT <= 0) return 0; + return (int) Math.ceil(maxT); + } + private void updateScenarioStatus(String scenarioId, String status, String failDetail) { try { Scenario scenario = new Scenario(); diff --git a/business-css/src/main/java/com/yfd/business/css/service/CriticalDataService.java b/business-css/src/main/java/com/yfd/business/css/service/CriticalDataService.java index e8a58b5..50125ac 100644 --- a/business-css/src/main/java/com/yfd/business/css/service/CriticalDataService.java +++ b/business-css/src/main/java/com/yfd/business/css/service/CriticalDataService.java @@ -20,4 +20,6 @@ public interface CriticalDataService extends IService { byte[] templateCriticalDataV2(String deviceType); + int deleteByDeviceType(String deviceType); + } diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java index a4b02d7..158cbb0 100644 --- a/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java +++ b/business-css/src/main/java/com/yfd/business/css/service/impl/CriticalDataServiceImpl.java @@ -1,5 +1,6 @@ package com.yfd.business.css.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.business.css.domain.CriticalData; import com.yfd.business.css.mapper.CriticalDataMapper; @@ -143,6 +144,13 @@ public class CriticalDataServiceImpl } } + @Override + public int deleteByDeviceType(String deviceType) { + if (deviceType == null || deviceType.isBlank()) return 0; + String dt = deviceType.trim(); + return this.baseMapper.delete(new QueryWrapper().eq("device_type", dt)); + } + private boolean importExcel(Workbook workbook, String deviceType) { try (Workbook wb = workbook) { FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); diff --git a/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java b/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java index fa4459c..6dcc17c 100644 --- a/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java +++ b/business-css/src/main/java/com/yfd/business/css/service/impl/ProjectServiceImpl.java @@ -1576,8 +1576,8 @@ public class ProjectServiceImpl Event ev = new Event(); ev.setEventId(eventId); ev.setScenarioId(cell(df, r, eh.get("scenario_id"))); - ev.setDeviceId(cell(df, r, eh.get("device_id"))); - ev.setMaterialId(cell(df, r, eh.get("material_id"))); + ev.setDeviceId(normalizeJsonText(cell(df, r, eh.get("device_id")))); + ev.setMaterialId(normalizeJsonText(cell(df, r, eh.get("material_id")))); ev.setTriggerTime(parseDoubleObj(cell(df, r, eh.get("trigger_time")))); ev.setAttrChanges(normalizeJsonText(cell(df, r, eh.get("attr_changes")))); ev.setModifier(cell(df, r, eh.get("modifier")));