|
|
import React, { useState, useEffect, useRef } from 'react';
|
|
|
import styles from './style/index.module.less';
|
|
|
import {
|
|
|
Button,
|
|
|
Divider,
|
|
|
Input,
|
|
|
Space,
|
|
|
Table,
|
|
|
Radio,
|
|
|
Pagination,
|
|
|
Modal,
|
|
|
Message,
|
|
|
Rate,
|
|
|
Tag
|
|
|
} from '@arco-design/web-react';
|
|
|
import { IconSearch } from '@arco-design/web-react/icon';
|
|
|
import {
|
|
|
getMyComponentList,
|
|
|
getCooperationComponentList,
|
|
|
remove,
|
|
|
exportComponent,
|
|
|
getImportComponentInfo,
|
|
|
importComponent
|
|
|
} from '@/api/componentBase';
|
|
|
import { deleteComponentMarket, getComponentHistoryReview } from '@/api/componentMarket';
|
|
|
import { componentRelease, componentRevoke } from '@/api/componentRelease';
|
|
|
import { ComponentItem } from '@/api/interface';
|
|
|
import AddComponentModal from '@/pages/componentDevelopment/componentList/addComponentModal';
|
|
|
import PublishComponentModal from '@/pages/componentDevelopment/componentList/publishComponentModal';
|
|
|
import ImportComponentModal from '@/pages/componentDevelopment/componentList/importComponentModal';
|
|
|
import HandleButtonGroup from '@/pages/componentDevelopment/componentList/handleButtonGroup';
|
|
|
import CompAudit from '@/pages/componentDevelopment/componentList/compAudit';
|
|
|
import {
|
|
|
componentStatusConstant,
|
|
|
componentStatusDict,
|
|
|
publicStatusDict,
|
|
|
publishStatusDict
|
|
|
} from '@/const/isdp/componentBase';
|
|
|
import dayjs from 'dayjs';
|
|
|
import { updateComponentCodingPath } from '@/store/ideContainer';
|
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
|
import { componentOffSale } from '@/api/componentDeploy';
|
|
|
|
|
|
const Group = Radio.Group;
|
|
|
|
|
|
const GlobalVarContainer = () => {
|
|
|
const [selectedItem, setSelectedItem] = useState('我的组件');
|
|
|
const [selectComponent, setSelectComponent] = useState(null);
|
|
|
const [componentData, setComponentData] = useState<ComponentItem[]>([]);
|
|
|
const [pagination, setPagination] = useState({
|
|
|
total: 0,
|
|
|
size: 10,
|
|
|
current: 1
|
|
|
});
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
const [visible, setVisible] = useState(false);
|
|
|
const [publishModalVisible, setPublishModalVisible] = useState(false);
|
|
|
const [selectedPublishComponent, setSelectedPublishComponent] = useState(null);
|
|
|
const [mode, setMode] = useState<'create' | 'edit' | 'copy'>('create'); // 添加模式状态
|
|
|
const [searchValue, setSearchValue] = useState(''); // 添加搜索状态
|
|
|
const [componentStatus, setComponentStatus] = useState(''); // 添加组件状态筛选
|
|
|
const [importModalVisible, setImportModalVisible] = useState(false); // 导入弹窗
|
|
|
const [importComponentInfo, setImportComponentInfo] = useState(null); // 导入组件信息
|
|
|
const [importLoading, setImportLoading] = useState(false); // 导入加载状态
|
|
|
const [showOffSaleModal, setShowOffSaleModal] = useState(false);
|
|
|
const [offSaleComponent, setOffSaleComponent] = useState(null);
|
|
|
|
|
|
// 审核历史弹窗状态
|
|
|
const [historyModalVisible, setHistoryModalVisible] = useState(false);
|
|
|
const [historyLoading, setHistoryLoading] = useState(false);
|
|
|
const [historyData, setHistoryData] = useState([]);
|
|
|
const [currentReviewComponent, setCurrentReviewComponent] = useState(null);
|
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
const skipNextFetchRef = useRef(false); // 用于跳过下一次由分页变化触发的请求
|
|
|
|
|
|
// 获取用户信息,判断是否为超管
|
|
|
const userInfo = useSelector((state: any) => state.user?.userInfo);
|
|
|
// TODO: 等后端提供角色标识字段后,替换这里的判断逻辑
|
|
|
const isAdmin = userInfo?.role === 'admin' || userInfo?.isAdmin === true;
|
|
|
|
|
|
const menuItems = [
|
|
|
{
|
|
|
key: '1',
|
|
|
label: '我的组件',
|
|
|
icon: '/ideContainer/icon/myComp.png',
|
|
|
activeIcon: '/ideContainer/icon/myComp_active.png'
|
|
|
},
|
|
|
{
|
|
|
key: '2',
|
|
|
label: '协同组件',
|
|
|
icon: '/ideContainer/icon/teamComp.png',
|
|
|
activeIcon: '/ideContainer/icon/teamComp_active.png'
|
|
|
},
|
|
|
{
|
|
|
key: '3',
|
|
|
label: '组件审核',
|
|
|
icon: '/ideContainer/icon/compAudit.png',
|
|
|
activeIcon: '/ideContainer/icon/compAudit_active.png'
|
|
|
}
|
|
|
];
|
|
|
|
|
|
const columns = [
|
|
|
{
|
|
|
title: '组件名称',
|
|
|
dataIndex: 'name'
|
|
|
},
|
|
|
{
|
|
|
title: '组件标识',
|
|
|
dataIndex: 'projectId'
|
|
|
},
|
|
|
{
|
|
|
title: '分类',
|
|
|
dataIndex: 'componentClassify'
|
|
|
},
|
|
|
{
|
|
|
title: '创建人',
|
|
|
dataIndex: 'createUserName'
|
|
|
},
|
|
|
{
|
|
|
title: '代码语言',
|
|
|
dataIndex: 'codeLanguage'
|
|
|
},
|
|
|
{
|
|
|
title: '组件类型',
|
|
|
dataIndex: 'type',
|
|
|
render: (_, record) => {
|
|
|
return (
|
|
|
<span>{record.type === 'normal' ? '普通组件' : '监听组件'}</span>
|
|
|
);
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '组件状态',
|
|
|
dataIndex: 'componentStatus',
|
|
|
render: (_, record) => {
|
|
|
const formattedData = componentStatusDict.find(item => item.value === componentStatusConstant[record.componentStatus]) || { label: '' };
|
|
|
return (
|
|
|
<span>{formattedData.label}</span>
|
|
|
);
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '发布状态',
|
|
|
dataIndex: 'publicStatus',
|
|
|
render: (_, record) => {
|
|
|
const formattedData = publicStatusDict.find(item => item.value === record.publicStatus) || { label: '' };
|
|
|
return (
|
|
|
<span>{formattedData.label}</span>
|
|
|
);
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '公开状态',
|
|
|
dataIndex: 'publishStatus',
|
|
|
render: (_, record) => {
|
|
|
const formattedData = publishStatusDict.find(item => item.value === record.publishStatus) || { label: '' };
|
|
|
return (
|
|
|
<span>{formattedData.label}</span>
|
|
|
);
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '修改时间',
|
|
|
dataIndex: 'updateTime',
|
|
|
render: (_, record) => {
|
|
|
return (
|
|
|
<span>{dayjs(record.updateTime).format('YYYY-MM-DD HH:mm:ss')}</span>
|
|
|
);
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '操作',
|
|
|
dataIndex: 'operations',
|
|
|
fixed: 'right' as const,
|
|
|
width: 400,
|
|
|
render: (_, record, index) => (
|
|
|
<HandleButtonGroup
|
|
|
row={record}
|
|
|
index={index}
|
|
|
onHandlePublishComponent={(row) => {
|
|
|
setSelectedPublishComponent(row);
|
|
|
setPublishModalVisible(true);
|
|
|
}}
|
|
|
onGoToReview={(row) => {
|
|
|
if (isAdmin) {
|
|
|
// 超管:切换到组件审核页面
|
|
|
setSelectedItem('组件审核');
|
|
|
}
|
|
|
else {
|
|
|
// 普通用户:弹出审核历史弹窗
|
|
|
handleShowReviewHistory(row);
|
|
|
}
|
|
|
}}
|
|
|
onPublishOrRevokeComponent={async (action, identifier, version) => {
|
|
|
try {
|
|
|
if (action === 'publish') {
|
|
|
await componentRelease({ identifier, version });
|
|
|
Message.success('组件公开成功');
|
|
|
}
|
|
|
else if (action === 'revoke') {
|
|
|
await componentRevoke({ identifier, version });
|
|
|
Message.success('组件撤销成功');
|
|
|
}
|
|
|
// 重新获取数据以更新状态
|
|
|
fetchComponentData();
|
|
|
} catch (error) {
|
|
|
console.error('操作失败:', error);
|
|
|
Message.error(`组件${action === 'publish' ? '公开' : '撤销'}失败: ${error.message || ''}`);
|
|
|
}
|
|
|
}}
|
|
|
onSourceCodeView={(row) => {
|
|
|
dispatch(updateComponentCodingPath({
|
|
|
localProjectPath: row.localProjectPath,
|
|
|
name: row.name,
|
|
|
projectId: row.projectId,
|
|
|
id: row.id
|
|
|
}));
|
|
|
const event = new CustomEvent('navigateToTab', {
|
|
|
detail: {
|
|
|
path: 'componentCoding'
|
|
|
}
|
|
|
});
|
|
|
|
|
|
document.dispatchEvent(event);
|
|
|
}}
|
|
|
onShowEdit={(row, index) => {
|
|
|
setSelectComponent(row);
|
|
|
setVisible(true);
|
|
|
setMode('edit'); // 设置模式为复制
|
|
|
}}
|
|
|
onCopyHandler={(row) => {
|
|
|
setSelectComponent(row);
|
|
|
setVisible(true);
|
|
|
setMode('copy'); // 设置模式为复制
|
|
|
}}
|
|
|
onShareCollaboration={(row) => {
|
|
|
// TODO: 实现分享协作逻辑
|
|
|
console.log('Share collaboration', row);
|
|
|
}}
|
|
|
onExportComponent={(row) => {
|
|
|
// 实现导出组件逻辑
|
|
|
onExportComponent(row);
|
|
|
}}
|
|
|
onStopComponentShow={(row) => {
|
|
|
setOffSaleComponent(row);
|
|
|
setShowOffSaleModal(true);
|
|
|
}}
|
|
|
onCancelPublish={handleCancelPublish}
|
|
|
onRowDel={(row) => {
|
|
|
// 显示确认框
|
|
|
Modal.confirm({
|
|
|
title: '确认删除',
|
|
|
content: `确定要删除组件 "${row.name}" 吗?此操作不可恢复。`,
|
|
|
okButtonProps: { status: 'danger' },
|
|
|
onOk: async () => {
|
|
|
try {
|
|
|
const res = await remove(row.id);
|
|
|
console.log('res:', res);
|
|
|
Message.success('组件删除成功');
|
|
|
// 重新获取数据
|
|
|
fetchComponentData();
|
|
|
} catch (error) {
|
|
|
console.error('删除组件失败:', error);
|
|
|
Message.error('组件删除失败');
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
}}
|
|
|
/>
|
|
|
)
|
|
|
}
|
|
|
];
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (selectedItem === '我的组件' || selectedItem === '协同组件') {
|
|
|
if (pagination.current !== 1) {
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
current: 1
|
|
|
}));
|
|
|
}
|
|
|
else {
|
|
|
// 第一页j就直接请求数据
|
|
|
fetchComponentData({ current: 1, size: pagination.size });
|
|
|
}
|
|
|
}
|
|
|
}, [selectedItem]);
|
|
|
|
|
|
// 监听来自其他页面的搜索关键词
|
|
|
useEffect(() => {
|
|
|
const handleNavigateWithSearch = (event: any) => {
|
|
|
const { searchKeyword } = event.detail || {};
|
|
|
if (searchKeyword) {
|
|
|
setSearchValue(searchKeyword);
|
|
|
// 标记跳过下一次由分页变化触发的请求
|
|
|
skipNextFetchRef.current = true;
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
current: 1
|
|
|
}));
|
|
|
setTimeout(() => {
|
|
|
fetchComponentData({ current: 1, size: pagination.size, name: searchKeyword });
|
|
|
}, 500);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 监听导航事件(如果有搜索关键词)
|
|
|
window.addEventListener('componentListSearch', handleNavigateWithSearch);
|
|
|
|
|
|
return () => {
|
|
|
window.removeEventListener('componentListSearch', handleNavigateWithSearch);
|
|
|
};
|
|
|
}, [pagination.size]);
|
|
|
|
|
|
// 下架组件
|
|
|
const componentOffSaleHandler = async (stopInstance: boolean) => {
|
|
|
const res: any = await componentOffSale({ identifier: offSaleComponent.identifier, stopInstance });
|
|
|
if (res.code === 200) {
|
|
|
setShowOffSaleModal(false);
|
|
|
setOffSaleComponent(null);
|
|
|
fetchComponentData();
|
|
|
}
|
|
|
else {
|
|
|
Modal.error({
|
|
|
title: '下架失败',
|
|
|
content: res.message
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 取消发布组件
|
|
|
const handleCancelPublish = async (row: ComponentItem) => {
|
|
|
Modal.confirm({
|
|
|
title: '确认取消发布',
|
|
|
content: `确定要取消发布组件 "${row.name}" 吗?取消后该组件将从组件市场下架。`,
|
|
|
okButtonProps: { status: 'warning' },
|
|
|
onOk: async () => {
|
|
|
try {
|
|
|
const res: any = await deleteComponentMarket(row.id);
|
|
|
if (res.code === 200) {
|
|
|
Message.success('取消发布成功');
|
|
|
// 重新获取数据以更新状态
|
|
|
fetchComponentData();
|
|
|
}
|
|
|
else {
|
|
|
Message.error(res.message || '取消发布失败');
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('取消发布失败:', error);
|
|
|
Message.error('取消发布失败');
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
};
|
|
|
|
|
|
// 处理导入组件 - 文件选择后获取组件信息
|
|
|
const handleImportFileSelect = async (file: File) => {
|
|
|
try {
|
|
|
setImportLoading(true);
|
|
|
const res: any = await getImportComponentInfo({ file });
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
setImportComponentInfo(res.data);
|
|
|
Message.success('组件信息解析成功');
|
|
|
}
|
|
|
else {
|
|
|
Message.error(res.msg || '解析组件信息失败');
|
|
|
setImportComponentInfo(null);
|
|
|
}
|
|
|
} catch (error) {
|
|
|
Message.error('解析组件信息失败');
|
|
|
setImportComponentInfo(null);
|
|
|
} finally {
|
|
|
setImportLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 处理导入组件 - 确认上传
|
|
|
const handleImportConfirm = async (files) => {
|
|
|
try {
|
|
|
setImportLoading(true);
|
|
|
|
|
|
const params = {
|
|
|
file: files.map(file => file.file)
|
|
|
};
|
|
|
|
|
|
const res: any = await importComponent(params);
|
|
|
|
|
|
console.log('res:', res);
|
|
|
if (res.code === 200) {
|
|
|
Message.success('组件导入成功');
|
|
|
setImportModalVisible(false);
|
|
|
setImportComponentInfo(null);
|
|
|
fetchComponentData(); // 刷新列表
|
|
|
}
|
|
|
else {
|
|
|
Message.error(res.msg || '组件导入失败');
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
console.error('导入组件失败:', error);
|
|
|
Message.error('导入组件失败');
|
|
|
} finally {
|
|
|
setImportLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 关闭导入弹窗
|
|
|
const handleImportCancel = () => {
|
|
|
setImportModalVisible(false);
|
|
|
setImportComponentInfo(null);
|
|
|
};
|
|
|
|
|
|
// 查看审核历史
|
|
|
const handleShowReviewHistory = async (row) => {
|
|
|
setCurrentReviewComponent(row);
|
|
|
setHistoryModalVisible(true);
|
|
|
setHistoryLoading(true);
|
|
|
|
|
|
try {
|
|
|
const res: any = await getComponentHistoryReview({
|
|
|
identifier: row.identifier
|
|
|
});
|
|
|
|
|
|
if (res.code === 200 && res.data) {
|
|
|
setHistoryData(res.data.list || []);
|
|
|
}
|
|
|
else {
|
|
|
Message.error(res.msg || '获取审核历史失败');
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('获取审核历史失败:', error);
|
|
|
Message.error('获取审核历史失败');
|
|
|
} finally {
|
|
|
setHistoryLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 获取组件列表数据,支持传入额外参数
|
|
|
const fetchComponentData = async (extraParams: any = {}) => {
|
|
|
setLoading(true);
|
|
|
const apiMap = {
|
|
|
'我的组件': getMyComponentList,
|
|
|
'协同组件': getCooperationComponentList
|
|
|
};
|
|
|
try {
|
|
|
const params: any = {
|
|
|
current: extraParams.current ?? pagination.current,
|
|
|
size: extraParams.size ?? pagination.size
|
|
|
};
|
|
|
|
|
|
const searchName = extraParams.name !== undefined ? extraParams.name : searchValue.trim();
|
|
|
if (searchName) {
|
|
|
params.name = searchName;
|
|
|
}
|
|
|
|
|
|
const status = extraParams.componentStatus !== undefined ? extraParams.componentStatus : componentStatus;
|
|
|
if (status) {
|
|
|
params.componentStatus = status.toUpperCase();
|
|
|
}
|
|
|
|
|
|
const res: any = await apiMap[selectedItem](params);
|
|
|
|
|
|
setComponentData(res.data.records || res.data.list);
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
total: res.data.total || res.data.totalCount
|
|
|
}));
|
|
|
} catch (error) {
|
|
|
console.error('获取组件列表失败:', error);
|
|
|
Message.error('获取组件列表失败');
|
|
|
} finally {
|
|
|
setLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const handlePageChange = (page: number, size?: number) => {
|
|
|
const newSize = size || pagination.size;
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
current: page,
|
|
|
size: newSize
|
|
|
}));
|
|
|
};
|
|
|
|
|
|
// 监听分页变化
|
|
|
useEffect(() => {
|
|
|
if (skipNextFetchRef.current) {
|
|
|
skipNextFetchRef.current = false;
|
|
|
return;
|
|
|
}
|
|
|
if (selectedItem === '我的组件' || selectedItem === '协同组件') {
|
|
|
fetchComponentData({ current: pagination.current, size: pagination.size });
|
|
|
}
|
|
|
}, [pagination.current, pagination.size, componentStatus]);
|
|
|
|
|
|
// 搜索处理函数
|
|
|
const searchHandle = () => {
|
|
|
if (pagination.current !== 1) {
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
current: 1
|
|
|
}));
|
|
|
}
|
|
|
else {
|
|
|
fetchComponentData({ current: 1, size: pagination.size });
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 重置搜索
|
|
|
const resetSearch = () => {
|
|
|
setSearchValue('');
|
|
|
setComponentStatus('');
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
current: 1
|
|
|
}));
|
|
|
fetchComponentData({ current: 1, size: pagination.size, name: '', componentStatus: '' });
|
|
|
};
|
|
|
|
|
|
// 修改导出组件的回调函数
|
|
|
const onExportComponent = async (row) => {
|
|
|
/*
|
|
|
* 特殊说明, next.js 使用rewrites 代理和静态导出会导致代理异常,这个时候使用dev运行会出现二进制接口返回异常的问题,
|
|
|
* 导致无法正确处理二进制数据并把二进制数据转换成字符串,导致导出功能异常。这里需要使用 pnpm run build 和pnpm run start 运行项目。
|
|
|
* */
|
|
|
try {
|
|
|
const res: any = await exportComponent(row.id);
|
|
|
|
|
|
console.log('导出响应:', {
|
|
|
type: typeof res,
|
|
|
isBlob: res instanceof Blob,
|
|
|
size: res?.size,
|
|
|
blobType: res?.type
|
|
|
});
|
|
|
|
|
|
// 如果后端返回错误,可能会是 JSON 格式
|
|
|
if (res instanceof Blob && res.type === 'application/json') {
|
|
|
const text = await res.text();
|
|
|
const errorData = JSON.parse(text);
|
|
|
console.error('后端返回错误:', errorData);
|
|
|
Message.error(errorData.msg || '导出失败');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 确保 res 是 Blob 对象
|
|
|
if (!(res instanceof Blob)) {
|
|
|
console.error('响应不是 Blob 对象:', res);
|
|
|
Message.error('导出失败:响应格式错误');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// 直接使用返回的 blob
|
|
|
const url = window.URL.createObjectURL(res);
|
|
|
const link = document.createElement('a');
|
|
|
link.href = url;
|
|
|
|
|
|
// 设置文件名
|
|
|
const fileName = `${row.name}.zip`;
|
|
|
link.setAttribute('download', fileName);
|
|
|
|
|
|
// 触发下载
|
|
|
document.body.appendChild(link);
|
|
|
link.click();
|
|
|
|
|
|
// 清理
|
|
|
document.body.removeChild(link);
|
|
|
window.URL.revokeObjectURL(url);
|
|
|
|
|
|
Message.success('组件导出成功');
|
|
|
} catch (error) {
|
|
|
console.error('导出组件失败:', error);
|
|
|
Message.error('组件导出失败');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 组件状态筛选处理函数
|
|
|
const handleStatusChange = (value) => {
|
|
|
setComponentStatus(value);
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
<div className={styles['comp-list-container']}>
|
|
|
{/*左侧菜单*/}
|
|
|
<div className={styles['comp-list-menu']}>
|
|
|
{menuItems.map((item, index) => (
|
|
|
<div
|
|
|
key={index}
|
|
|
className={selectedItem === item.label ? styles['selected'] : ''}
|
|
|
onClick={() => setSelectedItem(item.label)}
|
|
|
>
|
|
|
<img src={selectedItem === item.label ? item.activeIcon : item.icon} alt=""
|
|
|
style={{ width: 20, height: 20, marginRight: 12 }} />
|
|
|
<span>{item.label}</span>
|
|
|
</div>
|
|
|
))}
|
|
|
</div>
|
|
|
<div className={styles['comp-list-content']}>
|
|
|
{selectedItem !== '组件审核' && (
|
|
|
<>
|
|
|
{/*头部*/}
|
|
|
<div className={styles['comp-list-header']}>
|
|
|
<div className={styles['comp-list-search']}>
|
|
|
<Space>
|
|
|
<Input
|
|
|
prefix={<IconSearch />}
|
|
|
placeholder={'输入组件名称搜索'}
|
|
|
style={{ width: 236 }}
|
|
|
value={searchValue}
|
|
|
onChange={(value) => setSearchValue(value)}
|
|
|
onPressEnter={searchHandle}
|
|
|
/>
|
|
|
<Button
|
|
|
type="primary"
|
|
|
style={{ marginLeft: 5, borderRadius: 4 }}
|
|
|
onClick={searchHandle}
|
|
|
>
|
|
|
搜索
|
|
|
</Button>
|
|
|
<Button
|
|
|
type="outline"
|
|
|
style={{ marginLeft: 5, borderRadius: 4 }}
|
|
|
onClick={resetSearch}
|
|
|
>
|
|
|
重置
|
|
|
</Button>
|
|
|
</Space>
|
|
|
</div>
|
|
|
<div className={styles['comp-list-handle']}>
|
|
|
<Radio.Group
|
|
|
defaultValue={''}
|
|
|
name="button-radio-group"
|
|
|
value={componentStatus}
|
|
|
onChange={handleStatusChange}
|
|
|
style={{ marginRight: 30 }}
|
|
|
>
|
|
|
{[{ label: '全部', value: '' }, ...componentStatusDict].map((item) => {
|
|
|
return (
|
|
|
<Radio key={item.value} value={item.value}>
|
|
|
{({ checked }) => {
|
|
|
return (
|
|
|
<Button
|
|
|
tabIndex={-1}
|
|
|
key={item.value}
|
|
|
shape="round"
|
|
|
type={checked ? 'primary' : 'default'}
|
|
|
>
|
|
|
{item.label}
|
|
|
</Button>
|
|
|
);
|
|
|
}}
|
|
|
</Radio>
|
|
|
);
|
|
|
})}
|
|
|
</Radio.Group>
|
|
|
{selectedItem === '我的组件' && <Space split={<Divider type="vertical" />}>
|
|
|
{/*<Button type="secondary" status="success" style={{ borderRadius: 4 }}>生成组件</Button>*/}
|
|
|
<Button
|
|
|
type="outline"
|
|
|
style={{ borderRadius: 4 }}
|
|
|
onClick={() => setImportModalVisible(true)}
|
|
|
>
|
|
|
导入组件
|
|
|
</Button>
|
|
|
<Button type="primary" style={{ borderRadius: 4 }} onClick={() => {
|
|
|
setSelectComponent(null);
|
|
|
setVisible(true);
|
|
|
}}>+
|
|
|
新增组件</Button>
|
|
|
</Space>}
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
{/*数据列表*/}
|
|
|
<div className={styles['comp-list-list']}>
|
|
|
<Table
|
|
|
columns={columns}
|
|
|
data={componentData}
|
|
|
loading={loading}
|
|
|
pagination={false}
|
|
|
scroll={{ x: 1500, y: 'calc(100vh - 280px)' }}
|
|
|
border={{
|
|
|
wrapper: true,
|
|
|
cell: true
|
|
|
}}
|
|
|
/>
|
|
|
<div className={styles['pagination-container']}>
|
|
|
<Pagination
|
|
|
current={pagination.current}
|
|
|
pageSize={pagination.size}
|
|
|
total={pagination.total}
|
|
|
onChange={handlePageChange}
|
|
|
/>
|
|
|
</div>
|
|
|
</div>
|
|
|
</>
|
|
|
)}
|
|
|
|
|
|
{selectedItem === '组件审核' && (
|
|
|
<CompAudit />
|
|
|
)}
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
{/*新增弹窗*/}
|
|
|
<AddComponentModal
|
|
|
visible={visible}
|
|
|
baseInfo={selectComponent}
|
|
|
setVisible={(visible) => {
|
|
|
setVisible(visible);
|
|
|
// 当关闭模态框时重置模式为create
|
|
|
if (!visible) {
|
|
|
setMode('create');
|
|
|
}
|
|
|
}}
|
|
|
onReFresh={fetchComponentData}
|
|
|
mode={mode} // 传递模式
|
|
|
/>
|
|
|
|
|
|
{/*发布组件弹窗*/}
|
|
|
<PublishComponentModal
|
|
|
visible={publishModalVisible}
|
|
|
componentInfo={selectedPublishComponent}
|
|
|
onCancel={() => {
|
|
|
setPublishModalVisible(false);
|
|
|
setSelectedPublishComponent(null);
|
|
|
}}
|
|
|
onSuccess={() => {
|
|
|
fetchComponentData();
|
|
|
}}
|
|
|
/>
|
|
|
|
|
|
{/*导入组件弹窗*/}
|
|
|
<ImportComponentModal
|
|
|
visible={importModalVisible}
|
|
|
onCancel={handleImportCancel}
|
|
|
onOk={handleImportConfirm}
|
|
|
onFileSelect={handleImportFileSelect}
|
|
|
componentInfo={importComponentInfo}
|
|
|
loading={importLoading}
|
|
|
/>
|
|
|
|
|
|
{/* 审核历史弹窗 */}
|
|
|
<Modal
|
|
|
title={`审核历史 - ${currentReviewComponent?.name || ''}`}
|
|
|
visible={historyModalVisible}
|
|
|
onCancel={() => setHistoryModalVisible(false)}
|
|
|
footer={null}
|
|
|
style={{ width: '90%', maxWidth: 1400, minWidth: 800 }}
|
|
|
>
|
|
|
<div style={{ minHeight: 400 }}>
|
|
|
<Table
|
|
|
columns={[
|
|
|
{
|
|
|
title: '组件名称',
|
|
|
dataIndex: 'name',
|
|
|
width: 150,
|
|
|
render: (_, record: any) => record.main?.name || '-'
|
|
|
},
|
|
|
{
|
|
|
title: '分类',
|
|
|
dataIndex: 'componentClassify',
|
|
|
width: 120,
|
|
|
render: (_, record: any) => record.main?.componentClassify || '-'
|
|
|
},
|
|
|
{
|
|
|
title: '组件标识',
|
|
|
dataIndex: 'identifier',
|
|
|
width: 180,
|
|
|
render: (_, record: any) => record.main?.identifier || '-'
|
|
|
},
|
|
|
{
|
|
|
title: '组件版本',
|
|
|
dataIndex: 'componentVersion',
|
|
|
width: 100,
|
|
|
render: (_, record: any) => record.main?.componentVersion ? `v${record.main.componentVersion}` : '-'
|
|
|
},
|
|
|
{
|
|
|
title: '发布状态',
|
|
|
dataIndex: 'publicStatus',
|
|
|
width: 120,
|
|
|
render: (_, record: any) => {
|
|
|
const status = record.main?.publicStatus;
|
|
|
const statusMap = {
|
|
|
'-1': { text: '未发布', color: 'orange' },
|
|
|
0: { text: '未发布', color: 'orange' },
|
|
|
1: { text: '已发布', color: 'green' },
|
|
|
2: { text: '审核中', color: 'arcoblue' },
|
|
|
3: { text: '审核被拒', color: 'red' }
|
|
|
};
|
|
|
const statusInfo = statusMap[status] || { text: '未知', color: 'gray' };
|
|
|
return <Tag color={statusInfo.color}>{statusInfo.text}</Tag>;
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '组件评分',
|
|
|
dataIndex: 'stars',
|
|
|
width: 200,
|
|
|
render: (_, record: any) => {
|
|
|
const stars = record.main?.stars;
|
|
|
if (stars < 0) return <span style={{ color: '#999' }}>暂无评分</span>;
|
|
|
return <Rate disabled allowHalf value={stars} />;
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
title: '审核人',
|
|
|
dataIndex: 'reviewUserName',
|
|
|
width: 120,
|
|
|
render: (_, record: any) => record.main?.reviewUserName || '-'
|
|
|
},
|
|
|
{
|
|
|
title: '审核结果',
|
|
|
dataIndex: 'reviewOpinion',
|
|
|
render: (_, record: any) => record.main?.reviewOpinion || '-'
|
|
|
}
|
|
|
]}
|
|
|
data={historyData}
|
|
|
loading={historyLoading}
|
|
|
pagination={false}
|
|
|
scroll={{ x: 1600, y: 500 }}
|
|
|
border={{
|
|
|
wrapper: true,
|
|
|
cell: true
|
|
|
}}
|
|
|
/>
|
|
|
</div>
|
|
|
</Modal>
|
|
|
|
|
|
<Modal
|
|
|
title={'下架组件'}
|
|
|
visible={showOffSaleModal}
|
|
|
style={{ width: '45%' }}
|
|
|
onCancel={() => {
|
|
|
setSelectedItem(null);
|
|
|
setShowOffSaleModal(false);
|
|
|
}}
|
|
|
footer={[
|
|
|
<Button key="cancel" onClick={() => setShowOffSaleModal(false)}>
|
|
|
取消
|
|
|
</Button>,
|
|
|
<Button key="offshelf" type="primary" onClick={() => {
|
|
|
componentOffSaleHandler(false);
|
|
|
}}>
|
|
|
仅下架组件
|
|
|
</Button>,
|
|
|
<Button key="stopAndOffshelf" type="primary" status="danger" onClick={() => {
|
|
|
componentOffSaleHandler(true);
|
|
|
}}>
|
|
|
停止线上实例并下架组件
|
|
|
</Button>
|
|
|
]}
|
|
|
>
|
|
|
<p>下架后该组件状态为编码中,不可继续新增实例等。</p>
|
|
|
<p> 该组件存在线上部署的实例,可继续使用原有的代码逻辑继续运行,是否需要同步停止所有线上实例?</p>
|
|
|
</Modal>
|
|
|
</>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default GlobalVarContainer; |