根据设备类型删除临界数据,bug修改

This commit is contained in:
wanxiaoli 2026-07-08 16:14:50 +08:00
parent 6a27d4d7d0
commit 8d2e7e1cee
7 changed files with 108 additions and 4 deletions

View File

@ -272,7 +272,7 @@ public class SimBuilder {
// 简化起见假设 Event 表中 device_id 有值或者我们在 buildEvents 时传入 devToMat 映射关系? // 简化起见假设 Event 表中 device_id 有值或者我们在 buildEvents 时传入 devToMat 映射关系?
// Event 表有 device_id 字段可以直接用 // Event 表有 device_id 字段可以直接用
if ("material".equals(entityType)) { 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); SimPropertyKey key = SimPropertyKey.of(targetUnitId, property);

View File

@ -113,6 +113,26 @@ public class CriticalDataController {
return criticalDataService.removeByIds(ids); return criticalDataService.removeByIds(ids);
} }
@PreAuthorize("hasAuthority('criticalData:del')")
@Log(value = "按设备类型清空临界数据", module = "临界数据管理")
@DeleteMapping("/by-device-type")
public ResponseEntity<Map<String, Object>> 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 * 4. 导入临界数据Excel
* 输入参数表单文件字段 file * 输入参数表单文件字段 file

View File

