1、对接海葵云、EP接口

This commit is contained in:
2025-12-22 10:14:25 +08:00
parent bf26f136c0
commit d830d5dc98
27 changed files with 1011 additions and 4 deletions

View File

@@ -11,6 +11,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Vector;
@@ -409,6 +410,135 @@ public class FilesUtil {
}
}
/**
* 获取指定目录下的所有文件(不递归子目录)
* @param dirPath 目录路径
* @return 目录下所有文件的List集合
* @throws IllegalArgumentException 目录路径不合法时抛出
*/
public static List<File> getAllFiles(String dirPath) {
return getAllFiles(dirPath, false);
}
/**
* 获取指定目录下的所有文件
* @param dirPath 目录路径
* @param recursive 是否递归遍历子目录
* @return 目录下所有文件的List集合
* @throws IllegalArgumentException 目录路径不合法时抛出
*/
public static List<File> getAllFiles(String dirPath, boolean recursive) {
// 1. 校验目录路径合法性
File directory = validateDirectory(dirPath);
// 2. 初始化文件集合
List<File> fileList = new ArrayList<>();
// 3. 遍历目录收集文件
collectFiles(directory, fileList, recursive);
return fileList;
}
/**
* 校验目录合法性
* @param dirPath 目录路径
* @return 合法的目录File对象
* @throws IllegalArgumentException 目录不合法时抛出异常
*/
private static File validateDirectory(String dirPath) {
if (dirPath == null || dirPath.trim().isEmpty()) {
throw new IllegalArgumentException("目录路径不能为空");
}
File directory = new File(dirPath);
if (!directory.exists()) {
throw new IllegalArgumentException("目录不存在: " + dirPath);
}
if (!directory.isDirectory()) {
throw new IllegalArgumentException("指定路径不是目录: " + dirPath);
}
if (!directory.canRead()) {
throw new IllegalArgumentException("没有目录读取权限: " + dirPath);
}
return directory;
}
/**
* 递归收集目录下的文件
* @param directory 目录
* @param fileList 文件集合
* @param recursive 是否递归
*/
private static void collectFiles(File directory, List<File> fileList, boolean recursive) {
// 获取目录下的所有文件/子目录
File[] files = directory.listFiles();
// 空目录直接返回
if (files == null || files.length == 0) {
return;
}
for (File file : files) {
if (file.isFile()) {
// 是文件则加入集合
fileList.add(file);
} else if (file.isDirectory() && recursive) {
// 是目录且需要递归则继续遍历
collectFiles(file, fileList, recursive);
}
}
}
/**
* 非递归删除:仅删除指定文件夹下的一级文件/空文件夹,最后删除文件夹本身
* @param folderPath 目标文件夹路径
* @throws IOException 文件夹不存在、非文件夹、删除失败时抛出异常
*/
public static void deleteFolderNonRecursive(String folderPath) throws IOException {
// 1. 校验文件夹合法性
File targetFolder = new File(folderPath);
if (!targetFolder.exists()) {
throw new IOException("文件夹不存在: " + folderPath);
}
if (!targetFolder.isDirectory()) {
throw new IOException("指定路径不是文件夹: " + folderPath);
}
// 2. 非递归遍历一级内容
File[] files = targetFolder.listFiles();
if (files != null) { // 处理权限问题导致listFiles返回null的情况
for (File file : files) {
if (file.isFile()) {
// 删除一级文件
boolean deleted = file.delete();
if (deleted) {
log.info("已删除文件:{}" , file.getAbsolutePath());
} else {
log.error("删除文件失败:{}" , file.getAbsolutePath());
}
} else if (file.isDirectory()) {
// 仅删除空的一级子文件夹,非空则跳过
if (file.listFiles() == null || file.listFiles().length == 0) {
boolean deleted = file.delete();
if (deleted) {
log.info("已删除空文件夹: {}" , file.getAbsolutePath());
} else {
log.error("删除空文件夹失败: {}" , file.getAbsolutePath());
}
} else {
log.info("跳过非空子文件夹: {}" , file.getAbsolutePath());
}
}
}
}
// 3. 检查目标文件夹是否为空,为空则删除本身
File[] remainingFiles = targetFolder.listFiles();
if (remainingFiles == null || remainingFiles.length == 0) {
boolean folderDeleted = targetFolder.delete();
if (folderDeleted) {
log.info("已删除目标文件夹本身: {}" , targetFolder.getAbsolutePath());
} else {
throw new IOException("删除目标文件夹失败,可能是权限不足: " + folderPath);
}
} else {
throw new IOException("目标文件夹仍有非空内容,无法删除本身: " + folderPath);
}
}
}

