项目权限
This commit is contained in:
parent
86c7d1c7a9
commit
f59dd61da4
@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
|
||||
import com.yfd.platform.annotation.Log;
|
||||
@ -45,6 +46,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@Log(value = "新增算法", module = "算法管理")
|
||||
// @PreAuthorize("hasAuthority('algorithm:add')")
|
||||
@PostMapping
|
||||
@Operation(summary = "新增算法", description = "请求体传入算法对象,返回是否新增成功")
|
||||
public boolean createAlgorithm(@RequestBody Algorithm algorithm) {
|
||||
@ -55,6 +57,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@Log(value = "修改算法", module = "算法管理")
|
||||
// @PreAuthorize("hasAuthority('algorithm:update')")
|
||||
@PutMapping
|
||||
@Operation(summary = "修改算法", description = "请求体传入算法对象(需包含主键),返回是否修改成功")
|
||||
public boolean updateAlgorithm(@RequestBody Algorithm algorithm) {
|
||||
@ -64,6 +67,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@Log(value = "删除算法", module = "算法管理")
|
||||
// @PreAuthorize("hasAuthority('algorithm:delete')")
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除算法(单条)", description = "根据算法ID删除算法")
|
||||
public boolean deleteAlgorithm(@PathVariable String id) {
|
||||
@ -71,6 +75,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@Log(value = "批量删除算法", module = "算法管理")
|
||||
// @PreAuthorize("hasAuthority('algorithm:deleteBatch')")
|
||||
@DeleteMapping
|
||||
@Operation(summary = "删除算法(批量)", description = "请求体传入算法ID列表,批量删除算法")
|
||||
public boolean deleteAlgorithms(@RequestBody List<String> ids) {
|
||||
@ -78,7 +83,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@Log(value = "激活算法", module = "算法管理")
|
||||
//算法类型激活
|
||||
// @PreAuthorize("hasAuthority('algorithm:activate')")
|
||||
@PostMapping("/activate")
|
||||
@Operation(summary = "激活算法", description = "激活当前算法类型")
|
||||
public boolean activate(@RequestParam String algorithmId) {
|
||||
@ -92,7 +97,7 @@ public class AlgorithmController {
|
||||
}
|
||||
|
||||
@Log(value = "关闭算法", module = "算法管理")
|
||||
//算法类型关闭
|
||||
// @PreAuthorize("hasAuthority('algorithm:unactivate')")
|
||||
@PostMapping("/unactivate")
|
||||
@Operation(summary = "关闭算法", description = "关闭当前算法类型")
|
||||
public boolean unactivate(@RequestParam String algorithmId) {
|
||||
|
||||
@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
|
||||
import com.yfd.platform.annotation.Log;
|
||||
@ -53,6 +54,7 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@Log(value = "新增模型版本", module = "算法模型管理")
|
||||
// @PreAuthorize("hasAuthority('algorithmModel:add')")
|
||||
@PostMapping
|
||||
@Operation(summary = "新增模型版本", description = "请求体传入模型版本对象,返回是否新增成功")
|
||||
public boolean create(@RequestBody AlgorithmModel model) {
|
||||
@ -63,6 +65,7 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@Log(value = "修改模型版本", module = "算法模型管理")
|
||||
// @PreAuthorize("hasAuthority('algorithmModel:update')")
|
||||
@PutMapping
|
||||
@Operation(summary = "修改模型版本", description = "请求体传入模型版本对象(需包含主键),返回是否修改成功")
|
||||
public boolean update(@RequestBody AlgorithmModel model) {
|
||||
@ -72,6 +75,7 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@Log(value = "删除模型版本", module = "算法模型管理")
|
||||
// @PreAuthorize("hasAuthority('algorithmModel:delete')")
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除模型版本(单条)", description = "根据模型ID删除模型版本")
|
||||
public boolean delete(@PathVariable String id) {
|
||||
@ -79,6 +83,7 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@Log(value = "批量删除模型版本", module = "算法模型管理")
|
||||
// @PreAuthorize("hasAuthority('algorithmModel:deleteBatch')")
|
||||
@DeleteMapping
|
||||
@Operation(summary = "删除模型版本(批量)", description = "请求体传入模型ID列表,批量删除模型版本")
|
||||
public boolean deleteBatch(@RequestBody List<String> ids) {
|
||||
@ -124,7 +129,7 @@ public class AlgorithmModelController {
|
||||
}
|
||||
|
||||
@Log(value = "激活模型版本", module = "算法模型管理")
|
||||
//版本激活
|
||||
@PreAuthorize("hasAuthority('algorithmModel:activate')")
|
||||
@PostMapping("/activate")
|
||||
@Operation(summary = "激活模型版本", description = "将目标模型版本设为当前,并将同组(算法+设备+材料)其他版本设为非当前")
|
||||
public boolean activate(@RequestParam String algorithmModelId) {
|
||||
|
||||
@ -3,6 +3,7 @@ package com.yfd.business.css.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.business.css.domain.Device;
|
||||
import com.yfd.business.css.security.ProjectAccessHelper;
|
||||
import com.yfd.business.css.service.DeviceService;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -24,6 +25,8 @@ public class DeviceController {
|
||||
private DeviceService deviceService;
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
@Resource
|
||||
private ProjectAccessHelper projectAccessHelper;
|
||||
|
||||
/**
|
||||
* 1. 新增设备
|
||||
@ -35,6 +38,9 @@ public class DeviceController {
|
||||
@Log(value = "新增设备", module = "设备管理")
|
||||
@PostMapping
|
||||
public boolean create(@RequestBody Device device) {
|
||||
if (device.getProjectId() != null && !device.getProjectId().isBlank() && !"-1".equals(device.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(device.getProjectId());
|
||||
}
|
||||
device.setModifier(currentUsername());
|
||||
return deviceService.createDevice(device);
|
||||
}
|
||||
@ -42,6 +48,9 @@ public class DeviceController {
|
||||
@Log(value = "保存或更新设备", module = "设备管理")
|
||||
@PostMapping("/saveOrUpdate")
|
||||
public boolean saveOrUpdate(@RequestBody Device device) {
|
||||
if (device.getProjectId() != null && !device.getProjectId().isBlank() && !"-1".equals(device.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(device.getProjectId());
|
||||
}
|
||||
device.setModifier(currentUsername());
|
||||
return deviceService.saveOrUpdateByBusiness(device);
|
||||
}
|
||||
@ -56,6 +65,12 @@ public class DeviceController {
|
||||
@Log(value = "编辑设备", module = "设备管理")
|
||||
@PutMapping
|
||||
public boolean update(@RequestBody Device device) {
|
||||
if (device.getDeviceId() != null && !device.getDeviceId().isBlank()) {
|
||||
Device db = deviceService.getById(device.getDeviceId());
|
||||
if (db != null && db.getProjectId() != null && !db.getProjectId().isBlank() && !"-1".equals(db.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(db.getProjectId());
|
||||
}
|
||||
}
|
||||
device.setModifier(currentUsername());
|
||||
device.setUpdatedAt(LocalDateTime.now());
|
||||
return deviceService.updateById(device);
|
||||
@ -71,6 +86,10 @@ public class DeviceController {
|
||||
@Log(value = "删除设备", module = "设备管理")
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean delete(@PathVariable String id) {
|
||||
Device db = deviceService.getById(id);
|
||||
if (db != null && db.getProjectId() != null && !db.getProjectId().isBlank() && !"-1".equals(db.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(db.getProjectId());
|
||||
}
|
||||
return deviceService.removeById(id);
|
||||
}
|
||||
|
||||
@ -84,6 +103,14 @@ public class DeviceController {
|
||||
@Log(value = "批量删除设备", module = "设备管理")
|
||||
@DeleteMapping
|
||||
public boolean deleteBatch(@RequestBody List<String> ids) {
|
||||
if (ids != null && !ids.isEmpty()) {
|
||||
List<Device> list = deviceService.list(new QueryWrapper<Device>().in("device_id", ids));
|
||||
for (Device d : list) {
|
||||
if (d.getProjectId() != null && !d.getProjectId().isBlank() && !"-1".equals(d.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(d.getProjectId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return deviceService.removeByIds(ids);
|
||||
}
|
||||
|
||||
@ -113,6 +140,9 @@ public class DeviceController {
|
||||
*/
|
||||
@GetMapping("/by-project")
|
||||
public List<Device> listByProject(@RequestParam String projectId) {
|
||||
if (projectId != null && !projectId.isBlank() && !"-1".equals(projectId)) {
|
||||
projectAccessHelper.assertCanReadProject(projectId);
|
||||
}
|
||||
return deviceService.list(
|
||||
new QueryWrapper<Device>()
|
||||
.eq("project_id", projectId)
|
||||
|
||||
@ -2,7 +2,10 @@ package com.yfd.business.css.controller;
|
||||
|
||||
import com.yfd.business.css.domain.Device;
|
||||
import com.yfd.business.css.domain.Event;
|
||||
import com.yfd.business.css.domain.Scenario;
|
||||
import com.yfd.business.css.security.ProjectAccessHelper;
|
||||
import com.yfd.business.css.service.EventService;
|
||||
import com.yfd.business.css.service.ScenarioService;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -40,6 +43,10 @@ public class EventController {
|
||||
private ObjectMapper objectMapper;
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
@Resource
|
||||
private ScenarioService scenarioService;
|
||||
@Resource
|
||||
private ProjectAccessHelper projectAccessHelper;
|
||||
|
||||
|
||||
/**
|
||||
@ -48,6 +55,7 @@ public class EventController {
|
||||
@Log(value = "新增始发事件", module = "事件管理")
|
||||
@PostMapping
|
||||
public ResponseEntity<Map<String, Object>> addEvent(@RequestBody Event event) {
|
||||
assertCanWriteByScenarioId(event.getScenarioId());
|
||||
event.setModifier(currentUsername());
|
||||
eventService.save(event);
|
||||
Event savedEvent = event;
|
||||
@ -69,6 +77,14 @@ public class EventController {
|
||||
@Log(value = "修改始发事件", module = "事件管理")
|
||||
@PutMapping
|
||||
public boolean update(@RequestBody Event event) {
|
||||
if (event.getScenarioId() != null && !event.getScenarioId().isBlank()) {
|
||||
assertCanWriteByScenarioId(event.getScenarioId());
|
||||
} else if (event.getEventId() != null && !event.getEventId().isBlank()) {
|
||||
Event db = eventService.getById(event.getEventId());
|
||||
if (db != null) {
|
||||
assertCanWriteByScenarioId(db.getScenarioId());
|
||||
}
|
||||
}
|
||||
event.setModifier(currentUsername());
|
||||
event.setUpdatedAt(LocalDateTime.now());
|
||||
return eventService.updateById(event);
|
||||
@ -89,6 +105,14 @@ public class EventController {
|
||||
List<Event> savedEvents = new ArrayList<>();
|
||||
|
||||
for (Event event : events) {
|
||||
if (event.getScenarioId() != null && !event.getScenarioId().isBlank()) {
|
||||
assertCanWriteByScenarioId(event.getScenarioId());
|
||||
} else if (event.getEventId() != null && !event.getEventId().isBlank()) {
|
||||
Event db = eventService.getById(event.getEventId());
|
||||
if (db != null) {
|
||||
assertCanWriteByScenarioId(db.getScenarioId());
|
||||
}
|
||||
}
|
||||
if (event.getEventId() != null && eventService.getById(event.getEventId()) != null) {
|
||||
// 更新逻辑
|
||||
event.setModifier(currentUser);
|
||||
@ -122,6 +146,10 @@ public class EventController {
|
||||
@PathVariable String eventId,
|
||||
@RequestBody Map<String, Object> requestBody
|
||||
) {
|
||||
Event db = eventService.getById(eventId);
|
||||
if (db != null) {
|
||||
assertCanWriteByScenarioId(db.getScenarioId());
|
||||
}
|
||||
Object attrChanges = requestBody.get("attr_changes");
|
||||
if (attrChanges == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
@ -159,6 +187,7 @@ public class EventController {
|
||||
*/
|
||||
@GetMapping("/by-scenario")
|
||||
public List<Event> listByScenario(@RequestParam String scenarioId) {
|
||||
assertCanReadByScenarioId(scenarioId);
|
||||
return eventService.list(
|
||||
new QueryWrapper<Event>()
|
||||
.select("event_id","scenario_id","device_id","material_id","attr_changes","trigger_time","created_at","modifier")
|
||||
@ -177,6 +206,10 @@ public class EventController {
|
||||
@Log(value = "删除始发事件", module = "事件管理")
|
||||
@DeleteMapping("/{eventId}")
|
||||
public ResponseEntity<Map<String, Object>> deleteEvent(@PathVariable String eventId) {
|
||||
Event db = eventService.getById(eventId);
|
||||
if (db != null) {
|
||||
assertCanWriteByScenarioId(db.getScenarioId());
|
||||
}
|
||||
boolean ok = eventService.removeById(eventId);
|
||||
if (ok) {
|
||||
return ResponseEntity.ok(Map.of(
|
||||
@ -201,6 +234,9 @@ public class EventController {
|
||||
@GetMapping("/{eventId}/attr-parse")
|
||||
public ResponseEntity<Map<String, Object>> parseAttrChanges(@PathVariable String eventId) {
|
||||
Event ev = eventService.getById(eventId);
|
||||
if (ev != null) {
|
||||
assertCanReadByScenarioId(ev.getScenarioId());
|
||||
}
|
||||
List<String> issues = new ArrayList<>();
|
||||
EventAttrParseResult result = new EventAttrParseResult();
|
||||
result.setEventId(eventId);
|
||||
@ -384,6 +420,22 @@ public class EventController {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
private void assertCanReadByScenarioId(String scenarioId) {
|
||||
if (scenarioId == null || scenarioId.isBlank()) return;
|
||||
Scenario sc = scenarioService.getById(scenarioId);
|
||||
if (sc == null) return;
|
||||
if (sc.getProjectId() == null || sc.getProjectId().isBlank()) return;
|
||||
projectAccessHelper.assertCanReadProject(sc.getProjectId());
|
||||
}
|
||||
|
||||
private void assertCanWriteByScenarioId(String scenarioId) {
|
||||
if (scenarioId == null || scenarioId.isBlank()) return;
|
||||
Scenario sc = scenarioService.getById(scenarioId);
|
||||
if (sc == null) return;
|
||||
if (sc.getProjectId() == null || sc.getProjectId().isBlank()) return;
|
||||
projectAccessHelper.assertCanWriteProject(sc.getProjectId());
|
||||
}
|
||||
|
||||
private String currentUsername() {
|
||||
try {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.business.css.domain.Device;
|
||||
import com.yfd.business.css.domain.Material;
|
||||
import com.yfd.business.css.security.ProjectAccessHelper;
|
||||
import com.yfd.business.css.service.MaterialService;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -25,6 +26,8 @@ public class MaterialController {
|
||||
private MaterialService materialService;
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
@Resource
|
||||
private ProjectAccessHelper projectAccessHelper;
|
||||
|
||||
/**
|
||||
* 1. 新增物料
|
||||
@ -36,6 +39,9 @@ public class MaterialController {
|
||||
@Log(value = "新增物料", module = "物料管理")
|
||||
@PostMapping
|
||||
public boolean create(@RequestBody Material material) {
|
||||
if (material.getProjectId() != null && !material.getProjectId().isBlank() && !"-1".equals(material.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(material.getProjectId());
|
||||
}
|
||||
material.setModifier(currentUsername());
|
||||
return materialService.saveMaterial(material);
|
||||
}
|
||||
@ -43,6 +49,9 @@ public class MaterialController {
|
||||
@Log(value = "保存或更新物料", module = "物料管理")
|
||||
@PostMapping("/saveOrUpdate")
|
||||
public boolean saveOrUpdate(@RequestBody Material material) {
|
||||
if (material.getProjectId() != null && !material.getProjectId().isBlank() && !"-1".equals(material.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(material.getProjectId());
|
||||
}
|
||||
material.setModifier(currentUsername());
|
||||
return materialService.saveOrUpdateByBusiness(material);
|
||||
}
|
||||
@ -57,6 +66,12 @@ public class MaterialController {
|
||||
@Log(value = "编辑物料", module = "物料管理")
|
||||
@PutMapping
|
||||
public boolean update(@RequestBody Material material) {
|
||||
if (material.getMaterialId() != null && !material.getMaterialId().isBlank()) {
|
||||
Material db = materialService.getById(material.getMaterialId());
|
||||
if (db != null && db.getProjectId() != null && !db.getProjectId().isBlank() && !"-1".equals(db.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(db.getProjectId());
|
||||
}
|
||||
}
|
||||
material.setModifier(currentUsername());
|
||||
material.setUpdatedAt(LocalDateTime.now());
|
||||
return materialService.updateById(material);
|
||||
@ -72,6 +87,10 @@ public class MaterialController {
|
||||
@Log(value = "删除物料", module = "物料管理")
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean delete(@PathVariable String id) {
|
||||
Material db = materialService.getById(id);
|
||||
if (db != null && db.getProjectId() != null && !db.getProjectId().isBlank() && !"-1".equals(db.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(db.getProjectId());
|
||||
}
|
||||
return materialService.removeById(id);
|
||||
}
|
||||
|
||||
@ -85,6 +104,14 @@ public class MaterialController {
|
||||
@Log(value = "批量删除物料", module = "物料管理")
|
||||
@DeleteMapping
|
||||
public boolean deleteBatch(@RequestBody List<String> ids) {
|
||||
if (ids != null && !ids.isEmpty()) {
|
||||
List<Material> list = materialService.list(new QueryWrapper<Material>().in("material_id", ids));
|
||||
for (Material m : list) {
|
||||
if (m.getProjectId() != null && !m.getProjectId().isBlank() && !"-1".equals(m.getProjectId())) {
|
||||
projectAccessHelper.assertCanWriteProject(m.getProjectId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return materialService.removeByIds(ids);
|
||||
}
|
||||
|
||||
@ -130,6 +157,9 @@ public class MaterialController {
|
||||
public Page<Material> pageByProject(@RequestParam String projectId,
|
||||
@RequestParam(defaultValue = "1") long pageNum,
|
||||
@RequestParam(defaultValue = "20") long pageSize) {
|
||||
if (projectId != null && !projectId.isBlank() && !"-1".equals(projectId)) {
|
||||
projectAccessHelper.assertCanReadProject(projectId);
|
||||
}
|
||||
QueryWrapper<Material> qw = new QueryWrapper<Material>()
|
||||
.eq("project_id", projectId)
|
||||
.orderByDesc("created_at");
|
||||
|
||||
@ -9,6 +9,7 @@ import com.yfd.business.css.service.ModelTrainService;
|
||||
import com.yfd.business.css.service.TrainWebSocketService;
|
||||
import com.yfd.platform.config.ResponseResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import com.yfd.platform.annotation.Log;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@ -57,13 +58,17 @@ public class ModelTrainController {
|
||||
@PostMapping("/upload")
|
||||
public ResponseResult upload(@RequestParam("file") MultipartFile file) {
|
||||
String path = modelTrainService.uploadDataset(file);
|
||||
return ResponseResult.successData(path);
|
||||
return ResponseResult.successData(Map.of(
|
||||
"path", path,
|
||||
"columns", modelTrainService.parseDatasetColumns(path)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交训练任务 (支持文件上传和 JSON 参数)
|
||||
*/
|
||||
@Log(value = "提交训练任务", module = "模型训练")
|
||||
// @PreAuthorize("hasAuthority('modelTrain:submit')")
|
||||
@PostMapping("/submit")
|
||||
public ResponseResult submit(@RequestPart("task") String taskJson,
|
||||
@RequestPart(value = "file", required = false) MultipartFile file) {
|
||||
@ -137,6 +142,7 @@ public class ModelTrainController {
|
||||
* 发布模型
|
||||
*/
|
||||
@Log(value = "发布训练模型", module = "模型训练")
|
||||
// @PreAuthorize("hasAuthority('modelTrain:publish')")
|
||||
@PostMapping("/publish")
|
||||
public ResponseResult publish(@RequestBody Map<String, String> body) {
|
||||
String taskId = body.get("taskId");
|
||||
@ -149,6 +155,8 @@ public class ModelTrainController {
|
||||
* 删除训练任务
|
||||
*/
|
||||
@Log(value = "删除训练任务", module = "模型训练")
|
||||
@PreAuthorize("hasAuthority('modelTrain:delete')")
|
||||
//删除训练任务
|
||||
@DeleteMapping("/{taskId}")
|
||||
public ResponseResult delete(@PathVariable String taskId) {
|
||||
boolean success = modelTrainService.removeById(taskId);
|
||||
|
||||
@ -3,6 +3,7 @@ package com.yfd.business.css.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.business.css.domain.Project;
|
||||
import com.yfd.business.css.security.ProjectAccessHelper;
|
||||
import com.yfd.business.css.service.ProjectService;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
@ -16,6 +17,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import com.yfd.platform.annotation.Log;
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationToken;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.util.List;
|
||||
@ -33,6 +35,8 @@ public class ProjectController {
|
||||
private com.fasterxml.jackson.databind.ObjectMapper objectMapper;
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
@Resource
|
||||
private ProjectAccessHelper projectAccessHelper;
|
||||
|
||||
/**
|
||||
* 1. 新增项目
|
||||
@ -45,6 +49,15 @@ public class ProjectController {
|
||||
@PostMapping
|
||||
@Operation(summary = "新增项目", description = "请求体传入项目对象,返回是否新增成功")
|
||||
public boolean create(@RequestBody Project project) {
|
||||
if (project.getVisibility() == null || project.getVisibility().isBlank()) {
|
||||
project.setVisibility("PRIVATE");
|
||||
} else {
|
||||
project.setVisibility(projectAccessHelper.normalizeVisibility(project.getVisibility()));
|
||||
}
|
||||
if (project.getCreator() == null || project.getCreator().isBlank()) {
|
||||
var u = userService.getUserInfo();
|
||||
if (u != null) project.setCreator(u.getId());
|
||||
}
|
||||
project.setModifier(currentUsername());
|
||||
return projectService.save(project);
|
||||
}
|
||||
@ -60,11 +73,32 @@ public class ProjectController {
|
||||
@PutMapping
|
||||
@Operation(summary = "修改项目", description = "请求体传入项目对象(需包含主键),返回是否修改成功")
|
||||
public boolean update(@RequestBody Project project) {
|
||||
if (project.getProjectId() != null) {
|
||||
projectAccessHelper.assertCanWriteProject(project.getProjectId());
|
||||
}
|
||||
project.setModifier(currentUsername());
|
||||
project.setUpdatedAt(LocalDateTime.now());
|
||||
return projectService.updateById(project);
|
||||
}
|
||||
|
||||
@Log(value = "修改项目可见性", module = "项目管理")
|
||||
@PutMapping("/{id}/visibility")
|
||||
@Operation(summary = "修改项目可见性", description = "仅项目所有者或管理员可修改(PRIVATE/READONLY/PUBLIC)")
|
||||
public boolean updateVisibility(@PathVariable @Parameter(description = "项目ID", required = true) String id,
|
||||
@RequestBody Map<String, String> body) {
|
||||
projectAccessHelper.assertCanManageVisibility(id);
|
||||
String visibility = body == null ? null : body.get("visibility");
|
||||
if (visibility == null || visibility.isBlank()) {
|
||||
return false;
|
||||
}
|
||||
Project p = new Project();
|
||||
p.setProjectId(id);
|
||||
p.setVisibility(projectAccessHelper.normalizeVisibility(visibility));
|
||||
p.setModifier(currentUsername());
|
||||
p.setUpdatedAt(LocalDateTime.now());
|
||||
return projectService.updateById(p);
|
||||
}
|
||||
|
||||
private String currentUsername() {
|
||||
try {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
@ -88,6 +122,7 @@ public class ProjectController {
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除项目(单条)", description = "根据项目ID删除项目")
|
||||
public boolean delete(@PathVariable @Parameter(description = "项目ID", required = true) String id) {
|
||||
projectAccessHelper.assertCanWriteProject(id);
|
||||
return projectService.removeById(id);
|
||||
}
|
||||
|
||||
@ -102,6 +137,11 @@ public class ProjectController {
|
||||
@DeleteMapping
|
||||
@Operation(summary = "删除项目(批量)", description = "请求体传入项目ID列表,批量删除项目")
|
||||
public boolean deleteBatch(@RequestBody List<String> ids) {
|
||||
if (ids != null) {
|
||||
for (String id : ids) {
|
||||
projectAccessHelper.assertCanWriteProject(id);
|
||||
}
|
||||
}
|
||||
return projectService.removeByIds(ids);
|
||||
}
|
||||
|
||||
@ -142,6 +182,7 @@ public class ProjectController {
|
||||
@GetMapping("/{id}/exportProject")
|
||||
@Operation(summary = "导出项目工程(多Sheet)", description = "根据项目ID导出工程数据,返回 Excel 附件 project_{id}.xlsx")
|
||||
public ResponseEntity<byte[]> exportProjectExcel(@PathVariable @Parameter(description = "项目ID", required = true) String id) {
|
||||
projectAccessHelper.assertCanReadProject(id);
|
||||
byte[] bytes = projectService.exportProjectEngineeringExcel(id);
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=project_" + id + ".xlsx")
|
||||
@ -149,6 +190,15 @@ public class ProjectController {
|
||||
.body(bytes);
|
||||
}
|
||||
|
||||
@Log(value = "导入项目工程", module = "项目管理")
|
||||
@PostMapping("/importProject")
|
||||
@Operation(summary = "导入项目工程(多Sheet)", description = "上传 Excel 工程文件;若项目ID存在且 overwrite=false 则返回提示;overwrite=true 将先删除再导入")
|
||||
public ResponseEntity<Map<String, Object>> importProject(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam(defaultValue = "false") boolean overwrite) {
|
||||
var res = projectService.importProjectEngineeringExcel(file, overwrite);
|
||||
return ResponseEntity.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 6. 根据项目名称搜索(可为空)并分页返回
|
||||
* 输入参数:查询参数 name(项目名称关键词,可为空),pageNum(页码,默认1),pageSize(每页条数,默认10)
|
||||
@ -167,6 +217,14 @@ public class ProjectController {
|
||||
if (name != null && !name.isEmpty()) {
|
||||
qw.like("name", name);
|
||||
}
|
||||
if (!projectAccessHelper.isAdmin()) {
|
||||
String uid = projectAccessHelper.currentUserId();
|
||||
qw.and(w -> w.isNull("visibility")
|
||||
.or().eq("visibility", "")
|
||||
.or().eq("visibility", "PUBLIC")
|
||||
.or().eq("visibility", "READONLY")
|
||||
.or().eq("creator", uid));
|
||||
}
|
||||
Page<Project> page = new Page<>(pageNum, pageSize, true);
|
||||
return projectService.page(page, qw);
|
||||
}
|
||||
@ -181,7 +239,13 @@ public class ProjectController {
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "根据项目ID获取项目信息", description = "项目不存在时返回空对象")
|
||||
public Project getById(@PathVariable @Parameter(description = "项目ID", required = true) String id) {
|
||||
return projectService.getById(id);
|
||||
Project p = projectService.getById(id);
|
||||
if (p != null) {
|
||||
if (!projectAccessHelper.canRead(p)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,6 +261,7 @@ public class ProjectController {
|
||||
@Operation(summary = "更新项目拓扑结构", description = "请求体需包含合法的 topology JSON(对象或字符串)")
|
||||
public ResponseEntity<Map<String, Object>> updateTopology(@PathVariable @Parameter(description = "项目ID", required = true) String id,
|
||||
@RequestBody Map<String, Object> requestBody) {
|
||||
projectAccessHelper.assertCanWriteProject(id);
|
||||
Object topology = requestBody.get("topology");
|
||||
if (topology == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of(
|
||||
@ -240,6 +305,7 @@ public class ProjectController {
|
||||
*/
|
||||
@Operation(summary = "解析项目拓扑结构", description = "返回属性节点、影响边与线性计算计划")
|
||||
public ResponseEntity<Map<String, Object>> parseTopology(@PathVariable @Parameter(description = "项目ID", required = true) String id) {
|
||||
projectAccessHelper.assertCanReadProject(id);
|
||||
var result = projectService.parseTopology(id);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"code", 0,
|
||||
@ -256,6 +322,7 @@ public class ProjectController {
|
||||
*/
|
||||
@Operation(summary = "解析拓扑设备顺序", description = "根据 devices 出现顺序返回设备与物料属性视图")
|
||||
public ResponseEntity<Map<String, Object>> parseDeviceOrder(@PathVariable @Parameter(description = "项目ID", required = true) String id) {
|
||||
projectAccessHelper.assertCanReadProject(id);
|
||||
Object list = projectService.parseDeviceOrderWithMaterials(id);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"code", 0,
|
||||
@ -272,6 +339,7 @@ public class ProjectController {
|
||||
*/
|
||||
@Operation(summary = "解析画布视图数据", description = "返回设备/管线/边界与显示配置")
|
||||
public ResponseEntity<Map<String, Object>> parseCanvas(@PathVariable @Parameter(description = "项目ID", required = true) String id) {
|
||||
projectAccessHelper.assertCanReadProject(id);
|
||||
var view = projectService.parseCanvasView(id);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"code", 0,
|
||||
@ -285,6 +353,7 @@ public class ProjectController {
|
||||
public ResponseEntity<Map<String, Object>> initSimulation(@RequestParam @Parameter(description = "项目ID", required = true) String projectId,
|
||||
@RequestParam @Parameter(description = "情景ID", required = true) String scenarioId,
|
||||
@RequestBody(required = false) Map<String, Object> params) {
|
||||
projectAccessHelper.assertCanWriteProject(projectId);
|
||||
var res = projectService.initSimulation(projectId, scenarioId, params == null ? Map.of() : params);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"code", 0,
|
||||
@ -299,6 +368,7 @@ public class ProjectController {
|
||||
public ResponseEntity<Map<String, Object>> runSimulation(@RequestParam @Parameter(description = "项目ID", required = true) String projectId,
|
||||
@RequestParam @Parameter(description = "情景ID", required = true) String scenarioId,
|
||||
@RequestBody(required = false) Map<String, Object> params) {
|
||||
projectAccessHelper.assertCanWriteProject(projectId);
|
||||
var res = projectService.runSimulation(projectId, scenarioId, params == null ? Map.of() : params);
|
||||
return ResponseEntity.ok(Map.of(
|
||||
"code", 0,
|
||||
|
||||
@ -3,6 +3,7 @@ package com.yfd.business.css.controller;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.business.css.domain.Scenario;
|
||||
import com.yfd.business.css.security.ProjectAccessHelper;
|
||||
import com.yfd.business.css.service.ScenarioService;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -23,6 +24,8 @@ public class ScenarioController {
|
||||
private ScenarioService scenarioService;
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
@Resource
|
||||
private ProjectAccessHelper projectAccessHelper;
|
||||
|
||||
/**
|
||||
* 1. 新增情景
|
||||
@ -34,6 +37,9 @@ public class ScenarioController {
|
||||
@Log(value = "新增情景", module = "情景管理")
|
||||
@PostMapping
|
||||
public boolean create(@RequestBody Scenario scenario) {
|
||||
if (scenario.getProjectId() != null && !scenario.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanWriteProject(scenario.getProjectId());
|
||||
}
|
||||
scenario.setModifier(currentUsername());
|
||||
scenario.setCreatedAt(LocalDateTime.now());
|
||||
scenario.setUpdatedAt(LocalDateTime.now());
|
||||
@ -51,6 +57,9 @@ public class ScenarioController {
|
||||
@Log(value = "新增情景并返回", module = "情景管理")
|
||||
@PostMapping("/createAndReturn")
|
||||
public java.util.Map<String, Object> createAndReturn(@RequestBody Scenario scenario) {
|
||||
if (scenario.getProjectId() != null && !scenario.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanWriteProject(scenario.getProjectId());
|
||||
}
|
||||
scenario.setModifier(currentUsername());
|
||||
scenario.setCreatedAt(LocalDateTime.now());
|
||||
scenario.setUpdatedAt(LocalDateTime.now());
|
||||
@ -72,6 +81,12 @@ public class ScenarioController {
|
||||
@Log(value = "修改情景", module = "情景管理")
|
||||
@PutMapping
|
||||
public boolean update(@RequestBody Scenario scenario) {
|
||||
if (scenario.getScenarioId() != null && !scenario.getScenarioId().isBlank()) {
|
||||
Scenario db = scenarioService.getById(scenario.getScenarioId());
|
||||
if (db != null && db.getProjectId() != null && !db.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanWriteProject(db.getProjectId());
|
||||
}
|
||||
}
|
||||
scenario.setModifier(currentUsername());
|
||||
scenario.setUpdatedAt(LocalDateTime.now());
|
||||
return scenarioService.updateById(scenario);
|
||||
@ -87,6 +102,10 @@ public class ScenarioController {
|
||||
@Log(value = "删除情景", module = "情景管理")
|
||||
@DeleteMapping("/{id}")
|
||||
public boolean delete(@PathVariable String id) {
|
||||
Scenario db = scenarioService.getById(id);
|
||||
if (db != null && db.getProjectId() != null && !db.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanWriteProject(db.getProjectId());
|
||||
}
|
||||
return scenarioService.removeById(id);
|
||||
}
|
||||
|
||||
@ -100,6 +119,14 @@ public class ScenarioController {
|
||||
@Log(value = "批量删除情景", module = "情景管理")
|
||||
@DeleteMapping
|
||||
public boolean deleteBatch(@RequestBody List<String> ids) {
|
||||
if (ids != null && !ids.isEmpty()) {
|
||||
List<Scenario> list = scenarioService.list(new QueryWrapper<Scenario>().in("scenario_id", ids));
|
||||
for (Scenario sc : list) {
|
||||
if (sc.getProjectId() != null && !sc.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanWriteProject(sc.getProjectId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return scenarioService.removeByIds(ids);
|
||||
}
|
||||
|
||||
@ -114,7 +141,11 @@ public class ScenarioController {
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public Scenario getById(@PathVariable String id) {
|
||||
return scenarioService.getById(id);
|
||||
Scenario sc = scenarioService.getById(id);
|
||||
if (sc != null && sc.getProjectId() != null && !sc.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanReadProject(sc.getProjectId());
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -132,6 +163,9 @@ public class ScenarioController {
|
||||
@RequestParam(required = false) String name,
|
||||
@RequestParam(defaultValue = "1") long pageNum,
|
||||
@RequestParam(defaultValue = "20") long pageSize) {
|
||||
if (projectId != null && !projectId.isBlank()) {
|
||||
projectAccessHelper.assertCanReadProject(projectId);
|
||||
}
|
||||
QueryWrapper<Scenario> qw = new QueryWrapper<Scenario>().eq("project_id", projectId).orderByDesc("created_at");
|
||||
if (name != null && !name.isEmpty()) {
|
||||
qw.like("name", name);
|
||||
|
||||
@ -2,8 +2,11 @@ package com.yfd.business.css.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.yfd.business.css.domain.Scenario;
|
||||
import com.yfd.business.css.domain.ScenarioResult;
|
||||
import com.yfd.business.css.security.ProjectAccessHelper;
|
||||
import com.yfd.business.css.service.ScenarioResultService;
|
||||
import com.yfd.business.css.service.ScenarioService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -23,6 +26,10 @@ public class ScenarioResultController {
|
||||
|
||||
@Resource
|
||||
private ScenarioResultService scenarioResultService;
|
||||
@Resource
|
||||
private ScenarioService scenarioService;
|
||||
@Resource
|
||||
private ProjectAccessHelper projectAccessHelper;
|
||||
|
||||
/**
|
||||
* 根据场景ID分页查询模拟结果
|
||||
@ -43,6 +50,10 @@ public class ScenarioResultController {
|
||||
@RequestParam(defaultValue = "1") long pageNum,
|
||||
@RequestParam(defaultValue = "10") long pageSize
|
||||
) {
|
||||
Scenario sc = scenarioService.getById(scenarioId);
|
||||
if (sc != null && sc.getProjectId() != null && !sc.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanReadProject(sc.getProjectId());
|
||||
}
|
||||
QueryWrapper<ScenarioResult> qw = new QueryWrapper<ScenarioResult>()
|
||||
.eq("scenario_id", scenarioId);
|
||||
if (deviceId != null && !deviceId.isEmpty()) {
|
||||
@ -79,6 +90,10 @@ public class ScenarioResultController {
|
||||
@RequestParam(required = false) String deviceId,
|
||||
@RequestParam(required = false) Integer stepFrom,
|
||||
@RequestParam(required = false) Integer stepTo) throws IOException {
|
||||
Scenario sc = scenarioService.getById(scenarioId);
|
||||
if (sc != null && sc.getProjectId() != null && !sc.getProjectId().isBlank()) {
|
||||
projectAccessHelper.assertCanReadProject(sc.getProjectId());
|
||||
}
|
||||
|
||||
// 设置响应头信息以便浏览器识别并触发下载行为
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
|
||||
@ -5,6 +5,7 @@ import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
@TableName(value = "model_train_task", autoResultMap = true)
|
||||
@ -48,6 +49,9 @@ public class ModelTrainTask implements Serializable {
|
||||
@TableField("error_log")
|
||||
private String errorLog;
|
||||
|
||||
@TableField(exist = false)
|
||||
private Map<String, Object> featureMapConfig;
|
||||
|
||||
@TableField(value = "created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
@ -30,6 +30,12 @@ public class Project implements Serializable {
|
||||
@TableField("topology")
|
||||
private String topology;
|
||||
|
||||
@TableField("visibility")
|
||||
private String visibility;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("created_at")
|
||||
private LocalDateTime createdAt;
|
||||
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
package com.yfd.business.css.security;
|
||||
|
||||
import com.yfd.business.css.common.exception.BizException;
|
||||
import com.yfd.business.css.domain.Project;
|
||||
import com.yfd.business.css.service.ProjectService;
|
||||
import com.yfd.platform.system.domain.SysUser;
|
||||
import com.yfd.platform.system.service.IUserService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ProjectAccessHelper {
|
||||
|
||||
@Resource
|
||||
private ProjectService projectService;
|
||||
|
||||
@Resource
|
||||
private IUserService userService;
|
||||
|
||||
public boolean isAdmin() {
|
||||
SysUser u = userService.getUserInfo();
|
||||
return u != null && u.getUsertype() != null && u.getUsertype() == 0;
|
||||
}
|
||||
|
||||
public String currentUserId() {
|
||||
SysUser u = userService.getUserInfo();
|
||||
return u == null ? null : u.getId();
|
||||
}
|
||||
|
||||
public void assertCanReadProject(String projectId) {
|
||||
Project p = projectService.getById(projectId);
|
||||
if (p == null) {
|
||||
throw new BizException("项目不存在");
|
||||
}
|
||||
if (!canRead(p)) {
|
||||
throw new BizException("无权限访问该项目");
|
||||
}
|
||||
}
|
||||
|
||||
public void assertCanWriteProject(String projectId) {
|
||||
Project p = projectService.getById(projectId);
|
||||
if (p == null) {
|
||||
throw new BizException("项目不存在");
|
||||
}
|
||||
if (!canWrite(p)) {
|
||||
throw new BizException("无权限修改该项目");
|
||||
}
|
||||
}
|
||||
|
||||
public void assertCanManageVisibility(String projectId) {
|
||||
Project p = projectService.getById(projectId);
|
||||
if (p == null) {
|
||||
throw new BizException("项目不存在");
|
||||
}
|
||||
if (!canManageVisibility(p)) {
|
||||
throw new BizException("无权限修改项目可见性");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canRead(Project p) {
|
||||
if (p == null) return false;
|
||||
if (isAdmin()) return true;
|
||||
String visibility = normalizeVisibility(p.getVisibility());
|
||||
if ("PUBLIC".equals(visibility) || "READONLY".equals(visibility)) return true;
|
||||
if ("PRIVATE".equals(visibility)) {
|
||||
String uid = currentUserId();
|
||||
return uid != null && uid.equals(p.getCreator());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean canWrite(Project p) {
|
||||
if (p == null) return false;
|
||||
if (isAdmin()) return true;
|
||||
String uid = currentUserId();
|
||||
if (uid != null && uid.equals(p.getCreator())) return true;
|
||||
String visibility = normalizeVisibility(p.getVisibility());
|
||||
return "PUBLIC".equals(visibility);
|
||||
}
|
||||
|
||||
public boolean canManageVisibility(Project p) {
|
||||
if (p == null) return false;
|
||||
if (isAdmin()) return true;
|
||||
String uid = currentUserId();
|
||||
return uid != null && uid.equals(p.getCreator());
|
||||
}
|
||||
|
||||
public String normalizeVisibility(String visibility) {
|
||||
if (visibility == null || visibility.isBlank()) return "PUBLIC";
|
||||
String v = visibility.trim().toUpperCase();
|
||||
if ("PRIVATE".equals(v) || "READONLY".equals(v) || "PUBLIC".equals(v)) return v;
|
||||
return "PUBLIC";
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.yfd.business.css.domain.ModelTrainTask;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface ModelTrainService extends IService<ModelTrainTask> {
|
||||
/**
|
||||
* 上传数据集
|
||||
@ -12,6 +14,8 @@ public interface ModelTrainService extends IService<ModelTrainTask> {
|
||||
*/
|
||||
String uploadDataset(MultipartFile file);
|
||||
|
||||
List<String> parseDatasetColumns(String datasetPath);
|
||||
|
||||
/**
|
||||
* 提交训练任务
|
||||
* @param task 任务信息
|
||||
|
||||
@ -18,6 +18,8 @@ public interface ProjectService extends IService<Project> {
|
||||
*/
|
||||
byte[] exportProjectEngineeringExcel(String projectId);
|
||||
|
||||
java.util.Map<String, Object> importProjectEngineeringExcel(org.springframework.web.multipart.MultipartFile file, boolean overwrite);
|
||||
|
||||
/**
|
||||
* 解析指定项目的拓扑结构
|
||||
* @param projectId 项目ID
|
||||
|
||||
@ -23,9 +23,17 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@ -33,6 +41,9 @@ import java.nio.file.StandardCopyOption;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
@ -108,6 +119,25 @@ public class ModelTrainServiceImpl extends ServiceImpl<ModelTrainTaskMapper, Mod
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> parseDatasetColumns(String datasetPath) {
|
||||
if (datasetPath == null || datasetPath.isBlank()) {
|
||||
throw new BizException("数据集路径不能为空");
|
||||
}
|
||||
Path p = Paths.get(datasetPath);
|
||||
if (!Files.exists(p)) {
|
||||
throw new BizException("数据集文件不存在: " + datasetPath);
|
||||
}
|
||||
String lower = p.getFileName().toString().toLowerCase();
|
||||
if (lower.endsWith(".xlsx") || lower.endsWith(".xls")) {
|
||||
return parseExcelHeader(p.toFile());
|
||||
}
|
||||
if (lower.endsWith(".csv")) {
|
||||
return parseCsvHeader(p);
|
||||
}
|
||||
throw new BizException("不支持的数据集格式: " + p.getFileName());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public String submitTask(ModelTrainTask task) {
|
||||
@ -116,6 +146,20 @@ public class ModelTrainServiceImpl extends ServiceImpl<ModelTrainTaskMapper, Mod
|
||||
if (task.getTaskId() == null) {
|
||||
task.setTaskId(UUID.randomUUID().toString());
|
||||
}
|
||||
if (task.getFeatureMapConfig() != null && !task.getFeatureMapConfig().isEmpty()) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (task.getTrainParams() != null && !task.getTrainParams().isBlank()) {
|
||||
try {
|
||||
params.putAll(objectMapper.readValue(task.getTrainParams(), new TypeReference<Map<String, Object>>() {}));
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
params.put("feature_map", task.getFeatureMapConfig());
|
||||
try {
|
||||
task.setTrainParams(objectMapper.writeValueAsString(params));
|
||||
} catch (JsonProcessingException ignored) {
|
||||
}
|
||||
}
|
||||
this.save(task);
|
||||
|
||||
// 2. 异步调用 Python 训练
|
||||
@ -145,6 +189,12 @@ public class ModelTrainServiceImpl extends ServiceImpl<ModelTrainTaskMapper, Mod
|
||||
try {
|
||||
Map<String, Object> params = objectMapper.readValue(task.getTrainParams(), new TypeReference<Map<String, Object>>() {});
|
||||
request.put("hyperparameters", params);
|
||||
if (task.getFeatureMapConfig() == null) {
|
||||
Object fm = params.get("feature_map");
|
||||
if (fm instanceof Map) {
|
||||
request.put("feature_map", fm);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析训练参数失败,将作为原始字符串发送: {}", e.getMessage());
|
||||
request.put("hyperparameters", task.getTrainParams());
|
||||
@ -152,6 +202,9 @@ public class ModelTrainServiceImpl extends ServiceImpl<ModelTrainTaskMapper, Mod
|
||||
} else {
|
||||
request.put("hyperparameters", new HashMap<>());
|
||||
}
|
||||
if (task.getFeatureMapConfig() != null && !task.getFeatureMapConfig().isEmpty()) {
|
||||
request.put("feature_map", task.getFeatureMapConfig());
|
||||
}
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||
@ -200,6 +253,69 @@ public class ModelTrainServiceImpl extends ServiceImpl<ModelTrainTaskMapper, Mod
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> parseExcelHeader(File file) {
|
||||
DataFormatter df = new DataFormatter();
|
||||
try (Workbook wb = WorkbookFactory.create(file)) {
|
||||
Sheet sheet = wb.getNumberOfSheets() > 0 ? wb.getSheetAt(0) : null;
|
||||
if (sheet == null) return List.of();
|
||||
Row row = sheet.getRow(sheet.getFirstRowNum());
|
||||
if (row == null) return List.of();
|
||||
short last = row.getLastCellNum();
|
||||
List<String> cols = new ArrayList<>();
|
||||
for (int i = 0; i < last; i++) {
|
||||
String v = df.formatCellValue(row.getCell(i));
|
||||
if (v != null) {
|
||||
String t = v.trim();
|
||||
if (!t.isBlank()) cols.add(t);
|
||||
}
|
||||
}
|
||||
return cols;
|
||||
} catch (Exception e) {
|
||||
throw new BizException("解析Excel表头失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> parseCsvHeader(Path p) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(Files.newInputStream(p), StandardCharsets.UTF_8))) {
|
||||
String line = br.readLine();
|
||||
if (line == null) return List.of();
|
||||
List<String> cols = parseCsvLine(line).stream()
|
||||
.map(s -> s == null ? "" : s.trim())
|
||||
.filter(s -> !s.isBlank())
|
||||
.toList();
|
||||
return cols;
|
||||
} catch (Exception e) {
|
||||
throw new BizException("解析CSV表头失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> parseCsvLine(String line) {
|
||||
List<String> out = new ArrayList<>();
|
||||
if (line == null) return out;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean inQuotes = false;
|
||||
for (int i = 0; i < line.length(); i++) {
|
||||
char c = line.charAt(i);
|
||||
if (c == '"') {
|
||||
if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
|
||||
sb.append('"');
|
||||
i++;
|
||||
} else {
|
||||
inQuotes = !inQuotes;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c == ',' && !inQuotes) {
|
||||
out.add(sb.toString());
|
||||
sb.setLength(0);
|
||||
continue;
|
||||
}
|
||||
sb.append(c);
|
||||
}
|
||||
out.add(sb.toString());
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTrainTask syncTaskStatus(String taskId) {
|
||||
ModelTrainTask task = this.getById(taskId);
|
||||
|
||||
@ -43,8 +43,13 @@ import java.util.Comparator;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.ss.usermodel.Cell;
|
||||
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -1308,6 +1313,283 @@ public class ProjectServiceImpl
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> importProjectEngineeringExcel(MultipartFile file, boolean overwrite) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return Map.of("code", 1, "msg", "文件不能为空");
|
||||
}
|
||||
|
||||
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
DataFormatter df = new DataFormatter();
|
||||
|
||||
try (Workbook wb = new XSSFWorkbook(file.getInputStream())) {
|
||||
Sheet projectsSheet = wb.getSheet("projects");
|
||||
if (projectsSheet == null) {
|
||||
return Map.of("code", 1, "msg", "缺少 projects Sheet");
|
||||
}
|
||||
Row header = projectsSheet.getRow(0);
|
||||
Row dataRow = projectsSheet.getRow(1);
|
||||
if (header == null || dataRow == null) {
|
||||
return Map.of("code", 1, "msg", "projects Sheet 内容为空");
|
||||
}
|
||||
Map<String, Integer> h = headerIndex(header, df);
|
||||
String projectId = cell(df, dataRow, h.get("project_id"));
|
||||
if (projectId == null || projectId.isBlank()) {
|
||||
return Map.of("code", 1, "msg", "project_id 不能为空");
|
||||
}
|
||||
|
||||
Project exists = this.getById(projectId);
|
||||
if (exists != null && !overwrite) {
|
||||
return Map.of("code", 2, "msg", "项目ID已存在", "data", Map.of("projectId", projectId));
|
||||
}
|
||||
if (exists != null) {
|
||||
deleteProjectCascade(projectId);
|
||||
}
|
||||
|
||||
Project p = new Project();
|
||||
p.setProjectId(projectId);
|
||||
p.setCode(cell(df, dataRow, h.get("code")));
|
||||
p.setName(cell(df, dataRow, h.get("name")));
|
||||
p.setDescription(cell(df, dataRow, h.get("description")));
|
||||
p.setTopology(cell(df, dataRow, h.get("topology")));
|
||||
p.setModifier(cell(df, dataRow, h.get("modifier")));
|
||||
|
||||
String visibility = cell(df, dataRow, h.get("visibility"));
|
||||
if (visibility != null && !visibility.isBlank()) {
|
||||
p.setVisibility(visibility);
|
||||
}
|
||||
String creator = cell(df, dataRow, h.get("creator"));
|
||||
if (creator != null && !creator.isBlank()) {
|
||||
p.setCreator(creator);
|
||||
}
|
||||
|
||||
String createdAt = cell(df, dataRow, h.get("created_at"));
|
||||
if (createdAt != null && !createdAt.isBlank()) {
|
||||
try { p.setCreatedAt(LocalDateTime.parse(createdAt, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
String updatedAt = cell(df, dataRow, h.get("updated_at"));
|
||||
if (updatedAt != null && !updatedAt.isBlank()) {
|
||||
try { p.setUpdatedAt(LocalDateTime.parse(updatedAt, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
|
||||
this.save(p);
|
||||
|
||||
Sheet devicesSheet = wb.getSheet("devices");
|
||||
if (devicesSheet != null) {
|
||||
List<Device> devices = new ArrayList<>();
|
||||
Map<String, Integer> dh = headerIndex(devicesSheet.getRow(0), df);
|
||||
int last = devicesSheet.getLastRowNum();
|
||||
for (int i = 1; i <= last; i++) {
|
||||
Row r = devicesSheet.getRow(i);
|
||||
if (r == null) continue;
|
||||
String deviceId = cell(df, r, dh.get("device_id"));
|
||||
if (deviceId == null || deviceId.isBlank()) continue;
|
||||
Device d = new Device();
|
||||
d.setDeviceId(deviceId);
|
||||
d.setProjectId(projectId);
|
||||
d.setCode(cell(df, r, dh.get("code")));
|
||||
d.setType(cell(df, r, dh.get("type")));
|
||||
d.setName(cell(df, r, dh.get("name")));
|
||||
d.setSize(cell(df, r, dh.get("size")));
|
||||
d.setVolume(parseDoubleObj(cell(df, r, dh.get("volume"))));
|
||||
d.setFlowRate(parseDoubleObj(cell(df, r, dh.get("flow_rate"))));
|
||||
d.setPulseVelocity(parseDoubleObj(cell(df, r, dh.get("pulse_velocity"))));
|
||||
d.setModifier(cell(df, r, dh.get("modifier")));
|
||||
String dCreated = cell(df, r, dh.get("created_at"));
|
||||
if (dCreated != null && !dCreated.isBlank()) {
|
||||
try { d.setCreatedAt(LocalDateTime.parse(dCreated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
String dUpdated = cell(df, r, dh.get("updated_at"));
|
||||
if (dUpdated != null && !dUpdated.isBlank()) {
|
||||
try { d.setUpdatedAt(LocalDateTime.parse(dUpdated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
devices.add(d);
|
||||
}
|
||||
if (!devices.isEmpty()) {
|
||||
deviceService.saveBatch(devices);
|
||||
}
|
||||
}
|
||||
|
||||
Sheet materialsSheet = wb.getSheet("materials");
|
||||
if (materialsSheet != null) {
|
||||
List<Material> materials = new ArrayList<>();
|
||||
Map<String, Integer> mh = headerIndex(materialsSheet.getRow(0), df);
|
||||
int last = materialsSheet.getLastRowNum();
|
||||
for (int i = 1; i <= last; i++) {
|
||||
Row r = materialsSheet.getRow(i);
|
||||
if (r == null) continue;
|
||||
String materialId = cell(df, r, mh.get("material_id"));
|
||||
if (materialId == null || materialId.isBlank()) continue;
|
||||
Material m = new Material();
|
||||
m.setMaterialId(materialId);
|
||||
m.setProjectId(projectId);
|
||||
m.setName(cell(df, r, mh.get("name")));
|
||||
m.setUConcentration(parseBigDecimal(cell(df, r, mh.get("u_concentration"))));
|
||||
m.setUo2Density(parseBigDecimal(cell(df, r, mh.get("uo2_density"))));
|
||||
m.setUEnrichment(parseBigDecimal(cell(df, r, mh.get("u_enrichment"))));
|
||||
m.setPuConcentration(parseBigDecimal(cell(df, r, mh.get("pu_concentration"))));
|
||||
m.setPuo2Density(parseBigDecimal(cell(df, r, mh.get("puo2_density"))));
|
||||
m.setPuIsotope(parseBigDecimal(cell(df, r, mh.get("pu_isotope"))));
|
||||
m.setHno3Acidity(parseBigDecimal(cell(df, r, mh.get("hno3_acidity"))));
|
||||
m.setH2c2o4Concentration(parseBigDecimal(cell(df, r, mh.get("h2c2o4_concentration"))));
|
||||
m.setOrganicRatio(parseBigDecimal(cell(df, r, mh.get("organic_ratio"))));
|
||||
m.setMoistureContent(parseBigDecimal(cell(df, r, mh.get("moisture_content"))));
|
||||
m.setCustomAttrs(cell(df, r, mh.get("custom_attrs")));
|
||||
m.setModifier(cell(df, r, mh.get("modifier")));
|
||||
String mCreated = cell(df, r, mh.get("created_at"));
|
||||
if (mCreated != null && !mCreated.isBlank()) {
|
||||
try { m.setCreatedAt(LocalDateTime.parse(mCreated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
String mUpdated = cell(df, r, mh.get("updated_at"));
|
||||
if (mUpdated != null && !mUpdated.isBlank()) {
|
||||
try { m.setUpdatedAt(LocalDateTime.parse(mUpdated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
materials.add(m);
|
||||
}
|
||||
if (!materials.isEmpty()) {
|
||||
materialService.saveBatch(materials);
|
||||
}
|
||||
}
|
||||
|
||||
Sheet scenariosSheet = wb.getSheet("scenarios");
|
||||
List<String> scenarioIds = new ArrayList<>();
|
||||
if (scenariosSheet != null) {
|
||||
List<Scenario> scenarios = new ArrayList<>();
|
||||
Map<String, Integer> sh = headerIndex(scenariosSheet.getRow(0), df);
|
||||
int last = scenariosSheet.getLastRowNum();
|
||||
for (int i = 1; i <= last; i++) {
|
||||
Row r = scenariosSheet.getRow(i);
|
||||
if (r == null) continue;
|
||||
String scenarioId = cell(df, r, sh.get("scenario_id"));
|
||||
if (scenarioId == null || scenarioId.isBlank()) continue;
|
||||
Scenario sc = new Scenario();
|
||||
sc.setScenarioId(scenarioId);
|
||||
sc.setProjectId(projectId);
|
||||
sc.setName(cell(df, r, sh.get("name")));
|
||||
sc.setDescription(cell(df, r, sh.get("description")));
|
||||
sc.setModifier(cell(df, r, sh.get("modifier")));
|
||||
String sCreated = cell(df, r, sh.get("created_at"));
|
||||
if (sCreated != null && !sCreated.isBlank()) {
|
||||
try { sc.setCreatedAt(LocalDateTime.parse(sCreated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
String sUpdated = cell(df, r, sh.get("updated_at"));
|
||||
if (sUpdated != null && !sUpdated.isBlank()) {
|
||||
try { sc.setUpdatedAt(LocalDateTime.parse(sUpdated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
scenarios.add(sc);
|
||||
scenarioIds.add(scenarioId);
|
||||
}
|
||||
if (!scenarios.isEmpty()) {
|
||||
scenarioService.saveBatch(scenarios);
|
||||
}
|
||||
}
|
||||
|
||||
Sheet eventsSheet = wb.getSheet("events");
|
||||
if (eventsSheet != null) {
|
||||
List<Event> events = new ArrayList<>();
|
||||
Map<String, Integer> eh = headerIndex(eventsSheet.getRow(0), df);
|
||||
int last = eventsSheet.getLastRowNum();
|
||||
for (int i = 1; i <= last; i++) {
|
||||
Row r = eventsSheet.getRow(i);
|
||||
if (r == null) continue;
|
||||
String eventId = cell(df, r, eh.get("event_id"));
|
||||
if (eventId == null || eventId.isBlank()) continue;
|
||||
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.setTriggerTime(parseDoubleObj(cell(df, r, eh.get("trigger_time"))));
|
||||
ev.setAttrChanges(cell(df, r, eh.get("attr_changes")));
|
||||
ev.setModifier(cell(df, r, eh.get("modifier")));
|
||||
String eCreated = cell(df, r, eh.get("created_at"));
|
||||
if (eCreated != null && !eCreated.isBlank()) {
|
||||
try { ev.setCreatedAt(LocalDateTime.parse(eCreated, fmt)); } catch (Exception ignored) { }
|
||||
}
|
||||
events.add(ev);
|
||||
}
|
||||
if (!events.isEmpty()) {
|
||||
eventService.saveBatch(events);
|
||||
}
|
||||
}
|
||||
|
||||
Sheet resultsSheet = wb.getSheet("scenario_results");
|
||||
if (resultsSheet != null) {
|
||||
List<ScenarioResult> results = new ArrayList<>();
|
||||
Map<String, Integer> rh = headerIndex(resultsSheet.getRow(0), df);
|
||||
int last = resultsSheet.getLastRowNum();
|
||||
for (int i = 1; i <= last; i++) {
|
||||
Row r = resultsSheet.getRow(i);
|
||||
if (r == null) continue;
|
||||
String sid = cell(df, r, rh.get("scenario_id"));
|
||||
if (sid == null || sid.isBlank()) continue;
|
||||
ScenarioResult sr = new ScenarioResult();
|
||||
sr.setScenarioId(sid);
|
||||
sr.setDeviceId(cell(df, r, rh.get("device_id")));
|
||||
String step = cell(df, r, rh.get("step"));
|
||||
if (step != null && !step.isBlank()) {
|
||||
try { sr.setStep((int) Double.parseDouble(step)); } catch (Exception ignored) { }
|
||||
}
|
||||
sr.setKeffValue(parseBigDecimal(cell(df, r, rh.get("keff_value"))));
|
||||
sr.setAttrState(cell(df, r, rh.get("attr_state")));
|
||||
results.add(sr);
|
||||
}
|
||||
if (!results.isEmpty()) {
|
||||
scenarioResultService.saveBatch(results);
|
||||
}
|
||||
}
|
||||
|
||||
return Map.of("code", 0, "msg", "导入成功", "data", Map.of("projectId", projectId));
|
||||
} catch (Exception e) {
|
||||
return Map.of("code", 1, "msg", "导入失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteProjectCascade(String projectId) {
|
||||
List<Scenario> scenarios = scenarioService.list(new QueryWrapper<Scenario>().select("scenario_id").eq("project_id", projectId));
|
||||
List<String> scenarioIds = scenarios.stream().map(Scenario::getScenarioId).filter(Objects::nonNull).toList();
|
||||
if (!scenarioIds.isEmpty()) {
|
||||
scenarioResultService.remove(new QueryWrapper<ScenarioResult>().in("scenario_id", scenarioIds));
|
||||
eventService.remove(new QueryWrapper<Event>().in("scenario_id", scenarioIds));
|
||||
}
|
||||
scenarioService.remove(new QueryWrapper<Scenario>().eq("project_id", projectId));
|
||||
materialService.remove(new QueryWrapper<Material>().eq("project_id", projectId));
|
||||
deviceService.remove(new QueryWrapper<Device>().eq("project_id", projectId));
|
||||
this.removeById(projectId);
|
||||
}
|
||||
|
||||
private Map<String, Integer> headerIndex(Row header, DataFormatter df) {
|
||||
Map<String, Integer> map = new HashMap<>();
|
||||
if (header == null) return map;
|
||||
short last = header.getLastCellNum();
|
||||
for (int i = 0; i < last; i++) {
|
||||
Cell c = header.getCell(i);
|
||||
String v = c == null ? "" : df.formatCellValue(c);
|
||||
if (v != null && !v.isBlank()) {
|
||||
map.put(v.trim(), i);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private String cell(DataFormatter df, Row row, Integer idx) {
|
||||
if (row == null || idx == null) return null;
|
||||
Cell c = row.getCell(idx);
|
||||
if (c == null) return null;
|
||||
String v = df.formatCellValue(c);
|
||||
return v == null ? null : v.trim();
|
||||
}
|
||||
|
||||
private Double parseDoubleObj(String s) {
|
||||
if (s == null || s.isBlank()) return null;
|
||||
try { return Double.parseDouble(s); } catch (Exception e) { return null; }
|
||||
}
|
||||
|
||||
private BigDecimal parseBigDecimal(String s) {
|
||||
if (s == null || s.isBlank()) return null;
|
||||
try { return new BigDecimal(s.trim()); } catch (Exception e) { return null; }
|
||||
}
|
||||
|
||||
//运行项目模拟
|
||||
@Override
|
||||
public java.util.Map<String, Object> runSimulation(String projectId, String scenarioId, java.util.Map<String, Object> params) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user