This commit is contained in:
qiuyuan 2025-11-24 19:12:21 +08:00
commit e4142dc6f9
15 changed files with 493 additions and 68 deletions

BIN
src/assets/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
src/assets/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
src/assets/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/assets/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
src/assets/404.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

BIN
src/assets/avator.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/banner1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

BIN
src/assets/banner2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 KiB

BIN
src/assets/bottom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 KiB

BIN
src/assets/qr.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -23,6 +23,16 @@ const routes: RouteRecordRaw[] = [
name: "Login",
component: () => import("@/views/login/index.vue"),
},
{
path: "/404",
name: "404",
component: () => import("@/views/404.vue"),
},
{
path: "/:pathMatch(.*)*",
name: "NotFound",
component: () => import("@/views/404.vue"),
},
{
path: "/layout",
name: "Layout",
@ -80,11 +90,6 @@ const routes: RouteRecordRaw[] = [
],
},
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: () => import('@/views/404.vue')
}
],
},

113
src/views/404.vue Normal file
View File

@ -0,0 +1,113 @@
<template>
<div class="error">
<div class="error-flex">
<div class="left">
<div class="left-item">
<div class="left-item-animation left-item-num">404</div>
<div class="left-item-animation left-item-title">页面不存在</div>
<div class="left-item-animation left-item-msg">您可以先检查网址然后重新输入或给我们反馈问题</div>
<div class="left-item-animation left-item-btn">
<a-button type="primary" round @click="onGoHome">首页</a-button>
</div>
</div>
</div>
<div class="right">
<img :src="img" />
</div>
</div>
</div>
</template>
<script lang="ts">
import { useRouter } from 'vue-router';
import img from '@/assets/404.png'
export default {
name: '404',
setup() {
const router = useRouter();
const onGoHome = () => {
router.push('/');
};
return {
img,
onGoHome,
};
},
};
</script>
<style scoped lang="scss">
@keyframes error-num {
0% {
transform: translateY(60px);
opacity: 0;
}
100% {
transform: translateY(0);
opacity: 1;
}
}
@keyframes error-img {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.error {
height: 100%;
// background-color: var(--el-color-white);
display: flex;
.error-flex {
margin: auto;
display: flex;
height: 350px;
width: 900px;
.left {
flex: 1;
height: 100%;
align-items: center;
display: flex;
.left-item {
.left-item-animation {
opacity: 0;
animation-name: error-num;
animation-duration: 0.5s;
animation-fill-mode: forwards;
}
.left-item-num {
font-size: 55px;
}
.left-item-title {
font-size: 20px;
margin: 15px 0 5px 0;
animation-delay: 0.1s;
}
.left-item-msg {
font-size: 12px;
margin-bottom: 30px;
animation-delay: 0.2s;
}
.left-item-btn {
animation-delay: 0.2s;
}
}
}
.right {
flex: 1;
opacity: 0;
animation-name: error-img;
animation-duration: 2s;
animation-fill-mode: forwards;
img {
width: 100%;
height: 100%;
}
}
}
}
</style>

View File

@ -57,13 +57,13 @@ const menuItems: MenuItem[] = [
],
},
{
path: '/layout/admin',
path: '',
name: '账号',
icon: TeamOutlined,
children: [
{ path: '/layout/admin/security', name: '账号安全' },
{ path: '/layout/admin/history', name: '访问记录' },
// { path: '/controlPanel/account/security', name: '' },
{ path: '/layout/admin/account/history', name: '访问记录' },
{ path: '/controlPanel/account/security', name: '安全设置' },
],
},
];

View File