View File

@@ -1,10 +1,12 @@
package com.sdm.outbridge.mode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class HkUploadFileReq {
@Schema(description = "权限编码")
public String filePower = "2456236750149124114";

View File

@@ -100,6 +100,20 @@
</exclusions>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.5.0</version>
</dependency>
<!-- Spring整合Quartz如果是Spring/SpringBoot项目 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>6.1.14</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>

View File

@@ -0,0 +1,34 @@
package com.sdm.project.common.generator;
import java.security.SecureRandom;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class UniqueFileNameGenerator {
// 定义随机字符串的字符集(字母+数字避免混淆的字符如0/O、1/l已剔除
private static final String CHARACTERS = "abcdefghjkmnpqrstuvwxyz";
private static final int RANDOM_LENGTH = 12; // 随机字符串长度
private static final SecureRandom SECURE_RANDOM = new SecureRandom(); // 安全随机数生成器
// 日期格式化器年月日如20251221
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
/**
* 生成唯一文件名:年月日 + 12位随机字符串
* @return 格式化后的文件名如20251221akdesgdiujfs
*/
public static String generateUniqueFileName() {
// 1. 获取当前年月日并格式化
String currentDate = LocalDate.now().format(DATE_FORMATTER);
// 2. 生成12位随机字符串
StringBuilder randomStr = new StringBuilder(RANDOM_LENGTH);
for (int i = 0; i < RANDOM_LENGTH; i++) {
// 随机获取字符集索引
int randomIndex = SECURE_RANDOM.nextInt(CHARACTERS.length());
randomStr.append(CHARACTERS.charAt(randomIndex));
}
// 3. 拼接日期和随机字符串
return currentDate + "_" + randomStr;
}
}

View File

@@ -0,0 +1,36 @@
package com.sdm.project.config;
import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
/**
* 适配Spring 6.1.14的Quartz配置类
* 关键通过SchedulerFactoryBean实例获取Scheduler而非静态方法
*/
@Configuration
public class QuartzConfig {
/**
* 创建SchedulerFactoryBeanQuartz的核心工厂类
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
// 可选设置Quartz属性如线程池大小、集群配置等
// Properties props = new Properties();
// props.put("org.quartz.threadPool.threadCount", "10");
// factoryBean.setQuartzProperties(props);
return factoryBean;
}
/**
* 注入Scheduler实例从factoryBean中获取适配Spring 6非静态方法
*/
@Bean
public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {
// 这里调用的是实例方法getScheduler(),而非静态方法
return schedulerFactoryBean.getScheduler();
}
}

View File

@@ -0,0 +1,90 @@
package com.sdm.project.controller;
import com.sdm.common.common.SdmResponse;
import com.sdm.project.job.ProjectSyncJob;
import com.sdm.project.job.TodoSyncJob;
import com.sdm.project.manager.MultiJobManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.quartz.SchedulerException;
import java.text.ParseException;
import java.util.Collections;
/**
* 手动管理多Job的接口
*/
@RestController
@RefreshScope
public class MultiJobController {
@Autowired
private MultiJobManager multiJobManager;
private static final String TODO_SYNC_JOB_NAME = "todoSyncJob";
private static final String PROJECT_SYNC_JOB_NAME = "projectSyncJob";
@Value("${scheduler.todo}")
private String schedulerTodoTime;
@Value("${scheduler.project}")
private String schedulerProjectTime;
// 暂停指定分组的Job比如暂停数据同步任务/pauseJob/dataSyncGroup
@GetMapping("/pauseJob/{jobGroup}")
public String pauseJob(@PathVariable String jobGroup) {
try {
multiJobManager.pauseJobGroup(jobGroup);
return "已暂停分组[" + jobGroup + "]的所有任务";
} catch (SchedulerException e) {
return "暂停失败:" + e.getMessage();
}
}
// 恢复指定分组的Job
@GetMapping("/resumeJob/{jobGroup}")
public String resumeJob(@PathVariable String jobGroup) {
try {
multiJobManager.resumeJobGroup(jobGroup);
return "已恢复分组[" + jobGroup + "]的所有任务";
} catch (SchedulerException e) {
return "恢复失败:" + e.getMessage();
}
}
// 删除指定分组的Job
@GetMapping("/deleteJob")
public String deleteJob(@RequestParam String jobGroup) {
try {
multiJobManager.deleteJobGroup(jobGroup);
return "已删除分组[" + jobGroup + "]的所有任务";
} catch (SchedulerException e) {
return "删除失败:" + e.getMessage();
}
}
// 新增指定分组的Job
@GetMapping("/createJob")
public SdmResponse createJob(@RequestParam String jobGroup) {
try {
multiJobManager.deleteJobGroup(jobGroup);
if (TODO_SYNC_JOB_NAME.equals(jobGroup)) {
multiJobManager.createJob(TodoSyncJob.class,jobGroup, Collections.singletonList(schedulerTodoTime.replaceAll("\\.",":")));
}else {
multiJobManager.createJob(ProjectSyncJob.class,jobGroup, Collections.singletonList(schedulerProjectTime.replaceAll("\\.",":")));
}
return SdmResponse.success("创建" + jobGroup + "任务成功");
} catch (SchedulerException e) {
return SdmResponse.failed("创建" + jobGroup + "任务失败");
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -2,17 +2,28 @@ package com.sdm.project.controller;
import com.alibaba.excel.util.StringUtils;
import com.sdm.common.common.SdmResponse;
import com.sdm.common.utils.RandomUtil;
import com.sdm.outbridge.mode.HkUploadFileReq;
import com.sdm.outbridge.service.lyric.LyricIntegrateService;
import com.sdm.project.common.ApprovalStatusEnum;
import com.sdm.project.model.entity.SimulationNode;
import com.sdm.project.model.req.ProcessDataReq;
import com.sdm.project.model.req.PushReportReq;
import com.sdm.project.service.ILyricInternalService;
import com.sdm.project.service.ISimulationLyricNodeService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
@RestController
@RequestMapping(value = "/node")
@@ -23,7 +34,7 @@ public class SimulationLyricNodeController {
private ISimulationLyricNodeService nodeService;
@Autowired
private LyricIntegrateService lyricIntegrateService;
private ILyricInternalService lyricInternalService;
@GetMapping("/updateApprovalStatus")
@Operation(summary = "仿真节点审批状态更新", description = "仿真节点审批状态更新")
@@ -34,7 +45,33 @@ public class SimulationLyricNodeController {
@GetMapping("/getTodoList")
@Operation(summary = "获取待办列表", description = "获取待办列表")
public SdmResponse getTodoList() {
return lyricIntegrateService.getTodoList();
return lyricInternalService.getTodoList();
}
@GetMapping("/getProjectList")
@Operation(summary = "获取项目列表", description = "获取项目列表")
public SdmResponse getProjectList() {
return lyricInternalService.getProjectList();
}
/**
* 查询审批实例id
* @return
*/
@GetMapping("/getProcessData")
@Operation(summary = "查询审批实例id", description = "查询审批实例id")
public SdmResponse getProcessData(ProcessDataReq req) {
return lyricInternalService.getProcessData(req);
}
/**
* 推送报告
* @return
*/
@PostMapping("/pushReport")
@Operation(summary = "推送报告", description = "推送报告")
public SdmResponse pushReport(@RequestBody @Validated PushReportReq req) {
return lyricInternalService.pushReport(req);
}
}

View File

@@ -0,0 +1,17 @@
package com.sdm.project.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sdm.project.model.entity.SimulationProjectSchedulerConfig;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
/**
* <p>
* Mapper 接口
* </p>
*
* @author author
* @since 2025-11-03
*/
public interface SimulationProjectSchedulerConfigMapper extends BaseMapper<SimulationProjectSchedulerConfig> {
}

View File

@@ -0,0 +1,16 @@
package com.sdm.project.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
/**
* <p>
* Mapper 接口
* </p>
*
* @author author
* @since 2025-11-03
*/
public interface SimulationTodoSchedulerConfigMapper extends BaseMapper<SimulationTodoSchedulerConfig> {
}

View File

@@ -0,0 +1,21 @@
package com.sdm.project.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.time.LocalDateTime;
/**
* 自定义定时任务执行逻辑
*/
public class ProjectSyncJob implements Job {
/**
* 核心执行方法:这里写你需要定时执行的代码
*/
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
String triggerTime = context.getTrigger().getDescription();
System.out.println("【项目】定时任务执行成功!触发时间:" + triggerTime + ",当前系统时间:" + LocalDateTime.now());
}
}

View File

@@ -0,0 +1,23 @@
package com.sdm.project.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.time.LocalDateTime;
/**
* 自定义定时任务执行逻辑
*/
public class TodoSyncJob implements Job {
/**
* 核心执行方法:这里写你需要定时执行的代码
*/
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
String triggerTime = context.getTrigger().getDescription();
System.out.println("【待办】定时任务执行成功!触发时间:" + triggerTime + ",当前系统时间:" + LocalDateTime.now());
}
}

View File

@@ -0,0 +1,100 @@
package com.sdm.project.manager;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 通用定时任务管理类支持管理多个不同的Job
*/
@Component
public class MultiJobManager {
@Autowired
private Scheduler scheduler;
/**
* 创建指定Job的定时任务
* @param jobClass 要执行的Job类比如DataSyncJob.class、MessagePushJob.class
* @param jobGroup Job分组区分不同Job比如"dataSyncGroup"、"messagePushGroup"
* @param timeList 执行时间数组(如["15:00:00","16:00:00"]
*/
public void createJob(Class<? extends Job> jobClass, String jobGroup, List<String> timeList) throws SchedulerException, ParseException {
// 遍历时间数组为当前Job创建多个定时触发器
for (String time : timeList) {
// 1. 校验时间格式
if (!time.matches("^\\d{2}:\\d{2}:\\d{2}$")) {
throw new IllegalArgumentException("时间格式错误:" + time + "请使用HH:mm:ss格式");
}
// 2. 拆分时分秒构建Cron表达式
String[] timeParts = time.split(":");
int second = Integer.parseInt(timeParts[2]);
int minute = Integer.parseInt(timeParts[1]);
int hour = Integer.parseInt(timeParts[0]);
String cronExpression = String.format("%d %d %d * * ?", second, minute, hour);
// 3. 构建JobDetail绑定指定的Job类唯一标识jobName=时间+分组jobGroup=传入的分组)
String jobName = jobGroup + "_" + time;
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroup) // 唯一标识:名称+分组区分不同Job的任务
.build();
// 4. 构建Trigger触发器
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("trigger_" + jobName, jobGroup)
.withDescription(time)
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
// 5. 注册任务到调度器
scheduler.scheduleJob(jobDetail, trigger);
System.out.println("成功创建任务:[" + jobGroup + "] 每日" + time + "执行Cron" + cronExpression);
}
}
/**
* 停止指定分组的所有Job
* @param jobGroup Job分组如"dataSyncGroup"
*/
public void pauseJobGroup(String jobGroup) throws SchedulerException {
scheduler.pauseJobs(GroupMatcher.jobGroupEquals(jobGroup));
System.out.println("已暂停分组[" + jobGroup + "]的所有任务");
}
/**
* 启动指定分组的所有Job
* @param jobGroup Job分组
*/
public void resumeJobGroup(String jobGroup) throws SchedulerException {
scheduler.resumeJobs(GroupMatcher.jobGroupEquals(jobGroup));
System.out.println("已恢复分组[" + jobGroup + "]的所有任务");
}
/**
* 删除指定分组的所有Job
* @param jobGroup Job分组
*/
public void deleteJobGroup(String jobGroup) throws SchedulerException {
// 1. 获取指定分组下的所有TriggerKey返回Set
Set<TriggerKey> triggerKeySet = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(jobGroup));
// 2. 将Set转换为List使用Stream流简洁高效
List<TriggerKey> triggerKeyList = new ArrayList<>(triggerKeySet);
// 3. 取消触发器此时需要List参数
scheduler.unscheduleJobs(triggerKeyList);
// 4. 删除指定分组下的所有JobgetJobKeys返回Set但deleteJobs支持CollectionList/Set都可以
Set<JobKey> jobKeySet = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(jobGroup));
scheduler.deleteJobs(new ArrayList<>(jobKeySet));
System.out.println("已删除分组[" + jobGroup + "]的所有任务");
}
}

