import React, { useState, useRef, useEffect } from 'react'; import { Modal, Button, Message, Tabs } from '@arco-design/web-react'; import { IconUpload, IconDelete, IconFile } from '@arco-design/web-react/icon'; import styles from './style/importComponentModal.module.less'; interface ParsedComponentInfo { baseInfo?: any; operates?: any[]; } interface ImportComponentModalProps { visible: boolean; onCancel: () => void; onOk: (files: FileItem[]) => void; onFileSelect: (file: File) => Promise; loading: boolean; } interface FileItem { file: File; componentInfo: ParsedComponentInfo[]; // 该文件包含的组件列表 } const ImportComponentModal: React.FC = ({ visible, onCancel, onOk, onFileSelect, loading }) => { const [fileItems, setFileItems] = useState([]); const [activeTabKey, setActiveTabKey] = useState('0'); const fileInputRef = useRef(null); // 当弹窗关闭时清空所有状态 useEffect(() => { if (!visible) { setFileItems([]); setActiveTabKey('0'); } }, [visible]); const updateFileItem = (file: File, componentInfo: ParsedComponentInfo[] | ParsedComponentInfo) => { const componentList = Array.isArray(componentInfo) ? componentInfo : [componentInfo]; let nextActiveKey = '0'; setFileItems((prev) => { const existingIndex = prev.findIndex((item) => item.file.name === file.name); if (existingIndex >= 0) { nextActiveKey = String(existingIndex); const nextItems = [...prev]; nextItems[existingIndex] = { file, componentInfo: componentList }; return nextItems; } nextActiveKey = String(prev.length); return [ ...prev, { file, componentInfo: componentList } ]; }); setActiveTabKey(nextActiveKey); }; const handleFileChange = async (event: React.ChangeEvent) => { const selectedFiles = Array.from(event.target.files ?? []); if (selectedFiles.length === 0) return; const validFiles = selectedFiles.filter((file) => file.name.match(/\.zip$/i)); const invalidFileCount = selectedFiles.length - validFiles.length; if (invalidFileCount > 0) { Message.error('请选择 ZIP 压缩包文件'); } for (const file of validFiles) { const parsedComponentInfo = await onFileSelect(file); if (!parsedComponentInfo) { continue; } updateFileItem(file, parsedComponentInfo); } event.target.value = ''; }; const handleSelectFile = () => { fileInputRef.current?.click(); }; // 删除文件 const handleDeleteFile = (index: number) => { const newFileItems = fileItems.filter((_, i) => i !== index); setFileItems(newFileItems); // 如果删除的是当前激活的标签页,切换到第一个 if (String(index) === activeTabKey && newFileItems.length > 0) { setActiveTabKey('0'); } }; const handleUpload = () => { if (fileItems.length === 0) { Message.warning('请至少选择一个组件'); return; } onOk(fileItems); }; const handleClose = () => { setFileItems([]); setActiveTabKey('0'); onCancel(); }; return (
} >
{fileItems.length === 0 && (

请点击下方"添加文件"按钮选择组件压缩包

支持 .zip 格式文件,可添加多个文件

)} {fileItems.length > 0 && ( {fileItems.map((fileItem, fileIndex) => { const currentComponent = fileItem.componentInfo[0]; const baseInfo = currentComponent?.baseInfo || {}; const operates = currentComponent?.operates || []; return ( {fileItem.file.name}
} >
{baseInfo.name || baseInfo.identifier || baseInfo.projectId || '组件信息'}
{/* 组件基本信息 */}
{baseInfo.projectId && (
组件标识: {baseInfo.projectId}
)} {baseInfo.codeLanguage && (
代码语言: {baseInfo.codeLanguage}
)} {baseInfo.componentClassify && (
组件分类: {baseInfo.componentClassify}
)} {baseInfo.desc && (
{baseInfo.desc}
)}
{/* 接口列表 */} {operates.length > 0 && (
接口列表 ({operates.length})
{operates.map((operate: any, opIndex: number) => (
{operate.ident} {operate.type}
{operate.name && (
{operate.name}
)}
{operate.parameters && operate.parameters.length > 0 && ( 输入: {operate.parameters.length} 个参数 )} {operate.responses && operate.responses.length > 0 && ( 输出: {operate.responses.length} 个参数 )}
))}
)}
); })} )}
); }; export default ImportComponentModal;