# 磁盘空间管理 - 布局与组件结构描述
## 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: '确认