View File

@@ -0,0 +1,48 @@
package com.sdm.project.manager;
import com.sdm.project.job.ProjectSyncJob;
import com.sdm.project.job.TodoSyncJob;
import com.sdm.project.model.entity.SimulationProjectSchedulerConfig;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
import com.sdm.project.service.ISimulationProjectSchedulerConfigService;
import com.sdm.project.service.ISimulationTodoSchedulerConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 应用启动时自动初始化两个Job
*/
@Component
public class MultiJobStartupRunner implements CommandLineRunner {
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
@Autowired
private MultiJobManager multiJobManager;
@Value("${scheduler.todo}")
private String schedulerTodoTime;
@Value("${scheduler.project}")
private String schedulerProjectTime;
@Override
public void run(String... args) throws Exception {
// ========== 初始化第一个Job待办同步任务 ==========
schedulerTodoTime = schedulerTodoTime.replaceAll("\\.",":");
schedulerProjectTime = schedulerProjectTime.replaceAll("\\.",":");
multiJobManager.createJob(TodoSyncJob.class, "todoSyncJob", Collections.singletonList(schedulerTodoTime));
// ========== 初始化第二个Job项目同步任务 ==========
multiJobManager.createJob(ProjectSyncJob.class, "projectSyncJob", Collections.singletonList(schedulerProjectTime));
System.out.println("应用启动成功已初始化两个Job待办同步任务、项目同步任务");
}
}