@ -1,13 +1,255 @@
<!-- src/views/home/index.vue -->
<template>
<div >
<h1>首页 - 独立页面</h1>
<p>这个页面没有侧边栏</p>
<router-link to="/fileStore" style="color: blue; text-decoration: underline;">
点击进入文件存储有侧边栏
</router-link>
<div>
<div style="height: 550px; overflow: hidden;">
<a-carousel :after-change="onChange" style="height: 100%;">
<div class="banner-slide"></div>
<!-- 如果有多张可以 v-for -->
</a-carousel>
</div>
</template>
<div class="one">
<div>
<h3>GPU选型</h3>
<span>如何选择合适的GPU</span>
</div>
<div>
<h3>开具发票</h3>
<span>简单快速开具发票</span>
</div>
<div>
<h3>新手入门</h3>
<span>简单几步创建实例</span>
</div>
</div>
<div class="two">
<div>
<div>
<div style="margin-bottom: 40px;">
<div class="title">
<span>高性价比的算力服务</span>
</div>
<div class="subtitle">
高性价比+稳定性能算力服务适配多场景热门算力服务如下:
</div>
</div>
<script setup>
</script>
<div class="list_card">
<div v-for="(value, index) in source" style="padding: 0 10px;text-align: center;font-size: 16px;"
:style="{ 'border-top': `3px solid ${listColor[index]}` }">
<div class="name"
style="font-size: 24px;font-weight: bold;padding: 20px;border-bottom: 1px solid #c9c9c9;text-align: center;">
{{ value.title
}}</div>
<div class="price" style="margin: 30px 0;">
<span style="font-size: 24px;font-weight: bold;color: #5b85fe;">¥{{ value.price }}</span>
<span style="font-size: 12px;">/小时</span>
</div>
<div style="padding-bottom: 40px;line-height: 40px;">
<div>内存{{ value.memory }}</div>
<div>显存{{ value.graphicsMemory }}</div>
<div>GPU{{ value.GPU }}</div>
</div>
</div>
</div>
</div>
<div>
<div style="margin-bottom: 40px;">
<div class="title">
<span>产品优势</span>
</div>
<div class="subtitle">
按需租赁高算力稳定省心更省成本
</div>
</div>
<div class="avatary_list">
<div v-for="item in advantageList">
<img :src="item.img" alt="" srcset="" width="200" height="158">
<div class="title">{{ item.title }}</div>
<div class="subtitle">{{ item.subtitle }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="three"></div>
<div class="footer">
<div class="footer_contain">
<div>
<div style="color: #000000;">服务热线:</div>
<div style="font-size: 36px;font-weight: bold;padding: 20px 0;">400-110-6993</div>
<div>邮箱:service@hzzxxd.com</div>
<div>地址:江苏省南通市崇川区紫琅科技城3号楼</div>
</div>
<div>
<div style="color: #000000;">快速导航</div>
<div>算力中心</div>
<div>云主机</div>
<div>用户文档</div>
</div>
<div style="display: flex;align-items: center;gap: 60px;">
<div style="display: flex;flex-direction: column;align-items: center;">
<img src="@/assets/qr.jpg" alt="" srcset="" width="100">
<div>公众号</div>
</div>
<div style="display: flex;flex-direction: column;align-items: center;">
<img src="@/assets/qr.jpg" alt="" srcset="" width="100">
<div>企业微信</div>
</div>
</div>
</div>
<div
style="border-top: 1px solid #ebe4e4;height: 45px;text-align: center;line-height: 45px;color: #666666;font-size: 14px;">
苏备案号20251124号</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import one from '@/assets/1.png'
import two from '@/assets/2.png'
import three from '@/assets/3.png'
import firth from '@/assets/4.png'
const listColor = ref(['#7ed321', '#21d3c0', '#35a4de'])
const source = ref(
[
{ title: 'NVIDIA A100', price: '3.28', memory: '64GB', graphicsMemory: '40GB', GPU: 1 },
{ title: 'NVIDIA A100', price: '6.56', memory: '128GB', graphicsMemory: '80GB', GPU: 2 },
{ title: 'NVIDIA A100', price: '13.12', memory: '256GB', graphicsMemory: '16GB', GPU: 4 },
]
)
const advantageList = ref(
[
{ img: one, title: '灵活弹性', subtitle: '支持按需、包周期两种计费方式,可以根据使用场景选择。' },
{ img: two, title: '安全保障', subtitle: '提供网络防火墙功能,对公网连接进行严格访问控制' },
{ img: three, title: '方便易用', subtitle: '提供完善的API体系便捷的将云服务器与您的内部监控、运营系统相结合' },
{ img: firth, title: '服务优势', subtitle: '7*24小时服务支持60s之内问题相应机制' },
]
)
const onChange = (current: number) => {
console.log(current);
};
</script>
<style scoped lang="scss">
.banner-slide {
width: 100%;
height:550px;
background: url('@/assets/banner2.png') no-repeat center / cover;
}
.one {
display: flex;
justify-content: space-around;
align-items: center;
background-color: #cfe7fe;
padding: 30px 0;
&>div {
padding: 10;
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
& span {
color: #666666
}
}
}
.two {
background-image: linear-gradient(to bottom, #eaf7fc, #f4fafc);
padding-bottom: 80px;
&>div {
width: 1200px;
margin: 0 auto;
.title {
font-size: 28px;
font-weight: 700;
text-align: center;
}
&>div:first-child {
padding: 44px 0;
}
.subtitle {
margin-top: 20px;
color: rgb(153, 153, 153);
text-align: center;
}
.list_card {
margin-top: 30px;
display: flex;
justify-content: space-between;
gap: 20px;
&>div {
flex: 1;
background-color: #ffffff;
line-height: 30px;
transition: all 0.4s cubic-bezier(0.25, 0.1, 0.25, 1);
/* 更长的过渡时间和不同的缓动函数 */
}
&>div:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
}
.avatary_list {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 50px;
&>div {
display: flex;
flex-direction: column;
align-items: center;
}
.title {
color: #59b2f2;
font-size: 18px;
font-weight: bold;
line-height: 30px;
margin-top: 20px;
}
.subtitle {
color: #666666;
}
}
}
}
.three {
height: 180px;
background: url('@/assets/bottom.png') no-repeat center / 100% 100%;
}
.footer {
height: 260px;
background-color: #ffffff;
width: 100%;
.footer_contain {
width: 1200px;
margin: 0 auto;
height: calc(100% - 45px);
display: flex;
justify-content: space-around;
align-items: self-start;
padding: 20px 0;
&>div {
line-height: 30px;
color: #3a3939;
}
}
}
/* For demo */
</style>

View File

@ -1,107 +1,172 @@
<template>
<div class="gx_layout">
<div class="gx_layout_header">
<div class="logo">GxDL算力云</div>
<div class="menu">
<a-menu
v-model:selectedKeys="current"
mode="horizontal"
:items="leftRoutes"
@click="({ key }) => handleMenuClick(key)"
/>
<a-menu
v-model:selectedKeys="current"
mode="horizontal"
:items="rightRoutes"
@click="({ key }) => handleMenuClick(key)"
/>
</div>
<div class="user-info"></div>
<div class="gx_layout">
<div :class="isHome ? 'gx_layout_header_home' : 'gx_layout_header_noHome'" class="gx_layout_header">
<div class="logo">GxDL算力云</div>
<div class="menu">
<a-menu v-model:selectedKeys="current" :class="isHome?'custom-menu':''" mode="horizontal" :items="leftRoutes"
@click="({ key }) => handleMenuClick(key)" />
<a-menu v-model:selectedKeys="current" mode="horizontal" :class="isHome?'custom-menu':''" :items="rightRoutes"
@click="({ key }) => handleMenuClick(key)" />
</div>
<div class="user-info">
<a-dropdown>
<div style="display: flex;align-items: center;justify-content: flex-end;">
<a-avatar :size="24" :src="avatar">
<!-- <template #icon>
<UserOutlined />
</template> -->
</a-avatar>
<span style="font-size: 14px;padding-left:5px;">管理员</span>
</div>
<template #overlay>
<a-card hoverable style="width: 240px">
<template #cover>
<img alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" />
</template>
<a-card-meta title="Europe Street beat">
<template #description>www.instagram.com</template>
</a-card-meta>
<template #actions>
<!-- <setting-outlined key="setting" />
<edit-outlined key="edit" />
<ellipsis-outlined key="ellipsis" /> -->
<a-button block type="text" @click="logout">退出登录</a-button>
</template>
</a-card>
</template>
</a-dropdown>
</div>
</div>
<div class="gx_layout_content">
<router-view />
</div>
</div>
<div class="gx_layout_content">
<router-view />
</div>
</div>
</template>
<script setup>
import { ref, watch } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { UserOutlined } from '@ant-design/icons-vue';
import avatar from '@/assets/avator.png'
const router = useRouter()
const route = useRoute()
const isHome = ref(true)
// /layout
const getActiveKeyFromRoute = () => {
const path = route.path
if (path.startsWith('/layout')) {
const key = path.replace('/layout', '') || '/home'
return [key.startsWith('/') ? key : '/' + key]
}
return ['/home']
const path = route.path
if (path.startsWith('/layout')) {
const key = path.replace('/layout', '') || '/home'
return [key.startsWith('/') ? key : '/' + key]
}
return ['/home']
}
const current = ref(getActiveKeyFromRoute())
// 退
watch(() => route.path, () => {
current.value = getActiveKeyFromRoute()
current.value = getActiveKeyFromRoute()
if (current.value == '/home') {
isHome.value = true
} else {
isHome.value = false
}
})
// key 使 '/admin'
const leftRoutes = ref([
{ key: '/home', label: '首页' },
{ key: '/center', label: '算力中心' },
{ key: '/yunmain', label: '云主机' }
{ key: '/home', label: '首页' },
{ key: '/center', label: '算力中心' },
{ key: '/yunmain', label: '云主机' }
])
const rightRoutes = ref([
{ key: '/document', label: '用户文档' },
{ key: '/admin/home', label: '控制台' }
{ key: '/document', label: '用户文档' },
{ key: '/admin/home', label: '控制台' }
])
//
const handleMenuClick = (key) => {
// key "/admin" "/layout/admin"
const fullPath = `/layout${key}`
router.push(fullPath)
// key "/admin" "/layout/admin"
const fullPath = `/layout${key}`
router.push(fullPath)
}
const logout = () => {
router.replace('/login')
}
</script>
<style lang="scss" scoped>
.gx_layout{
.gx_layout {
width: 100%;
height:100vh;
.gx_layout_header{
height: 60px;
background: #ffffff;
height: 100vh;
.gx_layout_header_home {
background-color: #cfe7fe;
border-bottom: none;
}
.gx_layout_header_noHome {
border-bottom: 1px solid rgb(216 216 216);
}
.gx_layout_header {
z-index: 999;
width: 100%;
height: 60px;
position: fixed;
top: 0;
left: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
flex: 1;
.logo{
.logo {
width: 200px;
}
.user-info{
.user-info {
width: 100px;
}
.menu{
.menu {
flex: 1;
display: flex;
justify-content: space-around;
align-items: center;
&>ul:first-child{
&>ul:first-child {
width: 100%;
border-bottom: none;
}
&>ul{
&>ul {
border-bottom: none;
}
}
}
.gx_layout_content{
.gx_layout_content {
margin-top: 60px;
height: calc(100% - 60px);
background-color: rgba(240, 240, 240, 1);
}
}
/* 自定义菜单主题 */
.custom-menu {
/* 背景色 */
background: #cfe7fe !important;
}
/* 选中项文字颜色 + 左侧竖条horizontal 模式下是底部横线) */
.custom-menu :deep(.ant-menu-item-selected) {
color: #2563eb !important;
}
/* hover 效果 */
.custom-menu :deep(.ant-menu-item:hover) {
color: #2563eb !important;
}
</style>