# 磁盘空间管理 - 布局与组件结构描述 ## 1️⃣ 页面概述 磁盘空间管理页面用于监控和管理系统中各个磁盘分区的使用情况,提供可视化的磁盘空间展示和清理功能。页面以卡片形式展示每个磁盘分区的使用状态、容量信息,并提供快速清理操作。 ## 2️⃣ 布局结构(使用约定术语) ### Page Layout - **Layout Type**: Vertical Stack Layout(垂直堆叠布局) - **Direction**: Vertical(垂直方向) - **Spacing**: 24px between sections - **Padding**: 24px all around ### Component Hierarchy(层级结构) ``` Page (页面) └── Main Container (主容器) ├── Header Section (头部区域) │ └── Title Component (标题组件) │ └── Typography.Title (H3) │ ├── Content Region (内容区域) │ └── Grid Layout (栅格布局) │ ├── Disk Card 1 (磁盘卡片 1) │ │ ├── Card Header (卡片头部) │ │ │ └── Disk Name (磁盘名称) │ │ ├── Card Body (卡片主体) │ │ │ ├── Progress Component (进度组件) │ │ │ │ └── Circle Progress (圆形进度条) │ │ │ └── Space Info (空间信息) │ │ │ ├── Used Space (已用空间) │ │ │ └── Total Space (总空间) │ │ └── Card Footer (卡片底部) │ │ └── Button: 清理 │ │ │ ├── Disk Card 2 (磁盘卡片 2) │ ├── Disk Card 3 (磁盘卡片 3) │ ├── Disk Card 4 (磁盘卡片 4) │ ├── Disk Card 5 (磁盘卡片 5) │ └── Disk Card 6 (磁盘卡片 6) │ └── Footer Section (底部操作区) └── Action Buttons (操作按钮组) ├── Button: 全部清理 └── Button: 刷新 ``` ### Layout Properties(布局属性) #### Main Container - **Type**: Flexbox Layout - **Direction**: Column - **Padding**: 24px - **Gap**: 24px - **Background**: Token.colorBgContainer - **Border-radius**: 8px #### Header Section - **Height**: Auto - **Margin-bottom**: 16px #### Content Region (Grid Layout) - **Type**: Grid Layout - **Columns**: 3 columns - **Gap**: 24px (horizontal and vertical) - **Grid Template**: repeat(3, 1fr) - **Responsive**: - XL (>= 1600px): 3 columns - LG (>= 1200px): 3 columns - MD (>= 992px): 2 columns - SM (< 992px): 1 column #### Disk Card - **Type**: Card Component - **Width**: 100% of grid cell - **Min-height**: 280px - **Padding**: 24px - **Border**: 1px solid Token.colorBorderSecondary - **Border-radius**: 8px - **Box-shadow**: Token.boxShadowTertiary - **Hover Effect**: Elevated shadow #### Card Layout - **Type**: Vertical Flex Layout - **Direction**: Column - **Justify**: Space-between - **Align**: Center - **Gap**: 16px #### Circle Progress - **Size**: 120px diameter - **Stroke Width**: 8px - **Animation**: Smooth transition #### Footer Section - **Height**: 64px - **Margin-top**: 24px - **Alignment**: Right - **Gap**: 12px ## 3️⃣ Ant Design 组件选择 ### 使用的组件及理由 | 组件 | 用途 | 选择理由 | |------|------|---------| | **Typography.Title** | 页面标题 | - 提供标准的标题样式
- 自动适配主题
- 语义化HTML标签 | | **Card** | 磁盘信息卡片 | - 提供完整的卡片容器
- 内置头部、主体、底部布局
- 支持悬停效果
- 优秀的视觉层次
- 响应式设计 | | **Progress** (Circle) | 磁盘使用率展示 | - 圆形进度条直观展示使用率
- 支持百分比和自定义内容
- 多种颜色状态(成功、警告、危险)
- 流畅的动画效果
- 可定制样式 | | **Statistic** | 空间数据展示 | - 专门用于数值展示
- 支持格式化
- 清晰的数据呈现
- 可添加前缀后缀 | | **Button** | 操作按钮 | - 提供多种按钮样式
- 支持加载状态
- 图标支持
- 主题一致性 | | **Row/Col** | 栅格布局 | - 响应式栅格系统
- 灵活的列配置
- 自动适配不同屏幕
- 间距控制 | | **Space** | 间距控制 | - 统一管理组件间距
- 响应式间距
- 灵活的方向配置 | | **Spin** | 加载状态 | - 数据加载时的反馈
- 优雅的加载动画
- 可配置大小和提示文本 | | **Message** | 操作反馈 | - 操作成功/失败提示
- 自动消失
- 不打断用户操作 | | **Modal** | 确认对话框 | - 清理操作确认
- 显示详细信息
- 阻止误操作 | ### Progress Circle 组件选择理由 使用 **Progress Circle(圆形进度条)** 的原因: - ✅ 直观展示磁盘使用率百分比 - ✅ 占用空间小,适合卡片布局 - ✅ 支持多种颜色状态,可根据使用率显示不同颜色(绿色-正常,黄色-警告,红色-危险) - ✅ 中心可显示百分比数值 - ✅ 流畅的动画效果,提升用户体验 - ✅ 易于识别和理解 ### Card 组件选择理由 使用 **Card** 组件展示每个磁盘的原因: - ✅ 提供清晰的视觉边界,每个磁盘信息独立展示 - ✅ 内置完整的布局结构(头部、主体、底部) - ✅ 支持悬停效果,增强交互感 - ✅ 响应式设计,适配不同屏幕尺寸 - ✅ 统一的视觉风格,符合现代UI设计 ### Grid 布局选择理由 使用 **Row/Col 栅格布局** 的原因: - ✅ 灵活的列配置,支持响应式 - ✅ 自动适配不同屏幕尺寸 - ✅ 统一的间距管理 - ✅ 易于维护和扩展 - ✅ Ant Design 原生支持 ## 4️⃣ 功能清单 ### 数据展示功能 - [x] **磁盘列表展示** - [ ] 显示所有磁盘分区 - [ ] 显示磁盘名称(盘符) - [ ] 显示磁盘使用率(百分比) - [ ] 显示已用空间 - [ ] 显示总空间 - [ ] 使用率颜色状态(正常/警告/危险) - [x] **数据加载** - [ ] 初始加载磁盘信息 - [ ] 加载状态指示 - [ ] 加载失败处理 - [ ] 定时自动刷新 - [x] **响应式布局** - [ ] 大屏:3列显示 - [ ] 中屏:2列显示 - [ ] 小屏:1列显示 ### 清理功能 - [x] **单个磁盘清理** - [ ] 点击清理按钮 - [ ] 确认对话框 - [ ] 执行清理操作 - [ ] 清理进度显示 - [ ] 清理结果反馈 - [ ] 更新磁盘使用信息 - [x] **批量清理** - [ ] 全部清理按钮 - [ ] 批量确认对话框 - [ ] 并行/串行清理 - [ ] 总体进度显示 - [ ] 清理报告 - [x] **清理策略** - [ ] 临时文件清理 - [ ] 日志文件清理 - [ ] 缓存清理 - [ ] DICOM 归档文件清理 - [ ] 自定义清理规则 ### 刷新功能 - [x] **手动刷新** - [ ] 刷新按钮 - [ ] 重新加载磁盘信息 - [ ] 刷新状态提示 - [x] **自动刷新** - [ ] 定时轮询(可配置间隔) - [ ] 清理后自动刷新 - [ ] 后台自动刷新 ### 监控与告警 - [x] **使用率监控** - [ ] 实时监控磁盘使用率 - [ ] 使用率颜色编码 - [ ] 阈值设置 - [x] **告警功能** - [ ] 使用率超过阈值告警 - [ ] 磁盘空间不足警告 - [ ] 告警通知 ### 详细信息 - [x] **磁盘详情** - [ ] 点击卡片查看详情 - [ ] 显示文件系统类型 - [ ] 显示挂载点 - [ ] 显示可用空间 - [ ] 显示最后清理时间 ## 5️⃣ 功能需求与思考 ### 功能1:磁盘信息展示与加载 **需求描述**: - 页面加载时自动获取所有磁盘分区信息 - 以卡片形式展示每个磁盘的使用情况 - 使用圆形进度条直观显示使用率 - 根据使用率显示不同颜色状态 **交互流程**: 1. 页面挂载时触发数据加载 2. 显示加载状态(Skeleton 或 Spin) 3. 数据加载成功后渲染卡片 4. 根据使用率设置进度条颜色 5. 加载失败显示错误提示,提供重试按钮 **数据结构**: ```typescript interface DiskInfo { id: string; // 磁盘ID name: string; // 磁盘名称(如 C:, D:) label?: string; // 磁盘标签 totalSpace: number; // 总空间(字节) usedSpace: number; // 已用空间(字节) freeSpace: number; // 可用空间(字节) usagePercent: number; // 使用率(百分比) fileSystem: string; // 文件系统类型 mountPoint: string; // 挂载点 lastCleanTime?: string; // 最后清理时间 status: 'normal' | 'warning' | 'danger'; // 状态 } interface DiskListResponse { disks: DiskInfo[]; totalDisks: number; timestamp: string; } ``` **使用率颜色规则**: - 0-70%:绿色(正常) - 71-85%:黄色(警告) - 86-100%:红色(危险) **边界情况**: - 无磁盘数据 - 磁盘读取失败 - 网络超时 - 数据格式错误 - 磁盘动态挂载/卸载 ### 功能2:单个磁盘清理 **需求描述**: - 点击卡片上的"清理"按钮 - 显示确认对话框,说明清理内容 - 执行清理操作并显示进度 - 清理完成后更新磁盘信息 **交互流程**: 1. 用户点击某个磁盘的"清理"按钮 2. 弹出确认 Modal,显示将要清理的内容: - 临时文件 - 日志文件 - 缓存文件 - 其他可清理文件 - 预计可释放空间 3. 用户确认后开始清理 4. Modal 显示清理进度 5. 清理完成: - 显示清理结果(释放的空间) - 关闭 Modal - 刷新磁盘信息 - 显示成功消息 6. 清理失败: - 显示错误信息 - 提供重试选项 **清理策略**: ```typescript interface CleanupStrategy { tempFiles: boolean; // 临时文件 logFiles: boolean; // 日志文件 cacheFiles: boolean; // 缓存文件 oldBackups: boolean; // 旧备份文件 dicomArchives: boolean; // DICOM归档 customPaths: string[]; // 自定义路径 daysToKeep: number; // 保留天数 } interface CleanupRequest { diskId: string; strategy: CleanupStrategy; } interface CleanupResponse { success: boolean; freedSpace: number; // 释放的空间(字节) filesRemoved: number; // 删除的文件数 duration: number; // 清理耗时(秒) errors?: string[]; // 错误信息 } ``` **安全考虑**: - 二次确认,防止误操作 - 只清理安全的文件类型 - 保留必要的系统文件 - 清理过程可取消 - 清理失败回滚机制 - 清理操作日志记录 **边界情况**: - 磁盘正在被占用 - 权限不足 - 磁盘空间不足导致清理失败 - 清理过程中断 - 并发清理请求 ### 功能3:批量清理 **需求描述**: - 提供"全部清理"按钮 - 同时清理所有磁盘或选中的磁盘 - 显示总体清理进度 - 生成清理报告 **交互流程**: 1. 用户点击"全部清理"按钮 2. 弹出批量清理确认 Modal: - 显示将要清理的磁盘列表 - 每个磁盘的预计可释放空间 - 总计可释放空间 - 清理策略选择 3. 用户确认后开始批量清理 4. Modal 显示清理进度: - 当前清理的磁盘 - 每个磁盘的清理进度 - 总体进度 5. 清理完成后显示报告: - 每个磁盘的清理结果 - 总计释放空间 - 清理耗时 - 失败项目(如有) **批量清理策略**: - **串行清理**:逐个磁盘清理,避免系统负载过高 - **并行清理**:同时清理多个磁盘,提高效率(可配置并发数) **边界情况**: - 部分磁盘清理失败 - 清理过程中新增磁盘 - 用户取消批量清理 - 系统资源不足 ### 功能4:自动刷新与监控 **需求描述**: - 定时自动刷新磁盘信息 - 实时监控磁盘使用率 - 超过阈值时告警 **交互流程**: 1. 页面加载后启动定时器 2. 每隔N秒(可配置)自动刷新 3. 刷新时显示刷新状态(可选) 4. 检查使用率是否超过阈值 5. 如果超过阈值: - 改变进度条颜色 - 显示警告图标 - 发送通知(可选) **配置选项**: ```typescript interface MonitorConfig { autoRefresh: boolean; // 是否自动刷新 refreshInterval: number; // 刷新间隔(秒) warningThreshold: number; // 警告阈值(百分比) dangerThreshold: number; // 危险阈值(百分比) enableNotifications: boolean; // 是否启用通知 notifyOnWarning: boolean; // 警告时通知 notifyOnDanger: boolean; // 危险时通知 } ``` **通知方式**: - 浏览器通知(需要权限) - 系统托盘通知 - 应用内消息提示 - 邮件通知(可选) **边界情况**: - 长时间运行的性能影响 - 网络不稳定导致刷新失败 - 用户离开页面后的处理 ### 功能5:磁盘详情查看 **需求描述**: - 点击卡片查看详细信息 - 显示更多磁盘属性 - 查看清理历史 **交互流程**: 1. 用户点击磁盘卡片(非按钮区域) 2. 打开详情 Modal 或 Drawer 3. 显示详细信息: - 基本信息(名称、总容量、已用、可用) - 文件系统信息 - 挂载点 - 读写速度 - 最后清理时间 - 清理历史记录 4. 提供操作按钮: - 清理 - 刷新 - 关闭 **详情数据结构**: ```typescript interface DiskDetail extends DiskInfo { readSpeed: number; // 读取速度(MB/s) writeSpeed: number; // 写入速度(MB/s) temperature?: number; // 温度(可选) health: 'good' | 'warning' | 'bad'; // 健康状态 cleanupHistory: CleanupRecord[]; // 清理历史 } interface CleanupRecord { id: string; timestamp: string; freedSpace: number; filesRemoved: number; duration: number; status: 'success' | 'partial' | 'failed'; } ``` ## 6️⃣ 后续实现建议 ### 状态管理 #### Redux Slice 设计 ```typescript // states/diskManagementSlice.ts interface DiskManagementState { // 磁盘列表数据 disks: { data: DiskInfo[]; loading: boolean; error: string | null; lastUpdate: string; }; // 清理状态 cleanup: { inProgress: boolean; currentDisk: string | null; progress: number; error: string | null; }; // 监控配置 monitor: MonitorConfig; // 详情 detail: { visible: boolean; diskId: string | null; data: DiskDetail | null; loading: boolean; }; // 自动刷新 autoRefresh: { enabled: boolean; interval: number; timerId: number | null; }; } // 异步 Thunks export const fetchDisks = createAsyncThunk( 'diskManagement/fetchDisks', async () => { const response = await getDisksInfo(); return response; } ); export const cleanupDisk = createAsyncThunk( 'diskManagement/cleanupDisk', async (request: CleanupRequest) => { const response = await cleanupDiskAPI(request); return response; } ); export const batchCleanup = createAsyncThunk( 'diskManagement/batchCleanup', async (diskIds: string[]) => { const responses = await Promise.all( diskIds.map(id => cleanupDiskAPI({ diskId: id, strategy: defaultStrategy })) ); return responses; } ); export const fetchDiskDetail = createAsyncThunk( 'diskManagement/fetchDiskDetail', async (diskId: string) => { const response = await getDiskDetailAPI(diskId); return response; } ); ``` ### API 接口设计 ```typescript // API/disk.ts // 获取磁盘列表 export const getDisksInfo = (): Promise => { return request.get('/api/system/disks'); }; // 获取单个磁盘详情 export const getDiskDetailAPI = (diskId: string): Promise => { return request.get(`/api/system/disks/${diskId}`); }; // 清理磁盘 export const cleanupDiskAPI = (request: CleanupRequest): Promise => { return request.post('/api/system/disks/cleanup', request); }; // 批量清理 export const batchCleanupAPI = (diskIds: string[]): Promise => { return request.post('/api/system/disks/batch-cleanup', { diskIds }); }; // 获取清理历史 export const getCleanupHistoryAPI = (diskId: string): Promise => { return request.get(`/api/system/disks/${diskId}/history`); }; // 获取监控配置 export const getMonitorConfigAPI = (): Promise => { return request.get('/api/system/disks/monitor-config'); }; // 更新监控配置 export const updateMonitorConfigAPI = (config: MonitorConfig): Promise => { return request.put('/api/system/disks/monitor-config', config); }; ``` ### 工具函数 ```typescript // utils/disk.ts // 格式化字节大小 export const formatBytes = (bytes: number, decimals: number = 2): string => { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; }; // 获取使用率状态 export const getUsageStatus = (usagePercent: number): 'normal' | 'warning' | 'danger' => { if (usagePercent < 71) return 'normal'; if (usagePercent < 86) return 'warning'; return 'danger'; }; // 获取进度条颜色 export const getProgressColor = (usagePercent: number): string => { const status = getUsageStatus(usagePercent); switch (status) { case 'normal': return '#52c41a'; // 绿色 case 'warning': return '#faad14'; // 黄色 case 'danger': return '#f5222d'; // 红色 default: return '#1890ff'; } }; // 计算预计可释放空间 export const estimateFreeable = (disk: DiskInfo, strategy: CleanupStrategy): number => { // 根据清理策略估算可释放空间 let estimate = 0; if (strategy.tempFiles) { estimate += disk.usedSpace * 0.05; // 假设临时文件占5% } if (strategy.logFiles) { estimate += disk.usedSpace * 0.03; // 假设日志文件占3% } if (strategy.cacheFiles) { estimate += disk.usedSpace * 0.02; // 假设缓存占2% } return estimate; }; ``` ### 组件实现骨架 ```typescript // sections/SystemHome/DiskManagement.tsx import React, { useEffect, useState } from 'react'; import { Card, Row, Col, Progress, Button, Typography, Space, Statistic, Modal, Spin, message, } from 'antd'; import { DeleteOutlined, ReloadOutlined, ExclamationCircleOutlined, } from '@ant-design/icons'; import { useAppDispatch, useAppSelector } from '@/states/store'; import { fetchDisks, cleanupDisk, batchCleanup, } from '@/states/diskManagementSlice'; import { formatBytes, getProgressColor, getUsageStatus } from '@/utils/disk'; const { Title } = Typography; const DiskManagement: React.FC = () => { const dispatch = useAppDispatch(); const { disks, cleanup } = useAppSelector(state => state.diskManagement); const [cleanupVisible, setCleanupVisible] = useState(false); const [selectedDisk, setSelectedDisk] = useState(null); // 加载磁盘信息 useEffect(() => { dispatch(fetchDisks()); }, [dispatch]); // 自动刷新 useEffect(() => { const interval = setInterval(() => { dispatch(fetchDisks()); }, 30000); // 每30秒刷新一次 return () => clearInterval(interval); }, [dispatch]); // 处理单个磁盘清理 const handleCleanup = (diskId: string) => { setSelectedDisk(diskId); setCleanupVisible(true); }; // 确认清理 const confirmCleanup = async () => { if (!selectedDisk) return; try { const result = await dispatch(cleanupDisk({ diskId: selectedDisk, strategy: { tempFiles: true, logFiles: true, cacheFiles: true, oldBackups: false, dicomArchives: false, customPaths: [], daysToKeep: 30, }, })).unwrap(); message.success(`清理成功!释放了 ${formatBytes(result.freedSpace)}`); setCleanupVisible(false); dispatch(fetchDisks()); } catch (error) { message.error('清理失败'); } }; // 处理批量清理 const handleBatchCleanup = () => { Modal.confirm({ title: '确认