Merge branch 'main' of https://gitlab.guxuan.icu/Leo_Ding/GPU_Web
This commit is contained in:
commit
e78faa9f0d
42
src/App.vue
42
src/App.vue
@ -1,17 +1,45 @@
|
|||||||
<!-- src/App.vue -->
|
|
||||||
<template>
|
<template>
|
||||||
<router-view />
|
<div id="app">
|
||||||
|
<Header />
|
||||||
|
<main class="main-content">
|
||||||
|
<router-view />
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Header from '@/components/Header.vue'
|
||||||
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* 全局重置 */
|
|
||||||
* {
|
* {
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
html, body, #app {
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
overflow-x: hidden; /* 可选:防止水平滚动 */
|
||||||
|
}
|
||||||
|
|
||||||
|
#app {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 假设 Header 高度是 66px */
|
||||||
|
header {
|
||||||
|
height: 66px;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
padding-top: 30px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
123
src/components/Header.vue
Normal file
123
src/components/Header.vue
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<!-- src/components/Header.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="header">
|
||||||
|
<!-- 左侧导航 -->
|
||||||
|
<nav class="nav-left">
|
||||||
|
<a href="/" class="nav-item">首页</a>
|
||||||
|
<a href="/compute" class="nav-item">算力中心</a>
|
||||||
|
<a href="/cloud-server" class="nav-item">云主机</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- 右侧导航 -->
|
||||||
|
<nav class="nav-right">
|
||||||
|
<a href="/docs" class="nav-item">用户文档</a>
|
||||||
|
<a href="/controlPanel" class="nav-item active">控制台</a>
|
||||||
|
<button class="login-btn" @click="goToLogin">登录/注册</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// 使用 Vue Router 编程式导航跳转登录页(避免页面刷新)
|
||||||
|
const goToLogin = () => {
|
||||||
|
router.push('/login')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 40px;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
height: 64px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-left,
|
||||||
|
.nav-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-left {
|
||||||
|
padding-left: 8px; /* 增加左侧内边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-right {
|
||||||
|
padding-right: 8px; /* 增加右侧内边距 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #333;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
padding: 8px 4px;
|
||||||
|
position: relative;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active {
|
||||||
|
color: #1890ff;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: -2px;
|
||||||
|
left: 4px;
|
||||||
|
right: 4px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: #1890ff;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
padding: 8px 20px;
|
||||||
|
background-color: #1890ff;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(24, 144, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn:hover {
|
||||||
|
background-color: #096dd9;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 8px rgba(24, 144, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.header {
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-left,
|
||||||
|
.nav-right {
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,51 +1,49 @@
|
|||||||
<!-- src/components/Layout.vue -->
|
<!-- src/components/Layout.vue -->
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<div class="sidebar-container">
|
<!-- 侧边栏 -->
|
||||||
<Sidebar />
|
<div class="sidebar-container custom-sidebar">
|
||||||
|
<Sidebar />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主要内容区域 -->
|
||||||
|
<div class="main-content">
|
||||||
|
<div class="content">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main-content">
|
|
||||||
<div class="content">
|
|
||||||
<router-view />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import Sidebar from './sidebar.vue'
|
import Sidebar from './Sidebar.vue'
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.layout {
|
.layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
width: 200px;
|
width: 240px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-content {
|
.main-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
min-height: calc(100vh - 40px);
|
min-height: calc(100vh - 40px);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -7,26 +7,33 @@
|
|||||||
:open-keys="openKeys"
|
:open-keys="openKeys"
|
||||||
@click="handleMenuClick"
|
@click="handleMenuClick"
|
||||||
theme="light"
|
theme="light"
|
||||||
|
class="custom-menu"
|
||||||
>
|
>
|
||||||
<template v-for="item in menuItems" :key="item.path">
|
<template v-for="item in menuItems" :key="item.path">
|
||||||
<!-- 有子菜单的项 -->
|
<!-- 有子菜单的项 -->
|
||||||
<a-sub-menu v-if="item.children && item.children.length" :key="item.path">
|
<a-sub-menu v-if="item.children && item.children.length" :key="item.path">
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="menu-item-content">
|
<span class="menu-item-content">
|
||||||
<span class="icon">{{ item.icon }}</span>
|
<span class="icon">
|
||||||
<span>{{ item.name }}</span>
|
<component :is="item.icon" />
|
||||||
|
</span>
|
||||||
|
<span class="menu-text">{{ item.name }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<a-menu-item v-for="child in item.children" :key="child.path">
|
<a-menu-item v-for="child in item.children" :key="child.path">
|
||||||
<router-link :to="child.path">{{ child.name }}</router-link>
|
<router-link :to="child.path" class="submenu-item">
|
||||||
|
<span class="menu-text">{{ child.name }}</span>
|
||||||
|
</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-sub-menu>
|
</a-sub-menu>
|
||||||
|
|
||||||
<!-- 没有子菜单的项 -->
|
<!-- 没有子菜单的项 -->
|
||||||
<a-menu-item v-else :key="item.path">
|
<a-menu-item v-else :key="item.path">
|
||||||
<router-link :to="item.path" class="menu-item-content">
|
<router-link :to="item.path" class="menu-item-content">
|
||||||
<span class="icon">{{ item.icon }}</span>
|
<span class="icon">
|
||||||
<span>{{ item.name }}</span>
|
<component :is="item.icon" />
|
||||||
|
</span>
|
||||||
|
<span class="menu-text">{{ item.name }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</template>
|
</template>
|
||||||
@ -37,6 +44,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { HomeOutlined,FolderOpenOutlined,ConsoleSqlOutlined ,GlobalOutlined,LaptopOutlined,MoneyCollectOutlined,TeamOutlined} from '@ant-design/icons-vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -44,20 +52,20 @@ const router = useRouter()
|
|||||||
interface MenuItem {
|
interface MenuItem {
|
||||||
path: string
|
path: string
|
||||||
name: string
|
name: string
|
||||||
icon: string
|
icon: any
|
||||||
children?: { path: string; name: string }[]
|
children?: { path: string; name: string }[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重要:路径要与路由配置匹配,使用 /controlPanel 前缀
|
|
||||||
const menuItems: MenuItem[] = [
|
const menuItems: MenuItem[] = [
|
||||||
{ path: '/controlPanel/fileStore', name: '文件存储', icon: '💾' },
|
{ path: '/controlPanel/overview', name: '总览', icon: HomeOutlined },
|
||||||
{ path: '/controlPanel/container', name: '容器实例', icon: '🐳' },
|
{ path: '/controlPanel/container', name: '容器实例', icon: ConsoleSqlOutlined },
|
||||||
{ path: '/controlPanel/image', name: '镜像', icon: '🖼️' },
|
{ path: '/controlPanel/fileStore', name: '文件存储', icon: FolderOpenOutlined },
|
||||||
{ path: '/controlPanel/publicData', name: '公开数据', icon: '📚' },
|
{ path: '/controlPanel/image', name: '镜像', icon: GlobalOutlined },
|
||||||
|
{ path: '/controlPanel/publicData', name: '公开数据', icon: LaptopOutlined },
|
||||||
{
|
{
|
||||||
path: '/controlPanel/fee',
|
path: '/controlPanel/fee',
|
||||||
name: '费用',
|
name: '费用',
|
||||||
icon: '💰',
|
icon: MoneyCollectOutlined,
|
||||||
children: [
|
children: [
|
||||||
{ path: '/controlPanel/fee/detail', name: '详情' },
|
{ path: '/controlPanel/fee/detail', name: '详情' },
|
||||||
{ path: '/controlPanel/fee/bill', name: '账单' }
|
{ path: '/controlPanel/fee/bill', name: '账单' }
|
||||||
@ -66,20 +74,17 @@ const menuItems: MenuItem[] = [
|
|||||||
{
|
{
|
||||||
path: '/controlPanel/account',
|
path: '/controlPanel/account',
|
||||||
name: '账号',
|
name: '账号',
|
||||||
icon: '👤',
|
icon: TeamOutlined,
|
||||||
children: [
|
children: [
|
||||||
{ path: '/controlPanel/account/profile', name: '个人资料' },
|
{ path: '/accountSecurity', name: '账号安全' },
|
||||||
|
{ path: '/accountHistory', name: '访问记录' },
|
||||||
{ path: '/controlPanel/account/security', name: '安全设置' }
|
{ path: '/controlPanel/account/security', name: '安全设置' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
// 选中的菜单项
|
const selectedKeys = computed(() => [route.path])
|
||||||
const selectedKeys = computed(() => {
|
|
||||||
return [route.path]
|
|
||||||
})
|
|
||||||
|
|
||||||
// 展开的菜单项
|
|
||||||
const openKeys = computed(() => {
|
const openKeys = computed(() => {
|
||||||
const keys: string[] = []
|
const keys: string[] = []
|
||||||
if (route.path.startsWith('/controlPanel/fee')) keys.push('/controlPanel/fee')
|
if (route.path.startsWith('/controlPanel/fee')) keys.push('/controlPanel/fee')
|
||||||
@ -87,7 +92,6 @@ const openKeys = computed(() => {
|
|||||||
return keys
|
return keys
|
||||||
})
|
})
|
||||||
|
|
||||||
// 菜单点击处理
|
|
||||||
const handleMenuClick = ({ key }: { key: string }) => {
|
const handleMenuClick = ({ key }: { key: string }) => {
|
||||||
router.push(key)
|
router.push(key)
|
||||||
}
|
}
|
||||||
@ -95,33 +99,110 @@ const handleMenuClick = ({ key }: { key: string }) => {
|
|||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.sidebar {
|
.sidebar {
|
||||||
width: 200px;
|
width: 240px;
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
|
||||||
overflow-y: auto;
|
padding-top:30px;
|
||||||
|
/* overflow-y: auto; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item-content {
|
.menu-item-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
margin-right: 8px;
|
|
||||||
width: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 修复链接样式 */
|
|
||||||
:deep(.ant-menu-item a) {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.ant-menu-submenu-title) {
|
.icon {
|
||||||
|
margin-right: 12px; /* 增加图标和文字的间距 */
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 16px; /* 图标大小 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-text {
|
||||||
|
font-size: 14px; /* 文字大小 */
|
||||||
|
font-weight: 500; /* 中等字重 */
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu-item {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 32px; /* 子菜单项缩进 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义菜单样式 */
|
||||||
|
:deep(.custom-menu.ant-menu) {
|
||||||
|
font-size: 14px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu.ant-menu-inline) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-item) {
|
||||||
|
height: 48px; /* 增加菜单项高度 */
|
||||||
|
line-height: 48px;
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-item:not(:last-child)) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-submenu-title) {
|
||||||
|
height: 48px; /* 增加子菜单标题高度 */
|
||||||
|
line-height: 48px;
|
||||||
padding-right: 12px !important;
|
padding-right: 12px !important;
|
||||||
|
border-radius: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-submenu .ant-menu-item) {
|
||||||
|
height: 40px; /* 子菜单项稍矮一些 */
|
||||||
|
line-height: 40px;
|
||||||
|
padding-left: 48px !important; /* 子菜单项缩进 */
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-item-selected) {
|
||||||
|
background-color: #e6f7ff; /* 选中背景色 */
|
||||||
|
border-right: 3px solid #1890ff; /* 选中指示条 */
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-item:active),
|
||||||
|
:deep(.custom-menu .ant-menu-submenu-title:active) {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-item a) {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-submenu-arrow) {
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 鼠标悬停效果 */
|
||||||
|
:deep(.custom-menu .ant-menu-item:hover),
|
||||||
|
:deep(.custom-menu .ant-menu-submenu-title:hover) {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.custom-menu .ant-menu-item:hover .icon),
|
||||||
|
:deep(.custom-menu .ant-menu-submenu-title:hover .icon) {
|
||||||
|
color: #1890ff;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
13
src/main.ts
13
src/main.ts
@ -2,19 +2,14 @@
|
|||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import Antd from 'ant-design-vue';
|
|
||||||
|
// 引入 Ant Design Vue 组件
|
||||||
|
import Antd from 'ant-design-vue'
|
||||||
import 'ant-design-vue/dist/reset.css'
|
import 'ant-design-vue/dist/reset.css'
|
||||||
// 引入更多必要的组件
|
|
||||||
// import {
|
|
||||||
// Menu,
|
|
||||||
// MenuItem,
|
|
||||||
// SubMenu
|
|
||||||
// } from 'ant-design-vue'
|
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
// 注册组件
|
|
||||||
app.use(Antd)
|
|
||||||
app.use(router)
|
app.use(router)
|
||||||
|
app.use(Antd) // 全局注册所有 Ant Design 组件
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
@ -3,18 +3,18 @@ import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
|||||||
import Layout from '@/components/Layout.vue'
|
import Layout from '@/components/Layout.vue'
|
||||||
import { Components } from 'ant-design-vue/es/date-picker/generatePicker'
|
import { Components } from 'ant-design-vue/es/date-picker/generatePicker'
|
||||||
|
|
||||||
// 按需导入视图组件
|
|
||||||
const HomeView = () => import('@/views/home/index.vue')
|
const HomeView = () => import('@/views/home/index.vue')
|
||||||
const FileStore = () => import('@/views/controlPanel/fileStore/index.vue')
|
const FileStore = () => import('@/views/controlPanel/fileStore/index.vue')
|
||||||
const Container = () => import('@/views/controlPanel/container/index.vue')
|
// 账号安全
|
||||||
const Image = () => import('@/views/controlPanel/image/index.vue')
|
const AccountSecurity = () => import('@/views/controlPanel/account/security/index.vue')
|
||||||
// 其他视图组件...
|
// 访问记录
|
||||||
|
const AccountHistory = () => import('@/views/controlPanel/account/history/index.vue')
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
component: HomeView // 这个页面独立,不包含侧边栏
|
component: HomeView // 这个页面独立,不使用Layout
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path:'/login',
|
path:'/login',
|
||||||
@ -25,23 +25,40 @@ const routes: RouteRecordRaw[] = [
|
|||||||
path: '/controlPanel',
|
path: '/controlPanel',
|
||||||
component: Layout, // 这个路径下的所有页面都使用 Layout(包含侧边栏)
|
component: Layout, // 这个路径下的所有页面都使用 Layout(包含侧边栏)
|
||||||
redirect: '/controlPanel/fileStore', // 添加重定向到默认子路由
|
redirect: '/controlPanel/fileStore', // 添加重定向到默认子路由
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/fileStore',
|
||||||
|
name: 'FileStore',
|
||||||
|
component: Layout, // 使用Layout包装FileStore
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/controlPanel', // 或者写成 'fileStore'(相对路径)
|
path: '', // 空路径,访问 /fileStore 时显示FileStore组件
|
||||||
name: 'FileStore',
|
name: 'FileStoreContent',
|
||||||
component: FileStore,
|
component: FileStore
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/controlPanel/container',
|
path: '/accountSecurity',
|
||||||
name: 'Container',
|
name: 'AccountSecurity',
|
||||||
component: Container,
|
component: AccountSecurity
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/accountHistory',
|
||||||
|
name: 'AccountHistory',
|
||||||
|
component: AccountHistory
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// 可以继续添加其他使用Layout的路由
|
||||||
|
{
|
||||||
|
path: '/container',
|
||||||
|
name: 'Container',
|
||||||
|
component: Layout,
|
||||||
|
children: [
|
||||||
{
|
{
|
||||||
path: '/controlPanel/image',
|
path: '',
|
||||||
name: 'Image',
|
name: 'ContainerContent',
|
||||||
component: Image,
|
component: () => import('@/views/controlPanel/container/index.vue')
|
||||||
},
|
}
|
||||||
// 可以继续添加其他子路由...
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
116
src/views/controlPanel/account/history/index.vue
Normal file
116
src/views/controlPanel/account/history/index.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<!-- src/components/AccessLog.vue -->
|
||||||
|
<template>
|
||||||
|
<div class="access-log">
|
||||||
|
<div class="title-wrapper">
|
||||||
|
<h3>访问记录</h3>
|
||||||
|
<span class="desc">以下显示内容为账号及其子账号近3个月的登录记录</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="loginRecords"
|
||||||
|
:pagination="false"
|
||||||
|
size="middle"
|
||||||
|
:bordered="true"
|
||||||
|
class="login-table"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
// 定义类型
|
||||||
|
interface LoginRecord {
|
||||||
|
id: number;
|
||||||
|
time: string;
|
||||||
|
ip: string;
|
||||||
|
city: string;
|
||||||
|
type: string;
|
||||||
|
operator: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟数据
|
||||||
|
const loginRecords = ref<LoginRecord[]>([
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
time: '2025-11-21 09:58:38',
|
||||||
|
ip: '183.209.69.36',
|
||||||
|
city: '中国 江苏省',
|
||||||
|
type: 'Web微信登录',
|
||||||
|
operator: '炼丹师5075',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
time: '2025-11-19 17:07:13',
|
||||||
|
ip: '183.209.69.36',
|
||||||
|
city: '中国 江苏省',
|
||||||
|
type: 'Web微信登录',
|
||||||
|
operator: '炼丹师5075',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 表格列配置
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '访问时间',
|
||||||
|
dataIndex: 'time',
|
||||||
|
key: 'time',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '访问IP地址',
|
||||||
|
dataIndex: 'ip',
|
||||||
|
key: 'ip',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '访问城市',
|
||||||
|
dataIndex: 'city',
|
||||||
|
key: 'city',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '登录类型',
|
||||||
|
dataIndex: 'type',
|
||||||
|
key: 'type',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作人',
|
||||||
|
dataIndex: 'operator',
|
||||||
|
key: 'operator',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.access-log {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-wrapper h3 {
|
||||||
|
margin: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
color: #faad14;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-table {
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
203
src/views/controlPanel/account/security/index.vue
Normal file
203
src/views/controlPanel/account/security/index.vue
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<!-- src/components/AccountSecurity.vue -->
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { CheckCircleOutlined, ExclamationCircleOutlined } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
// 定义安全项接口
|
||||||
|
interface SecurityItem {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
status: 'unset' | 'bound' | 'unverified' | 'verified';
|
||||||
|
actionText: string;
|
||||||
|
actionHandler: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const securityItems = ref<SecurityItem[]>([
|
||||||
|
{
|
||||||
|
title: '登录密码',
|
||||||
|
description: '安全性高的密码可以使账号更安全。建议您定期更换密码,设置一个包含字母和数字且长度超过8位的密码',
|
||||||
|
status: 'unset',
|
||||||
|
actionText: '设置',
|
||||||
|
actionHandler: () => alert('跳转到设置密码页面'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '手机绑定',
|
||||||
|
description: '您已绑定了手机178****5075您的手机号可以直接用于登录、找回密码等',
|
||||||
|
status: 'bound',
|
||||||
|
actionText: '修改',
|
||||||
|
actionHandler: () => alert('跳转到修改手机号页面'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '实名认证',
|
||||||
|
description: '实名认证后可以使用AutoDL更完整的功能,如打开实例的自定义服务等',
|
||||||
|
status: 'unverified',
|
||||||
|
actionText: '立即认证',
|
||||||
|
actionHandler: () => alert('跳转到实名认证页面'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '微信绑定',
|
||||||
|
description: '您已绑定微信,可快速扫码登录',
|
||||||
|
status: 'bound',
|
||||||
|
actionText: '解绑',
|
||||||
|
actionHandler: () => alert('确认解绑微信?'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '邮箱绑定',
|
||||||
|
description: '绑定邮箱后可接收系统消息,如余额不足、实例即将到期、实例即将释放等消息',
|
||||||
|
status: 'unset',
|
||||||
|
actionText: '绑定',
|
||||||
|
actionHandler: () => alert('跳转到绑定邮箱页面'),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 根据状态返回对应图标和颜色
|
||||||
|
const getStatusIcon = (status: SecurityItem['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'bound':
|
||||||
|
return CheckCircleOutlined;
|
||||||
|
case 'unverified':
|
||||||
|
case 'unset':
|
||||||
|
return ExclamationCircleOutlined;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusColor = (status: SecurityItem['status']) => {
|
||||||
|
switch (status) {
|
||||||
|
case 'bound':
|
||||||
|
return 'green';
|
||||||
|
case 'unverified':
|
||||||
|
case 'unset':
|
||||||
|
return 'red';
|
||||||
|
default:
|
||||||
|
return 'gray';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getActionColor = (status: SecurityItem['status']) => {
|
||||||
|
if (status === 'bound') {
|
||||||
|
return 'blue';
|
||||||
|
}
|
||||||
|
return 'blue'; // 默认蓝色
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="account-security">
|
||||||
|
<h2>账号安全</h2>
|
||||||
|
<div v-for="(item, index) in securityItems" :key="index" class="security-item">
|
||||||
|
<div class="item-header">
|
||||||
|
<span class="title">{{ item.title }}</span>
|
||||||
|
<div class="status">
|
||||||
|
<component
|
||||||
|
:is="getStatusIcon(item.status)"
|
||||||
|
v-if="getStatusIcon(item.status)"
|
||||||
|
:class="['icon', `color-${getStatusColor(item.status)}`]"
|
||||||
|
/>
|
||||||
|
<span :class="['text', `color-${getStatusColor(item.status)}`]">
|
||||||
|
{{ item.status === 'bound' ? '已绑定' : item.status === 'unverified' ? '未认证' : '未设置' }}
|
||||||
|
</span>
|
||||||
|
<span class="divider">|</span>
|
||||||
|
<button
|
||||||
|
class="action-btn"
|
||||||
|
:class="`color-${getActionColor(item.status)}`"
|
||||||
|
@click="item.actionHandler"
|
||||||
|
>
|
||||||
|
{{ item.actionText }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="description">{{ item.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.account-security {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-security h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #333;
|
||||||
|
font-size: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.security-item {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider {
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
color: #0066cc;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0;
|
||||||
|
margin-left: 8px;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-green {
|
||||||
|
color: #52c41a !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-red {
|
||||||
|
color: #ff4d4f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-blue {
|
||||||
|
color: #0066cc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
color: #666;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,15 +1,255 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div style="padding: 20px;">
|
<div class="container">
|
||||||
<h1>📁 File Store</h1>
|
<!-- 标题 -->
|
||||||
<p>这里只有文件存储的内容,没有 logo,没有 HelloWorld!</p>
|
<div class="header">
|
||||||
|
<h1>文件存储</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 区域选择 -->
|
||||||
|
<div class="region-section">
|
||||||
|
<h2 class="section-title">选择存储区域</h2>
|
||||||
|
<div class="region-tabs">
|
||||||
|
<button
|
||||||
|
v-for="region in regions"
|
||||||
|
:key="region.id"
|
||||||
|
:class="['region-tab', { active: selectedRegion === region.id }]"
|
||||||
|
@click="selectRegion(region.id)"
|
||||||
|
>
|
||||||
|
{{ region.name }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 中心图标 -->
|
||||||
|
<div class="center-section">
|
||||||
|
<div class="center-icon">
|
||||||
|
<i class="icon-book"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 主要操作按钮 -->
|
||||||
|
<div class="action-section">
|
||||||
|
<button class="btn-primary" @click="initializeStorage">
|
||||||
|
初始化文件存储
|
||||||
|
</button>
|
||||||
|
<p class="action-hint">将在 {{ getSelectedRegionName() }} 创建存储空间</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部帮助链接 -->
|
||||||
|
<div class="help-section">
|
||||||
|
<div class="help-links">
|
||||||
|
<a href="#" class="link" @click.prevent="viewHelp">文件存储使用介绍</a>
|
||||||
|
<a href="#" class="link" @click.prevent="viewPricing">查看计费规则</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
</style>
|
// 定义区域选项
|
||||||
|
interface Region {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const regions = [
|
||||||
|
{ id: 'a100', name: 'A100专区' },
|
||||||
|
{ id: 'v100', name: 'V100专区' },
|
||||||
|
{ id: 'foshan', name: '佛山区' },
|
||||||
|
{ id: 'beijing', name: '北京B区' }
|
||||||
|
]
|
||||||
|
|
||||||
|
const selectedRegion = ref('a100') // 默认选中 A100
|
||||||
|
|
||||||
|
// 方法:获取选中区域名称
|
||||||
|
const getSelectedRegionName = () => {
|
||||||
|
const region = regions.find(r => r.id === selectedRegion.value)
|
||||||
|
return region ? region.name : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法:选择区域
|
||||||
|
const selectRegion = (id: string) => {
|
||||||
|
selectedRegion.value = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法:初始化存储
|
||||||
|
const initializeStorage = () => {
|
||||||
|
alert(`正在初始化 ${selectedRegion.value} 的文件存储...`)
|
||||||
|
// 这里可以跳转到下一步流程
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法:查看帮助
|
||||||
|
const viewHelp = () => {
|
||||||
|
alert('文件存储使用介绍')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 方法:查看计费规则
|
||||||
|
const viewPricing = () => {
|
||||||
|
alert('计费规则详情')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.container {
|
||||||
|
/* max-width: 800px;
|
||||||
|
margin: 0 auto; */
|
||||||
|
padding: 40px 30px;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 标题区域 */
|
||||||
|
.header {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 区域选择 */
|
||||||
|
.region-section {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #555;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tab {
|
||||||
|
padding: 12px 24px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
background: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
font-size: 14px;
|
||||||
|
min-width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tab:hover {
|
||||||
|
border-color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tab.active {
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
border-color: #3498db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 中心图标区域 */
|
||||||
|
.center-section {
|
||||||
|
margin: 40px 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-icon {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-book {
|
||||||
|
font-size: 36px;
|
||||||
|
color: #3498db;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-book::before {
|
||||||
|
content: "📁";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 操作区域 */
|
||||||
|
.action-section {
|
||||||
|
margin: 40px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 14px 32px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-hint {
|
||||||
|
margin-top: 12px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 帮助区域 */
|
||||||
|
.help-section {
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-links {
|
||||||
|
display: flex;
|
||||||
|
gap: 30px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #3498db;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link:hover {
|
||||||
|
color: #2980b9;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 30px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tabs {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.region-tab {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-links {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-section {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,22 +1,13 @@
|
|||||||
<!-- src/views/HomeView.vue -->
|
<!-- src/views/home/index.vue -->
|
||||||
<script setup lang="ts">
|
|
||||||
// import HelloWorld from '@/components/HelloWorld.vue'
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div >
|
||||||
|
<h1>首页 - 独立页面</h1>
|
||||||
|
<p>这个页面没有侧边栏</p>
|
||||||
<div class="links">
|
<router-link to="/fileStore" style="color: blue; text-decoration: underline;">
|
||||||
<router-link to="/controlPanel/fileStore">File Store</router-link>
|
点击进入文件存储(有侧边栏)
|
||||||
</div>
|
</router-link>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<script setup>
|
||||||
.logo { height: 6em; padding: 1.5em; }
|
</script>
|
||||||
.logo:hover { filter: drop-shadow(0 0 2em #646cffaa); }
|
|
||||||
.logo.vue:hover { filter: drop-shadow(0 0 2em #42b883aa); }
|
|
||||||
</style>
|
|
||||||
Loading…
x
Reference in New Issue
Block a user