237 lines
6.1 KiB
TypeScript
237 lines
6.1 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
||
import { Card, Table, Tag, Button, Space, Modal, message, Popconfirm } from 'antd';
|
||
import {
|
||
PlusOutlined,
|
||
EditOutlined,
|
||
DeleteOutlined,
|
||
EyeOutlined
|
||
} from '@ant-design/icons';
|
||
import './index.less';
|
||
|
||
interface ImageItem {
|
||
id: string;
|
||
name: string;
|
||
version: string;
|
||
size: string;
|
||
status: 'active' | 'inactive' | 'building';
|
||
createTime: string;
|
||
description: string;
|
||
}
|
||
|
||
const ImageList: React.FC = () => {
|
||
const [images, setImages] = useState<ImageItem[]>([]);
|
||
const [loading, setLoading] = useState(false);
|
||
const [selectedImage, setSelectedImage] = useState<ImageItem | null>(null);
|
||
const [detailVisible, setDetailVisible] = useState(false);
|
||
|
||
useEffect(() => {
|
||
loadImages();
|
||
console.log('cyt==>测试push');
|
||
|
||
}, []);
|
||
|
||
const loadImages = () => {
|
||
setLoading(true);
|
||
// 模拟数据加载
|
||
setTimeout(() => {
|
||
const mockData: ImageItem[] = [
|
||
{
|
||
id: '1',
|
||
name: 'Windows 10 专业版',
|
||
version: 'v1.0.0',
|
||
size: '15.2 GB',
|
||
status: 'active',
|
||
createTime: '2024-01-15 10:30:00',
|
||
description: 'Windows 10 专业版镜像,包含常用办公软件'
|
||
},
|
||
{
|
||
id: '2',
|
||
name: 'Ubuntu 22.04 LTS',
|
||
version: 'v2.1.0',
|
||
size: '8.5 GB',
|
||
status: 'active',
|
||
createTime: '2024-01-10 14:20:00',
|
||
description: 'Ubuntu 22.04 LTS 服务器版本,适用于开发环境'
|
||
},
|
||
{
|
||
id: '3',
|
||
name: 'CentOS 8',
|
||
version: 'v1.5.0',
|
||
size: '12.1 GB',
|
||
status: 'building',
|
||
createTime: '2024-01-20 09:15:00',
|
||
description: 'CentOS 8 企业级服务器操作系统'
|
||
},
|
||
{
|
||
id: '4',
|
||
name: 'macOS Monterey',
|
||
version: 'v1.2.0',
|
||
size: '18.7 GB',
|
||
status: 'inactive',
|
||
createTime: '2024-01-05 16:45:00',
|
||
description: 'macOS Monterey 开发环境镜像'
|
||
}
|
||
];
|
||
setImages(mockData);
|
||
setLoading(false);
|
||
}, 1000);
|
||
};
|
||
|
||
const getStatusTag = (status: string) => {
|
||
const statusMap = {
|
||
active: { color: 'green', text: '可用' },
|
||
inactive: { color: 'red', text: '不可用' },
|
||
building: { color: 'orange', text: '构建中' }
|
||
};
|
||
const config = statusMap[status as keyof typeof statusMap];
|
||
return <Tag color={config.color}>{config.text}</Tag>;
|
||
};
|
||
|
||
const handleViewDetail = (record: ImageItem) => {
|
||
setSelectedImage(record);
|
||
setDetailVisible(true);
|
||
};
|
||
|
||
|
||
|
||
const handleEdit = (record: ImageItem) => {
|
||
message.info(`编辑镜像:${record.name}`);
|
||
};
|
||
|
||
const handleDelete = (record: ImageItem) => {
|
||
Modal.confirm({
|
||
title: '确认删除',
|
||
content: `确定要删除镜像 "${record.name}" 吗?`,
|
||
onOk: () => {
|
||
setImages(images.filter(img => img.id !== record.id));
|
||
message.success('删除成功');
|
||
}
|
||
});
|
||
};
|
||
|
||
const columns = [
|
||
{
|
||
title: '镜像名称',
|
||
dataIndex: 'name',
|
||
key: 'name',
|
||
width: 200,
|
||
},
|
||
{
|
||
title: '版本',
|
||
dataIndex: 'version',
|
||
key: 'version',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '大小',
|
||
dataIndex: 'size',
|
||
key: 'size',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '状态',
|
||
dataIndex: 'status',
|
||
key: 'status',
|
||
width: 100,
|
||
render: (status: string) => getStatusTag(status),
|
||
},
|
||
{
|
||
title: '创建时间',
|
||
dataIndex: 'createTime',
|
||
key: 'createTime',
|
||
width: 180,
|
||
},
|
||
{
|
||
title: '操作',
|
||
key: 'action',
|
||
width: 200,
|
||
render: (_: any, record: ImageItem) => (
|
||
<Space size="small">
|
||
<Button
|
||
type="text"
|
||
icon={<EyeOutlined />}
|
||
onClick={() => handleViewDetail(record)}
|
||
title="查看详情"
|
||
/>
|
||
<Popconfirm
|
||
title="确定要删除这个镜像吗?"
|
||
description="删除后无法恢复,请谨慎操作。"
|
||
onConfirm={() => handleDelete(record)}
|
||
okText="确定"
|
||
cancelText="取消"
|
||
>
|
||
<Button
|
||
type="text"
|
||
icon={<DeleteOutlined />}
|
||
title="删除"
|
||
danger
|
||
/>
|
||
</Popconfirm>
|
||
</Space>
|
||
),
|
||
},
|
||
];
|
||
|
||
return (
|
||
<div className="image-list">
|
||
<Card>
|
||
<Table
|
||
columns={columns}
|
||
dataSource={images}
|
||
rowKey="id"
|
||
loading={loading}
|
||
pagination={{
|
||
total: images.length,
|
||
pageSize: 10,
|
||
showSizeChanger: true,
|
||
showQuickJumper: true,
|
||
showTotal: (total) => `共 ${total} 条记录`,
|
||
}}
|
||
/>
|
||
</Card>
|
||
|
||
<Modal
|
||
title="镜像详情"
|
||
open={detailVisible}
|
||
onCancel={() => setDetailVisible(false)}
|
||
footer={[
|
||
<Button key="close" onClick={() => setDetailVisible(false)}>
|
||
关闭
|
||
</Button>
|
||
]}
|
||
width={600}
|
||
>
|
||
{selectedImage && (
|
||
<div className="image-detail">
|
||
<div className="detail-item">
|
||
<label>镜像名称:</label>
|
||
<span>{selectedImage.name}</span>
|
||
</div>
|
||
<div className="detail-item">
|
||
<label>版本:</label>
|
||
<span>{selectedImage.version}</span>
|
||
</div>
|
||
<div className="detail-item">
|
||
<label>大小:</label>
|
||
<span>{selectedImage.size}</span>
|
||
</div>
|
||
<div className="detail-item">
|
||
<label>状态:</label>
|
||
<span>{getStatusTag(selectedImage.status)}</span>
|
||
</div>
|
||
<div className="detail-item">
|
||
<label>创建时间:</label>
|
||
<span>{selectedImage.createTime}</span>
|
||
</div>
|
||
<div className="detail-item">
|
||
<label>描述:</label>
|
||
<p>{selectedImage.description}</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</Modal>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default ImageList;
|