GPU_Web/src/views/admin/home/index.vue
2025-12-04 15:06:08 +08:00

575 lines
17 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="home-page">
<!-- 主布局左右两栏 -->
<a-row :gutter="24">
<!-- 左侧栏实例数据常见问题 -->
<a-col :span="16">
<!-- 实例卡片 -->
<a-card title="实例" :bordered="false" class="card">
<a-row :gutter="32" align="middle">
<!-- 第一栏容器实例和运行中 -->
<a-col :span="8">
<div class="stats-column">
<div class="stats-row">
<div class="stat-item">
<div class="stat-label">容器实例</div>
<div class="stat-value">{{ userInfo.caseNum }}</div>
</div>
<div class="stat-item">
<div class="stat-label">运行中</div>
<div class="stat-value">0</div>
</div>
</div>
</div>
</a-col>
<!-- 第二栏即将到期和即将释放 -->
<a-col :span="8">
<div class="stats-column">
<div class="vertical-divider"></div>
<div class="stats-row">
<div class="stat-item">
<div class="stat-label">
<span>即将到期</span>
<a-tooltip title="7天内到期的实例数量">
<QuestionCircleOutlined class="tooltip-icon" />
</a-tooltip>
</div>
<div class="stat-value orange">0</div>
</div>
<div class="stat-item">
<div class="stat-label">
<span>即将释放</span>
<a-tooltip title="3天内即将释放的实例数量">
<QuestionCircleOutlined class="tooltip-icon" />
</a-tooltip>
</div>
<div class="stat-value orange">0</div>
</div>
</div>
</div>
</a-col>
<!-- 第三栏预警设置 -->
<a-col :span="8">
<div class="stats-column">
<div class="vertical-divider"></div>
<div class="warning-row">
<!-- 到期释放短信预警 -->
<div class="warning-module">
<div class="warning-label">
<span>到期释放</span>
<a-tooltip title="开启后,实例到期前会发送短信提醒">
<QuestionCircleOutlined class="tooltip-icon" />
</a-tooltip>
</div>
<div class="warning-controls">
<a-switch v-model:checked="switch1" size="small" />
<div class="warning-status">{{ switch1 ? '已开启' : '未开启' }}</div>
</div>
<div class="warning-actions">
<a-button type="link" size="small">发送记录</a-button>
<a-button type="link" size="small" danger>去绑定邮箱</a-button>
</div>
</div>
<!-- 余额不足短信预警 -->
<div class="warning-module">
<div class="warning-label">
<span>余额不足</span>
<a-tooltip title="开启后,余额不足时会发送短信提醒">
<QuestionCircleOutlined class="tooltip-icon" />
</a-tooltip>
</div>
<div class="warning-controls">
<a-switch v-model:checked="switch2" size="small" />
<div class="warning-status">{{ switch2 ? '已开启' : '未开启' }}</div>
</div>
<!-- 无操作按钮 -->
</div>
</div>
</div>
</a-col>
</a-row>
</a-card>
<!-- 数据卡片 -->
<a-card title="数据" :bordered="false" class="card margin-top">
<a-row type="flex" align="middle" style="height: 100%;">
<!-- 第一栏容器实例数据盘 -->
<a-col :span="8">
<div class="data-column">
<div class="data-label">容器实例数据盘</div>
<div class="data-value">付费扩容容量</div>
<div class="data-unit">0 <span class="data-gb">GB</span></div>
</div>
</a-col>
<!-- 第二栏镜像 -->
<a-col :span="8">
<div class="data-column">
<div class="vertical-divider"></div>
<div class="data-label">镜像</div>
<div class="data-value">付费容量</div>
<div class="data-unit">0 <span class="data-gb">GB</span></div>
</div>
</a-col>
<!-- 第三栏文件存储 -->
<a-col :span="8">
<div class="data-column">
<div class="vertical-divider"></div>
<div class="data-label">文件存储</div>
<div class="data-value">付费容量</div>
<div class="data-unit">0 <span class="data-gb">GB</span></div>
</div>
</a-col>
</a-row>
</a-card>
<!-- 常见问题卡片 -->
<a-card title="常见问题" :bordered="false" class="card margin-top">
<a-list item-layout="horizontal" :data-source="faqList">
<template #renderItem="{ item }">
<a-list-item class="faq-item">
<a-list-item-meta>
<template #title>
<a href="javascript:;" class="faq-title" style="color: #999;">{{ item.question }}</a>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
<div class="more-container">
<a-button type="link" class="more-btn">查看更多问题</a-button>
</div>
</a-card>
</a-col>
<!-- 右侧栏用户信息 + 费用信息 -->
<a-col :span="8">
<!-- 用户信息卡片 -->
<a-card :bordered="false" class="card">
<div class="user-info">
<div class="user-name">{{ userInfo.userName }}</div>
<a-tag color="orange">{{ userInfo.accountType === 'USER' ? '个人认证' : '企业认证' }}</a-tag>
</div>
<div class="user-member">
<UserOutlined class="member-icon" />
<span>炼丹会员<span style="color: #999;">23天后到期</span></span>
</div>
<div class="member-actions">
<a-button type="link" class="member-btn">认证学生升级炼丹会员</a-button>
<a-button type="link" class="member-btn">等级与会员福利</a-button>
</div>
<div class="growth">
<div class="growth-title">成长值</div>
<a-progress :percent="10" status="active" strokeColor="#d46b08" />
<div class="growth-text">距离升级还需90成长值 <a href="#">升级攻略</a></div>
<a-button type="link" class="growth-btn">进入成长值主页></a-button>
</div>
</a-card>
<!-- 费用信息卡片 -->
<a-card :bordered="false" class="card margin-top">
<div class="fee-header">
<div class="fee-title">我的余额</div>
<a-button type="primary" size="small" danger>去充值</a-button>
</div>
<div class="fee-info">
<div class="fee-item">
<span>可用</span>
<span class="fee-value">¥{{ userInfo.noFreezeBalace }}</span>
<span class="fee-divider">|</span>
<span>冻结</span>
<span class="fee-value">¥{{ userInfo.freezeBalace }}</span>
</div>
<div class="fee-item">
<GiftOutlined class="fee-icon" />
<span>代金券</span>
<span class="fee-value">¥0.00</span>
</div>
<div class="fee-item">
<TagOutlined class="fee-icon" />
<span>优惠券</span>
<span class="fee-value">暂无</span>
</div>
<div class="fee-item">
<CreditCardOutlined class="fee-icon" />
<span>授信</span>
<span class="fee-value">暂无</span>
</div>
</div>
<a-divider />
<div class="fee-links">
<a-button type="link" class="fee-link">我的订单></a-button>
<a-button type="link" class="fee-link">我的账单></a-button>
<a-button type="link" class="fee-link">我的代金券></a-button>
<a-button type="link" class="fee-link">开发票></a-button>
</div>
</a-card>
</a-col>
</a-row>
</div>
</template>
<script setup lang="ts">
import { ref,onBeforeMount } from 'vue'
import {
UserOutlined,
GiftOutlined,
TagOutlined,
CreditCardOutlined,
QuestionCircleOutlined
} from '@ant-design/icons-vue'
import { on } from 'events'
// 实例卡片的开关状态
const switch1 = ref(true)
const switch2 = ref(false)
const userInfo=ref<any>({})
onBeforeMount(() => {
userInfo.value = JSON.parse(localStorage.getItem('userInfo') || '{}');
console.log(userInfo.value)
})
// 常见问题列表
const faqList = ref([
{ id: 1, question: '如何选择GPU?' },
{ id: 2, question: '如何上传数据?' },
{ id: 3, question: '如何开具发票?' },
{ id: 4, question: '如何成为炼丹会员?' },
])
</script>
<style lang="scss" scoped>
.home-page {
padding: 15px;
background: #fff;
// min-height: 100vh;
}
.card {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
background: #fff;
margin-bottom: 20px;
}
.margin-top {
margin-top: 20px;
}
/* 实例卡片样式 */
.stats-column {
display: flex;
align-items: center;
height: 100%;
position: relative;
margin-top: -10px;
}
.vertical-divider {
width: 1px;
height: 80px;
background: #e8e8e8;
margin: 0 16px;
}
.stats-row {
display: flex;
gap: 10px;
/* 从 32px 减小 */
align-items: flex-start;
width: 100%;
}
.stat-item {
text-align: center;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
.stat-label {
font-size: 14px;
color: #666;
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
.stat-value {
font-size: 24px;
font-weight: 600;
color: #1890ff;
}
.orange {
color: #fa8c16;
}
.tooltip-icon {
color: #bfbfbf;
cursor: pointer;
font-size: 12px;
}
.tooltip-icon:hover {
color: #1890ff;
}
/* 预警设置样式 */
.warning-row {
display: flex;
flex-direction: row;
gap: 16px;
/* 模块间距 */
width: 100%;
/* align-items: flex-start; */
margin-top: 30px;
}
.warning-module {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 12px;
min-width: 0;
flex: 1;
}
.warning-item {
flex: 1;
min-width: 0;
/* 防止内容撑开 */
}
.warning-content {
display: flex;
flex-direction: column;
gap: 4px;
/* 更紧凑 */
font-size: 12px;
}
.warning-label {
font-size: 14px;
color: #666;
display: flex;
align-items: center;
gap: 4px;
white-space: nowrap;
}
.warning-controls {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: nowrap;
}
.warning-status {
font-size: 11px;
color: #999;
min-width: 36px;
}
.warning-actions {
display: flex;
flex-direction: column;
gap: 4px;
margin-top: 2px;
}
.warning-actions .ant-btn {
padding: 0;
height: auto;
font-size: 12px;
text-align: left;
font-weight: bold;
}
/* 数据卡片样式 */
.data-column {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
padding: 12px 0;
position: relative;
}
.data-column .vertical-divider {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
}
.data-label {
font-size: 14px;
color: #333;
margin-bottom: 4px;
}
.data-value {
font-size: 14px;
color: #999;
margin-bottom: 4px;
}
.data-unit {
font-size: 18px;
font-weight: 600;
color: #1890ff;
font-weight: 600;
.data-gb {
font-size: 12px;
color: #333;
}
}
.faq-item {
padding: 5px 0;
border-bottom: 0px solid #fff;
}
.faq-item:last-child {
border-bottom: none;
}
.faq-title {
color: #1890ff;
text-decoration: none;
}
.faq-title:hover {
color: #40a9ff;
}
.more-container {
display: flex;
justify-content: center;
margin-top: 16px;
}
.more-btn {
color: #1890ff;
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.user-name {
font-size: 18px;
font-weight: 600;
margin-right: 8px;
}
.user-member {
display: flex;
align-items: center;
margin-bottom: 12px;
color: #333;
}
.member-icon {
color: #faad14;
margin-right: 8px;
}
.member-actions {
margin-bottom: 16px;
}
.member-btn {
display: block;
margin-top: 4px;
color: #1890ff;
padding: 0;
height: auto;
}
.growth {
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid #f0f0f0;
}
.growth-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 12px;
}
.growth-text {
font-size: 12px;
color: #666;
margin: 8px 0;
}
.growth-btn {
padding: 0;
height: auto;
color: #1890ff;
}
.fee-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
}
.fee-title {
font-size: 16px;
font-weight: 600;
}
.fee-info {
margin-bottom: 16px;
}
.fee-item {
display: flex;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
}
.fee-icon {
color: #faad14;
margin-right: 8px;
}
.fee-value {
color: #1890ff;
margin-left: 4px;
font-weight: 500;
}
.fee-divider {
margin: 0 8px;
color: #d9d9d9;
}
.fee-links {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.fee-link {
padding: 0;
height: auto;
color: #1890ff;
}
</style>