This commit is contained in:
Leo_Ding 2025-12-08 14:13:40 +08:00
commit e8ec15836e
3 changed files with 105 additions and 237 deletions

View File

@ -5,4 +5,7 @@ import request from '@/utils/index'
export const orderList = (params:any) => request.get('/v1/order/pay_list',{params}) export const orderList = (params:any) => request.get('/v1/order/pay_list',{params})
// 我的订单 // 我的订单
export const useList = (params:any) => request.get('/v1/order/use_list',{params}) export const useList = (params:any) => request.get('/v1/order/use_list',{params})
// 容器实例列表
export const hostCaseList = (params:any) => request.get('/v1/hostCase/list',{params})

View File

@ -41,14 +41,6 @@ import { ref,onBeforeMount } from 'vue'
import { usePagination } from '@/hooks' import { usePagination } from '@/hooks'
import { orderList } from '@/apis/admin' import { orderList } from '@/apis/admin'
import dayjs from 'dayjs' import dayjs from 'dayjs'
// const listData=ref([ {title:1}])
// const paginationState=ref({
// total: 0,
// current: 1,
// pageSize: 10,
// showTotal: (total) => ` ${total} `,
// pageSizeOptions: ['10', '20', '30', '40'],
// })
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination() const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
const columns = ref([ const columns = ref([
{ title: '日期', dataIndex: 'created_at', key: 'created_at' }, { title: '日期', dataIndex: 'created_at', key: 'created_at' },

View File

@ -25,7 +25,7 @@
</span> </span>
</div> --> </div> -->
</div> </div>
<div class="header-bottom"> <div class="header-bottom">
<div class="header-actions"> <div class="header-actions">
<a-button type="primary" @click="handleRent" class="action-btn">租用新实例</a-button> <a-button type="primary" @click="handleRent" class="action-btn">租用新实例</a-button>
@ -35,226 +35,99 @@
</a-button> </a-button>
</div> </div>
<div class="header-filter"> <div class="header-filter">
<a-select <a-select placeholder="筛选标签" style="width: 160px;" size="large">
placeholder="筛选标签"
style="width: 160px;"
size="large"
>
<a-select-option value="all">全部标签</a-select-option> <a-select-option value="all">全部标签</a-select-option>
<a-select-option value="running">运行中</a-select-option> <a-select-option value="running">运行中</a-select-option>
<a-select-option value="stopped">已停止</a-select-option> <a-select-option value="stopped">已停止</a-select-option>
</a-select> </a-select>
<a-input-search <a-input-search placeholder="搜索实例名称/ID" style="width: 240px; margin-left: 12px;" size="large"
placeholder="搜索实例名称/ID" @search="onSearch" />
style="width: 240px; margin-left: 12px;"
size="large"
@search="onSearch"
/>
</div> </div>
</div> </div>
</div> </div>
<!-- 表格 --> <!-- 表格 -->
<div class="table-container"> <div class="table-container">
<a-table <a-table :dataSource="listData" :columns="columns" bordered :pagination="paginationState" @change="onTableChange">
:columns="columns" <template #bodyCell="{ column, record }">
:data-source="dataSource" <template v-if="column.key === 'gpu_model'">
:pagination="false" <div>
:loading="loading" {{ 'GPU型号:' + record.gpu_model,'GPU数量:' + record.gpu_count ,'单卡显存GB:' + record.gpu_memory_gb , 'CPU核数:' + record.cpu_cores , '内存MB:' + record.memory_mb}}
row-key="id"
class="instance-table"
>
<template #empty>
<div class="empty-state">
<div class="empty-icon">
<inbox-outlined />
</div> </div>
<div class="empty-text">暂无数据</div> </template>
<div class="empty-desc">当前没有实例数据您可以租用新实例开始使用</div>
</div>
</template> </template>
</a-table> </a-table>
</div> </div>
<!-- 分页 --> <!-- 分页 -->
<div class="pagination-container">
<div class="pagination-left">
<span class="total-text"> {{ total }} </span>
</div>
<div class="pagination-center">
<a-pagination
v-model:current="currentPage"
v-model:page-size="pageSize"
:total="total"
:page-size-options="['10', '20', '50', '100']"
show-size-changer
show-quick-jumper
size="small"
/>
</div>
<div class="pagination-right">
<span class="goto-text">前往</span>
<a-input-number
v-model:value="currentPage"
:min="1"
:max="Math.ceil(total / pageSize)"
size="small"
style="width: 60px; margin: 0 8px;"
/>
<span class="goto-text"></span>
</div>
</div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts" setup>
import { defineComponent, ref, h } from 'vue'; import { ref, onBeforeMount } from 'vue'
import { Button, Table, Input, Select, Pagination, InputNumber } from 'ant-design-vue'; import { usePagination } from '@/hooks'
import { import { hostCaseList } from '@/apis/admin'
ReloadOutlined,
ExclamationCircleOutlined,
BellOutlined,
KeyOutlined,
AppstoreOutlined,
InboxOutlined
} from '@ant-design/icons-vue';
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
const router = useRouter()
import dayjs from 'dayjs'
const { listData, loading, showLoading, hideLoading, paginationState, resetPagination, searchFormData } = usePagination()
const columns = ref([
{ title: '实例ID', dataIndex: 'id', key: 'id' },
{ title: '名称', dataIndex: 'name', key: 'name' },
{ title: '状态', dataIndex: 'status', key: 'status' },
{ title: '规格详情', dataIndex: 'gpu_model', key: 'gpu_model' },
{ title: '本地磁盘', dataIndex: 'system_disk', key: 'system_disk' },
{ title: '健康状态', dataIndex: 'health_status', key: 'health_status' },
{ title: '付费方式', dataIndex: 'price_type', key: 'price_type' },
{ title: '释放时间', dataIndex: 'release_at', key: 'release_at' },
{ title: '停机时间', dataIndex: 'down_at', key: 'down_at' },
{ title: 'SSH登陆', dataIndex: 'ssh_link', key: 'ssh_link' },
{ title: '操作', dataIndex: 'aciton', key: 'aciton' },
])
onBeforeMount(() => {
getPageList()
})
const getPageList = async () => {
try {
const { pageSize, current } = paginationState
const res: any = await hostCaseList({ pageSize: pageSize, pageNum: current });
listData.value = res.list;
paginationState.total = res?.Total;
export default defineComponent({ } catch (error: any) {
name: 'InstanceList', console.error('产品优势请求失败:', error);
components: { }
AButton: Button, }
ATable: Table, /**
AInput: Input, * 分页
AInputSearch: Input.Search, */
ASelect: Select, function onTableChange({ current, pageSize }) {
ASelectOption: Select.Option, paginationState.current = current
APagination: Pagination, paginationState.pageSize = pageSize
AInputNumber: InputNumber, getPageList()
ReloadOutlined, }
ExclamationCircleOutlined, /**
BellOutlined, * 搜索
KeyOutlined, */
AppstoreOutlined, function handleSearch() {
InboxOutlined, resetPagination()
}, getPageList()
}
/**
* 重置
*/
function handleResetSearch() {
searchFormData.value = {}
resetPagination()
getPageList()
}
setup() { //
const router = useRouter() const handleRent = () => {
const loading = ref(false); router.push('/layout/admin/instanceCreate');
const currentPage = ref(1); }
const pageSize = ref(10);
const total = ref(0);
//
const columns = [
{
title: '实例ID / 名称',
dataIndex: 'id',
key: 'id',
width: 200,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 120,
customRender: ({ text }: { text: string }) => {
return h('span', { class: `status-${text.toLowerCase()}` }, text);
},
},
{
title: '规格详情',
dataIndex: 'spec',
key: 'spec',
width: 150,
},
{
title: '本地磁盘',
dataIndex: 'disk',
key: 'disk',
width: 120,
},
{
title: '健康状态',
dataIndex: 'health',
key: 'health',
width: 120,
},
{
title: '付费方式',
dataIndex: 'payment',
key: 'payment',
width: 120,
},
{
title: '释放时间/停机时间',
dataIndex: 'releaseTime',
key: 'releaseTime',
width: 180,
},
{
title: 'SSH登录',
dataIndex: 'ssh',
key: 'ssh',
width: 120,
},
{
title: '快捷工具',
dataIndex: 'tools',
key: 'tools',
width: 120,
},
{
title: '操作',
dataIndex: 'action',
key: 'action',
width: 150,
},
];
//
const dataSource = ref([]);
//
const fetchInstances = () => {
loading.value = true;
setTimeout(() => {
dataSource.value = [];
total.value = 0;
loading.value = false;
}, 500);
};
fetchInstances();
const handleRent = () => {
router.push('/layout/admin/instanceCreate');
};
const handleRenew = () => {
console.log('批量续费');
};
const onSearch = (value: string) => {
console.log('搜索:', value);
};
return {
columns,
dataSource,
loading,
currentPage,
pageSize,
total,
handleRent,
handleRenew,
onSearch,
};
},
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@ -279,14 +152,14 @@ export default defineComponent({
margin-bottom: 20px; margin-bottom: 20px;
flex-wrap: wrap; flex-wrap: wrap;
gap: 16px; gap: 16px;
.header-left { .header-left {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
gap: 16px; gap: 16px;
flex: 1; flex: 1;
min-width: 300px; min-width: 300px;
.page-title { .page-title {
font-size: 20px; font-size: 20px;
font-weight: 600; font-weight: 600;
@ -294,7 +167,7 @@ export default defineComponent({
line-height: 1.4; line-height: 1.4;
white-space: nowrap; white-space: nowrap;
} }
.warning-tip { .warning-tip {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
@ -303,7 +176,7 @@ export default defineComponent({
line-height: 1.4; line-height: 1.4;
flex: 1; flex: 1;
margin-top: 4px; margin-top: 4px;
.warning-icon { .warning-icon {
margin-right: 8px; margin-right: 8px;
font-size: 16px; font-size: 16px;
@ -312,13 +185,13 @@ export default defineComponent({
} }
} }
} }
.header-quick-actions { .header-quick-actions {
display: flex; display: flex;
gap: 24px; gap: 24px;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
.quick-action-item { .quick-action-item {
display: flex; display: flex;
align-items: center; align-items: center;
@ -328,11 +201,11 @@ export default defineComponent({
cursor: pointer; cursor: pointer;
transition: color 0.3s; transition: color 0.3s;
white-space: nowrap; white-space: nowrap;
&:hover { &:hover {
color: #40a9ff; color: #40a9ff;
} }
.quick-action-icon { .quick-action-icon {
margin-right: 6px; margin-right: 6px;
font-size: 14px; font-size: 14px;
@ -349,18 +222,18 @@ export default defineComponent({
gap: 16px; gap: 16px;
padding-top: 16px; padding-top: 16px;
border-top: 1px solid #f0f0f0; border-top: 1px solid #f0f0f0;
.header-actions { .header-actions {
display: flex; display: flex;
gap: 12px; gap: 12px;
align-items: center; align-items: center;
.action-btn { .action-btn {
height: 36px; height: 36px;
padding: 0 16px; padding: 0 16px;
font-weight: 500; font-weight: 500;
} }
.refresh-btn { .refresh-btn {
height: 36px; height: 36px;
width: 36px; width: 36px;
@ -369,7 +242,7 @@ export default defineComponent({
justify-content: center; justify-content: center;
} }
} }
.header-filter { .header-filter {
display: flex; display: flex;
gap: 12px; gap: 12px;
@ -388,25 +261,25 @@ export default defineComponent({
.empty-state { .empty-state {
padding: 60px 20px; padding: 60px 20px;
text-align: center; text-align: center;
.empty-icon { .empty-icon {
font-size: 64px; font-size: 64px;
color: #d9d9d9; color: #d9d9d9;
margin-bottom: 16px; margin-bottom: 16px;
} }
.empty-text { .empty-text {
font-size: 16px; font-size: 16px;
color: #8c8c8c; color: #8c8c8c;
margin-bottom: 8px; margin-bottom: 8px;
} }
.empty-desc { .empty-desc {
font-size: 14px; font-size: 14px;
color: #bfbfbf; color: #bfbfbf;
} }
} }
// //
:deep(.status-running) { :deep(.status-running) {
color: #52c41a; color: #52c41a;
@ -415,7 +288,7 @@ export default defineComponent({
border-radius: 4px; border-radius: 4px;
font-size: 12px; font-size: 12px;
} }
:deep(.status-stopped) { :deep(.status-stopped) {
color: #ff4d4f; color: #ff4d4f;
background: #fff2f0; background: #fff2f0;
@ -434,24 +307,24 @@ export default defineComponent({
background: #fff; background: #fff;
border-radius: 8px; border-radius: 8px;
border: 1px solid #e8e8e8; border: 1px solid #e8e8e8;
.pagination-left { .pagination-left {
.total-text { .total-text {
color: #8c8c8c; color: #8c8c8c;
font-size: 14px; font-size: 14px;
} }
} }
.pagination-center { .pagination-center {
flex: 1; flex: 1;
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.pagination-right { .pagination-right {
display: flex; display: flex;
align-items: center; align-items: center;
.goto-text { .goto-text {
color: #8c8c8c; color: #8c8c8c;
font-size: 14px; font-size: 14px;
@ -466,7 +339,7 @@ export default defineComponent({
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
} }
.header-quick-actions { .header-quick-actions {
gap: 16px; gap: 16px;
} }
@ -477,37 +350,37 @@ export default defineComponent({
.instance-list { .instance-list {
padding: 16px; padding: 16px;
} }
.header-top { .header-top {
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
.header-left { .header-left {
min-width: auto; min-width: auto;
} }
.header-quick-actions { .header-quick-actions {
justify-content: flex-start; justify-content: flex-start;
} }
} }
.header-bottom { .header-bottom {
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
.header-actions { .header-actions {
justify-content: flex-start; justify-content: flex-start;
} }
.header-filter { .header-filter {
justify-content: flex-start; justify-content: flex-start;
} }
} }
.pagination-container { .pagination-container {
flex-direction: column; flex-direction: column;
gap: 16px; gap: 16px;
.pagination-left, .pagination-left,
.pagination-right { .pagination-right {
width: 100%; width: 100%;