feat(apps): 添加应用导入导出功能并优化资源监控仪表盘

master
钟良源 1 week ago
parent 3ef8df6087
commit 0146db8b59

@ -55,17 +55,17 @@ export function copyApp(data: any) {
}
// 导入应用
export function importApp(data: any) {
return axios.post(`${urlPrefix}/apps/import`, data);
export function importApp(file: File) {
return axios.post(`${urlPrefix}/apps/import`, { file });
}
// 导出应用
export function exportApp(data: any) {
export function exportApp(srcId: any) {
return axios({
method: 'post',
url: `${urlPrefix}/apps/export`,
responseType: 'blob',
data: data
data: { srcId }
});
}

@ -53,11 +53,19 @@ const ResourceMonitorModal: React.FC<ResourceMonitorModalProps> = ({
// CPU 使用率仪表盘配置
const getCpuGaugeOption = (): EChartsOption => {
return {
grid: {
top: '25%',
bottom: '10%',
left: '10%',
right: '10%',
},
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
center: ['50%', '70%'],
radius: '90%',
min: 0,
max: 100,
splitNumber: 10,
@ -128,11 +136,19 @@ const ResourceMonitorModal: React.FC<ResourceMonitorModalProps> = ({
// 内存使用率仪表盘配置
const getMemoryGaugeOption = (): EChartsOption => {
return {
grid: {
top: '25%',
bottom: '10%',
left: '10%',
right: '10%',
},
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
center: ['50%', '70%'],
radius: '90%',
min: 0,
max: 100,
splitNumber: 10,

@ -10,7 +10,8 @@ import {
Message,
Dropdown,
Menu,
Popconfirm
Popconfirm,
Upload
} from '@arco-design/web-react';
import {
IconApps,
@ -24,7 +25,8 @@ import {
IconExpand,
IconShrink,
IconLeft,
IconLoading
IconLoading,
IconUpload
} from '@arco-design/web-react/icon';
import { menuData1, menuData2 } from './config/menuData';
import { Selected } from '@/pages/ideContainer/types';
@ -39,7 +41,7 @@ import {
updateIsRunning,
updateRuntimeId
} from '@/store/ideContainer';
import { addApp, getProjectEnv, editApp, deleteApp } from '@/api/apps';
import { addApp, getProjectEnv, editApp, deleteApp, exportApp, importApp } from '@/api/apps';
import _ from 'lodash';
import { getAppInfoNew } from '@/api/appRes';
import { getAppEventData } from '@/api/appEvent';
@ -201,6 +203,9 @@ const SideBar: React.FC<SideBarProps> = ({
const [showModal, setShowModal] = useState(false);
const [modalType, setModalType] = useState<'ADD' | 'EDIT'>('ADD');
const [currentApp, setCurrentApp] = useState<any>(null);
const [showImportModal, setShowImportModal] = useState(false); // 导入应用弹窗
const [importFile, setImportFile] = useState<File | null>(null); // 导入的文件
const [importing, setImporting] = useState(false); // 导入中状态
const [contextMenu, setContextMenu] = useState<{
visible: boolean;
x: number;
@ -685,6 +690,36 @@ const SideBar: React.FC<SideBarProps> = ({
// 只有当 node.dataRef.id 存在时才渲染操作按钮
if (!node.dataRef?.id) return null;
// 导出应用处理函数
const handleExportApp = async () => {
try {
const response: any = await exportApp(node.dataRef.id);
// 创建下载链接
const url = window.URL.createObjectURL(new Blob([response]));
const link = document.createElement('a');
link.href = url;
// 设置文件名,使用应用名称
const fileName = `${node.dataRef.name || 'app'}_${new Date().getTime()}.zip`;
link.setAttribute('download', fileName);
// 触发下载
document.body.appendChild(link);
link.click();
// 清理
document.body.removeChild(link);
window.URL.revokeObjectURL(url);
Message.success('应用导出成功');
setContextMenu(prev => ({ ...prev, visible: false })); // 隐藏右键菜单
} catch (error) {
console.error('导出应用失败:', error);
Message.error('导出应用失败');
}
};
const dropList = (
<Menu>
<MenuItem
@ -701,6 +736,15 @@ const SideBar: React.FC<SideBarProps> = ({
</span>
</MenuItem>
<MenuItem
key="exportApp"
onClick={handleExportApp}
>
<span style={{ color: 'rgba(161, 165, 194, 1)' }}>
<IconExpand style={{ marginRight: 6 }} />
</span>
</MenuItem>
<MenuItem
key="deleteApp"
onClick={() => {
@ -850,10 +894,10 @@ const SideBar: React.FC<SideBarProps> = ({
/>
<Button
type="secondary"
icon={isAllExpanded ? <IconShrink /> : <IconExpand />}
icon={<IconUpload />}
style={{ marginLeft: 5 }}
onClick={toggleExpandAll}
title={isAllExpanded ? '折叠全部' : '展开全部'}
onClick={() => setShowImportModal(true)}
title="导入应用"
/>
<Button
type="primary"
@ -956,6 +1000,66 @@ const SideBar: React.FC<SideBarProps> = ({
onRefresh={onRefresh}
></AppHandleModal>
)}
{/* 导入应用 */}
<Modal
title="导入应用"
visible={showImportModal}
onCancel={() => {
setShowImportModal(false);
setImportFile(null);
}}
onOk={async () => {
if (!importFile) {
Message.warning('请选择要导入的文件');
return;
}
try {
setImporting(true);
const res: any = await importApp(importFile);
if (res.code === 200) {
Message.success('应用导入成功');
setShowImportModal(false);
setImportFile(null);
onRefresh(); // 刷新应用列表
}
else {
Message.error(res.msg || '应用导入失败');
}
} catch (error) {
console.error('导入应用失败:', error);
Message.error('应用导入失败');
} finally {
setImporting(false);
}
}}
confirmLoading={importing}
okText="上传"
cancelText="取消"
>
<Upload
accept=".zip"
limit={1}
autoUpload={false}
fileList={importFile ? [{
uid: '-1',
name: importFile.name,
status: 'done',
originFile: importFile
}] : []}
onChange={(fileList) => {
if (fileList.length > 0) {
setImportFile(fileList[0].originFile as File);
}
else {
setImportFile(null);
}
}}
tip="只能上传 zip 格式的应用文件"
/>
</Modal>
</div>
);
};

Loading…
Cancel
Save