import React, { useEffect, useMemo, useState } from "react"; import { Button, Card, Checkbox, Input, Select, Tag, Tooltip, } from "antd"; import { SearchOutlined, StarFilled, StarOutlined } from "@ant-design/icons"; import { Layers } from "lucide-react"; import { CategoryI, OperatorI } from "@/pages/OperatorMarket/operator.model"; import { updateOperatorByIdUsingPut } from "@/pages/OperatorMarket/operator.api"; type GroupedCategoryOption = { label: string; title: string; options: Array>; }; interface OperatorListProps { operators: OperatorI[]; favorites: Set; toggleFavorite: (id: string) => void; toggleOperator: (operator: OperatorI) => void; selectedOperators: OperatorI[]; onDragOperator: ( e: React.DragEvent, item: OperatorI, source: "library" ) => void; } const handleStar = async ( operator: OperatorI, toggleFavorite: (id: string) => void ) => { const data = { id: operator.id, isStar: !operator.isStar, }; await updateOperatorByIdUsingPut(operator.id, data); toggleFavorite(operator.id); }; const OperatorList: React.FC = ({ operators, favorites, toggleFavorite, toggleOperator, selectedOperators, onDragOperator, }) => (
{operators.map((operator) => { const isSelected = selectedOperators.some((op) => op.id === operator.id); return ( onDragOperator(event, operator, "library")} onClick={() => toggleOperator(operator)} >
{operator.name}
{ event.stopPropagation(); handleStar(operator, toggleFavorite); }} > {favorites.has(operator.id) ? ( ) : ( )}
); })}
); interface OperatorLibraryProps { selectedOperators: OperatorI[]; operatorList: OperatorI[]; categoryOptions: CategoryI[]; setSelectedOperators: (operators: OperatorI[]) => void; toggleOperator: (operator: OperatorI) => void; handleDragStart: ( e: React.DragEvent, item: OperatorI, source: "library" ) => void; } const OperatorLibrary: React.FC = ({ selectedOperators, operatorList, categoryOptions, setSelectedOperators, toggleOperator, handleDragStart, }) => { const [searchTerm, setSearchTerm] = useState(""); const [showFavorites, setShowFavorites] = useState(false); const [favorites, setFavorites] = useState>(new Set()); const [selectedCategory, setSelectedCategory] = useState([]); const [operatorListFiltered, setOperatorListFiltered] = useState( [] ); useMemo(() => { const groups: Record = {}; let operatorFilteredList: OperatorI[]; categoryOptions.forEach((cat) => { groups[cat.id] = { type: cat.type, operators: operatorList.filter((op) => op.categories?.includes(cat.id)), }; }); if (selectedCategory.length) { const groupedFiltered: Record = {}; selectedCategory.forEach((cat: string) => { const parent = groups[cat]?.type; if (!parent) { return; } 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 currentList; } const currentIds = new Set(currentList.map((item) => item.id)); return acc.filter((item) => currentIds.has(item.id)); }, [] ); } else { operatorFilteredList = [...operatorList]; } if (searchTerm) { operatorFilteredList = operatorFilteredList.filter((operator) => operator.name.toLowerCase().includes(searchTerm.toLowerCase()) ); } if (showFavorites) { operatorFilteredList = operatorFilteredList.filter((operator) => favorites.has(operator.id) ); } setOperatorListFiltered([...operatorFilteredList]); return groups; }, [ categoryOptions, selectedCategory, operatorList, searchTerm, showFavorites, favorites, ]); const toggleFavorite = (operatorId: string) => { const newFavorites = new Set(favorites); if (newFavorites.has(operatorId)) { newFavorites.delete(operatorId); } else { newFavorites.add(operatorId); } setFavorites(newFavorites); }; useEffect(() => { const newFavorites = new Set(); operatorList.forEach((item) => { if (item.isStar) { newFavorites.add(item.id); } }); setFavorites(newFavorites); }, [operatorList]); const handleSelectAll = (operators: OperatorI[]) => { const newSelected = [...selectedOperators]; operators.forEach((operator) => { if (!newSelected.some((op) => op.id === operator.id)) { newSelected.push(operator); } }); setSelectedOperators(newSelected); }; const handleSelectCategory = (source: CategoryI[]): GroupedCategoryOption[] => { const groups: Record = {}; const tree: GroupedCategoryOption[] = []; source.forEach((item) => { const groupName = item.type || "未分组"; if (!groups[groupName]) { const newGroup = { label: groupName, title: groupName, options: [], }; groups[groupName] = newGroup; tree.push(newGroup); } const childItem: Omit = { id: item.id, name: item.name, count: item.count, parentId: item.parentId, value: item.value, createdAt: item.createdAt, }; groups[groupName].options.push(childItem); }); return tree; }; return (
标注算子库({operatorList.length})
} placeholder="搜索算子名称..." value={searchTerm} allowClear onChange={(event) => setSearchTerm(event.target.value)} />