添加创建人

This commit is contained in:
wanxiaoli 2025-12-19 12:08:07 +08:00
parent 7499a6e295
commit 5fbdb08f67
23 changed files with 500 additions and 229 deletions

View File

@ -66,18 +66,6 @@
<classifier>plain</classifier>
</dependency>
<!-- Apache POI 用于 Excel 导入 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<!-- Lombok -->
<dependency>
@ -101,6 +89,29 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce-java</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>[17,)</version>
</requireJavaVersion>
<requireMavenVersion>
<version>[3.6.3,)</version>
</requireMavenVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>

View File

@ -0,0 +1,28 @@
package com.yfd.business.css.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI businessCssOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Business CSS API")
.description("临界事故情景分析业务接口")
.version("v1"));
}
@Bean
public GroupedOpenApi businessCssGroup() {
return GroupedOpenApi.builder()
.group("business-css")
.packagesToScan("com.yfd.business.css.controller")
.build();
}
}

View File

@ -16,16 +16,6 @@ public class AlgorithmController {
@Autowired
private AlgorithmService algorithmService;
@GetMapping
public List<Algorithm> getAllAlgorithms() {
return algorithmService.list();
}
@GetMapping("/page")
public Page<Algorithm> getAlgorithmsPage(@RequestParam(defaultValue = "1") int current,
@RequestParam(defaultValue = "10") int size) {
return algorithmService.page(new Page<>(current, size));
}
@GetMapping("/{id}")
public Algorithm getAlgorithmById(@PathVariable String id) {
@ -48,12 +38,29 @@ public class AlgorithmController {
return algorithmService.removeById(id);
}
@DeleteMapping
public boolean deleteAlgorithms(@RequestBody List<String> ids) {
return algorithmService.removeByIds(ids);
}
/**
* 根据算法名称搜索并分页返回
* 输入参数查询参数 name算法名称关键词可为空pageNum页码默认1pageSize每页条数默认10
* 输出参数算法分页列表
* @param name 算法名称关键词可为空
* @param pageNum 页码
* @param pageSize 每页条数
* @return 算法分页列表
*/
@GetMapping("/search")
public List<Algorithm> searchAlgorithms(@RequestParam String keyword) {
public Page<Algorithm> searchAlgorithms(@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "10") long pageSize) {
QueryWrapper<Algorithm> queryWrapper = new QueryWrapper<>();
queryWrapper.like("name", keyword)
.or()
.like("description", keyword);
return algorithmService.list(queryWrapper);
if (name != null && !name.isEmpty()) {
queryWrapper.like("name", name);
}
Page<Algorithm> page = new Page<>(pageNum, pageSize);
return algorithmService.page(page, queryWrapper);
}
}

View File

@ -1,6 +1,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.CriticalData;
import com.yfd.business.css.service.CriticalDataService;
import org.springframework.web.bind.annotation.*;
@ -81,15 +82,21 @@ public class CriticalDataController {
/**
* 6. 根据设备类型获取临界数据列表
* 输入参数查询参数 deviceType设备类型
* 输出参数临界数据列表按创建时间倒序
* 6. 根据设备类型获取临界数据分页列表
* 输入参数查询参数 deviceType设备类型pageNum页码默认1pageSize每页条数默认10
* 输出参数临界数据分页列表按创建时间倒序
* @param deviceType 设备类型
* @return 临界数据列表
* @param pageNum 页码
* @param pageSize 每页条数
* @return 临界数据分页列表
*/
@GetMapping("/by-device-type")
public List<CriticalData> listByDeviceType(@RequestParam String deviceType) {
return criticalDataService.list(
public Page<CriticalData> listByDeviceType(@RequestParam String deviceType,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "10") long pageSize) {
Page<CriticalData> page = new Page<>(pageNum, pageSize);
return criticalDataService.page(
page,
new QueryWrapper<CriticalData>()
.eq("device_type", deviceType)
.orderByDesc("created_at")

View File

@ -1,6 +1,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.service.DeviceService;
import org.springframework.web.bind.annotation.*;
@ -96,34 +97,24 @@ public class DeviceController {
}
/**
* 6. 根据设备类型获取设备列表
* 输入参数查询参数 type设备类型
* 输出参数设备列表按创建时间倒序
* @param type 设备类型
* @return 设备列表
*/
@GetMapping("/by-type")
public List<Device> listByType(@RequestParam String type) {
return deviceService.list(
new QueryWrapper<Device>()
.eq("type", type)
.orderByDesc("created_at")
);
}
/**
* 7. 设备查询类型 + 名称
* 输入参数查询参数 type可选name可选
* 输出参数设备列表按创建时间倒序
* 6. 设备分页查询类型 可选 + 名称 可选
* 输入参数查询参数 type可选name可选pageNum页码默认1pageSize每页条数默认10
* 输出参数设备分页列表按创建时间倒序
* @param type 设备类型可选
* @param name 设备名称关键词可选
* @return 设备列表
* @param pageNum 页码
* @param pageSize 每页条数
* @return 设备分页列表
*/
@GetMapping("/search")
public List<Device> search(@RequestParam(required = false) String type,
@RequestParam(required = false) String name) {
public Page<Device> search(@RequestParam(required = false) String type,
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "20") long pageSize) {
Page<Device> page = new Page<>(pageNum, pageSize);
QueryWrapper<Device> wrapper = new QueryWrapper<>();
if (type != null && !type.isEmpty()) {
@ -133,6 +124,6 @@ public class DeviceController {
wrapper.like("name", name);
}
return deviceService.list(wrapper.orderByDesc("created_at"));
return deviceService.page(page, wrapper.orderByDesc("created_at"));
}
}

View File

@ -33,6 +33,32 @@ public class EventController {
));
}
/**
* 修改始发事件
* 输入参数路径参数 eventId事件ID请求体中的事件对象
* 输出参数标准响应结构包含修改后的事件对象
* @param eventId 事件ID
* @param event 事件对象
* @return 修改结果
*/
@PutMapping("/{eventId}")
public ResponseEntity<Map<String, Object>> updateEvent(@PathVariable String eventId,
@RequestBody Event event) {
event.setEventId(eventId);
boolean ok = eventService.updateById(event);
if (!ok) {
return ResponseEntity.badRequest().body(Map.of(
"code", 1,
"msg", "修改失败"
));
}
return ResponseEntity.ok(Map.of(
"code", 0,
"msg", "修改成功",
"data", event
));
}
/**
* 修改 Event attr_changes
*/

View File

@ -1,6 +1,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.Material;
import com.yfd.business.css.service.MaterialService;
import org.springframework.web.bind.annotation.*;
@ -79,18 +80,23 @@ public class MaterialController {
}
/**
* 5. 根据物料名称搜索
* 输入参数查询参数 name物料名称关键词
* 输出参数物料列表按创建时间倒序
* @param name 物料名称关键词
* @return 物料列表
* 5. 根据物料名称搜索可为空并分页返回
* 输入参数查询参数 name物料名称关键词可为空pageNum页码默认1pageSize每页条数默认10
* 输出参数物料分页列表按创建时间倒序
* @param name 物料名称关键词可为空
* @param pageNum 页码
* @param pageSize 每页条数
* @return 物料分页列表
*/
@GetMapping("/search")
public List<Material> search(@RequestParam String name) {
return materialService.list(
new QueryWrapper<Material>()
.like("name", name)
.orderByDesc("created_at")
);
public Page<Material> search(@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "10") long pageSize) {
QueryWrapper<Material> wrapper = new QueryWrapper<>();
if (name != null && !name.isEmpty()) {
wrapper.like("name", name);
}
Page<Material> page = new Page<>(pageNum, pageSize);
return materialService.page(page, wrapper.orderByDesc("created_at"));
}
}

View File

@ -1,6 +1,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.service.ProjectService;
import org.springframework.http.HttpHeaders;
@ -11,6 +12,12 @@ import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.io.ByteArrayOutputStream;
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.xssf.usermodel.XSSFWorkbook;
import java.time.format.DateTimeFormatter;
@RestController
@RequestMapping("/projects")
@ -67,63 +74,65 @@ public class ProjectController {
return projectService.removeByIds(ids);
}
/**
* 4. 导出所有项目
* 输入参数
* 导出描述返回所有项目的 JSON 数组作为附件 `projects.json`
* 输出参数附件字节流application/octet-stream
* @return 附件响应文件名为 projects.json
*/
@GetMapping("/export/all")
public ResponseEntity<byte[]> exportAll() {
byte[] data = projectService.exportAllProjects();
/**
* 4.1 导出所有项目Excel
* 输入参数
* 导出描述返回所有项目的 Excel 附件 `projects.xlsx`
* 导出列project_id, code, name, description, created_at, updated_at
* @return 附件响应文件名为 projects.xlsx
*/
@GetMapping("/exportAllExports")
public ResponseEntity<byte[]> exportAllExports() {
byte[] bytes = projectService.exportAllProjectsExcel();
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=projects.json")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=projects.xlsx")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(data);
.body(bytes);
}
/**
* 5. 导出项目工程
* 5.1 导出项目工程Excel Sheet
* 输入参数路径参数项目ID
* 导出描述返回 ZIP 附件 `project_{id}.zip`包含以下 JSON 文件
* - project.json项目对象
* - devices.json设备列表
* - materials.json物料列表
* - scenarios.json情景列表
* - events.json事件列表
* - scenario-results.json情景结果列表
* 导出描述返回 Excel 附件 `project_{id}.xlsx`包含以下 Sheet
* - projects项目- project_id, code, name, description, created_at, updated_at
* - devices设备- device_id, project_id, code, type, name, size, volume, flow_rate, pulse_velocity, created_at, updated_at
* - materials物料- material_id, project_id, name, u_concentration, uo2_density, u_enrichment, pu_concentration, puo2_density, pu_isotope, hno3_acidity, h2c2o4_concentration, organic_ratio, moisture_content, custom_attrs, created_at, updated_at
* - scenarios情景- scenario_id, project_id, name, description, created_at, updated_at
* - events事件- event_id, scenario_id, device_id, material_id, trigger_time, attr_changes, created_at
* - scenario_results情景结果- scenario_id, device_id, step, keff_value, attr_state
* 输出参数附件字节流application/octet-stream
* @param id 项目ID
* @return 附件响应文件名为 project_{id}.zip
* @return 附件响应文件名为 project_{id}.xlsx
*/
@GetMapping("/{id}/export")
public ResponseEntity<byte[]> exportProject(@PathVariable String id) {
byte[] data = projectService.exportProjectEngineering(id);
@GetMapping("/{id}/exportProject")
public ResponseEntity<byte[]> exportProjectExcel(@PathVariable String id) {
byte[] bytes = projectService.exportProjectEngineeringExcel(id);
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=project_" + id + ".zip")
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=project_" + id + ".xlsx")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(data);
.body(bytes);
}
/**
* 6. 根据项目名称搜索
* 输入参数查询参数 name项目名称关键词
* 输出参数项目列表
* @param name 项目名称关键词
* @return 匹配的项目列表
* 6. 根据项目名称搜索可为空并分页返回
* 输入参数查询参数 name项目名称关键词可为空pageNum页码默认1pageSize每页条数默认10
* 输出参数项目分页列表按创建时间倒序
* @param name 项目名称关键词可为空
* @param pageNum 页码
* @param pageSize 每页条数
* @return 项目分页列表
*/
@GetMapping("/search")
public List<Project> searchByName(@RequestParam String name) {
return projectService.list(
new QueryWrapper<Project>()
.like("name", name)
.orderByDesc("created_at")
);
public Page<Project> search(@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "10") long pageSize) {
QueryWrapper<Project> wrapper = new QueryWrapper<>();
if (name != null && !name.isEmpty()) {
wrapper.like("name", name);
}
Page<Project> page = new Page<>(pageNum, pageSize);
return projectService.page(page, wrapper.orderByDesc("created_at"));
}
/**

View File

@ -1,6 +1,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.service.ScenarioService;
import org.springframework.web.bind.annotation.*;
@ -63,21 +64,7 @@ public class ScenarioController {
return scenarioService.removeByIds(ids);
}
/**
* 4. 根据情景名称搜索
* 输入参数查询参数 name情景名称关键词
* 输出参数情景列表按创建时间倒序
* @param name 情景名称关键词
* @return 情景列表
*/
@GetMapping("/search")
public List<Scenario> searchByName(@RequestParam String name) {
return scenarioService.list(
new QueryWrapper<Scenario>()
.like("name", name)
.orderByDesc("created_at")
);
}
/**
* 5. 根据情景ID获取情景记录
@ -92,18 +79,25 @@ public class ScenarioController {
}
/**
* 6. 根据项目ID查询情景列表
* 输入参数查询参数 projectId项目ID
* 输出参数情景列表按创建时间倒序
* 6. 根据项目ID与情景名称查询情景列表分页
* 输入参数projectId项目IDname情景名称关键词可为空pageNum默认1pageSize默认20
* 输出参数情景分页列表按创建时间倒序
* @param projectId 项目ID
* @return 情景列表
* @param name 情景名称关键词可为空
* @param pageNum 页码
* @param pageSize 每页条数
* @return 情景分页列表
*/
@GetMapping("/by-project")
public List<Scenario> listByProject(@RequestParam String projectId) {
return scenarioService.list(
new QueryWrapper<Scenario>()
.eq("project_id", projectId)
.orderByDesc("created_at")
);
public Page<Scenario> listByProject(@RequestParam String projectId,
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "20") long pageSize) {
Page<Scenario> page = new Page<>(pageNum, pageSize);
QueryWrapper<Scenario> wrapper = new QueryWrapper<Scenario>().eq("project_id", projectId);
if (name != null && !name.isEmpty()) {
wrapper.like("name", name);
}
return scenarioService.page(page, wrapper.orderByDesc("created_at"));
}
}

View File

@ -6,8 +6,16 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
import java.util.Map;
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.xssf.usermodel.XSSFWorkbook;
import jakarta.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@RestController
@RequestMapping("/scenario-results")
@ -34,21 +42,65 @@ public class ScenarioResultController {
}
/**
* 根据情景ID与设备ID获取情景结果列表
* 输入参数查询参数 scenarioId情景IDdeviceId设备ID
* 输出参数情景结果列表按时间点 step 排序
* 根据情景ID与设备ID获取情景结果分页列表
* 输入参数查询参数 scenarioId情景IDdeviceId设备IDpageNum页码默认1pageSize每页条数默认10
* 输出参数情景结果分页列表按时间点 step 排序
* @param scenarioId 情景ID
* @param deviceId 设备ID
* @return 情景结果列表
* @param pageNum 页码
* @param pageSize 每页条数
* @return 情景结果分页列表
*/
@GetMapping("/by-scenario")
public List<ScenarioResult> listByScenario(@RequestParam String scenarioId,
@RequestParam String deviceId) {
return scenarioResultService.list(
public Page<ScenarioResult> listByScenario(@RequestParam String scenarioId,
@RequestParam String deviceId,
@RequestParam(defaultValue = "1") long pageNum,
@RequestParam(defaultValue = "10") long pageSize) {
Page<ScenarioResult> page = new Page<>(pageNum, pageSize);
return scenarioResultService.page(
page,
new QueryWrapper<ScenarioResult>()
.eq("scenario_id", scenarioId)
.eq("device_id", deviceId)
.orderByAsc("step")
);
}
/**
* 导出情景结果到 Excel
* 输入参数查询参数 scenarioId情景IDdeviceId设备ID
* 输出参数Excel 文件包含 stepdevice_idkeff_valueattr_state
*/
@GetMapping("/export")
public void exportScenarioResults(@RequestParam String scenarioId,
@RequestParam String deviceId,
HttpServletResponse response) throws Exception {
List<ScenarioResult> results = scenarioResultService.list(
new QueryWrapper<ScenarioResult>()
.eq("scenario_id", scenarioId)
.eq("device_id", deviceId)
.orderByAsc("step")
);
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("ScenarioResults");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("step");
header.createCell(1).setCellValue("device_id");
header.createCell(2).setCellValue("keff_value");
header.createCell(3).setCellValue("attr_state");
for (int i = 0; i < results.size(); i++) {
ScenarioResult r = results.get(i);
Row row = sheet.createRow(i + 1);
row.createCell(0).setCellValue(r.getStep() == null ? 0 : r.getStep());
row.createCell(1).setCellValue(r.getDeviceId() == null ? "" : r.getDeviceId());
row.createCell(2).setCellValue(r.getKeffValue() == null ? "" : r.getKeffValue().toPlainString());
row.createCell(3).setCellValue(r.getAttrState() == null ? "" : r.getAttrState());
}
String fileName = "scenario_results_" + scenarioId + "_" + deviceId + ".xlsx";
String encoded = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replaceAll("\\+", "%20");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encoded);
workbook.write(response.getOutputStream());
workbook.close();
}
}

View File

@ -38,4 +38,7 @@ public class Algorithm implements Serializable {
@TableField("output_params")
private String outputParams;
@TableField("modifer")
private String modifier;
}

View File

@ -45,4 +45,7 @@ public class CriticalData implements Serializable {
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("modifer")
private String modifier;
}

View File

@ -47,4 +47,7 @@ public class Device implements Serializable {
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("modifer")
private String modifier;
}

View File

@ -35,4 +35,7 @@ public class Event implements Serializable {
@TableField("created_at")
private LocalDateTime createdAt;
@TableField("modifer")
private String modifier;
}

View File

@ -63,4 +63,7 @@ public class Material implements Serializable {
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("modifer")
private String modifier;
}

View File

@ -35,4 +35,7 @@ public class Project implements Serializable {
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("modifer")
private String modifier;
}

View File

@ -32,4 +32,7 @@ public class Scenario implements Serializable {
@TableField("updated_at")
private LocalDateTime updatedAt;
@TableField("modifer")
private String modifier;
}

View File

@ -4,14 +4,15 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.business.css.domain.Project;
public interface ProjectService extends IService<Project> {
/**
* 导出所有项目
*/
byte[] exportAllProjects();
/**
* 导出项目工程设备 + 物料 + 场景 + 事件 + 结果
* 导出所有项目为 Excel
*/
byte[] exportProjectEngineering(String projectId);
byte[] exportAllProjectsExcel();
/**
* 导出项目工程为 Excel Sheet
*/
byte[] exportProjectEngineeringExcel(String projectId);
}

View File

@ -19,9 +19,12 @@ import com.yfd.business.css.service.ScenarioService;
import com.yfd.business.css.service.EventService;
import com.yfd.business.css.service.ScenarioResultService;
import java.util.List;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;
import java.io.ByteArrayOutputStream;
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.xssf.usermodel.XSSFWorkbook;
import java.time.format.DateTimeFormatter;
@Service
public class ProjectServiceImpl
@ -39,35 +42,44 @@ public class ProjectServiceImpl
private EventService eventService;
@Resource
private ScenarioResultService scenarioResultService;
@Override
public byte[] exportAllProjects() {
try {
List<Project> projects = this.list();
return objectMapper.writeValueAsBytes(projects);
public byte[] exportAllProjectsExcel() {
try (Workbook wb = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
List<Project> list = this.list(new QueryWrapper<Project>().orderByDesc("created_at"));
Sheet sheet = wb.createSheet("projects");
int r = 0;
Row header = sheet.createRow(r++);
String[] cols = {"project_id","code","name","description","created_at","updated_at"};
for (int i = 0; i < cols.length; i++) header.createCell(i).setCellValue(cols[i]);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (Project p : list) {
Row row = sheet.createRow(r++);
row.createCell(0).setCellValue(p.getProjectId());
row.createCell(1).setCellValue(p.getCode() == null ? "" : p.getCode());
row.createCell(2).setCellValue(p.getName() == null ? "" : p.getName());
row.createCell(3).setCellValue(p.getDescription() == null ? "" : p.getDescription());
row.createCell(4).setCellValue(p.getCreatedAt() == null ? "" : fmt.format(p.getCreatedAt()));
row.createCell(5).setCellValue(p.getUpdatedAt() == null ? "" : fmt.format(p.getUpdatedAt()));
}
for (int i = 0; i < cols.length; i++) sheet.autoSizeColumn(i);
wb.write(out);
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public byte[] exportProjectEngineering(String projectId) {
try {
Project project = this.getById(projectId);
if (project == null) {
throw new IllegalArgumentException("项目不存在: " + projectId);
}
public byte[] exportProjectEngineeringExcel(String projectId) {
try (Workbook wb = new XSSFWorkbook(); ByteArrayOutputStream out = new ByteArrayOutputStream()) {
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
List<Device> devices = deviceService.list(
new QueryWrapper<Device>().eq("project_id", projectId)
);
List<Material> materials = materialService.list(
new QueryWrapper<Material>().eq("project_id", projectId)
);
List<Scenario> scenarios = scenarioService.list(
new QueryWrapper<Scenario>().eq("project_id", projectId)
);
List<Project> projects = this.list(new QueryWrapper<Project>().eq("project_id", projectId));
List<Device> devices = deviceService.list(new QueryWrapper<Device>().eq("project_id", projectId));
List<Material> materials = materialService.list(new QueryWrapper<Material>().eq("project_id", projectId));
List<Scenario> scenarios = scenarioService.list(new QueryWrapper<Scenario>().eq("project_id", projectId));
List<String> scenarioIds = scenarios.stream().map(Scenario::getScenarioId).toList();
List<Event> events = scenarioIds.isEmpty()
? List.of()
: eventService.list(new QueryWrapper<Event>().in("scenario_id", scenarioIds));
@ -75,39 +87,107 @@ public class ProjectServiceImpl
? List.of()
: scenarioResultService.list(new QueryWrapper<ScenarioResult>().in("scenario_id", scenarioIds));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
// 项目信息
zos.putNextEntry(new ZipEntry("project.json"));
zos.write(objectMapper.writeValueAsBytes(project));
zos.closeEntry();
// 设备
zos.putNextEntry(new ZipEntry("devices.json"));
zos.write(objectMapper.writeValueAsBytes(devices));
zos.closeEntry();
// 物料
zos.putNextEntry(new ZipEntry("materials.json"));
zos.write(objectMapper.writeValueAsBytes(materials));
zos.closeEntry();
// 情景
zos.putNextEntry(new ZipEntry("scenarios.json"));
zos.write(objectMapper.writeValueAsBytes(scenarios));
zos.closeEntry();
// 事件
zos.putNextEntry(new ZipEntry("events.json"));
zos.write(objectMapper.writeValueAsBytes(events));
zos.closeEntry();
// 结果
zos.putNextEntry(new ZipEntry("scenario-results.json"));
zos.write(objectMapper.writeValueAsBytes(results));
zos.closeEntry();
Sheet s1 = wb.createSheet("projects");
String[] h1 = {"project_id","code","name","description","created_at","updated_at"};
int r = 0; Row rh1 = s1.createRow(r++); for (int i=0;i<h1.length;i++) rh1.createCell(i).setCellValue(h1[i]);
for (Project p : projects) {
Row row = s1.createRow(r++);
row.createCell(0).setCellValue(p.getProjectId());
row.createCell(1).setCellValue(p.getCode()==null?"":p.getCode());
row.createCell(2).setCellValue(p.getName()==null?"":p.getName());
row.createCell(3).setCellValue(p.getDescription()==null?"":p.getDescription());
row.createCell(4).setCellValue(p.getCreatedAt()==null?"":fmt.format(p.getCreatedAt()));
row.createCell(5).setCellValue(p.getUpdatedAt()==null?"":fmt.format(p.getUpdatedAt()));
}
return baos.toByteArray();
for (int i=0;i<h1.length;i++) s1.autoSizeColumn(i);
Sheet s2 = wb.createSheet("devices");
String[] h2 = {"device_id","project_id","code","type","name","size","volume","flow_rate","pulse_velocity","created_at","updated_at"};
r = 0; Row rh2 = s2.createRow(r++); for (int i=0;i<h2.length;i++) rh2.createCell(i).setCellValue(h2[i]);
for (Device d : devices) {
Row row = s2.createRow(r++);
row.createCell(0).setCellValue(d.getDeviceId());
row.createCell(1).setCellValue(d.getProjectId());
row.createCell(2).setCellValue(d.getCode()==null?"":d.getCode());
row.createCell(3).setCellValue(d.getType()==null?"":d.getType());
row.createCell(4).setCellValue(d.getName()==null?"":d.getName());
row.createCell(5).setCellValue(d.getSize()==null?"":d.getSize());
row.createCell(6).setCellValue(d.getVolume()==null?0:d.getVolume());
row.createCell(7).setCellValue(d.getFlowRate()==null?0:d.getFlowRate());
row.createCell(8).setCellValue(d.getPulseVelocity()==null?0:d.getPulseVelocity());
row.createCell(9).setCellValue(d.getCreatedAt()==null?"":fmt.format(d.getCreatedAt()));
row.createCell(10).setCellValue(d.getUpdatedAt()==null?"":fmt.format(d.getUpdatedAt()));
}
for (int i=0;i<h2.length;i++) s2.autoSizeColumn(i);
Sheet s3 = wb.createSheet("materials");
String[] h3 = {"material_id","project_id","name","u_concentration","uo2_density","u_enrichment","pu_concentration","puo2_density","pu_isotope","hno3_acidity","h2c2o4_concentration","organic_ratio","moisture_content","custom_attrs","created_at","updated_at"};
r = 0; Row rh3 = s3.createRow(r++); for (int i=0;i<h3.length;i++) rh3.createCell(i).setCellValue(h3[i]);
for (Material m : materials) {
Row row = s3.createRow(r++);
row.createCell(0).setCellValue(m.getMaterialId());
row.createCell(1).setCellValue(m.getProjectId());
row.createCell(2).setCellValue(m.getName()==null?"":m.getName());
row.createCell(3).setCellValue(m.getUConcentration()==null?"":m.getUConcentration().toPlainString());
row.createCell(4).setCellValue(m.getUo2Density()==null?"":m.getUo2Density().toPlainString());
row.createCell(5).setCellValue(m.getUEnrichment()==null?"":m.getUEnrichment().toPlainString());
row.createCell(6).setCellValue(m.getPuConcentration()==null?"":m.getPuConcentration().toPlainString());
row.createCell(7).setCellValue(m.getPuo2Density()==null?"":m.getPuo2Density().toPlainString());
row.createCell(8).setCellValue(m.getPuIsotope()==null?"":m.getPuIsotope().toPlainString());
row.createCell(9).setCellValue(m.getHno3Acidity()==null?"":m.getHno3Acidity().toPlainString());
row.createCell(10).setCellValue(m.getH2c2o4Concentration()==null?"":m.getH2c2o4Concentration().toPlainString());
row.createCell(11).setCellValue(m.getOrganicRatio()==null?"":m.getOrganicRatio().toPlainString());
row.createCell(12).setCellValue(m.getMoistureContent()==null?"":m.getMoistureContent().toPlainString());
row.createCell(13).setCellValue(m.getCustomAttrs()==null?"":m.getCustomAttrs());
row.createCell(14).setCellValue(m.getCreatedAt()==null?"":fmt.format(m.getCreatedAt()));
row.createCell(15).setCellValue(m.getUpdatedAt()==null?"":fmt.format(m.getUpdatedAt()));
}
for (int i=0;i<h3.length;i++) s3.autoSizeColumn(i);
Sheet s4 = wb.createSheet("scenarios");
String[] h4 = {"scenario_id","project_id","name","description","created_at","updated_at"};
r = 0; Row rh4 = s4.createRow(r++); for (int i=0;i<h4.length;i++) rh4.createCell(i).setCellValue(h4[i]);
for (Scenario sc : scenarios) {
Row row = s4.createRow(r++);
row.createCell(0).setCellValue(sc.getScenarioId());
row.createCell(1).setCellValue(sc.getProjectId());
row.createCell(2).setCellValue(sc.getName()==null?"":sc.getName());
row.createCell(3).setCellValue(sc.getDescription()==null?"":sc.getDescription());
row.createCell(4).setCellValue(sc.getCreatedAt()==null?"":fmt.format(sc.getCreatedAt()));
row.createCell(5).setCellValue(sc.getUpdatedAt()==null?"":fmt.format(sc.getUpdatedAt()));
}
for (int i=0;i<h4.length;i++) s4.autoSizeColumn(i);
Sheet s5 = wb.createSheet("events");
String[] h5 = {"event_id","scenario_id","device_id","material_id","trigger_time","attr_changes","created_at"};
r = 0; Row rh5 = s5.createRow(r++); for (int i=0;i<h5.length;i++) rh5.createCell(i).setCellValue(h5[i]);
for (Event ev : events) {
Row row = s5.createRow(r++);
row.createCell(0).setCellValue(ev.getEventId());
row.createCell(1).setCellValue(ev.getScenarioId());
row.createCell(2).setCellValue(ev.getDeviceId());
row.createCell(3).setCellValue(ev.getMaterialId());
row.createCell(4).setCellValue(ev.getTriggerTime()==null?0:ev.getTriggerTime());
row.createCell(5).setCellValue(ev.getAttrChanges()==null?"":ev.getAttrChanges());
row.createCell(6).setCellValue(ev.getCreatedAt()==null?"":fmt.format(ev.getCreatedAt()));
}
for (int i=0;i<h5.length;i++) s5.autoSizeColumn(i);
Sheet s6 = wb.createSheet("scenario_results");
String[] h6 = {"scenario_id","device_id","step","keff_value","attr_state"};
r = 0; Row rh6 = s6.createRow(r++); for (int i=0;i<h6.length;i++) rh6.createCell(i).setCellValue(h6[i]);
for (ScenarioResult sr : results) {
Row row = s6.createRow(r++);
row.createCell(0).setCellValue(sr.getScenarioId());
row.createCell(1).setCellValue(sr.getDeviceId());
row.createCell(2).setCellValue(sr.getStep()==null?0:sr.getStep());
row.createCell(3).setCellValue(sr.getKeffValue()==null?"":sr.getKeffValue().toPlainString());
row.createCell(4).setCellValue(sr.getAttrState()==null?"":sr.getAttrState());
}
for (int i=0;i<h6.length;i++) s6.autoSizeColumn(i);
wb.write(out);
return out.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}

View File

@ -355,33 +355,6 @@
</goals>
</execution>
</executions>
</plugin>
<!-- 固化构建规则Maven Enforcer -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce-rules</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<!-- 推荐升级 Maven 到 3.8+;临时放宽版本以便构建 -->
<requireMavenVersion>
<version>[3.6.3,)</version>
</requireMavenVersion>
<requireJavaVersion>
<version>[17,)</version>
</requireJavaVersion>
<dependencyConvergence/>
<!-- 如需严格校验插件版本,可在升级 Maven 后再启用 -->
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- 额外生成 classes JAR便于其他业务工程作为依赖引用 -->
<plugin>

45
mvn-settings.xml Normal file
View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
<mirrors>
<mirror>
<id>aliyunmaven</id>
<name>Aliyun Maven</name>
<mirrorOf>central</mirrorOf>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
<profiles>
<profile>
<id>aliyun</id>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<activeProfiles>
<activeProfile>aliyun</activeProfile>
</activeProfiles>
</settings>

4
scripts/mvn17.cmd Normal file
View File

@ -0,0 +1,4 @@
@echo off
set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot"
set "PATH=%JAVA_HOME%\bin;%PATH%"
mvn %*

View File

@ -162,6 +162,8 @@ src/main/resources
# 1. 安装 framework 到本地仓库
mvn -DskipTests clean install -pl framework
# 2. 启动业务模块(自动依赖 framework
mvn -DskipTests spring-boot:run -pl business-css
```
@ -219,3 +221,17 @@ business-css/target/business-css-1.0-SNAPSHOT.jar # 业务服务(含内嵌 To
---
> **一句话总结**framework 做“平台”business-css 做“产品”;平台沉淀,产品迭代,互不污染,横向复制。
## 快速稳定方案(作用:脚本先设置 JAVA_HOME 与 PATH 指向 17再调用 Maven确保所有构建/运行都用 JDK 17不受工具自带 JDK 8 影响。)
使用项目内脚本强制 JDK 17已为你添加
scripts\mvn17.cmd -s mvn-settings.xml -DskipTests -pl framework -am install
scripts\mvn17.cmd -s mvn-settings.xml -DskipTests -f business-css\pom.xml spring-boot:run -Dspring-boot.run.profiles=local
## 在工具内终端验证并调整到 17
- 验证: mvn -version 、 where java 、 where mvn
- 临时修正当前终端(一次性手动):
- set "JAVA_HOME=C:\Program Files\Eclipse Adoptium\jdk-17.0.17.10-hotspot"
- set "PATH=%JAVA_HOME%\bin;%PATH%"
- 再 mvn -version 应为 17