319 lines
8.3 KiB
Vue
319 lines
8.3 KiB
Vue
<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>
|