View File

@@ -0,0 +1,42 @@
package com.sdm.project.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author author
* @since 2025-12-17
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("simulation_project_scheduler_config")
@ApiModel(value = "SimulationWork对象", description = "")
public class SimulationProjectSchedulerConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "应完成任务")
@TableField("executeTime")
private String executeTime;
}

View File

@@ -0,0 +1,42 @@
package com.sdm.project.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
*
* </p>
*
* @author author
* @since 2025-12-17
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("simulation_todo_scheduler_config")
@ApiModel(value = "SimulationWork对象", description = "")
public class SimulationTodoSchedulerConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@ApiModelProperty(value = "应完成任务")
@TableField("executeTime")
private String executeTime;
}

View File

@@ -0,0 +1,14 @@
package com.sdm.project.model.req;
import lombok.Data;
@Data
public class ProcessDataDetailReq {
private String project_number;
private String station_no;
private String status;
}

View File

@@ -0,0 +1,17 @@
package com.sdm.project.model.req;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import java.util.List;
@Data
public class ProcessDataReq {
private String jobNo;
private String queryColumn;
private ProcessDataDetailReq conditionColumn;
}

View File

@@ -0,0 +1,23 @@
package com.sdm.project.model.req;
import com.sdm.common.entity.bo.UserInfo;
import com.sdm.common.entity.pojo.project.ProjectBase;
import com.sdm.common.entity.pojo.project.ProjectExpand;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Data
public class PushReportReq {
@NotEmpty(message = "文件id不能为空")
private List<Long> fileIdList;
private String projectCode;
private String workspaceCode;
}