@ -56,6 +56,8 @@ public class EventController {
@PostMapping @PostMapping
public ResponseEntity<Map<String, Object>> addEvent(@RequestBody Event event) { public ResponseEntity<Map<String, Object>> addEvent(@RequestBody Event event) {
assertCanWriteByScenarioId(event.getScenarioId()); assertCanWriteByScenarioId(event.getScenarioId());
event.setDeviceId(normalizeBlankToNull(event.getDeviceId()));
event.setMaterialId(normalizeBlankToNull(event.getMaterialId()));
event.setModifier(currentUsername()); event.setModifier(currentUsername());
eventService.save(event); eventService.save(event);
Event savedEvent = event; Event savedEvent = event;
@ -89,6 +91,8 @@ public class EventController {
} }
assertCanWriteByScenarioId(db.getScenarioId()); assertCanWriteByScenarioId(db.getScenarioId());
} }
event.setDeviceId(normalizeBlankToNull(event.getDeviceId()));
event.setMaterialId(normalizeBlankToNull(event.getMaterialId()));
event.setModifier(currentUsername()); event.setModifier(currentUsername());
event.setUpdatedAt(LocalDateTime.now()); event.setUpdatedAt(LocalDateTime.now());
return eventService.updateById(event); return eventService.updateById(event);
@ -133,12 +137,16 @@ public class EventController {
} }
if (event.getEventId() != null && !event.getEventId().isBlank() && exists != null) { if (event.getEventId() != null && !event.getEventId().isBlank() && exists != null) {
// 更新逻辑 // 更新逻辑
event.setDeviceId(normalizeBlankToNull(event.getDeviceId()));
event.setMaterialId(normalizeBlankToNull(event.getMaterialId()));
event.setModifier(currentUser); event.setModifier(currentUser);
event.setUpdatedAt(now); event.setUpdatedAt(now);
eventService.updateById(event); eventService.updateById(event);
savedEvents.add(event); savedEvents.add(event);
} else { } else {
// 新增逻辑 // 新增逻辑
event.setDeviceId(normalizeBlankToNull(event.getDeviceId()));
event.setMaterialId(normalizeBlankToNull(event.getMaterialId()));
event.setCreatedAt(now); event.setCreatedAt(now);
event.setModifier(currentUser); event.setModifier(currentUser);
event.setUpdatedAt(now); event.setUpdatedAt(now);
@ -440,6 +448,12 @@ public class EventController {
return 0.0; 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) { private void assertCanReadByScenarioId(String scenarioId) {
if (scenarioId == null || scenarioId.isBlank()) { if (scenarioId == null || scenarioId.isBlank()) {
throw new RuntimeException("scenarioId不能为空"); throw new RuntimeException("scenarioId不能为空");

View File

@ -1,6 +1,7 @@
package com.yfd.business.css.controller; package com.yfd.business.css.controller;
import com.yfd.business.css.build.SimBuilder; 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.Scenario;
import com.yfd.business.css.domain.ScenarioResult; import com.yfd.business.css.domain.ScenarioResult;
import com.yfd.business.css.facade.SimDataFacade; 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.business.css.service.SimInferService;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import com.yfd.platform.annotation.Log; import com.yfd.platform.annotation.Log;
@ -39,6 +41,9 @@ public class SimController {
@Autowired private ScenarioResultService scenarioResultService; @Autowired private ScenarioResultService scenarioResultService;
@Autowired private ObjectMapper objectMapper; @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<String, Object> req) { public ResponseResult run(@RequestBody Map<String, Object> req) {
String projectId = (String) req.get("projectId"); String projectId = (String) req.get("projectId");
String scenarioId = (String) req.get("scenarioId"); 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")); boolean clearResult = Boolean.TRUE.equals(req.get("clearResult"));
Scenario sc = scenarioService.getById(scenarioId); Scenario sc = scenarioService.getById(scenarioId);
@ -76,6 +81,8 @@ public class SimController {
try { try {
// 1. Load Data: 获取项目设备和事件数据 // 1. Load Data: 获取项目设备和事件数据
SimDataPackage data = simDataFacade.loadSimulationData(projectId, scenarioId); SimDataPackage data = simDataFacade.loadSimulationData(projectId, scenarioId);
int steps = resolveSteps(requestedSteps, data.getEvents());
// 2. Build Model: 将原始数据转换为仿真模型 (Units, Events, Nodes) // 2. Build Model: 将原始数据转换为仿真模型 (Units, Events, Nodes)
List<SimUnit> units = simBuilder.buildUnits(data, materialService); List<SimUnit> units = simBuilder.buildUnits(data, materialService);
@ -90,6 +97,7 @@ public class SimController {
// 6. Convert Result: 将仿真结果转换为前端友好的格式包含静态属性补全和元数据 // 6. Convert Result: 将仿真结果转换为前端友好的格式包含静态属性补全和元数据
Map<String, Object> resultData = SimResultConverter.toFrames(ctx, units, projectId, scenarioId); Map<String, Object> resultData = SimResultConverter.toFrames(ctx, units, projectId, scenarioId);
resultData.put("steps", steps);
// 为了让前端明确感知推理是否启动成功这里增加一个状态提示 // 为了让前端明确感知推理是否启动成功这里增加一个状态提示
// 但因为是异步的我们只能保证已提交真正的成败由 asyncInferAndSave 决定 // 但因为是异步的我们只能保证已提交真正的成败由 asyncInferAndSave 决定
@ -118,6 +126,58 @@ public class SimController {
} }
} }
private int resolveSteps(Integer requestedSteps, List<Event> 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<Event> 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) { private void updateScenarioStatus(String scenarioId, String status, String failDetail) {
try { try {
Scenario scenario = new Scenario(); Scenario scenario = new Scenario();

View File

@ -20,4 +20,6 @@ public interface CriticalDataService extends IService<CriticalData> {
byte[] templateCriticalDataV2(String deviceType); byte[] templateCriticalDataV2(String deviceType);
int deleteByDeviceType(String deviceType);
} }

View File

@ -1,5 +1,6 @@
package com.yfd.business.css.service.impl; 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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.business.css.domain.CriticalData; import com.yfd.business.css.domain.CriticalData;
import com.yfd.business.css.mapper.CriticalDataMapper; 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<CriticalData>().eq("device_type", dt));
}
private boolean importExcel(Workbook workbook, String deviceType) { private boolean importExcel(Workbook workbook, String deviceType) {
try (Workbook wb = workbook) { try (Workbook wb = workbook) {
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();

View File

@ -1576,8 +1576,8 @@ public class ProjectServiceImpl
Event ev = new Event(); Event ev = new Event();
ev.setEventId(eventId); ev.setEventId(eventId);
ev.setScenarioId(cell(df, r, eh.get("scenario_id"))); ev.setScenarioId(cell(df, r, eh.get("scenario_id")));
ev.setDeviceId(cell(df, r, eh.get("device_id"))); ev.setDeviceId(normalizeJsonText(cell(df, r, eh.get("device_id"))));
ev.setMaterialId(cell(df, r, eh.get("material_id"))); ev.setMaterialId(normalizeJsonText(cell(df, r, eh.get("material_id"))));
ev.setTriggerTime(parseDoubleObj(cell(df, r, eh.get("trigger_time")))); ev.setTriggerTime(parseDoubleObj(cell(df, r, eh.get("trigger_time"))));
ev.setAttrChanges(normalizeJsonText(cell(df, r, eh.get("attr_changes")))); ev.setAttrChanges(normalizeJsonText(cell(df, r, eh.get("attr_changes"))));
ev.setModifier(cell(df, r, eh.get("modifier"))); ev.setModifier(cell(df, r, eh.get("modifier")));