Compare commits

..

3 Commits

Author SHA1 Message Date
cyc 2aef6b8fd7 解决超算任务名称的问题 2026-04-01 15:34:45 +08:00
cyc 2c123e04d1 Merge remote-tracking branch 'origin/dev-opt' into dev-opt 2026-04-01 14:56:59 +08:00
cyc e213c3ff1d skill 模块联调 2026-04-01 11:09:35 +08:00
6 changed files with 102 additions and 76 deletions

View File

@ -73,12 +73,12 @@ public class SkillsController extends BaseController {
return genericsSuccess(this.skillService.delete(id));
}
@PostMapping("/publish")
@PutMapping("/publish/{id}")
@ApiOperation(value = "发布")
@OperationNotification(value = "发布的Skill#{#skill.name}需要审核,请查看", type = 2, receiver = "ADMIN", notificationUrl = "/system/approval")
public AjaxResult publish(@RequestBody Skill skill, HttpServletRequest request) throws Exception {
public AjaxResult publish(@PathVariable("id") Long id, HttpServletRequest request) throws Exception {
LoginUser loginUser = SecurityUtils.getLoginUser();
return AjaxResult.success(skillService.publish(skill, loginUser, request));
return AjaxResult.success(skillService.publish( id, loginUser, request));
}
@PutMapping("/praise/{id}")
@ -102,7 +102,7 @@ public class SkillsController extends BaseController {
@CrossOrigin(origins = "*", allowedHeaders = "*")
@PostMapping("/upload")
@ApiOperation(value = "上传")
public AjaxResult uploadDataset(@RequestParam("file") MultipartFile files,Long id) throws Exception {
return AjaxResult.success(skillService.upload(files, id));
public AjaxResult uploadDataset(@RequestParam("file") MultipartFile files) throws Exception {
return AjaxResult.success(skillService.upload(files));
}
}

View File

@ -22,11 +22,11 @@ public interface SkillService {
String delete(Long id) throws Exception;
String publish(Skill skill, LoginUser loginUser, HttpServletRequest request);
Skill publish(Long id, LoginUser loginUser, HttpServletRequest request);
String praise(Long id);
Skill praise(Long id);
String unpraise(Long id);
Skill unpraise(Long id);
Map<String, Object> upload(MultipartFile files, Long id) throws IOException;
Map<String, Object> upload(MultipartFile files) throws IOException;
}

View File

@ -12,6 +12,7 @@ import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.platform.domain.TrainingTask;
import com.ruoyi.platform.domain.service.CSAuthInfo;
import com.ruoyi.platform.service.CSCollectService;
import com.ruoyi.platform.service.ServiceService;
import com.ruoyi.platform.utils.HttpUtils;
import com.ruoyi.platform.utils.MinioUtil;
import org.springframework.beans.factory.annotation.Autowired;
@ -58,6 +59,9 @@ public class CSCollectServiceImpl implements CSCollectService {
@Resource
private MinioUtil minioUtil;
@Resource
private ServiceService serviceService;
/**
* 算力中心列表接口
*
@ -131,8 +135,9 @@ public class CSCollectServiceImpl implements CSCollectService {
String jobName = taskInfo.get("name").toString();
CSAuthInfo csAuthInfo = getZSAuthInfoFromRedis();
List<Map<String, Object>> hpcBindingFiles = buildHpcBindingFiles(trainingTask.getTaskName(), taskParam, taskInfo);
JSONObject params = convertToJobRequest(trainingTask.getTaskName(), clusterId, jobName, hpcBindingFiles, csAuthInfo.getUserId(), ntasks, nodes);
com.ruoyi.platform.domain.service.Service service = serviceService.getService(trainingTask.getServiceId());
List<Map<String, Object>> hpcBindingFiles = buildHpcBindingFiles(service.getServiceTempName(), taskParam, taskInfo);
JSONObject params = convertToJobRequest(service.getServiceTempName(), clusterId, jobName, hpcBindingFiles, csAuthInfo.getUserId(), ntasks, nodes);
String url = csUrl + "/jsm/v2/jobs/submit";
String res = HttpUtils.sendBodyPostWithToken(url, params, csAuthInfo.getToken());
JSONObject resData = returnResDataWithOK(res);

View File

@ -28,6 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
@ -113,13 +114,13 @@ public class SkillServiceImpl implements SkillService {
}
@Override
public String publish(Skill skill, LoginUser loginUser, HttpServletRequest request) {
public Skill publish(Long id, LoginUser loginUser, HttpServletRequest request) {
Set<String> roles = loginUser.getRoles();
Skill skill = skillDao.getSkillById(id);
skill.setIsPublic(true);
if (roles.contains("admin")) {
//无需审批直接通过
skillDao.edit(skill);
return "发布成功";
}
String username = loginUser.getUsername();
@ -142,27 +143,29 @@ public class SkillServiceImpl implements SkillService {
approvalRequest.setContent(JSON.toJSONString(skill));
approvalInfoMapper.insertApproval(approvalRequest);
return "发布成功,待管理员审核";
return skill;
}
@Override
public String praise(Long id) {
public Skill praise(Long id) {
Skill skill = skillDao.getSkillById(id);
skill.setPraisesCount(skill.getPraisesCount() + 1);
int praiseCount = skill.getPraisesCount() == null ? 1 : skill.getPraisesCount() + 1;
skill.setPraisesCount(praiseCount);
skillDao.edit(skill);
return "点赞成功";
return skill;
}
@Override
public String unpraise(Long id) {
public Skill unpraise(Long id) {
Skill skill = skillDao.getSkillById(id);
skill.setPraisesCount(skill.getPraisesCount() - 1);
int praiseCount = skill.getPraisesCount() == null?0:skill.getPraisesCount() - 1;
skill.setPraisesCount(praiseCount);
skillDao.edit(skill);
return "取消点赞成功";
return skill;
}
@Override
public Map<String, Object> upload(MultipartFile file, Long id) throws IOException {
public Map<String, Object> upload(MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String fileType = getFileType(originalFilename);
if (fileType == null) {
@ -170,7 +173,6 @@ public class SkillServiceImpl implements SkillService {
}
Skill skill = new Skill();
skill.setId(id);
if ("md".equals(fileType)) {
skill.setMdContent(IoUtil.read(file.getInputStream(), StandardCharsets.UTF_8));
} else if ("zip".equals(fileType)) {
@ -178,10 +180,12 @@ public class SkillServiceImpl implements SkillService {
parseZipAndFillMetadata(file.getInputStream(), skill);
}
String savePath = "/mini-model-platform-data/skill_file/upload/" + id + "/" + cn.hutool.core.lang.UUID.fastUUID() + "/" + file.getOriginalFilename();
String savePath = "/mini-model-platform-data/skill_file/upload/" + "/" + cn.hutool.core.lang.UUID.fastUUID() + "/" + file.getOriginalFilename();
HashMap<String, Object> result = MapUtil.newHashMap();
result.put("filename", file.getOriginalFilename());
result.put("direct_url", savePath);
result.put("file_name", file.getOriginalFilename());
result.put("file_path", savePath);
result.put("md_content", skill.getMdContent());
result.put("file_tree_json", skill.getFileTreeJson());
// 异步上传原始文件到 MinIO
CompletableFuture.supplyAsync(() -> {
@ -192,9 +196,6 @@ public class SkillServiceImpl implements SkillService {
throw new RuntimeException("异步提交任务失败", e);
}
});
skill.setFilePath(savePath);
skillDao.edit(skill);
return result;
}
@ -214,65 +215,79 @@ public class SkillServiceImpl implements SkillService {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String entryName = entry.getName();
// 去除目录结尾的斜杠
if (entryName.endsWith("/")) {
entryName = entryName.substring(0, entryName.length() - 1);
}
boolean isSkillMd = isOuterSkillMd(entryName) && !entry.isDirectory();
// 使用 Hutool 分割路径
String[] parts = StrUtil.splitToArray(entryName, '/');
StringBuilder currentPath = new StringBuilder();
Map<String, Object> parentNode = pathToNode.get(""); // 根节点
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
if (i > 0) currentPath.append('/');
currentPath.append(part);
String fullPath = currentPath.toString();
Map<String, Object> node = pathToNode.get(fullPath);
if (node == null) {
boolean isDir = (i < parts.length - 1) || entry.isDirectory();
Map<String, Object> newNode = new HashMap<>();
newNode.put("name", part);
if (isDir) {
List<Map<String, Object>> children = new ArrayList<>();
newNode.put("children", children);
pathToNode.put(fullPath, newNode);
@SuppressWarnings("unchecked")
List<Map<String, Object>> parentChildren = (List<Map<String, Object>>) parentNode.get("children");
parentChildren.add(newNode);
} else {
newNode.put("children", null);
long sizeBytes = entry.getSize();
if (sizeBytes < 0) sizeBytes = 0;
newNode.put("fileSize", FileUtil.readableFileSize(sizeBytes));
pathToNode.put(fullPath, newNode);
@SuppressWarnings("unchecked")
List<Map<String, Object>> parentChildren = (List<Map<String, Object>>) parentNode.get("children");
parentChildren.add(newNode);
}
// 处理 SKILL.md 内容读取必须在任何其他操作之前
String skillMdText = null;
if (isSkillMd) {
// 使用 ByteArrayOutputStream 读取内容
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int len;
while ((len = zis.read(buffer)) > 0) {
baos.write(buffer, 0, len);
}
parentNode = node != null ? node : pathToNode.get(fullPath);
skillMdText = baos.toString(StandardCharsets.UTF_8.name());
}
// 读取最外层 Skill.md 内容
if (isOuterSkillMd(entryName) && !entry.isDirectory()) {
// 使用 Hutool 读取当前条目的内容
String content = IoUtil.read(zis, StandardCharsets.UTF_8);
skillMdContent.append(content);
// 构建目录树不读取流内容
if (!entryName.endsWith("/")) {
String cleanName = entryName;
if (cleanName.endsWith("/")) {
cleanName = cleanName.substring(0, cleanName.length() - 1);
}
String[] parts = StrUtil.splitToArray(cleanName, '/');
StringBuilder currentPath = new StringBuilder();
Map<String, Object> parentNode = pathToNode.get("");
for (int i = 0; i < parts.length; i++) {
String part = parts[i];
if (i > 0) currentPath.append('/');
currentPath.append(part);
String fullPath = currentPath.toString();
Map<String, Object> node = pathToNode.get(fullPath);
if (node == null) {
boolean isDir = (i < parts.length - 1) || entry.isDirectory();
Map<String, Object> newNode = new HashMap<>();
newNode.put("name", part);
if (isDir) {
List<Map<String, Object>> children = new ArrayList<>();
newNode.put("children", children);
pathToNode.put(fullPath, newNode);
@SuppressWarnings("unchecked")
List<Map<String, Object>> parentChildren = (List<Map<String, Object>>) parentNode.get("children");
parentChildren.add(newNode);
} else {
newNode.put("children", null);
long sizeBytes = entry.getSize();
if (sizeBytes < 0) sizeBytes = 0;
newNode.put("fileSize", FileUtil.readableFileSize(sizeBytes));
pathToNode.put(fullPath, newNode);
@SuppressWarnings("unchecked")
List<Map<String, Object>> parentChildren = (List<Map<String, Object>>) parentNode.get("children");
parentChildren.add(newNode);
}
}
parentNode = node != null ? node : pathToNode.get(fullPath);
}
}
if (skillMdText != null) {
skillMdContent.append(skillMdText);
}
zis.closeEntry();
}
}
// 使用 Hutool 序列化为 JSON
skill.setFileTreeJson(JSONUtil.toJsonStr(rootChildren));
skill.setMdContent(skillMdContent.toString());
}
private boolean isOuterSkillMd(String entryName) {
return "Skill.md".equals(entryName);
return "SKILL.md".equals(entryName);
}
private String getFileType(String fileName) {

View File

@ -37,4 +37,10 @@ public class SkillVo {
private Integer state;
private VersionVo fileVo;
private String filePath;
private String fileTreeJson;
private String mdContent;
}

View File

@ -2,9 +2,9 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.platform.mapper.SkillDao">
<insert id="save" keyProperty="id" useGeneratedKeys="true">
insert into skill(name, description, type, preview_pic, create_by, update_by)
insert into skill(name, description, type, preview_pic, create_by, update_by,file_path,file_tree_json,md_content)
values (#{skill.name}, #{skill.description}, #{skill.type},
#{skill.previewPic}, #{skill.createBy}, #{skill.updateBy})
#{skill.previewPic}, #{skill.createBy}, #{skill.updateBy},#{skill.filePath},#{skill.fileTreeJson},#{skill.mdContent})
</insert>
<update id="edit">
@ -52,7 +52,7 @@
<select id="queryByPage" resultType="com.ruoyi.platform.domain.Skill">
select * from skill
<include refid="common_condition"></include>
order by praises_count desc limit #{pageable.offset}, #{pageable.pageSize}
order by praises_count desc,update_time desc limit #{pageable.offset}, #{pageable.pageSize}
</select>
<select id="getSkillByName" resultType="com.ruoyi.platform.domain.Skill">