View File

@@ -0,0 +1,10 @@
package com.sdm.project.model.req;
import lombok.Data;
import java.util.List;
@Data
public class SchedulerReq {
List<String> timeList;
}

View File

@@ -0,0 +1,18 @@
package com.sdm.project.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdm.common.common.SdmResponse;
import com.sdm.outbridge.entity.ViewLyricconfig;
import com.sdm.project.model.req.ProcessDataReq;
import com.sdm.project.model.req.PushReportReq;
public interface ILyricInternalService {
SdmResponse getProcessData(ProcessDataReq req);
SdmResponse pushReport(PushReportReq req);
SdmResponse getTodoList();
SdmResponse getProjectList();
}

View File

@@ -0,0 +1,18 @@
package com.sdm.project.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdm.project.model.entity.SimulationProjectSchedulerConfig;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
/**
* <p>
* 服务类
* </p>
*
* @author author
* @since 2025-12-17
*/
public interface ISimulationProjectSchedulerConfigService extends IService<SimulationProjectSchedulerConfig> {
}

View File

@@ -0,0 +1,20 @@
package com.sdm.project.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.sdm.common.common.SdmResponse;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
import com.sdm.project.model.entity.SimulationWork;
import com.sdm.project.model.req.SpdmWorkReq;
/**
* <p>
* 服务类
* </p>
*
* @author author
* @since 2025-12-17
*/
public interface ISimulationTodoSchedulerConfigService extends IService<SimulationTodoSchedulerConfig> {
}

