初始化

This commit is contained in:
qiuyuan 2025-11-20 14:32:03 +08:00
parent e8059153d7
commit ed5bf8a245
10 changed files with 1545 additions and 32 deletions

1239
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}
}

View File

@ -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
View 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
View 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>

View File

@ -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
View 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

View 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
View 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>

View File

@ -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')
}
}
})