From 8273b7eebb653e17e60fe9a2931b4a9b998b854e Mon Sep 17 00:00:00 2001 From: zly Date: Mon, 20 Apr 2026 11:07:39 +0800 Subject: [PATCH] =?UTF-8?q?feat(componentList):=20=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E5=A2=9E=E5=8A=A0=E5=A4=9A=E9=80=89=E5=AF=BC?= =?UTF-8?q?=E5=85=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../componentList/importComponentModal.tsx | 96 ++++++++++--------- .../componentList/index.tsx | 12 +-- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/pages/componentDevelopment/componentList/importComponentModal.tsx b/src/pages/componentDevelopment/componentList/importComponentModal.tsx index 2482150..daf7e82 100644 --- a/src/pages/componentDevelopment/componentList/importComponentModal.tsx +++ b/src/pages/componentDevelopment/componentList/importComponentModal.tsx @@ -1,20 +1,24 @@ import React, { useState, useRef, useEffect } from 'react'; -import { Modal, Button, Message, Divider, Tabs, Checkbox } from '@arco-design/web-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) => void; - componentInfo: any; // 单次文件解析的结果 + onFileSelect: (file: File) => Promise; loading: boolean; } interface FileItem { file: File; - componentInfo: any[]; // 该文件包含的组件列表 + componentInfo: ParsedComponentInfo[]; // 该文件包含的组件列表 } const ImportComponentModal: React.FC = ({ @@ -22,12 +26,10 @@ const ImportComponentModal: React.FC = ({ onCancel, onOk, onFileSelect, - componentInfo, loading }) => { const [fileItems, setFileItems] = useState([]); const [activeTabKey, setActiveTabKey] = useState('0'); - const [pendingFile, setPendingFile] = useState(null); // 等待解析的文件 const fileInputRef = useRef(null); // 当弹窗关闭时清空所有状态 @@ -35,56 +37,60 @@ const ImportComponentModal: React.FC = ({ if (!visible) { setFileItems([]); setActiveTabKey('0'); - setPendingFile(null); } }, [visible]); - // 当 componentInfo 更新时,添加到 fileItems` - useEffect(() => { - if (pendingFile && componentInfo) { - const componentList = Array.isArray(componentInfo) ? componentInfo : [componentInfo]; + const updateFileItem = (file: File, componentInfo: ParsedComponentInfo[] | ParsedComponentInfo) => { + const componentList = Array.isArray(componentInfo) ? componentInfo : [componentInfo]; + let nextActiveKey = '0'; - // 检查文件是否已存在 - const existingIndex = fileItems.findIndex(item => item.file.name === pendingFile.name); + setFileItems((prev) => { + const existingIndex = prev.findIndex((item) => item.file.name === file.name); if (existingIndex >= 0) { - // 更新现有文件 - const newFileItems = [...fileItems]; - newFileItems[existingIndex] = { - file: pendingFile, + nextActiveKey = String(existingIndex); + const nextItems = [...prev]; + nextItems[existingIndex] = { + file, componentInfo: componentList }; - setFileItems(newFileItems); + return nextItems; } - else { - // 添加新文件 - const newFileItem: FileItem = { - file: pendingFile, + + nextActiveKey = String(prev.length); + return [ + ...prev, + { + file, componentInfo: componentList - }; - const updatedFileItems = [...fileItems, newFileItem]; - setFileItems(updatedFileItems); - setActiveTabKey(String(fileItems.length)); // 切换到新添加的标签页 - } + } + ]; + }); - setPendingFile(null); + 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 压缩包文件'); } - }, [componentInfo]); - const handleFileChange = (event: React.ChangeEvent) => { - const files = event.target.files; - if (!files || files.length === 0) return; + for (const file of validFiles) { + const parsedComponentInfo = await onFileSelect(file); - // 验证文件类型 (.zip) - const file = files[0]; - if (!file.name.match(/\.zip$/i)) { - Message.error('请选择ZIP压缩包文件'); - event.target.value = ''; - return; + if (!parsedComponentInfo) { + continue; + } + + updateFileItem(file, parsedComponentInfo); } - setPendingFile(file); - onFileSelect(file); event.target.value = ''; }; @@ -116,7 +122,6 @@ const ImportComponentModal: React.FC = ({ const handleClose = () => { setFileItems([]); setActiveTabKey('0'); - setPendingFile(null); onCancel(); }; @@ -151,6 +156,7 @@ const ImportComponentModal: React.FC = ({ > = ({ />
- {fileItems.length === 0 && !pendingFile && ( + {fileItems.length === 0 && (

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

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

@@ -172,9 +178,9 @@ const ImportComponentModal: React.FC = ({ type="card" > {fileItems.map((fileItem, fileIndex) => { - const current = fileItems[activeTabKey]; - const baseInfo = current.componentInfo[0].baseInfo; - const operates = current.componentInfo[0].operates; + const currentComponent = fileItem.componentInfo[0]; + const baseInfo = currentComponent?.baseInfo || {}; + const operates = currentComponent?.operates || []; return ( { { label: 'Python', value: 'Python' } ]; 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); @@ -423,16 +422,16 @@ const GlobalVarContainer = () => { const res: any = await getImportComponentInfo({ file }); if (res.code === 200) { - setImportComponentInfo(res.data); Message.success('组件信息解析成功'); + return res.data; } else { Message.error(res.msg || '解析组件信息失败'); - setImportComponentInfo(null); + return null; } } catch (error) { Message.error('解析组件信息失败'); - setImportComponentInfo(null); + return null; } finally { setImportLoading(false); } @@ -453,7 +452,6 @@ const GlobalVarContainer = () => { if (res.code === 200) { Message.success('组件导入成功'); setImportModalVisible(false); - setImportComponentInfo(null); fetchComponentData(); // 刷新列表 } else { @@ -471,7 +469,6 @@ const GlobalVarContainer = () => { // 关闭导入弹窗 const handleImportCancel = () => { setImportModalVisible(false); - setImportComponentInfo(null); }; // 查看审核历史 @@ -890,7 +887,6 @@ const GlobalVarContainer = () => { onCancel={handleImportCancel} onOk={handleImportConfirm} onFileSelect={handleImportFileSelect} - componentInfo={importComponentInfo} loading={importLoading} /> @@ -1026,4 +1022,4 @@ const GlobalVarContainer = () => { ); }; -export default GlobalVarContainer; \ No newline at end of file +export default GlobalVarContainer;