- 前后端分离架构 (Nuxt 3 + Element Plus) - SQLite 数据库 (better-sqlite3) - 比赛项目管理 (田赛/径赛/团体赛) - 队伍管理 (5 个组别) - 成绩录入与积分统计 - 记分板展示 (排名/奖牌榜) - 移动端响应式适配 - 侧边栏布局 + 抽屉菜单 - 自动生成初始化数据接口
223 lines
4.0 KiB
Vue
223 lines
4.0 KiB
Vue
<template>
|
|
<el-container class="layout-container">
|
|
<el-aside width="200px" class="sidebar desktop-only">
|
|
<div class="logo">
|
|
<h2>运动会记分板</h2>
|
|
</div>
|
|
<el-menu
|
|
:default-active="activeMenu"
|
|
class="sidebar-menu"
|
|
>
|
|
<el-menu-item
|
|
v-for="item in menuItems"
|
|
:key="item.path"
|
|
:index="item.path"
|
|
@click="onMenuClick(item.path)"
|
|
>
|
|
<el-icon><component :is="item.icon" /></el-icon>
|
|
<span>{{ item.label }}</span>
|
|
</el-menu-item>
|
|
</el-menu>
|
|
</el-aside>
|
|
<el-container>
|
|
<el-header class="header">
|
|
<div class="header-left">
|
|
<el-button class="mobile-only-btn" text @click="drawerOpen = true">
|
|
<el-icon><Menu /></el-icon>
|
|
</el-button>
|
|
<h3>运动会管理系统</h3>
|
|
</div>
|
|
</el-header>
|
|
<el-main class="main-content">
|
|
<slot />
|
|
</el-main>
|
|
<el-footer class="footer">
|
|
<p>© 2026 运动会记分板系统 - 版权所有</p>
|
|
</el-footer>
|
|
</el-container>
|
|
</el-container>
|
|
|
|
<el-drawer
|
|
v-model="drawerOpen"
|
|
direction="ltr"
|
|
size="70%"
|
|
:with-header="false"
|
|
class="mobile-only"
|
|
>
|
|
<div class="drawer-logo">
|
|
<h2>运动会记分板</h2>
|
|
</div>
|
|
<el-menu
|
|
:default-active="activeMenu"
|
|
class="drawer-menu"
|
|
>
|
|
<el-menu-item
|
|
v-for="item in menuItems"
|
|
:key="item.path"
|
|
:index="item.path"
|
|
@click="onMenuClick(item.path, true)"
|
|
>
|
|
<el-icon><component :is="item.icon" /></el-icon>
|
|
<span>{{ item.label }}</span>
|
|
</el-menu-item>
|
|
</el-menu>
|
|
</el-drawer>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { HomeFilled, Trophy, UserFilled, Edit, DataLine, Menu } from '@element-plus/icons-vue'
|
|
|
|
const route = useRoute()
|
|
const activeMenu = computed(() => route.path)
|
|
const drawerOpen = ref(false)
|
|
|
|
const menuItems = [
|
|
{ path: '/', label: '首页', icon: HomeFilled },
|
|
{ path: '/events', label: '比赛项目', icon: Trophy },
|
|
{ path: '/teams', label: '队伍管理', icon: UserFilled },
|
|
{ path: '/results', label: '成绩录入', icon: Edit },
|
|
{ path: '/scoreboard', label: '记分板', icon: DataLine }
|
|
]
|
|
|
|
const onMenuClick = (path: string, closeDrawer = false) => {
|
|
navigateTo(path)
|
|
if (closeDrawer) {
|
|
drawerOpen.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.layout-container {
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.sidebar {
|
|
background-color: #304156;
|
|
color: #fff;
|
|
}
|
|
|
|
.logo {
|
|
height: 60px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #2b3a4a;
|
|
}
|
|
|
|
.logo h2 {
|
|
color: #fff;
|
|
font-size: 18px;
|
|
margin: 0;
|
|
}
|
|
|
|
.sidebar-menu {
|
|
border-right: none;
|
|
background-color: #304156;
|
|
}
|
|
|
|
.sidebar-menu .el-menu-item {
|
|
color: #bfcbd9;
|
|
}
|
|
|
|
.sidebar-menu .el-menu-item:hover,
|
|
.sidebar-menu .el-menu-item.is-active {
|
|
background-color: #263445;
|
|
color: #409eff;
|
|
}
|
|
|
|
.header {
|
|
background-color: #fff;
|
|
border-bottom: 1px solid #e6e6e6;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 20px;
|
|
height: 56px;
|
|
}
|
|
|
|
.header-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.header h3 {
|
|
margin: 0;
|
|
color: #303133;
|
|
}
|
|
|
|
.main-content {
|
|
background-color: #f0f2f5;
|
|
padding: 20px;
|
|
}
|
|
|
|
.drawer-logo {
|
|
height: 56px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #2b3a4a;
|
|
color: #fff;
|
|
}
|
|
|
|
.drawer-logo h2 {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
color: #fff;
|
|
}
|
|
|
|
.drawer-menu {
|
|
border-right: none;
|
|
}
|
|
|
|
.desktop-only {
|
|
display: block;
|
|
}
|
|
|
|
.mobile-only {
|
|
display: none;
|
|
}
|
|
|
|
.mobile-only-btn {
|
|
display: none;
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
.desktop-only {
|
|
display: none;
|
|
}
|
|
|
|
.mobile-only {
|
|
display: block;
|
|
}
|
|
|
|
.mobile-only-btn {
|
|
display: inline-flex;
|
|
}
|
|
|
|
.header {
|
|
padding: 0 12px;
|
|
}
|
|
|
|
.main-content {
|
|
padding: 12px;
|
|
}
|
|
}
|
|
|
|
.footer {
|
|
background-color: #fff;
|
|
border-top: 1px solid #e6e6e6;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 40px;
|
|
padding: 0;
|
|
}
|
|
|
|
.footer p {
|
|
margin: 0;
|
|
color: #909399;
|
|
font-size: 12px;
|
|
}
|
|
</style>
|