237 lines
8.4 KiB
Vue
Executable File
237 lines
8.4 KiB
Vue
Executable File
<script setup>
|
|
import {inject, reactive, ref} from "vue";
|
|
import {
|
|
Bell,
|
|
ChatDotSquare, Check, Collection, DataLine,
|
|
Document, Files,
|
|
Location, Lock, Monitor,
|
|
Notification, Operation,
|
|
Position,
|
|
School, Search,
|
|
Umbrella, User
|
|
} from "@element-plus/icons-vue";
|
|
import LightCard from "@/components/LightCard.vue";
|
|
import UserInfo from "@/components/UserInfo.vue";
|
|
import {apiNotificationDelete, apiNotificationDeleteAll, apiNotificationList} from "@/net/api/user";
|
|
|
|
const userMenu = [
|
|
{
|
|
title: '校园论坛', icon: Location, sub: [
|
|
{ title: '帖子广场', icon: ChatDotSquare, index: '/index' },
|
|
{ title: '失物招领', icon: Bell },
|
|
{ title: '校园活动', icon: Notification },
|
|
{ title: '表白墙', icon: Umbrella },
|
|
{ title: '海文考研', icon: School }
|
|
]
|
|
}, {
|
|
title: '探索与发现', icon: Position, sub: [
|
|
{ title: '成绩查询', icon: Document },
|
|
{ title: '班级课程表', icon: Files },
|
|
{ title: '教务通知', icon: Monitor },
|
|
{ title: '在线图书馆', icon: Collection },
|
|
{ title: '预约教室', icon: DataLine }
|
|
]
|
|
}, {
|
|
title: '个人设置', icon: Operation, sub: [
|
|
{ title: '个人信息设置', icon: User, index: '/index/user-setting' },
|
|
{ title: '账号安全设置', icon: Lock, index: '/index/privacy-setting' }
|
|
]
|
|
}
|
|
]
|
|
|
|
const loading = inject('userLoading')
|
|
|
|
const searchInput = reactive({
|
|
type: '1',
|
|
text: ''
|
|
})
|
|
const notification = ref([])
|
|
|
|
const loadNotification =
|
|
() => apiNotificationList(data => notification.value = data)
|
|
loadNotification()
|
|
|
|
function confirmNotification(id, url) {
|
|
apiNotificationDelete(id, () => {
|
|
loadNotification()
|
|
window.open(url)
|
|
})
|
|
}
|
|
|
|
function deleteAllNotification() {
|
|
apiNotificationDeleteAll(loadNotification)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="main-content" v-loading="loading" element-loading-text="正在进入,请稍后...">
|
|
<el-container style="height: 100%" v-if="!loading">
|
|
<el-header class="main-content-header">
|
|
<div style="width: 320px;height: 32px">
|
|
<el-image class="logo" src="https://element-plus.org/images/element-plus-logo.svg"/>
|
|
</div>
|
|
<div style="flex: 1;padding: 0 20px;text-align: center">
|
|
<el-input v-model="searchInput.text" style="width: 100%;max-width: 500px"
|
|
placeholder="搜索论坛相关内容...">
|
|
<template #prefix>
|
|
<el-icon>
|
|
<Search/>
|
|
</el-icon>
|
|
</template>
|
|
<template #append>
|
|
<el-select style="width: 120px" v-model="searchInput.type">
|
|
<el-option value="1" label="帖子广场"/>
|
|
<el-option value="2" label="校园活动"/>
|
|
<el-option value="3" label="表白墙"/>
|
|
<el-option value="4" label="教务通知"/>
|
|
</el-select>
|
|
</template>
|
|
</el-input>
|
|
</div>
|
|
<user-info>
|
|
<el-popover placement="bottom" :width="350" trigger="click">
|
|
<template #reference>
|
|
<el-badge is-dot :hidden="!notification.length">
|
|
<div class="notification">
|
|
<el-icon><Bell/></el-icon>
|
|
<div style="font-size: 10px">消息</div>
|
|
</div>
|
|
</el-badge>
|
|
</template>
|
|
<el-empty :image-size="80" description="暂时没有未读消息哦~" v-if="!notification.length"/>
|
|
<el-scrollbar :max-height="500" v-else>
|
|
<light-card v-for="item in notification" class="notification-item"
|
|
@click="confirmNotification(item.id, item.url)">
|
|
<div>
|
|
<el-tag size="small" :type="item.type">消息</el-tag>
|
|
<span style="font-weight: bold">{{item.title}}</span>
|
|
</div>
|
|
<el-divider style="margin: 7px 0 3px 0"/>
|
|
<div style="font-size: 13px;color: grey">
|
|
{{item.content}}
|
|
</div>
|
|
</light-card>
|
|
</el-scrollbar>
|
|
<div style="margin-top: 10px">
|
|
<el-button size="small" type="info" :icon="Check" @click="deleteAllNotification"
|
|
style="width: 100%" plain>清除全部未读消息</el-button>
|
|
</div>
|
|
</el-popover>
|
|
</user-info>
|
|
</el-header>
|
|
<el-container>
|
|
<el-aside width="230px">
|
|
<el-scrollbar style="height: calc(100vh - 55px)">
|
|
<el-menu
|
|
router
|
|
:default-active="$route.path"
|
|
:default-openeds="['1', '2', '3']"
|
|
style="min-height: calc(100vh - 55px)">
|
|
<el-sub-menu :index="(index + 1).toString()"
|
|
v-for="(menu, index) in userMenu">
|
|
<template #title>
|
|
<el-icon>
|
|
<component :is="menu.icon"/>
|
|
</el-icon>
|
|
<span><b>{{ menu.title }}</b></span>
|
|
</template>
|
|
<el-menu-item :index="subMenu.index" v-for="subMenu in menu.sub">
|
|
<template #title>
|
|
<el-icon>
|
|
<component :is="subMenu.icon"/>
|
|
</el-icon>
|
|
{{ subMenu.title }}
|
|
</template>
|
|
</el-menu-item>
|
|
</el-sub-menu>
|
|
</el-menu>
|
|
</el-scrollbar>
|
|
</el-aside>
|
|
<el-main class="main-content-page">
|
|
<el-scrollbar style="height: calc(100vh - 55px)">
|
|
<router-view v-slot="{ Component }">
|
|
<transition name="el-fade-in-linear" mode="out-in">
|
|
<component :is="Component" style="height: 100%"/>
|
|
</transition>
|
|
</router-view>
|
|
</el-scrollbar>
|
|
</el-main>
|
|
</el-container>
|
|
</el-container>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.notification-item {
|
|
transition: .3s;
|
|
&:hover {
|
|
cursor: pointer;
|
|
opacity: 0.7;
|
|
}
|
|
}
|
|
|
|
.notification {
|
|
font-size: 22px;
|
|
line-height: 14px;
|
|
text-align: center;
|
|
transition: color .3s;
|
|
|
|
&:hover {
|
|
color: grey;
|
|
cursor: pointer;
|
|
}
|
|
}
|
|
|
|
.main-content-page {
|
|
padding: 0;
|
|
background-color: #f7f8fa;
|
|
}
|
|
|
|
.dark .main-content-page {
|
|
background-color: #212225;
|
|
}
|
|
|
|
.main-content {
|
|
height: 100vh;
|
|
width: 100vw;
|
|
}
|
|
|
|
.main-content-header {
|
|
border-bottom: solid 1px var(--el-border-color);
|
|
height: 55px;
|
|
display: flex;
|
|
align-items: center;
|
|
box-sizing: border-box;
|
|
|
|
.logo {
|
|
height: 32px;
|
|
}
|
|
|
|
.user-info {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: center;
|
|
|
|
.el-avatar:hover {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.profile {
|
|
text-align: right;
|
|
margin-right: 20px;
|
|
|
|
:first-child {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
line-height: 20px;
|
|
}
|
|
|
|
:last-child {
|
|
font-size: 10px;
|
|
color: grey;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|