diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/CategoryService.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/CategoryService.java index 190aed996..ff09dba19 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/CategoryService.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/CategoryService.java @@ -1,8 +1,10 @@ package com.datamate.operator.application; +import com.datamate.operator.domain.contants.OperatorConstant; import com.datamate.operator.domain.repository.CategoryRelationRepository; import com.datamate.operator.domain.repository.CategoryRepository; +import com.datamate.operator.domain.repository.OperatorRepository; import com.datamate.operator.interfaces.dto.CategoryDto; import com.datamate.operator.interfaces.dto.CategoryRelationDto; import com.datamate.operator.interfaces.dto.CategoryTreeResponse; @@ -11,9 +13,7 @@ import org.springframework.stereotype.Service; import java.time.LocalDateTime; -import java.util.Comparator; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import java.util.stream.Collectors; @@ -21,6 +21,8 @@ @Service @RequiredArgsConstructor public class CategoryService { + private final OperatorRepository operatorRepo; + private final CategoryRepository categoryRepo; private final CategoryRelationRepository categoryRelationRepo; @@ -40,7 +42,7 @@ public List getAllCategories() { .filter(relation -> !StringUtils.equals(relation.getParentId(), "0")) .collect(Collectors.groupingBy(CategoryDto::getParentId)); - return groupedByParentId.entrySet().stream() + List categoryTreeResponses = groupedByParentId.entrySet().stream() .sorted(categoryComparator(nameMap)) .map(entry -> { String parentId = entry.getKey(); @@ -55,7 +57,11 @@ public List getAllCategories() { }).sorted(Comparator.comparing(CategoryDto::getCreatedAt)).toList()); response.setCount(totalCount.get()); return response; - }).toList(); + }).collect(Collectors.toCollection(ArrayList::new)); + + int stars = operatorRepo.countOperatorByStar(true); + categoryTreeResponses.add(buildStarCategoryTree(stars)); + return categoryTreeResponses; } private Comparator>> categoryComparator(Map categoryMap) { @@ -65,4 +71,21 @@ private Comparator>> categoryComparator(Map< return index1.compareTo(index2); }; } + + private CategoryTreeResponse buildStarCategoryTree(int stars) { + CategoryTreeResponse starResponse = new CategoryTreeResponse(); + starResponse.setName("收藏状态"); + starResponse.setCount(stars); + starResponse.setId("257b27e0-bba9-11f0-89d7-00155d0a6153"); + CategoryDto star = new CategoryDto(); + star.setId(OperatorConstant.CATEGORY_STAR_ID); + star.setName("已收藏"); + star.setValue("isStar"); + star.setCount(stars); + star.setParentId("257b27e0-bba9-11f0-89d7-00155d0a6153"); + star.setCreatedAt(LocalDateTime.now()); + star.setType("predefined"); + starResponse.setCategories(Collections.singletonList(star)); + return starResponse; + } } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/OperatorService.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/OperatorService.java index 62fe42e30..3442b0c15 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/OperatorService.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/application/OperatorService.java @@ -2,24 +2,35 @@ import com.datamate.common.domain.model.ChunkUploadPreRequest; import com.datamate.common.domain.service.FileService; +import com.datamate.common.infrastructure.exception.BusinessException; import com.datamate.operator.domain.contants.OperatorConstant; import com.datamate.operator.infrastructure.converter.OperatorConverter; import com.datamate.operator.domain.model.OperatorView; import com.datamate.operator.domain.repository.CategoryRelationRepository; import com.datamate.operator.domain.repository.OperatorRepository; import com.datamate.operator.domain.repository.OperatorViewRepository; +import com.datamate.operator.infrastructure.exception.OperatorErrorCode; import com.datamate.operator.infrastructure.parser.ParserHolder; import com.datamate.operator.interfaces.dto.OperatorDto; import com.datamate.operator.interfaces.dto.UploadOperatorRequest; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.File; +import java.util.ArrayList; import java.util.List; +import java.util.Map; @Service +@Slf4j @RequiredArgsConstructor public class OperatorService { private final OperatorRepository operatorRepo; @@ -32,6 +43,8 @@ public class OperatorService { private final FileService fileService; + private final ObjectMapper objectMapper = new ObjectMapper(); + @Value("${operator.base.path:/operators}") private String operatorBasePath; @@ -53,19 +66,25 @@ public OperatorDto getOperatorById(String id) { @Transactional public OperatorDto createOperator(OperatorDto req) { + overrideSettings(req); operatorRepo.insertOperator(req); relationRepo.batchInsert(req.getId(), req.getCategories()); parserHolder.extractTo(getFileType(req.getFileName()), getUploadPath(req.getFileName()), - getExtractPath(getFileNameWithoutExtension(req.getFileName()))); + getExtractPath(getFileNameWithoutExtension(req.getFileName()))); return getOperatorById(req.getId()); } @Transactional public OperatorDto updateOperator(String id, OperatorDto req) { + overrideSettings(req); operatorRepo.updateOperator(req); - relationRepo.batchInsert(id, req.getCategories()); - parserHolder.extractTo(getFileType(req.getFileName()), getUploadPath(req.getFileName()), - getExtractPath(getFileNameWithoutExtension(req.getFileName()))); + if (CollectionUtils.isNotEmpty(req.getCategories())) { + relationRepo.batchUpdate(id, req.getCategories()); + } + if (StringUtils.isNotBlank(req.getFileName())) { + parserHolder.extractTo(getFileType(req.getFileName()), getUploadPath(req.getFileName()), + getExtractPath(getFileNameWithoutExtension(req.getFileName()))); + } return getOperatorById(id); } @@ -77,7 +96,7 @@ public void deleteOperator(String id) { public OperatorDto uploadOperator(String fileName) { return parserHolder.parseYamlFromArchive(getFileType(fileName), new File(getUploadPath(fileName)), - OperatorConstant.YAML_PATH); + OperatorConstant.YAML_PATH); } public String preUpload() { @@ -107,4 +126,76 @@ private String getUploadPath(String fileName) { private String getExtractPath(String fileName) { return operatorBasePath + File.separator + "extract" + File.separator + fileName; } + + private void overrideSettings(OperatorDto operatorDto) { + if (StringUtils.isBlank(operatorDto.getSettings()) || MapUtils.isEmpty(operatorDto.getOverrides())) { + return; + } + try { + Map> settings = objectMapper.readValue(operatorDto.getSettings(), Map.class); + for (Map.Entry entry : operatorDto.getOverrides().entrySet()) { + String key = entry.getKey(); + if (!settings.containsKey(key)) { + continue; + } + Object value = entry.getValue(); + Map setting = settings.get(key); + String type = setting.get("type").toString(); + switch (type) { + case "slider": + case "switch": + case "select": + case "input": + case "radio": + setting.put("defaultVal", value); + break; + case "checkbox": + setting.put("defaultVal", convertObjectToListString(value)); + break; + case "range": + updateProperties(setting, value); + default: + } + settings.put(key, setting); + } + operatorDto.setSettings(objectMapper.writeValueAsString(settings)); + } catch (JsonProcessingException e) { + throw BusinessException.of(OperatorErrorCode.SETTINGS_PARSE_FAILED, e.getMessage()); + } + } + + private String convertObjectToListString(Object object) { + if (object == null) { + return null; + } else if (object instanceof List list) { + List result = new ArrayList<>(); + for (Object item : list) { + result.add(String.valueOf(item)); + } + return String.join(",", result); + } else { + return object.toString(); + } + } + + private void updateProperties(Map setting, Object value) { + List defaultValue = new ArrayList<>(); + if (value instanceof List) { + defaultValue.addAll((List) value); + } + + Object properties = setting.get("properties"); + if (properties instanceof List list) { + if (defaultValue.size() != list.size()) { + return; + } + List> result = new ArrayList<>(); + for (int i = 0; i < list.size(); i++) { + Map map = objectMapper.convertValue(list.get(i), Map.class); + map.put("defaultVal", defaultValue.get(i)); + result.add(map); + } + setting.put("properties", result); + } + } } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/contants/OperatorConstant.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/contants/OperatorConstant.java index 35a871d65..144389e3e 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/contants/OperatorConstant.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/contants/OperatorConstant.java @@ -28,6 +28,8 @@ public class OperatorConstant { public static String CATEGORY_ALL_ID = "4d7dbd77-0a92-44f3-9056-2cd62d4a71e4"; + public static String CATEGORY_STAR_ID = "51847c24-bba9-11f0-888b-5b143cb738aa"; + public static Map CATEGORY_MAP = new HashMap<>(); static { diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/CategoryRelationRepository.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/CategoryRelationRepository.java index aac1c0598..bd719a83a 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/CategoryRelationRepository.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/CategoryRelationRepository.java @@ -12,5 +12,7 @@ public interface CategoryRelationRepository extends IRepository categories); + void batchUpdate(String operatorId, List categories); + void deleteByOperatorId(String operatorId); } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorRepository.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorRepository.java index 298fd056d..d99c1d03b 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorRepository.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorRepository.java @@ -14,4 +14,6 @@ public interface OperatorRepository extends IRepository { void insertOperator(OperatorDto operator); void deleteOperator(String id); + + int countOperatorByStar(boolean isStar); } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/exception/OperatorErrorCode.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/exception/OperatorErrorCode.java index 8026ade93..f8c88d874 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/exception/OperatorErrorCode.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/exception/OperatorErrorCode.java @@ -14,7 +14,9 @@ public enum OperatorErrorCode implements ErrorCode { YAML_NOT_FOUND("op.0002", "算子中缺少元数据文件"), - FIELD_NOT_FOUND("op.0003", "缺少必要的字段"); + FIELD_NOT_FOUND("op.0003", "缺少必要的字段"), + + SETTINGS_PARSE_FAILED("op.0004", "settings字段解析失败"); private final String code; private final String message; diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/CategoryRelationRepositoryImpl.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/CategoryRelationRepositoryImpl.java index 8184ea643..47fdc149f 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/CategoryRelationRepositoryImpl.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/CategoryRelationRepositoryImpl.java @@ -31,6 +31,17 @@ public void batchInsert(String operatorId, List categories) { mapper.insert(categoryRelations); } + @Override + public void batchUpdate(String operatorId, List categories) { + List categoryRelations = categories.stream() + .map(category -> new CategoryRelation(category, operatorId)) + .toList(); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(CategoryRelation::getOperatorId, operatorId); + mapper.delete(queryWrapper); + mapper.insert(categoryRelations); + } + @Override public void deleteByOperatorId(String operatorId) { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorRepositoryImpl.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorRepositoryImpl.java index 0eabdd468..505038e80 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorRepositoryImpl.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorRepositoryImpl.java @@ -1,5 +1,6 @@ package com.datamate.operator.infrastructure.persistence.Impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.repository.CrudRepository; import com.datamate.operator.infrastructure.converter.OperatorConverter; import com.datamate.operator.domain.model.Operator; @@ -35,4 +36,11 @@ public void insertOperator(OperatorDto operator) { public void deleteOperator(String id) { mapper.deleteById(id); } + + @Override + public int countOperatorByStar(boolean isStar) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Operator::getIsStar, isStar); + return Math.toIntExact(mapper.selectCount(queryWrapper)); + } } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorViewRepositoryImpl.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorViewRepositoryImpl.java index 1a64d5a66..7ec6a05cd 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorViewRepositoryImpl.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/Impl/OperatorViewRepositoryImpl.java @@ -27,7 +27,8 @@ public List findOperatorsByCriteria(Integer page, Integer size, St queryWrapper.in(CollectionUtils.isNotEmpty(categories), "category_id", categories) .like(StringUtils.isNotBlank(operatorName), "operator_name", operatorName) .eq(isStar != null, "is_star", isStar) - .groupBy("operator_id"); + .groupBy("operator_id") + .orderByDesc("created_at"); Page queryPage = null; if (size != null && page != null) { queryPage = new Page<>(page + 1, size); diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/mapper/OperatorViewMapper.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/mapper/OperatorViewMapper.java index 1d8740a36..d8a56ec4f 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/mapper/OperatorViewMapper.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/infrastructure/persistence/mapper/OperatorViewMapper.java @@ -24,7 +24,7 @@ IPage findOperatorsByCriteria(IPage page, @Select("SELECT operator_id AS id, operator_name AS name, description, version, inputs, outputs, runtime, " + "settings, is_star, created_at, updated_at, " + - "GROUP_CONCAT(category_id ORDER BY created_at DESC SEPARATOR ',') AS categories " + + "GROUP_CONCAT(category_name ORDER BY created_at DESC SEPARATOR ',') AS categories " + "FROM v_operator WHERE operator_id = #{id}") OperatorView findOperatorById(@Param("id") String id); } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorDto.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorDto.java index 249745aa0..fca9e58e0 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorDto.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorDto.java @@ -6,6 +6,7 @@ import java.time.LocalDateTime; import java.util.List; +import java.util.Map; /** * OperatorDto @@ -32,6 +33,8 @@ public class OperatorDto { private String settings; + private Map overrides; + private String fileName; private Boolean isStar; diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/OperatorController.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/OperatorController.java index ab07fd45d..ac0686290 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/OperatorController.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/OperatorController.java @@ -2,10 +2,12 @@ import com.datamate.common.interfaces.PagedResponse; import com.datamate.operator.application.OperatorService; +import com.datamate.operator.domain.contants.OperatorConstant; import com.datamate.operator.interfaces.dto.OperatorDto; import com.datamate.operator.interfaces.dto.OperatorsListPostRequest; import com.datamate.operator.interfaces.dto.UploadOperatorRequest; import lombok.RequiredArgsConstructor; +import org.apache.commons.collections4.CollectionUtils; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; @@ -19,10 +21,16 @@ public class OperatorController { @PostMapping("/list") public PagedResponse operatorsListPost(@RequestBody OperatorsListPostRequest request) { + Boolean isStar = null; + List categories = request.getCategories(); + if (CollectionUtils.isNotEmpty(request.getCategories()) && + request.getCategories().contains(OperatorConstant.CATEGORY_STAR_ID)) { + isStar = true; + categories.remove(OperatorConstant.CATEGORY_STAR_ID); + } List responses = operatorService.getOperators(request.getPage(), request.getSize(), - request.getCategories(), request.getOperatorName(), request.getIsStar()); - int count = operatorService.getOperatorsCount(request.getCategories(), request.getOperatorName(), - request.getIsStar()); + categories, request.getOperatorName(), isStar); + int count = operatorService.getOperatorsCount(categories, request.getOperatorName(), isStar); int totalPages = (count + request.getSize() + 1) / request.getSize(); return PagedResponse.of(responses, request.getPage(), count, totalPages); } diff --git a/frontend/src/components/DetailHeader.tsx b/frontend/src/components/DetailHeader.tsx index d1a1d75e5..526a4d204 100644 --- a/frontend/src/components/DetailHeader.tsx +++ b/frontend/src/components/DetailHeader.tsx @@ -112,7 +112,11 @@ function DetailHeader({ key={op.key} {...op.confirm} onConfirm={() => { - op?.confirm?.onConfirm?.(); + if (op.onClick) { + op.onClick() + } else { + op?.confirm?.onConfirm?.(); + } }} okType={op.danger ? "danger" : "primary"} overlayStyle={{ zIndex: 9999 }} diff --git a/frontend/src/pages/DataCleansing/Create/components/ParamConfig.tsx b/frontend/src/pages/DataCleansing/Create/components/ParamConfig.tsx index 93a44d885..dc8a79db0 100644 --- a/frontend/src/pages/DataCleansing/Create/components/ParamConfig.tsx +++ b/frontend/src/pages/DataCleansing/Create/components/ParamConfig.tsx @@ -227,7 +227,7 @@ const ParamConfig: React.FC = ({ return (
{param.properties.map((subParam) => ( - = {}; + Object.keys(configs).forEach((key) => { + const { value } = configs[key]; + defaultParams[key] = value; + }); + setParsedInfo({ ...res.data, fileName, configs, defaultParams}); setUploadStep("parsing"); } catch (err) { setParseError("文件解析失败," + err.data.message); @@ -91,7 +99,15 @@ export default function OperatorPluginCreate() { const onFetchOperator = async (operatorId: string) => { // 编辑模式,加载已有算子信息逻辑待实现 const { data } = await queryOperatorByIdUsingGet(operatorId); - setParsedInfo(data); + const configs = data.settings && typeof data.settings === "string" + ? JSON.parse(data.settings) + : {}; + const defaultParams: Record = {}; + Object.keys(configs).forEach((key) => { + const { value } = configs[key]; + defaultParams[key] = value; + }); + setParsedInfo({ ...data, configs, defaultParams}); setUploadStep("configure"); }; @@ -127,7 +143,7 @@ export default function OperatorPluginCreate() { icon: , }, { - title: "配置标签", + title: "配置信息", icon: , }, { diff --git a/frontend/src/pages/OperatorMarket/Create/components/ConfigureStep.tsx b/frontend/src/pages/OperatorMarket/Create/components/ConfigureStep.tsx index 2c76d261d..59753b71d 100644 --- a/frontend/src/pages/OperatorMarket/Create/components/ConfigureStep.tsx +++ b/frontend/src/pages/OperatorMarket/Create/components/ConfigureStep.tsx @@ -1,6 +1,7 @@ -import { Alert, Input, Form } from "antd"; +import {Alert, Input, Form} from "antd"; import TextArea from "antd/es/input/TextArea"; -import { useEffect } from "react"; +import React, {useEffect} from "react"; +import ParamConfig from "@/pages/DataCleansing/Create/components/ParamConfig.tsx"; export default function ConfigureStep({ parsedInfo, @@ -13,6 +14,24 @@ export default function ConfigureStep({ form.setFieldsValue(parsedInfo); }, [parsedInfo]); + const handleConfigChange = ( + operatorId: string, + paramKey: string, + value: any + ) => { + setParsedInfo((op) => + op.id === operatorId + ? { + ...op, + overrides: { + ...(op?.overrides || op?.defaultParams), + [paramKey]: value, + }, + } + : op + ) + }; + return ( <> {/* 解析结果 */} @@ -33,50 +52,54 @@ export default function ConfigureStep({ layout="vertical" initialValues={parsedInfo} onValuesChange={(_, allValues) => { - setParsedInfo({ ...parsedInfo, ...allValues }); + setParsedInfo({...parsedInfo, ...allValues}); }} > {/* 基本信息 */}

基本信息

- - + + - - + + - - + + -