2026-01-14 11:18:50 +08:00

319 lines
8.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="my-images-page">
<!-- 顶部警告提示 -->
<div class="top-warning">
<span class="title">我的镜像</span>
<span class="warning-text">
连续3个月未登录或欠费50元以上平台保留删除数据的权利具体规则请参考
<!-- <a href="#" class="link">文档</a> -->
</span>
</div>
<!--
<div class="storage-info">
<div class="storage-desc">
存储容量大小<strong>{{ storageUsed }}</strong>
今天容量使用峰值{{ storagePeak }}预计扣费{{ expectedFee }}
</div>
<a href="#" class="view-rule">查看计费规则</a>
</div>
<div class="progress-container">
<a-progress :percent="storagePercent" :show-info="true" />
</div>
<div class="capacity-info">
<span><span class="dot free"></span>免费{{ freeStorage }}</span>
<span><span class="dot paid"></span>付费{{ paidStorage }}</span>
</div> -->
<!-- 表格 -->
<div class="table-container">
<a-table :data-source="imageList" :columns="columns" :pagination="false" :scroll="{ x: 'max-content', y: 400 }"
:row-key="(record) => record.uid" :loading="loading" bordered class="image-table">
<template #action="{ record }">
<a-button type="link" size="small" @click="handleView(record)">查看</a-button>
<a-button type="link" size="small" danger @click="handleDelete(record)">删除</a-button>
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'status'">
<a-tag v-if="record.status == 'enabled'" color="green">启用</a-tag>
<a-tag v-if="record.status == 'disabled'" color="red">禁用</a-tag>
</template>
<template v-if="column.dataIndex === 'imageIsPublic'">
<a-tag v-if="record.imageIsPublic" color="green">公开</a-tag>
<a-tag v-else color="red">不公开</a-tag>
</template>
</template>
<template #empty>
<div class="table-empty">暂无数据</div>
</template>
</a-table>
</div>
<!-- 分页固定在底部 -->
<div class="pagination-container">
<a-pagination v-model:current="pagination.current" v-model:page-size="pagination.pageSize"
:total="pagination.total" show-size-changer show-jumper show-less-items :page-size-options="[5, 10, 20, 50]"
@change="onPageChange" @showSizeChange="onShowSizeChange" />
</div>
<editDialog ref="editDialogRef" />
</div>
</template>
<script setup lang="ts">
import editDialog from './editDialog.vue';
import { ref, reactive, onMounted, computed, } from 'vue';
import {
message,Modal,
} from 'ant-design-vue';
import apis from '@/apis';
import { getImageList, delImageItem } from '@/apis/admin';
import { on } from 'events';
// 表格列定义
interface ImageItem {
uid: string;
name: string;
size: string;
status: string;
shareInfo: string;
source: string;
region: string;
baseImage: string;
createTime: string;
}
// 模拟数据
const imageList = ref<ImageItem[]>([]);
const editDialogRef = ref<any>(null);
// 存储容量
const storageUsed = ref('12.5GB');
// 计算进度百分比
const storagePercent = computed(() => {
const usedGB = parseFloat(storageUsed.value.replace('GB', ''));
const totalGB = 30;
return Math.min(100, Math.round((usedGB / totalGB) * 100));
});
// 分页配置
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0,
});
// 定义列
const columns = [
{ title: '名称', dataIndex: 'name', key: 'name', width: 150 },
{ title: '镜像hash', dataIndex: 'imageHash', key: 'imageHash', width: 100 },
{ title: '镜像是否公开', dataIndex: 'imageIsPublic', key: 'imageIsPublic', width: 130 },
{ title: '镜像路径', dataIndex: 'imagePath', key: 'imagePath', width: 120 },
{ title: '镜像大小', dataIndex: 'imageSize', key: 'imageSize', width: 180 },
{ title: '镜像类型', dataIndex: 'imageType', key: 'imageType', width: 180 },
{ title: '镜像版本', dataIndex: 'imageVersion', key: 'imageVersion', width: 150 },
{ title: '状态', dataIndex: 'status', key: 'status', width: 80 },
// { title: '创建时间', dataIndex: 'createTime', key: 'createTime', width: 160 },
{
title: '操作',
key: 'action',
slots: { customRender: 'action' },
fixed: 'right',
width: 130
},
];
// 分页事件处理
const onPageChange = (page: number, pageSize: number) => {
console.log(`切换到第 ${page} 页,每页 ${pageSize} 条`);
pagination.current = page;
pagination.pageSize = pageSize;
};
const onShowSizeChange = (current: number, pageSize: number) => {
console.log(`每页显示 ${pageSize} 条`);
pagination.current = current;
pagination.pageSize = pageSize;
};
// 操作处理函数
const handleView = (record: ImageItem) => {
// message.info(`查看镜像: ${record.name}`);
editDialogRef.value.openDialog(record);
};
const handleDelete = (record:any) => {
Modal.confirm({
title: "确认删除该镜像吗",
okText: "确认",
onOk: () => {
return new Promise((resolve, reject) => {
; (async () => {
try {
const res:any= await delImageItem({image_id: record.id}).catch(() => {
throw new Error()
})
if (res.code === 0) {
resolve(true)
message.success('删除成功')
await getDataList()
}
} catch (error) {
reject()
}
})()
})
},
})
};
// 计算当前页数据
const getCurrentPageData = computed(() => {
const start = (pagination.current - 1) * pagination.pageSize;
const end = start + pagination.pageSize;
return imageList.value.slice(start, end);
});
// 加载状态
const loading = ref(false);
const getDataList = async () => {
loading.value = true;
try {
console.log('获取镜像列表');
const res: any = await getImageList({ page_num: pagination.current, page_size: pagination.pageSize });
console.log('镜像列表响应:', res);
imageList.value = res.data;
pagination.total = res.total;
} catch (error) {
console.error('获取镜像列表错误:', error);
message.error('获取镜像列表失败');
} finally {
loading.value = false;
}
};
onMounted(() => {
getDataList();
});
// getDataList()
</script>
<style scoped lang="scss">
.my-images-page {
padding: 24px;
background-color: #ffffff;
// min-height: 100vh;
display: flex;
flex-direction: column;
.top-warning {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 24px;
font-size: 14px;
color: #333;
.title {
font-weight: bold;
color: #000;
font-size: 18px;
}
.warning-text {
color: #f56a00;
font-size: 14px;
}
.link {
color: #1890ff;
text-decoration: underline;
}
}
.storage-info {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding: 16px;
background: #e6f7ff;
border-radius: 4px;
color: #333;
.storage-desc {
font-size: 14px;
strong {
font-size: 16px;
color: #1890ff;
}
}
.view-rule {
color: #1890ff;
font-size: 14px;
cursor: pointer;
}
}
.progress-container {
margin: 16px 0;
width: 100%;
max-width: 600px;
}
.capacity-info {
display: flex;
gap: 32px;
margin: 16px 0;
font-size: 14px;
color: #333;
.dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
}
.free {
background-color: #1890ff;
}
.paid {
background-color: #f56a00;
}
}
.table-container {
flex: 1;
margin: 24px 0;
}
.image-table {
background: white;
// box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
border-radius: 4px;
overflow: hidden;
height: 100%;
}
.table-empty {
text-align: center;
padding: 60px 0;
color: #999;
font-size: 14px;
}
.pagination-container {
margin-top: auto;
padding-top: 24px;
text-align: right;
// border-top: 1px solid #e8e8e8;
}
}
</style>