From 7d4dcb756b9ec1a8c6d16a8caf59a266b77902a1 Mon Sep 17 00:00:00 2001 From: hhhhsc701 <56435672+hhhhsc701@users.noreply.github.com> Date: Tue, 6 Jan 2026 17:57:25 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=85=A5=E5=BA=93?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E9=87=8D=E5=A4=8D;=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BC=98=E5=8C=96=20(#226)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修改数据清洗筛选逻辑-筛选修改为多选 * 修改数据清洗筛选逻辑-筛选修改为多选 * antd 组件库样式定制修改 * fix: 修复入库可能重复 * fix: 算子市场筛选逻辑优化 * fix: 清洗任务创建筛选逻辑优化 * fix: 清洗任务创建筛选逻辑优化 --------- Co-authored-by: chase --- .../operator/application/CategoryService.java | 27 +-- .../operator/application/OperatorService.java | 4 +- .../repository/OperatorViewRepository.java | 4 +- .../Impl/OperatorViewRepositoryImpl.java | 51 +++++- .../mapper/OperatorViewMapper.java | 2 +- .../dto/CategoryTreePagedResponse.java | 24 +++ .../dto/OperatorsListPostRequest.java | 2 +- .../interfaces/rest/CategoryController.java | 6 +- .../interfaces/rest/OperatorController.java | 14 +- frontend/src/hooks/useFetchData.ts | 8 +- frontend/src/main.tsx | 17 +- .../Create/components/OperatorLibrary.tsx | 156 +++++++++--------- .../OperatorMarket/Home/OperatorMarket.tsx | 20 +-- .../Home/components/Filters.tsx | 33 ++++ .../pages/OperatorMarket/operator.model.ts | 4 +- frontend/src/theme/components/menus.ts | 7 + frontend/src/theme/components/table.ts | 6 + frontend/src/theme/index.ts | 10 ++ .../sql_manager/persistence_atction.py | 4 +- 19 files changed, 247 insertions(+), 152 deletions(-) create mode 100644 backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/CategoryTreePagedResponse.java create mode 100644 frontend/src/theme/components/menus.ts create mode 100644 frontend/src/theme/components/table.ts create mode 100644 frontend/src/theme/index.ts 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 ff09dba..271db76 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,10 +1,8 @@ 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; @@ -21,7 +19,7 @@ import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class CategoryService { - private final OperatorRepository operatorRepo; + private final CategoryRepository categoryRepo; @@ -42,7 +40,7 @@ public class CategoryService { .filter(relation -> !StringUtils.equals(relation.getParentId(), "0")) .collect(Collectors.groupingBy(CategoryDto::getParentId)); - List categoryTreeResponses = groupedByParentId.entrySet().stream() + return groupedByParentId.entrySet().stream() .sorted(categoryComparator(nameMap)) .map(entry -> { String parentId = entry.getKey(); @@ -58,10 +56,6 @@ public class CategoryService { response.setCount(totalCount.get()); return response; }).collect(Collectors.toCollection(ArrayList::new)); - - int stars = operatorRepo.countOperatorByStar(true); - categoryTreeResponses.add(buildStarCategoryTree(stars)); - return categoryTreeResponses; } private Comparator>> categoryComparator(Map categoryMap) { @@ -71,21 +65,4 @@ public class CategoryService { 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 1542ea2..d624eb0 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 @@ -52,12 +52,12 @@ public class OperatorService { @Value("${operator.base.path:/operators}") private String operatorBasePath; - public List getOperators(Integer page, Integer size, List categories, + public List getOperators(Integer page, Integer size, List> categories, String keyword, Boolean isStar) { return operatorViewRepo.findOperatorsByCriteria(page, size, keyword, categories, isStar); } - public int getOperatorsCount(List categories, String keyword, Boolean isStar) { + public int getOperatorsCount(List> categories, String keyword, Boolean isStar) { return operatorViewRepo.countOperatorsByCriteria(keyword, categories, isStar); } diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorViewRepository.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorViewRepository.java index 8bcc7d7..6e24a47 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorViewRepository.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/domain/repository/OperatorViewRepository.java @@ -8,9 +8,9 @@ import java.util.List; public interface OperatorViewRepository extends IRepository { List findOperatorsByCriteria(Integer page, Integer size, String keyword, - List categories, Boolean isStar); + List> categories, Boolean isStar); - Integer countOperatorsByCriteria(String keyword, List categories, Boolean isStar); + int countOperatorsByCriteria(String keyword, List> categories, Boolean isStar); OperatorView findOperatorById(String id); } 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 bae4b6f..fba4082 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 @@ -16,6 +16,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Repository; import java.util.List; +import java.util.stream.Collectors; @Repository @RequiredArgsConstructor @@ -24,18 +25,36 @@ public class OperatorViewRepositoryImpl extends CrudRepository findOperatorsByCriteria(Integer page, Integer size, String keyword, - List categories, Boolean isStar) { + List> categories, Boolean isStar) { QueryWrapper queryWrapper = Wrappers.query(); - queryWrapper.in(CollectionUtils.isNotEmpty(categories), "category_id", categories) - .eq(isStar != null, "is_star", isStar); + queryWrapper.eq(isStar != null, "is_star", isStar); if (StringUtils.isNotEmpty(keyword)) { queryWrapper.and(w -> w.like("operator_name", keyword) .or() .like("description", keyword)); } + StringBuilder havingSql = new StringBuilder(); + if (CollectionUtils.isNotEmpty(categories)) { + queryWrapper.in("category_id", categories.stream().flatMap(List::stream).toList()); + int index = 0; + for (List category : categories) { + if (index > 0) { + havingSql.append(" AND "); + } + havingSql.append("SUM(CASE WHEN category_id IN ("); + havingSql.append(category.stream() + .map(id -> "'" + id + "'") + .collect(Collectors.joining(","))); + havingSql.append(") THEN 1 ELSE 0 END) > 0"); + index++; + } + } + queryWrapper.groupBy("operator_id") + .having(!havingSql.isEmpty(), havingSql.toString()) .orderByDesc("created_at"); + Page queryPage; if (size != null && page != null) { queryPage = new Page<>(page + 1, size); @@ -48,17 +67,35 @@ public class OperatorViewRepositoryImpl extends CrudRepository categories, Boolean isStar) { + public int countOperatorsByCriteria(String keyword, List> categories, Boolean isStar) { QueryWrapper queryWrapper = Wrappers.query(); - queryWrapper.in(CollectionUtils.isNotEmpty(categories),"category_id", categories) - .eq(isStar != null, "is_star", isStar); + queryWrapper.eq(isStar != null, "is_star", isStar); if (StringUtils.isNotEmpty(keyword)) { queryWrapper.and(w -> w.like("operator_name", keyword) .or() .like("description", keyword)); } - return mapper.countOperatorsByCriteria(queryWrapper); + StringBuilder havingSql = new StringBuilder(); + if (CollectionUtils.isNotEmpty(categories)) { + queryWrapper.in("category_id", categories.stream().flatMap(List::stream).toList()); + int index = 0; + for (List category : categories) { + if (index > 0) { + havingSql.append(" AND "); + } + havingSql.append("SUM(CASE WHEN category_id IN ("); + havingSql.append(category.stream() + .map(id -> "'" + id + "'") + .collect(Collectors.joining(","))); + havingSql.append(") THEN 1 ELSE 0 END) > 0"); + index++; + } + } + queryWrapper.groupBy("operator_id") + .having(!havingSql.isEmpty(), havingSql.toString()); + Integer count = mapper.countOperatorsByCriteria(queryWrapper); + return count != null ? count : 0; } @Override 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 d8a56ec..369b19e 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 @@ -19,7 +19,7 @@ public interface OperatorViewMapper extends BaseMapper { IPage findOperatorsByCriteria(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - @Select("SELECT COUNT(DISTINCT operator_id) AS count FROM v_operator ${ew.customSqlSegment}") + @Select("SELECT COUNT(1) FROM (SELECT 1 FROM v_operator ${ew.customSqlSegment}) AS t") Integer countOperatorsByCriteria(@Param(Constants.WRAPPER) Wrapper queryWrapper); @Select("SELECT operator_id AS id, operator_name AS name, description, version, inputs, outputs, runtime, " + diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/CategoryTreePagedResponse.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/CategoryTreePagedResponse.java new file mode 100644 index 0000000..cc584b2 --- /dev/null +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/CategoryTreePagedResponse.java @@ -0,0 +1,24 @@ +package com.datamate.operator.interfaces.dto; + +import com.datamate.common.interfaces.PagedResponse; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +public class CategoryTreePagedResponse extends PagedResponse { + Integer starCount; + + public CategoryTreePagedResponse(List content, Integer starCount) { + super(content); + this.starCount = starCount; + } + + public static CategoryTreePagedResponse of(List content, Integer starCount) { + return new CategoryTreePagedResponse(content, starCount); + } +} diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorsListPostRequest.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorsListPostRequest.java index 47f8683..7f23cc1 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorsListPostRequest.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/dto/OperatorsListPostRequest.java @@ -15,7 +15,7 @@ import lombok.Setter; @Getter @Setter public class OperatorsListPostRequest extends PagingQuery { - private List categories = new ArrayList<>(); + private List> categories = new ArrayList<>(); private String keyword; diff --git a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/CategoryController.java b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/CategoryController.java index 2a7dca8..fc093c5 100644 --- a/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/CategoryController.java +++ b/backend/services/operator-market-service/src/main/java/com/datamate/operator/interfaces/rest/CategoryController.java @@ -2,6 +2,8 @@ package com.datamate.operator.interfaces.rest; import com.datamate.common.interfaces.PagedResponse; import com.datamate.operator.application.CategoryService; +import com.datamate.operator.domain.repository.OperatorRepository; +import com.datamate.operator.interfaces.dto.CategoryTreePagedResponse; import com.datamate.operator.interfaces.dto.CategoryTreeResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; @@ -17,9 +19,11 @@ import java.util.List; public class CategoryController { private final CategoryService categoryService; + private final OperatorRepository operatorRepo; + @GetMapping("/tree") public PagedResponse categoryTreeGet() { List allCategories = categoryService.getAllCategories(); - return PagedResponse.of(allCategories); + return CategoryTreePagedResponse.of(allCategories, operatorRepo.countOperatorByStar(true)); } } 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 46a38d1..d235108 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 @@ -3,12 +3,10 @@ package com.datamate.operator.interfaces.rest; import com.datamate.common.infrastructure.common.IgnoreResponseWrap; 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.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -27,16 +25,10 @@ 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> categories = request.getCategories(); List responses = operatorService.getOperators(request.getPage(), request.getSize(), - categories, request.getKeyword(), isStar); - int count = operatorService.getOperatorsCount(categories, request.getKeyword(), isStar); + categories, request.getKeyword(), request.getIsStar()); + int count = operatorService.getOperatorsCount(categories, request.getKeyword(), request.getIsStar()); int totalPages = (count + request.getSize() + 1) / request.getSize(); return PagedResponse.of(responses, request.getPage(), count, totalPages); } diff --git a/frontend/src/hooks/useFetchData.ts b/frontend/src/hooks/useFetchData.ts index c3319c9..d3f112a 100644 --- a/frontend/src/hooks/useFetchData.ts +++ b/frontend/src/hooks/useFetchData.ts @@ -44,7 +44,8 @@ export default function useFetchData( status: [] as string[], tags: [] as string[], // 通用分类筛选(如算子市场的分类 ID 列表) - categories: [] as string[], + categories: [] as string[][], + selectedStar: false, }, current: 1, pageSize: 12, @@ -113,11 +114,10 @@ export default function useFetchData( // 同时执行主要数据获取和额外的轮询函数 const promises = [ fetchFunc({ - ...Object.fromEntries( - Object.entries(filter).filter(([_, value]) => value != null && value.length > 0) - ), + categories: filter.categories, ...extraParams, keyword, + isStar: filter.selectedStar ? true : undefined, type: getFirstOfArray(filter?.type) || undefined, status: getFirstOfArray(filter?.status) || undefined, tags: filter?.tags?.length ? filter.tags.join(",") : undefined, diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 4537c90..2a96cbc 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -2,21 +2,24 @@ import { StrictMode, Suspense } from "react"; import { createRoot } from "react-dom/client"; import { RouterProvider } from "react-router"; import router from "./routes/routes"; -import { App as AntdApp, Spin } from "antd"; +import { App as AntdApp, Spin, ConfigProvider } from "antd"; import "./index.css"; import TopLoadingBar from "./components/TopLoadingBar"; import { store } from "./store"; import { Provider } from "react-redux"; +import theme from "./theme"; createRoot(document.getElementById("root")!).render( - - }> - - - - + + + }> + + + + + ); diff --git a/frontend/src/pages/DataCleansing/Create/components/OperatorLibrary.tsx b/frontend/src/pages/DataCleansing/Create/components/OperatorLibrary.tsx index 3d1f403..f71c81e 100644 --- a/frontend/src/pages/DataCleansing/Create/components/OperatorLibrary.tsx +++ b/frontend/src/pages/DataCleansing/Create/components/OperatorLibrary.tsx @@ -100,57 +100,58 @@ const OperatorLibrary: React.FC = ({ const [searchTerm, setSearchTerm] = useState(""); const [showFavorites, setShowFavorites] = useState(false); const [favorites, setFavorites] = useState>(new Set()); - const [selectedCategory, setSelectedCategory] = useState("all"); - const [expandedCategories, setExpandedCategories] = useState>( - new Set([]) - ); + const [selectedCategory, setSelectedCategory] = useState([]); - // 按分类分组 + const [operatorListFiltered, setOperatorListFiltered] = useState([]); +// 按分类分组 const groupedOperators = useMemo(() => { - const groups: { [key: string]: OperatorI[] } = {}; + const groups: { [key: string]: any[] } = {}; + let operatorFilteredList: OperatorI[]; categoryOptions.forEach((cat: any) => { - groups[cat.name] = { + groups[cat.id] = { ...cat, operators: operatorList.filter((op) => op.categories?.includes(cat.id)), }; }); - if (selectedCategory && selectedCategory !== "all") { - Object.keys(groups).forEach((key) => { - if (groups[key].id !== selectedCategory) { - delete groups[key]; + if (selectedCategory.length) { + const groupedFiltered: { [key: string]: any[] } = {}; + selectedCategory.forEach((cat: any) => { + let parent = groups[cat].type; + if (!groupedFiltered[parent]) { + groupedFiltered[parent] = groups[cat].operators + } else { + groupedFiltered[parent] = Array.from( + new Map([...groupedFiltered[parent], ...groups[cat].operators].map(item => [item.id, item])).values() + ); } + }) + operatorFilteredList = Object.values(groupedFiltered).reduce((acc, currentList) => { + if (acc.length === 0) return []; + const currentIds = new Set(currentList.map(item => item.id)); + return acc.filter(item => currentIds.has(item.id)); }); + } else { + operatorFilteredList = [...operatorList]; } if (searchTerm) { - Object.keys(groups).forEach((key) => { - groups[key].operators = groups[key].operators.filter((operator) => - operator.name.toLowerCase().includes(searchTerm.toLowerCase()) - ); - if (groups[key].operators.length === 0) { - delete groups[key]; - } - }); + operatorFilteredList = operatorFilteredList.filter(operator => + operator.name.toLowerCase().includes(searchTerm.toLowerCase()) + ); } if (showFavorites) { - Object.keys(groups).forEach((key) => { - groups[key].operators = groups[key].operators.filter((operator) => - favorites.has(operator.id) - ); - if (groups[key].operators.length === 0) { - delete groups[key]; - } - }); + operatorFilteredList = operatorFilteredList.filter((operator) => + favorites.has(operator.id) + ); } - - setExpandedCategories(new Set(Object.keys(groups))); + setOperatorListFiltered([...operatorFilteredList]); return groups; }, [categoryOptions, selectedCategory, searchTerm, showFavorites]); // 过滤算子 - const filteredOperators = useMemo(() => { + useMemo(() => { return Object.values(groupedOperators).flatMap( (category) => category.operators ); @@ -190,17 +191,37 @@ const OperatorLibrary: React.FC = ({ setSelectedOperators(newSelected); }; + const handleSelectCategory = (categoryOptions) => { + const groups: Record = {}; + const tree: any[] = []; + categoryOptions.forEach(item => { + const groupName = item.type; + if (!groups[groupName]) { + const newGroup = { + label: groupName, + title: groupName, + options: [] + }; + groups[groupName] = newGroup; + tree.push(newGroup); + } + const { type, ...childItem } = item; + groups[groupName].options.push(childItem); + }); + return tree; + } + return (
- 算子库 + 算子库({operatorList.length})
{/* 过滤器 */} -
+
} placeholder="搜索算子名称..." @@ -210,8 +231,10 @@ const OperatorLibrary: React.FC = ({ /> @@ -227,53 +250,32 @@ const OperatorLibrary: React.FC = ({ )} +
+ +
{/* 算子列表 */}
- {/* 分类算子 */} - - setExpandedCategories( - new Set(Array.isArray(keys) ? keys : [keys]) - ) - } - > - {Object.entries(groupedOperators).map(([key, category]) => ( - - - {category.name} - {category.operators.length} - - -
- } - > - - - ))} - - {filteredOperators.length === 0 && ( + + + {operatorListFiltered.length === 0 && (
未找到匹配的算子
diff --git a/frontend/src/pages/OperatorMarket/Home/OperatorMarket.tsx b/frontend/src/pages/OperatorMarket/Home/OperatorMarket.tsx index 807587c..07a4787 100644 --- a/frontend/src/pages/OperatorMarket/Home/OperatorMarket.tsx +++ b/frontend/src/pages/OperatorMarket/Home/OperatorMarket.tsx @@ -37,10 +37,13 @@ export default function OperatorMarketPage() { const [showFilters, setShowFilters] = useState(true); const [categoriesTree, setCategoriesTree] = useState([]); + const [starCount, setStarCount] = useState(0); + const [selectedStar, setSelectedStar] = useState(false); const initCategoriesTree = async () => { const { data } = await queryCategoryTreeUsingGet({ page: 0, size: 1000 }); setCategoriesTree(data.content || []); + setStarCount(data.starCount || 0); }; useEffect(() => { @@ -104,16 +107,7 @@ export default function OperatorMarketPage() { ]; useEffect(() => { - const filteredIds = Object.values(selectedFilters).reduce( - (acc, filter: string[]) => { - if (filter.length) { - acc.push(...filter); - } - - return acc; - }, - [] - ); + const filteredIds = Object.values(selectedFilters).filter(item => item.length > 0); // 分类筛选变化时: // 1. 将分类 ID 写入通用 searchParams.filter.categories,确保分页时条件不会丢失 @@ -124,9 +118,10 @@ export default function OperatorMarketPage() { filter: { ...prev.filter, categories: filteredIds, + selectedStar: selectedStar, }, })); - }, [selectedFilters, setSearchParams]); + }, [selectedFilters, setSearchParams, selectedStar]); return (
@@ -162,8 +157,11 @@ export default function OperatorMarketPage() { setShowFilters(false)} categoriesTree={categoriesTree} + selectedStar={selectedStar} + starCount={starCount} selectedFilters={selectedFilters} setSelectedFilters={setSelectedFilters} + setSelectedStar={setSelectedStar} />
diff --git a/frontend/src/pages/OperatorMarket/Home/components/Filters.tsx b/frontend/src/pages/OperatorMarket/Home/components/Filters.tsx index d71f528..e674923 100644 --- a/frontend/src/pages/OperatorMarket/Home/components/Filters.tsx +++ b/frontend/src/pages/OperatorMarket/Home/components/Filters.tsx @@ -104,15 +104,21 @@ const FilterSection: React.FC = ({ interface FiltersProps { categoriesTree: CategoryTreeI[]; selectedFilters: { [key: string]: string[] }; + selectedStar: boolean; + starCount: number; hideFilter: () => void; setSelectedFilters: (filters: { [key: string]: string[] }) => void; + setSelectedStar: (item: boolean) => void; } const Filters: React.FC = ({ categoriesTree, selectedFilters, + selectedStar, + starCount, hideFilter, setSelectedFilters, + setSelectedStar, }) => { const clearAllFilters = () => { const newFilters = Object.keys(selectedFilters).reduce((acc, key) => { @@ -126,6 +132,17 @@ const Filters: React.FC = ({ (filters) => Array.isArray(filters) && filters.length > 0 ); + const starCategory = { + id: "starStatus", + count: starCount, + name: "收藏状态", + categories: [{ + id: "isStar", + count: starCount, + name: "已收藏" + }] + }; + return (
{/* Filter Header */} @@ -170,6 +187,22 @@ const Filters: React.FC = ({ showIcons={false} /> ))} + + ({ + key: cat.id.toString(), + label: cat.name, + count: cat.count, + }))} + selectedValues={selectedStar ? ["isStar"] : []} + onSelectionChange={(values) => { + values.length > 0 ? setSelectedStar(true) : setSelectedStar(false); + }} + showIcons={false} + />
); }; diff --git a/frontend/src/pages/OperatorMarket/operator.model.ts b/frontend/src/pages/OperatorMarket/operator.model.ts index 660b4fa..8ef4b18 100644 --- a/frontend/src/pages/OperatorMarket/operator.model.ts +++ b/frontend/src/pages/OperatorMarket/operator.model.ts @@ -46,11 +46,11 @@ export interface OperatorI { } export interface CategoryI { - id: number; + id: string; name: string; count: number; // 该分类下的算子数量 type: string; // e.g., "数据源", "数据清洗", "数据分析", "数据可视化" - parentId?: number; // 父分类ID,若无父分类则为null + parentId?: string; // 父分类ID,若无父分类则为null value: string; createdAt: string; } diff --git a/frontend/src/theme/components/menus.ts b/frontend/src/theme/components/menus.ts new file mode 100644 index 0000000..d39ade2 --- /dev/null +++ b/frontend/src/theme/components/menus.ts @@ -0,0 +1,7 @@ +const menuTheme = { + itemColor: 'rgba(55, 65, 81, 1)', + itemSelectedColor: 'rgba(29, 78, 216, 1)', + itemSelectedBg: 'rgb(219, 234, 254)', + itemBorderRadius: 6, +}; +export default menuTheme; \ No newline at end of file diff --git a/frontend/src/theme/components/table.ts b/frontend/src/theme/components/table.ts new file mode 100644 index 0000000..fb0db26 --- /dev/null +++ b/frontend/src/theme/components/table.ts @@ -0,0 +1,6 @@ +const tableTheme = { + rowSelectedHoverBg: '#F7F9FB', + headerColor: 'rgba(100, 116, 139, 1)', + headerBg: '#fff', +}; +export default tableTheme; \ No newline at end of file diff --git a/frontend/src/theme/index.ts b/frontend/src/theme/index.ts new file mode 100644 index 0000000..c6890df --- /dev/null +++ b/frontend/src/theme/index.ts @@ -0,0 +1,10 @@ +import menuTheme from "./components/menus"; +import tableTheme from "./components/table"; + +const theme = { + components: { + Menu: menuTheme, + Table: tableTheme, + }, +}; +export default theme; \ No newline at end of file diff --git a/runtime/python-executor/datamate/sql_manager/persistence_atction.py b/runtime/python-executor/datamate/sql_manager/persistence_atction.py index 4c425db..9137f26 100644 --- a/runtime/python-executor/datamate/sql_manager/persistence_atction.py +++ b/runtime/python-executor/datamate/sql_manager/persistence_atction.py @@ -25,7 +25,9 @@ class TaskInfoPersistence: with open(sql_config_path, 'r', encoding='utf-8') as f: return json.load(f) - def update_task_result(self, sample, file_id = str(uuid.uuid4())): + def update_task_result(self, sample, file_id = None): + if file_id is None: + file_id = str(uuid.uuid4()) instance_id = str(sample.get("instance_id")) src_file_name = str(sample.get("sourceFileName")) src_file_type = str(sample.get("sourceFileType"))