View File

@@ -0,0 +1,186 @@
package com.sdm.project.service.impl;
import com.sdm.common.common.SdmResponse;
import com.sdm.common.common.ThreadLocalContext;
import com.sdm.common.feign.impl.data.DataClientFeignClientImpl;
import com.sdm.common.utils.FilesUtil;
import com.sdm.common.utils.RandomUtil;
import com.sdm.outbridge.mode.HkUploadFileReq;
import com.sdm.outbridge.service.lyric.LyricIntegrateService;
import com.sdm.project.common.generator.UniqueFileNameGenerator;
import com.sdm.project.model.req.ProcessDataReq;
import com.sdm.project.model.req.PushReportReq;
import com.sdm.project.service.ILyricInternalService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Service
@Slf4j
public class LyricInternalServiceImpl implements ILyricInternalService {
private static final int BUFFER_SIZE = 1024 * 4; // 4KB缓冲区
private static final String TEMP_REPORT_PATH = "/opt/report/";
private static final String REPORT_ZIP_NAME = "report_";
private static final String ZIP_SUFFIX = ".zip";
@Autowired
private LyricIntegrateService lyricIntegrateService;
@Autowired
private DataClientFeignClientImpl dataFeignClient;
@Override
public SdmResponse getProcessData(ProcessDataReq req) {
// return lyricIntegrateService.getProcessData(req);
return SdmResponse.success();
}
@Override
public SdmResponse getTodoList() {
return null;
}
@Override
public SdmResponse getProjectList() {
return null;
}
@Override
public SdmResponse pushReport(PushReportReq req) {
// 根据文件id下载文件到临时目录
List<Long> fileIdList = req.getFileIdList();
String randomId = RandomUtil.generateString(16);
String tempPath = TEMP_REPORT_PATH + randomId;
if (CollectionUtils.isNotEmpty(fileIdList)) {
for (Long fileId : fileIdList) {
dataFeignClient.downloadFileToLocal(fileId, tempPath);
}
}
Path folder = Paths.get(tempPath);
if (!Files.exists(folder) || !Files.isDirectory(folder)) {
if (!new File(tempPath).mkdir()) {
log.error("创建临时文件夹:{}失败", tempPath);
throw new RuntimeException("推送报告失败,原因为:创建临时文件夹失败");
}
}
// 准备要打包的文件列表
List<File> filesToZip = FilesUtil.getAllFiles(tempPath);
// 指定生成的ZIP文件路径
String zipFilePath = tempPath + File.separator + REPORT_ZIP_NAME + UniqueFileNameGenerator.generateUniqueFileName() + ZIP_SUFFIX;
log.info("zipFilePath为{}", zipFilePath);
// 执行打包
try {
zipFiles(filesToZip, zipFilePath);
} catch (IOException e) {
log.error("打包文件异常:{}", e.getMessage());
try {
FilesUtil.deleteFolderNonRecursive(tempPath);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
throw new RuntimeException(e);
}
String jobNumber = ThreadLocalContext.getJobNumber();
HkUploadFileReq uploadFileReq = new HkUploadFileReq();
uploadFileReq.setFilePower("2456236750149124114");
uploadFileReq.setWaterMarkFlag(false);
uploadFileReq.setWaterMarkContent("spdm");
uploadFileReq.setSysId(1691399963692630016L);
uploadFileReq.setFormId(1847115435993071616L);
uploadFileReq.setComponentInstId(8000004142460000204L);
uploadFileReq.setTableName("oa_threee_d_review");
uploadFileReq.setColumnName("simulation_table");
uploadFileReq.setXmh(req.getProjectCode());
uploadFileReq.setGwh(req.getWorkspaceCode());
uploadFileReq.setFiles(Collections.singletonList(zipFilePath));
try {
lyricIntegrateService.uploadHkFile(jobNumber, uploadFileReq);
} catch (Exception e) {
log.error("推送zip异常{}", e.getMessage());
throw new RuntimeException(e);
} finally {
// 删除临时路径
log.info("删除临时路径:{},中。。。。。。", tempPath);
try {
FilesUtil.deleteFolderNonRecursive(tempPath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return SdmResponse.success();
}
/**
* 将多个文件打包成ZIP文件
*
* @param sourceFiles 要打包的文件列表
* @param zipFilePath 生成的ZIP文件路径
* @throws IOException IO异常
*/
public static void zipFiles(List<File> sourceFiles, String zipFilePath) throws IOException {
// 校验输入参数
if (sourceFiles == null || sourceFiles.isEmpty()) {
throw new IllegalArgumentException("待压缩的文件列表不能为空");
}
if (zipFilePath == null || zipFilePath.trim().isEmpty()) {
throw new IllegalArgumentException("ZIP文件路径不能为空");
}
// 声明流对象使用try-with-resources自动关闭资源
try (FileOutputStream fos = new FileOutputStream(zipFilePath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ZipOutputStream zos = new ZipOutputStream(bos)) {
zos.setLevel(9); // 设置压缩级别0-99为最高压缩率
// 遍历所有文件并添加到ZIP中
for (File file : sourceFiles) {
if (file.exists() && file.isFile()) { // 只处理存在的文件(跳过目录)
addFileToZip(zos, file);
} else {
log.info("跳过无效文件:{}" , file.getAbsolutePath());
}
}
log.info("ZIP文件创建成功:{}" , zipFilePath);
} catch (IOException e) {
log.error("创建ZIP文件失败:{}" , e.getMessage());
throw e; // 抛出异常让调用方处理
}
}
/**
* 将单个文件添加到ZIP输出流中
*
* @param zos ZIP输出流
* @param file 要添加的文件
* @throws IOException IO异常
*/
private static void addFileToZip(ZipOutputStream zos, File file) throws IOException {
// 创建ZIP条目使用文件名作为条目名
ZipEntry zipEntry = new ZipEntry(file.getName());
zos.putNextEntry(zipEntry);
// 读取文件内容并写入ZIP流
try (FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis, BUFFER_SIZE)) {
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
zos.write(buffer, 0, bytesRead);
}
zos.closeEntry(); // 关闭当前ZIP条目
}
}
}

View File

@@ -15,11 +15,11 @@ import java.util.List;
@Service
@Slf4j
public class ISimulationLyricNodeServiceImpl extends ServiceImpl<SimulationLyricNodeMapper, SimulationNode> implements ISimulationLyricNodeService {
public class SimulationLyricNodeServiceImpl extends ServiceImpl<SimulationLyricNodeMapper, SimulationNode> implements ISimulationLyricNodeService {
@Override
public SdmResponse updateApprovalStatus(String projectName, String workspaceName, Integer approvalStatus) {
log.info("仿真节点审批状态更新中projectName为{}workspaceName为{}approvalStatus为{}",projectName,workspaceName,approvalStatus);
// 0:未通过1已通过
String approvalStatusValue = String.valueOf(approvalStatus == 0 ? ApprovalStatusEnum.REJECTED.getCode() : ApprovalStatusEnum.PASSED.getCode());
List<SimulationNode> projectNodeList = this.lambdaQuery().eq(SimulationNode::getNodeName, projectName)

View File

@@ -0,0 +1,24 @@
package com.sdm.project.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sdm.project.dao.SimulationProjectSchedulerConfigMapper;
import com.sdm.project.dao.SimulationTodoSchedulerConfigMapper;
import com.sdm.project.model.entity.SimulationProjectSchedulerConfig;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
import com.sdm.project.service.ISimulationProjectSchedulerConfigService;
import com.sdm.project.service.ISimulationTodoSchedulerConfigService;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author author
* @since 2025-11-03
*/
@Service
public class SimulationProjectSchedulerConfigServiceImpl extends ServiceImpl<SimulationProjectSchedulerConfigMapper, SimulationProjectSchedulerConfig> implements ISimulationProjectSchedulerConfigService {
}

View File

@@ -0,0 +1,21 @@
package com.sdm.project.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sdm.project.dao.SimulationTodoSchedulerConfigMapper;
import com.sdm.project.model.entity.SimulationTodoSchedulerConfig;
import com.sdm.project.service.ISimulationTodoSchedulerConfigService;
import org.springframework.stereotype.Service;
/**
* <p>
* 服务实现类
* </p>
*
* @author author
* @since 2025-11-03
*/
@Service
public class SimulationTodoSchedulerConfigServiceImpl extends ServiceImpl<SimulationTodoSchedulerConfigMapper, SimulationTodoSchedulerConfig> implements ISimulationTodoSchedulerConfigService {
}

View File

@@ -137,3 +137,7 @@ YA:
#publicKeyUrl : http://s279983e.natappfree.cc/api-auth/clients/getPublicKey
publicKeyUrl : http://pisxwh.8866.org:8015/gateway/api-auth/clients/getPublicKey
frontendPrivateKey : MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjz2pItCtM2Itf3knLhA1ZWzTVtKKY692Eptk3ZUy4qjlv+2e6u78/cBYZsVa/1nOyHPtb2j9xZAsHYGKZGoh64UWSewUhRdUO15xBRr5DyGEdTWHjwc1GHf7c99rKCjKDO2Xdp7cpqYABOAxgkSA2vP5zqhSCq0FCqwleEPLG1aAa/kh/oUzCZLUoSjZIdqQOgHJTZojqNeQCOC6U8Q+kUcHdKbptewu1A6XK8DHV0WqiJJEG3kyaoAZ1kGtr6ETtGy++aRvJT9gZN4M4bIgucKtAu2dcqQHj9jZ1i2xwhY3nmLjqaz3y313/IEYpMTG8pnPb8eP5usHDaDmH8RqJAgMBAAECggEAAzz05WYGWxkGvEjpHYhJOUR3yWeuNSaodNhVf+ZVO2tGAmQuWz8d2zOshCqAw/8Jv3IaN+kbCvNG0okBufQP0ZoFZY1f/xXhzc7OTG4JEc7yuIEQl897btDl+lk97nOAJx7z9ws7MCwlFyEUAY6s29glkYTBrgmTmy1FXKIqImsLfVV3LgfL2Mkixn0YSSsbUh2b+dki1zxjct3hTGZVh29bKOpbflOaG0LqEO0UwSX92Y/ir+fKmC8zEFbi5HZANYODivm8DiwF7khpraayf78kG3liccOTMMLVxIHwNiS9wcLG8WPuVEphlXMT4Ev4lq5VFM3mVxtd9g21ESbuvwKBgQDmsgE8u66qKVBsndp2K9FV9VWYDA4fYfRswDAWnZDCzIdanT0NFPp8s3nZCVU4FfX4m958yOrJ/MVp6d58z6fgkYQh2qL2Wy6zRPaIxCc6JG3FheFSxfWyULU/mBBK02ntUZCXEs8XKjAfDvmxaVVeonv0nCSgVwxJ4ypB5BZ+owKBgQC1x0GDnWtMbNGUMx6tYtFGWQIgop4hVQe6ZNgkKaQX7gtMa5egEda6ga6wCTV3+ZvQ9tBa1DxUFb5N/TrtQdFm39gOSXyhWSrntUKqaSFo03GvXXvvze2D3+uXpk7S8yzWuuD3OYyYj9S3nFVZffymabfukuY7oY3AN0E0PALw4wKBgQDQiyGrMU6X7HkTdy9BnCLEvd7+cAdkPzyiAqp2B0IRlqrVM0c5SDmX+PaxSEqNROzyLJVX4Ji+t44OTKgf0+hCjckQgYDHi24QCMuEny2G1d+Vq40hMmsFIwh10JUJz0v2iMFYkFw86JpPuU3nHv1ZazD60xwZBhfJw10z62iaWQKBgH+EVgsUJS8pryO9cKnFBnXI/tsR+Mf9NDynfZBwvbIjxT1IxMb/fJi9XGQVMbMGIS5H1gXBmMiLsEJZgDrrzw/Ru2jaWFl/ib+dwjR1J4C3w6p3c/fXh+TY8hYiDm2hNTU1R5dmgaCMVXawbpcm8FN1Ghh8aJIwVJYgrNcNuiptAoGAO14DHGqUXZZ//erIYWVfL0CAMXqy38dqNmfbzSAXYyLDl6cn49CCHF0GXOfCOesQN9ToQbqpLrntFgcFe0hil5dIWYafk9fHjjR8N8g74ijErQmCEAQy22b06V0q7rLzEsU/HDVL+RZg2aY4hDN+ODHRdpdFkOxsCYV73gevVeo=
scheduler:
todo: 10.10.00
project: 10.11.00