398 lines
9.8 KiB
Vue
398 lines
9.8 KiB
Vue
<template>
|
|
<a-layout class="teacher-layout" :class="{ 'is-collapsed': collapsed }">
|
|
<a-layout-sider
|
|
v-model:collapsed="collapsed"
|
|
:trigger="null"
|
|
collapsible
|
|
class="teacher-sider"
|
|
:width="240"
|
|
:collapsed-width="80"
|
|
>
|
|
<div class="logo">
|
|
<img src="/logo.png" alt="Logo" class="logo-img" />
|
|
<div v-if="!collapsed" class="logo-text">
|
|
<span class="logo-tenant">{{ tenantName }}</span>
|
|
<span class="logo-title">少儿智慧阅读</span>
|
|
<span class="logo-subtitle">服务平台</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sider-scroll">
|
|
<a-menu
|
|
v-model:selectedKeys="selectedKeys"
|
|
mode="inline"
|
|
theme="light"
|
|
:inline-collapsed="collapsed"
|
|
@click="handleMenuClick"
|
|
class="side-menu"
|
|
>
|
|
<a-menu-item key="dashboard">
|
|
<template #icon><HomeOutlined /></template>
|
|
<span>首页</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="classes">
|
|
<template #icon><TeamOutlined /></template>
|
|
<span>我的班级</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="courses">
|
|
<template #icon><BookOutlined /></template>
|
|
<span>课程中心</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="school-courses">
|
|
<template #icon><FolderAddOutlined /></template>
|
|
<span>校本课程包</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="lessons">
|
|
<template #icon><CalendarOutlined /></template>
|
|
<span>上课记录</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="schedule">
|
|
<template #icon><ScheduleOutlined /></template>
|
|
<span>我的课表</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="tasks">
|
|
<template #icon><CheckSquareOutlined /></template>
|
|
<span>阅读任务</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="feedback">
|
|
<template #icon><FileTextOutlined /></template>
|
|
<span>课程反馈</span>
|
|
</a-menu-item>
|
|
<a-menu-item key="growth">
|
|
<template #icon><CameraOutlined /></template>
|
|
<span>成长档案</span>
|
|
</a-menu-item>
|
|
</a-menu>
|
|
</div>
|
|
</a-layout-sider>
|
|
|
|
<a-layout class="teacher-main">
|
|
<a-layout-header class="teacher-header">
|
|
<div class="header-left">
|
|
<MenuUnfoldOutlined
|
|
v-if="collapsed"
|
|
class="trigger"
|
|
@click="collapsed = !collapsed"
|
|
/>
|
|
<MenuFoldOutlined
|
|
v-else
|
|
class="trigger"
|
|
@click="collapsed = !collapsed"
|
|
/>
|
|
</div>
|
|
|
|
<div class="header-right">
|
|
<a-space>
|
|
<a-badge :count="notifications">
|
|
<BellOutlined style="font-size: 18px; cursor: pointer; color: #666;" />
|
|
</a-badge>
|
|
|
|
<a-dropdown>
|
|
<a-space class="user-info" style="cursor: pointer;">
|
|
<a-avatar :size="32" class="user-avatar">
|
|
<template #icon><UserOutlined /></template>
|
|
</a-avatar>
|
|
<span class="user-name">{{ userName }}</span>
|
|
<DownOutlined />
|
|
</a-space>
|
|
<template #overlay>
|
|
<a-menu @click="handleUserMenuClick">
|
|
<a-menu-item key="profile">
|
|
<UserOutlined />
|
|
个人信息
|
|
</a-menu-item>
|
|
<a-menu-divider />
|
|
<a-menu-item key="logout">
|
|
<LogoutOutlined />
|
|
退出登录
|
|
</a-menu-item>
|
|
</a-menu>
|
|
</template>
|
|
</a-dropdown>
|
|
</a-space>
|
|
</div>
|
|
</a-layout-header>
|
|
|
|
<a-layout-content class="teacher-content">
|
|
<router-view />
|
|
</a-layout-content>
|
|
</a-layout>
|
|
</a-layout>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, watch } from 'vue';
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
import { message } from 'ant-design-vue';
|
|
import {
|
|
HomeOutlined,
|
|
TeamOutlined,
|
|
BookOutlined,
|
|
CalendarOutlined,
|
|
FileTextOutlined,
|
|
MenuUnfoldOutlined,
|
|
MenuFoldOutlined,
|
|
BellOutlined,
|
|
UserOutlined,
|
|
LogoutOutlined,
|
|
DownOutlined,
|
|
CheckSquareOutlined,
|
|
ScheduleOutlined,
|
|
CameraOutlined,
|
|
FolderAddOutlined,
|
|
} from '@ant-design/icons-vue';
|
|
import { useUserStore } from '@/stores/user';
|
|
|
|
const router = useRouter();
|
|
const route = useRoute();
|
|
const userStore = useUserStore();
|
|
|
|
const collapsed = ref(false);
|
|
const selectedKeys = ref(['dashboard']);
|
|
const notifications = ref(0);
|
|
|
|
const userName = computed(() => userStore.user?.name || '教师');
|
|
const tenantName = computed(() => userStore.user?.tenantName || '');
|
|
|
|
// 根据路由设置选中的菜单
|
|
watch(
|
|
() => route.path,
|
|
(path) => {
|
|
if (path.startsWith('/teacher/classes')) {
|
|
selectedKeys.value = ['classes'];
|
|
} else if (path.startsWith('/teacher/courses')) {
|
|
selectedKeys.value = ['courses'];
|
|
} else if (path.startsWith('/teacher/school-courses')) {
|
|
selectedKeys.value = ['school-courses'];
|
|
} else if (path.startsWith('/teacher/lessons')) {
|
|
selectedKeys.value = ['lessons'];
|
|
} else if (path.startsWith('/teacher/schedule')) {
|
|
selectedKeys.value = ['schedule'];
|
|
} else if (path.startsWith('/teacher/tasks')) {
|
|
selectedKeys.value = ['tasks'];
|
|
} else if (path.startsWith('/teacher/feedback')) {
|
|
selectedKeys.value = ['feedback'];
|
|
} else if (path.startsWith('/teacher/growth')) {
|
|
selectedKeys.value = ['growth'];
|
|
} else {
|
|
selectedKeys.value = ['dashboard'];
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
const handleMenuClick = ({ key }: { key: string | number }) => {
|
|
router.push(`/teacher/${key}`);
|
|
};
|
|
|
|
const handleUserMenuClick = ({ key }: { key: string | number }) => {
|
|
const keyStr = String(key);
|
|
if (keyStr === 'logout') {
|
|
userStore.logout();
|
|
message.success('退出成功');
|
|
router.push('/login');
|
|
} else if (keyStr === 'profile') {
|
|
// 跳转到个人信息页面
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
// 少儿阅读主题配色
|
|
$primary-color: #FF8C42; // 温暖的橙色
|
|
$primary-light: #FFF4EC;
|
|
$primary-dark: #E67635;
|
|
$accent-color: #4CAF50; // 生机绿色
|
|
$text-color: #333333;
|
|
$text-secondary: #666666;
|
|
$border-color: #E8E8E8;
|
|
$bg-light: #FAFAFA;
|
|
|
|
$sider-width: 240px;
|
|
$sider-collapsed-width: 80px;
|
|
$header-height: 64px;
|
|
|
|
.teacher-layout {
|
|
min-height: 100vh;
|
|
background: $bg-light;
|
|
}
|
|
|
|
.teacher-sider {
|
|
background: white !important;
|
|
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.06);
|
|
border-right: 1px solid $border-color;
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
bottom: 0;
|
|
z-index: 100;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
:deep(.ant-layout-sider-children) {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
}
|
|
|
|
.logo {
|
|
height: 80px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 12px 16px;
|
|
border-bottom: 1px solid $border-color;
|
|
background: linear-gradient(135deg, $primary-light 0%, white 100%);
|
|
|
|
.logo-img {
|
|
width: 44px;
|
|
height: 44px;
|
|
object-fit: contain;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.logo-text {
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-left: 12px;
|
|
line-height: 1.4;
|
|
max-width: 140px;
|
|
|
|
.logo-tenant {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: $primary-color;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.logo-title {
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
color: $text-color;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.logo-subtitle {
|
|
font-size: 11px;
|
|
color: $text-secondary;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
}
|
|
|
|
.sider-scroll {
|
|
flex: 1 1 auto;
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
.side-menu {
|
|
border-right: none !important;
|
|
padding: 8px 12px;
|
|
|
|
:deep(.ant-menu-item) {
|
|
margin: 4px 0;
|
|
padding-left: 12px !important;
|
|
padding-right: 12px !important;
|
|
border-radius: 8px;
|
|
height: 44px;
|
|
line-height: 44px;
|
|
color: $text-color;
|
|
transition: all 0.3s;
|
|
display: flex;
|
|
align-items: center;
|
|
|
|
.ant-menu-title-content {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
&:hover {
|
|
background: $primary-light;
|
|
color: $primary-color;
|
|
}
|
|
|
|
&.ant-menu-item-selected {
|
|
background: linear-gradient(135deg, $primary-color 0%, $primary-dark 100%);
|
|
color: white;
|
|
|
|
&::after {
|
|
display: none;
|
|
}
|
|
|
|
.anticon {
|
|
color: white;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.teacher-main {
|
|
margin-left: $sider-width;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.teacher-header {
|
|
background: white;
|
|
padding: 0 24px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
|
border-bottom: 1px solid $border-color;
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
left: $sider-width;
|
|
height: $header-height;
|
|
z-index: 90;
|
|
|
|
.trigger {
|
|
font-size: 18px;
|
|
cursor: pointer;
|
|
transition: color 0.3s;
|
|
color: $text-secondary;
|
|
|
|
&:hover {
|
|
color: $primary-color;
|
|
}
|
|
}
|
|
|
|
.user-info {
|
|
padding: 0 12px;
|
|
}
|
|
|
|
.user-avatar {
|
|
background: linear-gradient(135deg, $primary-color 0%, $primary-dark 100%);
|
|
}
|
|
|
|
.user-name {
|
|
color: $text-color;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
|
|
.teacher-content {
|
|
margin: 20px;
|
|
margin-top: calc(#{$header-height} + 20px);
|
|
padding: 24px;
|
|
background: white;
|
|
border-radius: 12px;
|
|
min-height: calc(100vh - #{$header-height} - 40px);
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
|
}
|
|
|
|
.teacher-layout.is-collapsed {
|
|
.teacher-main {
|
|
margin-left: $sider-collapsed-width;
|
|
}
|
|
|
|
.teacher-header {
|
|
left: $sider-collapsed-width;
|
|
}
|
|
}
|
|
</style>
|