初始化
This commit is contained in:
parent
e8059153d7
commit
ed5bf8a245
1239
package-lock.json
generated
Normal file
1239
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^3.2.41"
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"vue": "^3.2.41",
|
||||
"vue-router": "^4.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^3.2.0",
|
||||
@ -17,4 +19,4 @@
|
||||
"vite": "^3.2.3",
|
||||
"vue-tsc": "^1.0.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
src/App.vue
38
src/App.vue
@ -1,31 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
// This starter template is using Vue 3 <script setup> SFCs
|
||||
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
</script>
|
||||
|
||||
<!-- src/App.vue -->
|
||||
<template>
|
||||
<div>
|
||||
<a href="https://vitejs.dev" target="_blank">
|
||||
<img src="/vite.svg" class="logo" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://vuejs.org/" target="_blank">
|
||||
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
|
||||
</a>
|
||||
</div>
|
||||
<HelloWorld msg="Vite + Vue" />
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
<style>
|
||||
/* 全局重置 */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
html, body, #app {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.logo.vue:hover {
|
||||
filter: drop-shadow(0 0 2em #42b883aa);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
51
src/components/layout.vue
Normal file
51
src/components/layout.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<!-- src/components/Layout.vue -->
|
||||
|
||||
|
||||
<template>
|
||||
<div class="layout">
|
||||
<div class="sidebar-container">
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div class="main-content">
|
||||
<div class="content">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import Sidebar from './sidebar.vue'
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.layout {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
width: 200px;
|
||||
flex-shrink: 0;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
min-height: calc(100vh - 40px);
|
||||
}
|
||||
</style>
|
||||
127
src/components/sidebar.vue
Normal file
127
src/components/sidebar.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<!-- src/components/Sidebar.vue -->
|
||||
<template>
|
||||
<div class="sidebar">
|
||||
<a-menu
|
||||
mode="inline"
|
||||
:selected-keys="selectedKeys"
|
||||
:open-keys="openKeys"
|
||||
@click="handleMenuClick"
|
||||
theme="light"
|
||||
>
|
||||
<template v-for="item in menuItems" :key="item.path">
|
||||
<!-- 有子菜单的项 -->
|
||||
<a-sub-menu v-if="item.children && item.children.length" :key="item.path">
|
||||
<template #title>
|
||||
<span class="menu-item-content">
|
||||
<span class="icon">{{ item.icon }}</span>
|
||||
<span>{{ item.name }}</span>
|
||||
</span>
|
||||
</template>
|
||||
<a-menu-item v-for="child in item.children" :key="child.path">
|
||||
<router-link :to="child.path">{{ child.name }}</router-link>
|
||||
</a-menu-item>
|
||||
</a-sub-menu>
|
||||
|
||||
<!-- 没有子菜单的项 -->
|
||||
<a-menu-item v-else :key="item.path">
|
||||
<router-link :to="item.path" class="menu-item-content">
|
||||
<span class="icon">{{ item.icon }}</span>
|
||||
<span>{{ item.name }}</span>
|
||||
</router-link>
|
||||
</a-menu-item>
|
||||
</template>
|
||||
</a-menu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
interface MenuItem {
|
||||
path: string
|
||||
name: string
|
||||
icon: string
|
||||
children?: { path: string; name: string }[]
|
||||
}
|
||||
|
||||
// 重要:路径要与路由配置匹配,使用 /controlPanel 前缀
|
||||
const menuItems: MenuItem[] = [
|
||||
{ path: '/controlPanel/fileStore', name: '文件存储', icon: '💾' },
|
||||
{ path: '/controlPanel/container', name: '容器实例', icon: '🐳' },
|
||||
{ path: '/controlPanel/image', name: '镜像', icon: '🖼️' },
|
||||
{ path: '/controlPanel/publicData', name: '公开数据', icon: '📚' },
|
||||
{
|
||||
path: '/controlPanel/fee',
|
||||
name: '费用',
|
||||
icon: '💰',
|
||||
children: [
|
||||
{ path: '/controlPanel/fee/detail', name: '详情' },
|
||||
{ path: '/controlPanel/fee/bill', name: '账单' }
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/controlPanel/account',
|
||||
name: '账号',
|
||||
icon: '👤',
|
||||
children: [
|
||||
{ path: '/controlPanel/account/profile', name: '个人资料' },
|
||||
{ path: '/controlPanel/account/security', name: '安全设置' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 选中的菜单项
|
||||
const selectedKeys = computed(() => {
|
||||
return [route.path]
|
||||
})
|
||||
|
||||
// 展开的菜单项
|
||||
const openKeys = computed(() => {
|
||||
const keys: string[] = []
|
||||
if (route.path.startsWith('/controlPanel/fee')) keys.push('/controlPanel/fee')
|
||||
if (route.path.startsWith('/controlPanel/account')) keys.push('/controlPanel/account')
|
||||
return keys
|
||||
})
|
||||
|
||||
// 菜单点击处理
|
||||
const handleMenuClick = ({ key }: { key: string }) => {
|
||||
router.push(key)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.sidebar {
|
||||
width: 200px;
|
||||
height: 100vh;
|
||||
background: #fff;
|
||||
box-shadow: 2px 0 4px rgba(0, 0, 0, 0.1);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.menu-item-content {
|
||||
display: flex;
|
||||
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%;
|
||||
}
|
||||
|
||||
:deep(.ant-menu-submenu-title) {
|
||||
padding-right: 12px !important;
|
||||
}
|
||||
</style>
|
||||
21
src/main.ts
21
src/main.ts
@ -1,5 +1,22 @@
|
||||
// src/main.ts
|
||||
import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
import 'ant-design-vue/dist/reset.css'
|
||||
// 引入更多必要的组件
|
||||
import {
|
||||
Menu,
|
||||
MenuItem,
|
||||
SubMenu
|
||||
} from 'ant-design-vue'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
// 注册组件
|
||||
app.use(Menu)
|
||||
app.use(MenuItem)
|
||||
app.use(SubMenu)
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
48
src/router/index.ts
Normal file
48
src/router/index.ts
Normal file
@ -0,0 +1,48 @@
|
||||
// src/router/index.ts
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
||||
import Layout from '@/components/Layout.vue'
|
||||
|
||||
// 按需导入视图组件
|
||||
const HomeView = () => import('@/views/home/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 routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'Home',
|
||||
component: HomeView // 这个页面独立,不包含侧边栏
|
||||
},
|
||||
{
|
||||
path: '/controlPanel',
|
||||
component: Layout, // 这个路径下的所有页面都使用 Layout(包含侧边栏)
|
||||
redirect: '/controlPanel/fileStore', // 添加重定向到默认子路由
|
||||
children: [
|
||||
{
|
||||
path: '/controlPanel', // 或者写成 'fileStore'(相对路径)
|
||||
name: 'FileStore',
|
||||
component: FileStore,
|
||||
},
|
||||
{
|
||||
path: '/controlPanel/container',
|
||||
name: 'Container',
|
||||
component: Container,
|
||||
},
|
||||
{
|
||||
path: '/controlPanel/image',
|
||||
name: 'Image',
|
||||
component: Image,
|
||||
},
|
||||
// 可以继续添加其他子路由...
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes
|
||||
})
|
||||
|
||||
export default router
|
||||
15
src/views/controlPanel/fileStore/index.vue
Normal file
15
src/views/controlPanel/fileStore/index.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div style="padding: 20px;">
|
||||
<h1>📁 File Store</h1>
|
||||
<p>这里只有文件存储的内容,没有 logo,没有 HelloWorld!</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
22
src/views/home/index.vue
Normal file
22
src/views/home/index.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<!-- src/views/HomeView.vue -->
|
||||
<script setup lang="ts">
|
||||
// import HelloWorld from '@/components/HelloWorld.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
|
||||
|
||||
<div class="links">
|
||||
<router-link to="/controlPanel/fileStore">File Store</router-link>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.logo { height: 6em; padding: 1.5em; }
|
||||
.logo:hover { filter: drop-shadow(0 0 2em #646cffaa); }
|
||||
.logo.vue:hover { filter: drop-shadow(0 0 2em #42b883aa); }
|
||||
</style>
|
||||
@ -1,7 +1,13 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'node:path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()]
|
||||
})
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src')
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user