feat(componentList): 导入组件增加多选导入功能

feature
钟良源 3 weeks ago
parent fd610e2bd8
commit 8273b7eebb

@ -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<ParsedComponentInfo[] | ParsedComponentInfo | null>;
loading: boolean;
}
interface FileItem {
file: File;
componentInfo: any[]; // 该文件包含的组件列表
componentInfo: ParsedComponentInfo[]; // 该文件包含的组件列表
}
const ImportComponentModal: React.FC<ImportComponentModalProps> = ({
@ -22,12 +26,10 @@ const ImportComponentModal: React.FC<ImportComponentModalProps> = ({
onCancel,
onOk,
onFileSelect,
componentInfo,
loading
}) => {
const [fileItems, setFileItems] = useState<FileItem[]>([]);
const [activeTabKey, setActiveTabKey] = useState<string>('0');
const [pendingFile, setPendingFile] = useState<File | null>(null); // 等待解析的文件
const fileInputRef = useRef<HTMLInputElement>(null);
// 当弹窗关闭时清空所有状态
@ -35,56 +37,60 @@ const ImportComponentModal: React.FC<ImportComponentModalProps> = ({
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<HTMLInputElement>) => {
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<HTMLInputElement>) => {
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<ImportComponentModalProps> = ({
const handleClose = () => {
setFileItems([]);
setActiveTabKey('0');
setPendingFile(null);
onCancel();
};
@ -151,6 +156,7 @@ const ImportComponentModal: React.FC<ImportComponentModalProps> = ({
>
<input
ref={fileInputRef}
multiple
type="file"
accept=".zip"
style={{ display: 'none' }}
@ -158,7 +164,7 @@ const ImportComponentModal: React.FC<ImportComponentModalProps> = ({
/>
<div className={styles['import-modal-content']}>
{fileItems.length === 0 && !pendingFile && (
{fileItems.length === 0 && (
<div className={styles['empty-state']}>
<p className={styles['empty-text']}>&#34;&#34;</p>
<p className={styles['empty-hint']}> .zip </p>
@ -172,9 +178,9 @@ const ImportComponentModal: React.FC<ImportComponentModalProps> = ({
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 (
<Tabs.TabPane
key={String(fileIndex)}

@ -84,7 +84,6 @@ const GlobalVarContainer = () => {
{ 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;
export default GlobalVarContainer;

Loading…
Cancel
Save