import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { Card, Grid, Input, Tag, Typography, Divider, Collapse, Button, Message } from '@arco-design/web-react'; import { IconSearch, IconSync } from '@arco-design/web-react/icon'; import styles from './style/market.module.less'; import { useSelector, useDispatch } from 'react-redux'; import { addProjectComp, addProjectBaseComp } from '@/api/scene'; import dayjs from 'dayjs'; import { getMyComponents, getPubComponents, getTeamComponents } from '@/api/components'; import { getMyFlowList, getPubFlowList } from '@/api/flow'; const { Row, Col } = Grid; const { Title, Text } = Typography; type componentItemType = { label: string; children?: any[]; }; interface MarketProps { updateProjectComp: () => void; } const Market: React.FC = ({ updateProjectComp }) => { const [compList, setCompList] = useState([]); const [searchValue, setSearchValue] = useState(''); // 添加搜索状态 const [firstLevelCategory, setFirstLevelCategory] = useState('全部'); // 第一层分类:全部,基础,复合 const [secondLevelCategory, setSecondLevelCategory] = useState('全部'); // 第二层分类:全部,我的,公开,协同 const { projectComponentData, info } = useSelector((state: any) => state.ideContainer); const dispatch = useDispatch(); // 第一层分类选项 const firstLevelCategories = [ { label: '全部', value: '全部' }, { label: '基础', value: '基础' }, { label: '复合', value: '复合' } ]; // 第二层分类选项 const secondLevelCategories = [ { label: '全部', value: '全部' }, { label: '我的', value: '我的' }, { label: '公开', value: '公开' }, { label: '协同', value: '协同' } ]; // 计算各分类的数量 const getCategoryCounts = useCallback(() => { if (!compList) return { allCount: 0, basicCount: 0, compositeCount: 0, myCount: 0, publicCount: 0, teamCount: 0, myFlowCount: 0, pubFlowCount: 0 }; // 基础组件数量 (myLibs, pubLibs, teamLibs) // 需要统计children中的组件数量 const myCount = compList.myLibs ? compList.myLibs.reduce((acc, cur) => acc + (cur.children ? cur.children.length : 0), 0) : 0; const publicCount = compList.pubLibs ? compList.pubLibs.reduce((acc, cur) => acc + (cur.children ? cur.children.length : 0), 0) : 0; const teamCount = compList.teamLibs ? compList.teamLibs.reduce((acc, cur) => acc + (cur.children ? cur.children.length : 0), 0) : 0; const basicCount = myCount + publicCount + teamCount; // 复合组件数量 (myFlow, pubFlow) - 直接统计数组长度 const myFlowCount = compList.myFlow ? compList.myFlow.length : 0; const pubFlowCount = compList.pubFlow ? compList.pubFlow.length : 0; const compositeCount = myFlowCount + pubFlowCount; return { allCount: basicCount + compositeCount, basicCount, compositeCount, myCount, publicCount, teamCount, myFlowCount, pubFlowCount }; }, [compList]); // 根据搜索值过滤组件列表 const filteredCompList = useMemo(() => { if (!searchValue) return compList; const filtered = { ...compList }; // 过滤基础组件 (myLibs, pubLibs, teamLibs) ['myLibs', 'pubLibs', 'teamLibs'].forEach(key => { if (filtered[key]) { filtered[key] = filtered[key].map(category => { if (category && category.children) { const filteredChildren = category.children.filter(child => { const label = child.label || child.name || ''; return label.toLowerCase().includes(searchValue.toLowerCase()); }); return { ...category, children: filteredChildren }; } return category; }).filter(category => category.children && category.children.length > 0); } }); // 过滤复合组件 (myFlow, pubFlow) ['myFlow', 'pubFlow'].forEach(key => { if (filtered[key]) { filtered[key] = filtered[key].filter(item => { const name = item.flowName || item.name || ''; return name.toLowerCase().includes(searchValue.toLowerCase()); }); } }); return filtered; }, [compList, searchValue]); // 渲染Tag选择器 const renderCategoryTage = useCallback(() => { /* * 分类规则:先分类(全部,基础,复合) 再分类(全部,我的,公开,协同:复合类型中没有协同组件) * 目前数据类型中存在的字段: 基础类型 [myLibs,pubLibs,teamLibs], 复合类型[pubFlow,myFlow] * 需要渲染出两层Tag标签的选择,第一次的选择影响第二层的部分渲染 * */ const counts = getCategoryCounts(); // 根据第一层分类动态调整第二层分类选项 const getFilteredSecondLevelCategories = () => { // 如果是复合类型,则不显示协同组件选项 if (firstLevelCategory === '复合') { return secondLevelCategories.filter(item => item.value !== '协同'); } return secondLevelCategories; }; // 获取第二层分类的数量 const getSecondLevelCount = (category: string) => { if (firstLevelCategory === '全部') { switch (category) { case '全部': return counts.allCount; case '我的': return counts.myCount + counts.myFlowCount; case '公开': return counts.publicCount + counts.pubFlowCount; case '协同': return counts.teamCount; default: return 0; } } else if (firstLevelCategory === '基础') { switch (category) { case '全部': return counts.basicCount; case '我的': return counts.myCount; case '公开': return counts.publicCount; case '协同': return counts.teamCount; default: return 0; } } else if (firstLevelCategory === '复合') { switch (category) { case '全部': return counts.compositeCount; case '我的': return counts.myFlowCount; case '公开': return counts.pubFlowCount; default: return 0; } } return 0; }; return (
{/* 第一层分类标签 */}
{firstLevelCategories.map((category) => { let count = 0; switch (category.value) { case '全部': count = counts.allCount; break; case '基础': count = counts.basicCount; break; case '复合': count = counts.compositeCount; break; } return ( { setFirstLevelCategory(category.value); // 当切换第一层分类时,默认选中"全部"作为第二层分类 setSecondLevelCategory('全部'); }} > {category.label} ({count}) ); })}
{/* 第二层分类标签 */}
{getFilteredSecondLevelCategories().map((category) => ( setSecondLevelCategory(category.value)} > {category.label} ({getSecondLevelCount(category.value)}) ))}
); }, [firstLevelCategory, secondLevelCategory, getCategoryCounts]); // 渲染组件分类 const renderComponentCategory = useCallback(() => { // 使用过滤后的组件列表 const currentCompList = searchValue ? filteredCompList : compList; // 根据第一层和第二层分类筛选组件 let filteredComponents = []; // 构建筛选条件 const conditions = { includeMyLibs: (firstLevelCategory === '全部' || firstLevelCategory === '基础') && (secondLevelCategory === '全部' || secondLevelCategory === '我的'), includePubLibs: (firstLevelCategory === '全部' || firstLevelCategory === '基础') && (secondLevelCategory === '全部' || secondLevelCategory === '公开'), includeTeamLibs: (firstLevelCategory === '全部' || firstLevelCategory === '基础') && (secondLevelCategory === '全部' || secondLevelCategory === '协同'), includeMyFlow: (firstLevelCategory === '全部' || firstLevelCategory === '复合') && (secondLevelCategory === '全部' || secondLevelCategory === '我的'), includePubFlow: (firstLevelCategory === '全部' || firstLevelCategory === '复合') && (secondLevelCategory === '全部' || secondLevelCategory === '公开') }; // 收集符合条件的基础组件 if (conditions.includeMyLibs && currentCompList.myLibs) { filteredComponents = [...filteredComponents, ...currentCompList.myLibs]; } if (conditions.includePubLibs && currentCompList.pubLibs) { filteredComponents = [...filteredComponents, ...currentCompList.pubLibs]; } if (conditions.includeTeamLibs && currentCompList.teamLibs) { filteredComponents = [...filteredComponents, ...currentCompList.teamLibs]; } // 收集符合条件的复合组件 const flowComponents = []; if (conditions.includeMyFlow && currentCompList.myFlow) { flowComponents.push(...currentCompList.myFlow.map(item => ({ ...item, isFlow: true }))); } if (conditions.includePubFlow && currentCompList.pubFlow) { flowComponents.push(...currentCompList.pubFlow.map(item => ({ ...item, isFlow: true }))); } // 合并相同标签的组件 const mergedComponents = {}; // 处理基础组件(按label分组) filteredComponents.forEach(category => { if (category && category.children && category.children.length > 0) { const label = category.label; if (!mergedComponents[label]) { mergedComponents[label] = { label: label, children: [] }; } mergedComponents[label].children.push(...category.children); } }); // 处理复合组件 if (flowComponents.length > 0) { const label = '复合组件'; if (!mergedComponents[label]) { mergedComponents[label] = { label: label, children: [] }; } mergedComponents[label].children.push(...flowComponents); } // 转换为数组格式 const resultComponents = Object.values(mergedComponents); // 如果没有组件,显示提示信息 if (resultComponents.length === 0) { return (
{searchValue ? '未找到匹配的组件' : '暂无组件数据'}
); } // 将组件添加到工程中 const addToProject = async (component) => { const params = { sceneId: info.id, compIds: [] }; params['compIds'].push(component.id || component.comp.id); params['type'] = component.fontCompType; if (component.fontCompType === 'complex') { const res: any = await addProjectComp(params); if (res.code === 200) Message.success('添加成功'); else Message.error('添加失败'); } else { const res: any = await addProjectBaseComp(params); if (res.code === 200) Message.success('添加成功'); else Message.error('添加失败'); } // 通知父组件更新 updateProjectComp(); }; // 渲染组件 return ( {resultComponents.map((category: componentItemType, index) => { // 确保category有children属性 if (!category || !category.children || category.children.length === 0) { return null; } return ( {category.label} } > {category.children.map((component, compIndex) => (
{component.label || component.flowName}
{/*两种状态 未添加的是primary 已添加的是secondary*/} { component.isAdd ? ( ) : ( ) }
))}
); }).filter(item => item !== null)}
); }, [compList, filteredCompList, firstLevelCategory, secondLevelCategory, searchValue]); // 给账号下的组件列表(本地存储中的组件列表)增加一个是否添加至工程的初始状态 const addInitState = (componentData) => { // 当前工程下已添加的组件ID列表 const projectComponent = projectComponentData[info.id]; const compListByProject = projectComponent.compIds.concat(projectComponent.flowIds); const objectKeys = Object.keys(componentData); /* * 账号下的组件列表分两种结构: * 1. myLibs,pubLibs,teamLibs 这三个是带有children数组的结构 * 2. pubFlow,myFlow 这两个是直接一个数组 * */ objectKeys.forEach(key => { if (key === 'pubFlow' || key === 'myFlow') { componentData[key].forEach(item => { item.isAdd = compListByProject.includes(item.id); }); } else if (key === 'myLibs' || key === 'pubLibs' || key === 'teamLibs') { componentData[key].length && componentData[key].forEach(item => { item.children.forEach(v => { v.isAdd = compListByProject.includes(v.comp.id); }); }); } }); setCompList(componentData); }; // 处理搜索输入变化 const handleSearchChange = (value: string) => { setSearchValue(value); }; // 从缓存中获取组件列表的信息 const getCompList = async () => { try { const requests = [ { promise: getMyComponents(), key: 'myLibs' }, { promise: getPubComponents(), key: 'pubLibs' }, { promise: getTeamComponents(), key: 'teamLibs' }, { promise: getPubFlowList({ currPage: 1, pageSize: 999 }), key: 'pubFlow' }, { promise: getMyFlowList({ currPage: 1, pageSize: 999 }), key: 'myFlow' } ]; const obj: any = { myLibs: null, pubLibs: null, teamLibs: null, pubFlow: null, myFlow: null, updateTime: dayjs().format('YYYY-MM-DD HH:mm:ss') }; const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}'); // 分别处理每个请求 for (const { promise, key } of requests) { try { const res: any = await promise; if (res?.code === 200) { if (key === 'pubFlow' || key === 'myFlow') { res?.data.list.forEach(item => { item['fontCompType'] = 'complex'; }); // 更新本地存储数据 obj[key] = res?.data.list || null; } // 给协同组件添加一个后续处理数据时使用的类型 else if (key === 'teamLibs') { res.data.forEach(item => { item.children.forEach(v => { v['fontCompType'] = 'team'; }); }); obj[key] = res?.data || null; } else { // 更新本地存储数据 res.data.forEach(item => { item.children.forEach(v => { v['fontCompType'] = 'normal'; }); }); obj[key] = res?.data || null; } } sessionStorage.setItem(`compLibs${userInfo.userId}`, JSON.stringify(obj)); const componentData = JSON.parse(sessionStorage.getItem(`compLibs${userInfo.userId}`)); addInitState(componentData); } catch (error) { console.error(`加载${key}失败:`, error); } } } catch (error) { console.error('更新组件库失败:', error); } }; useEffect(() => { getCompList(); }, []); // 监听 Redux 中 projectComponentData 的变化,更新组件列表状态 useEffect(() => { getCompList(); }, [projectComponentData]); return (
{/* 头部搜索区域 */}
组件仓库
} style={{ marginRight: 16 }} value={searchValue} onChange={handleSearchChange} />
{/* tag样式选择器 */}
{renderCategoryTage()}
{renderComponentCategory()}
); }; export default Market;