|
|
|
|
@ -1,195 +1,319 @@
|
|
|
|
|
import React from 'react';
|
|
|
|
|
import { Card, Grid, Input, Tag, Typography, Divider, Avatar } from '@arco-design/web-react';
|
|
|
|
|
import {
|
|
|
|
|
IconSearch,
|
|
|
|
|
IconStar,
|
|
|
|
|
IconDownload,
|
|
|
|
|
IconUser,
|
|
|
|
|
IconCalendar,
|
|
|
|
|
IconFilter
|
|
|
|
|
} from '@arco-design/web-react/icon';
|
|
|
|
|
import React, { useEffect, useState, useCallback } from 'react';
|
|
|
|
|
import { Card, Grid, Input, Tag, Typography, Divider, Collapse, Button } 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';
|
|
|
|
|
|
|
|
|
|
const { Row, Col } = Grid;
|
|
|
|
|
const { Title, Text } = Typography;
|
|
|
|
|
|
|
|
|
|
// 模拟组件数据
|
|
|
|
|
const components = [
|
|
|
|
|
{
|
|
|
|
|
id: 1,
|
|
|
|
|
name: '数据表格',
|
|
|
|
|
description: '功能强大的数据展示表格,支持排序、筛选、分页等功能',
|
|
|
|
|
author: '张三',
|
|
|
|
|
avatar: '',
|
|
|
|
|
downloads: 12560,
|
|
|
|
|
rating: 4.8,
|
|
|
|
|
tags: ['数据展示', '表格', '交互'],
|
|
|
|
|
category: '数据展示',
|
|
|
|
|
updateTime: '2023-10-15'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 2,
|
|
|
|
|
name: '表单生成器',
|
|
|
|
|
description: '可视化表单构建工具,支持多种表单元素和校验规则',
|
|
|
|
|
author: '李四',
|
|
|
|
|
avatar: '',
|
|
|
|
|
downloads: 8920,
|
|
|
|
|
rating: 4.6,
|
|
|
|
|
tags: ['表单', '生成器', '可视化'],
|
|
|
|
|
category: '表单',
|
|
|
|
|
updateTime: '2023-10-18'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 3,
|
|
|
|
|
name: '图表组件',
|
|
|
|
|
description: '基于ECharts的图表组件库,支持多种图表类型',
|
|
|
|
|
author: '王五',
|
|
|
|
|
avatar: '',
|
|
|
|
|
downloads: 15630,
|
|
|
|
|
rating: 4.9,
|
|
|
|
|
tags: ['图表', '数据可视化', 'ECharts'],
|
|
|
|
|
category: '数据可视化',
|
|
|
|
|
updateTime: '2023-10-10'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 4,
|
|
|
|
|
name: '流程设计器',
|
|
|
|
|
description: '可视化流程设计工具,支持拖拽式流程编排',
|
|
|
|
|
author: '赵六',
|
|
|
|
|
avatar: '',
|
|
|
|
|
downloads: 6750,
|
|
|
|
|
rating: 4.5,
|
|
|
|
|
tags: ['流程', '设计器', '可视化'],
|
|
|
|
|
category: '流程',
|
|
|
|
|
updateTime: '2023-10-20'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 5,
|
|
|
|
|
name: '文件上传',
|
|
|
|
|
description: '支持多种文件格式上传,包含进度显示和校验功能',
|
|
|
|
|
author: '孙七',
|
|
|
|
|
avatar: '',
|
|
|
|
|
downloads: 9800,
|
|
|
|
|
rating: 4.7,
|
|
|
|
|
tags: ['文件', '上传', '工具'],
|
|
|
|
|
category: '工具',
|
|
|
|
|
updateTime: '2023-10-12'
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 6,
|
|
|
|
|
name: '通知中心',
|
|
|
|
|
description: '系统通知管理组件,支持多种通知类型和样式',
|
|
|
|
|
author: '周八',
|
|
|
|
|
avatar: '',
|
|
|
|
|
downloads: 5420,
|
|
|
|
|
rating: 4.3,
|
|
|
|
|
tags: ['通知', '消息', '系统'],
|
|
|
|
|
category: '反馈',
|
|
|
|
|
updateTime: '2023-10-05'
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 分类数据
|
|
|
|
|
const categories = [
|
|
|
|
|
{ id: 1, name: '全部组件', count: 24 },
|
|
|
|
|
{ id: 2, name: '数据展示', count: 8 },
|
|
|
|
|
{ id: 3, name: '表单', count: 6 },
|
|
|
|
|
{ id: 4, name: '数据可视化', count: 5 },
|
|
|
|
|
{ id: 5, name: '流程', count: 3 },
|
|
|
|
|
{ id: 6, name: '工具', count: 7 },
|
|
|
|
|
{ id: 7, name: '反馈', count: 4 },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const Market: React.FC = () => {
|
|
|
|
|
const [compList, setCompList] = useState<any>([]);
|
|
|
|
|
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]);
|
|
|
|
|
|
|
|
|
|
// 渲染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;
|
|
|
|
|
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 (
|
|
|
|
|
<div className={styles['market-container']}>
|
|
|
|
|
{/* 头部搜索区域 */}
|
|
|
|
|
<div className={styles['market-header']}>
|
|
|
|
|
<Title heading={4}>组件市场</Title>
|
|
|
|
|
<Text type="secondary">发现和使用高质量的组件,提升开发效率</Text>
|
|
|
|
|
<div>
|
|
|
|
|
{/* 第一层分类标签 */}
|
|
|
|
|
<div style={{ marginBottom: '16px' }}>
|
|
|
|
|
{firstLevelCategories.map((category) => {
|
|
|
|
|
let count = 0;
|
|
|
|
|
switch (category.value) {
|
|
|
|
|
case '全部':
|
|
|
|
|
count = counts.allCount;
|
|
|
|
|
break;
|
|
|
|
|
case '基础':
|
|
|
|
|
count = counts.basicCount;
|
|
|
|
|
break;
|
|
|
|
|
case '复合':
|
|
|
|
|
count = counts.compositeCount;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<div className={styles['search-section']}>
|
|
|
|
|
<Input
|
|
|
|
|
return (
|
|
|
|
|
<Tag
|
|
|
|
|
size="large"
|
|
|
|
|
placeholder="搜索组件名称、功能或标签..."
|
|
|
|
|
prefix={<IconSearch />}
|
|
|
|
|
style={{ width: 400, marginRight: 16 }}
|
|
|
|
|
/>
|
|
|
|
|
<div className={styles['filter-tags']}>
|
|
|
|
|
<Tag icon={<IconFilter />} color="arcoblue">高级筛选</Tag>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
key={category.value}
|
|
|
|
|
color={firstLevelCategory === category.value ? 'arcoblue' : 'gray'}
|
|
|
|
|
style={{ cursor: 'pointer', marginRight: '20px', padding: '0 12px' }}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setFirstLevelCategory(category.value);
|
|
|
|
|
// 当切换第一层分类时,默认选中"全部"作为第二层分类
|
|
|
|
|
setSecondLevelCategory('全部');
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{category.label}
|
|
|
|
|
({count})
|
|
|
|
|
</Tag>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<Divider style={{ margin: '20px 0' }} />
|
|
|
|
|
|
|
|
|
|
{/* 分类导航 */}
|
|
|
|
|
<div className={styles['category-section']}>
|
|
|
|
|
<div className={styles['category-list']}>
|
|
|
|
|
{categories.map(category => (
|
|
|
|
|
{/* 第二层分类标签 */}
|
|
|
|
|
<div>
|
|
|
|
|
{getFilteredSecondLevelCategories().map((category) => (
|
|
|
|
|
<Tag
|
|
|
|
|
key={category.id}
|
|
|
|
|
className={styles['category-tag']}
|
|
|
|
|
size="large"
|
|
|
|
|
key={category.value}
|
|
|
|
|
color={secondLevelCategory === category.value ? 'arcoblue' : 'gray'}
|
|
|
|
|
style={{ cursor: 'pointer', marginRight: '20px', padding: '0 12px' }}
|
|
|
|
|
onClick={() => setSecondLevelCategory(category.value)}
|
|
|
|
|
>
|
|
|
|
|
{category.name} <span className={styles['category-count']}>({category.count})</span>
|
|
|
|
|
{category.label}
|
|
|
|
|
({getSecondLevelCount(category.value)})
|
|
|
|
|
</Tag>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}, [firstLevelCategory, secondLevelCategory, getCategoryCounts]);
|
|
|
|
|
|
|
|
|
|
{/* 组件列表 */}
|
|
|
|
|
<div className={styles['components-section']}>
|
|
|
|
|
<Row gutter={20}>
|
|
|
|
|
{components.map(component => (
|
|
|
|
|
<Col span={12} key={component.id} className={styles['component-col']}>
|
|
|
|
|
<Card className={styles['component-card']} hoverable>
|
|
|
|
|
<div className={styles['card-header']}>
|
|
|
|
|
<div className={styles['component-title']}>
|
|
|
|
|
<Title heading={6}>{component.name}</Title>
|
|
|
|
|
<Tag color="arcoblue">{component.category}</Tag>
|
|
|
|
|
</div>
|
|
|
|
|
<Text type="secondary" ellipsis>{component.description}</Text>
|
|
|
|
|
// 渲染组件分类
|
|
|
|
|
const renderComponentCategory = useCallback(() => {
|
|
|
|
|
// 根据第一层和第二层分类筛选组件
|
|
|
|
|
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 && compList.myLibs) {
|
|
|
|
|
filteredComponents = [...filteredComponents, ...compList.myLibs];
|
|
|
|
|
}
|
|
|
|
|
if (conditions.includePubLibs && compList.pubLibs) {
|
|
|
|
|
filteredComponents = [...filteredComponents, ...compList.pubLibs];
|
|
|
|
|
}
|
|
|
|
|
if (conditions.includeTeamLibs && compList.teamLibs) {
|
|
|
|
|
filteredComponents = [...filteredComponents, ...compList.teamLibs];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理复合组件
|
|
|
|
|
const flowComponents = { label: '复合组件', children: [] };
|
|
|
|
|
if (conditions.includeMyFlow && compList.myFlow) {
|
|
|
|
|
flowComponents.children.push(...compList.myFlow);
|
|
|
|
|
}
|
|
|
|
|
if (conditions.includePubFlow && compList.pubFlow) {
|
|
|
|
|
flowComponents.children.push(...compList.pubFlow);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果有复合组件,添加到筛选结果中
|
|
|
|
|
if (flowComponents.children.length > 0) {
|
|
|
|
|
filteredComponents = [...filteredComponents, flowComponents];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果没有组件,显示提示信息
|
|
|
|
|
if (filteredComponents.length === 0) {
|
|
|
|
|
return (
|
|
|
|
|
<div style={{ textAlign: 'center', padding: '40px 0', color: '#999' }}>
|
|
|
|
|
暂无组件数据
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
<div className={styles['card-content']}>
|
|
|
|
|
<div className={styles['component-meta']}>
|
|
|
|
|
<div className={styles['meta-item']}>
|
|
|
|
|
<IconUser />
|
|
|
|
|
<span>{component.author}</span>
|
|
|
|
|
// 渲染组件
|
|
|
|
|
return (
|
|
|
|
|
<Collapse expandIconPosition={'right'} bordered={false}>
|
|
|
|
|
{filteredComponents.map((category, index) => {
|
|
|
|
|
// 确保category有children属性
|
|
|
|
|
if (!category || !category.children || category.children.length === 0) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Collapse.Item
|
|
|
|
|
key={index}
|
|
|
|
|
name={`${category.label}_${index}`}
|
|
|
|
|
header={
|
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
|
|
|
|
<span
|
|
|
|
|
style={{ marginLeft: 10, marginRight: 8, color: '#6D7278', fontSize: 14 }}>{category.label}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles['meta-item']}>
|
|
|
|
|
<IconCalendar />
|
|
|
|
|
<span>{component.updateTime}</span>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
{category.children.map((component, compIndex) => (
|
|
|
|
|
<>
|
|
|
|
|
<div className={styles['component-list']} key={compIndex}>
|
|
|
|
|
<div className={styles['component-info']}>
|
|
|
|
|
<img src="/icons/compIcon.png" alt="" />
|
|
|
|
|
<span>{component.label}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{/*两种状态 未添加的是primary 已添加的是secondary*/}
|
|
|
|
|
<Button type="primary" style={{ borderRadius: 4 }}>添加</Button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className={styles['component-tags']}>
|
|
|
|
|
{component.tags.map((tag, index) => (
|
|
|
|
|
<Tag key={index} color="gray">{tag}</Tag>
|
|
|
|
|
<Divider />
|
|
|
|
|
</>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Collapse.Item>
|
|
|
|
|
);
|
|
|
|
|
}).filter(item => item !== null)}
|
|
|
|
|
</Collapse>
|
|
|
|
|
);
|
|
|
|
|
}, [compList, firstLevelCategory, secondLevelCategory]);
|
|
|
|
|
|
|
|
|
|
<div className={styles['card-footer']}>
|
|
|
|
|
<div className={styles['component-stats']}>
|
|
|
|
|
<div className={styles['stat-item']}>
|
|
|
|
|
<IconDownload />
|
|
|
|
|
<span>{component.downloads.toLocaleString()}</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles['stat-item']}>
|
|
|
|
|
<IconStar />
|
|
|
|
|
<span>{component.rating}</span>
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const userInfo = JSON.parse(sessionStorage.getItem('userInfo') || '{}');
|
|
|
|
|
const componentData = JSON.parse(sessionStorage.getItem(`compLibs${userInfo.userId}`));
|
|
|
|
|
setCompList(componentData);
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className={styles['market-container']}>
|
|
|
|
|
{/* 头部搜索区域 */}
|
|
|
|
|
<div className={styles['market-header']}>
|
|
|
|
|
<Title heading={5}>组件仓库</Title>
|
|
|
|
|
|
|
|
|
|
<div className={styles['search-section']}>
|
|
|
|
|
<Input
|
|
|
|
|
size="large"
|
|
|
|
|
placeholder="搜索组件"
|
|
|
|
|
prefix={<IconSearch />}
|
|
|
|
|
style={{ marginRight: 16 }}
|
|
|
|
|
/>
|
|
|
|
|
<div className={styles['filter-tags']}>
|
|
|
|
|
<Button type="primary" icon={<IconSync />}></Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles['component-actions']}>
|
|
|
|
|
<Text className={styles['install-btn']}>安装</Text>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* tag样式选择器 */}
|
|
|
|
|
<div className={styles['category-section']}>
|
|
|
|
|
{renderCategoryTage()}
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
</Col>
|
|
|
|
|
))}
|
|
|
|
|
</Row>
|
|
|
|
|
|
|
|
|
|
<Divider style={{ margin: '20px 0' }} />
|
|
|
|
|
|
|
|
|
|
<div className={styles['component-section']}>
|
|
|
|
|
{renderComponentCategory()}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
|