185 lines
5.6 KiB
Vue
Raw Normal View History

<template>
2024-12-12 18:03:40 +08:00
<el-container class="app__container">
<el-header class="app-header flex align-center">
<el-icon v-show="mdLess" size="30" @click="showVerticalHeaderMenu = true">
<icon-cs-menu />
</el-icon>
<router-link custom to="/" v-slot="{ navigate }">
2024-12-12 18:03:40 +08:00
<el-icon size="50" @click="navigate"><icon-cs-club /></el-icon>
2024-12-15 21:12:21 +08:00
<h3 v-show="showAppTitle" class="app__title" @click="navigate">社团展示系统</h3>
2024-12-12 18:03:40 +08:00
</router-link>
<header-menu v-show="!mdLess" mode="horizontal" />
<el-dropdown v-if="!mdLess && userStore.logined">
2024-12-15 10:02:18 +08:00
<header-user @login="onLoginButtonClick" @logout="logout" />
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :icon="CloseBold" @click="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
2024-12-12 18:03:40 +08:00
</template>
</el-dropdown>
2024-12-15 10:02:18 +08:00
<header-user v-else @login="onLoginButtonClick" @logout="logout" @click="onUserClick" />
2024-04-09 17:57:51 +08:00
</el-header>
2024-12-12 18:03:40 +08:00
<el-main class="app-main" v-loading="!!pageStore.pageLoadingCount">
<el-container class="app-router-component__wrapper">
<router-view v-slot="{ Component: comp }">
<transition appear mode="out-in" name="app-router-view">
<component class="app-router-component" :is="comp" />
</transition>
</router-view>
</el-container>
</el-main>
2024-04-09 17:57:51 +08:00
</el-container>
2024-12-12 18:03:40 +08:00
<login-register-dialog v-model="showLoginRegisterDialog" />
<el-drawer
class="app-vertical-drawer"
v-model="showVerticalHeaderMenu"
direction="ltr"
size="250"
:with-header="false"
>
2024-12-15 21:12:21 +08:00
<h3 v-show="!showAppTitle" class="app__title text-center">社团展示系统</h3>
2024-12-15 10:02:18 +08:00
<header-user v-if="userStore.logined" @login="showLoginRegisterDialog = true" />
2024-12-13 23:02:39 +08:00
<div v-else class="app-vertical-drawer__not-login-title flex center">尚未登录</div>
<el-button
v-if="userStore.logined"
class="app-vertical-drawer__logout"
type="primary"
:icon="CloseBold"
@click="logout"
>
退出登录
</el-button>
2024-12-15 10:02:18 +08:00
<header-menu mode="vertical" @select="showVerticalHeaderMenu = false" />
</el-drawer>
</template>
<style lang="scss">
.app-vertical-drawer {
--el-drawer-padding-primary: 0;
.el-drawer__body {
gap: 10px;
display: flex;
flex-direction: column;
}
2024-12-13 23:02:39 +08:00
> :first-child:not(.app-header-menu) {
margin-top: 10px;
}
2024-12-13 23:02:39 +08:00
&__not-login-title {
font-weight: bold;
}
&__logout {
margin: 0 10px;
}
}
</style>
<style lang="scss" scoped>
2024-12-12 18:03:40 +08:00
.app__container {
min-height: 100vh;
}
.app-header {
2024-12-12 18:03:40 +08:00
--el-header-height: var(--header-height);
--el-loading-spinner-size: 30px;
2024-12-15 21:12:21 +08:00
position: fixed;
width: 100%;
2024-12-15 21:52:30 +08:00
z-index: 100;
user-select: none;
2024-12-15 19:07:02 +08:00
top: 0;
background-color: white;
2024-12-12 18:03:40 +08:00
border-bottom: 1px solid var(--el-border-color);
2024-12-15 10:02:18 +08:00
// 侧边栏需要居中
.app-header-user {
margin-left: auto;
}
}
2024-12-12 18:03:40 +08:00
.app-main {
2024-12-15 21:12:21 +08:00
--el-main-padding: 0 0 0 0;
margin-top: var(--header-height);
display: flex;
}
2024-12-15 21:12:21 +08:00
.app-router-component {
--el-main-padding: 0;
}
2024-12-12 18:03:40 +08:00
.app-router-view-enter-active,
.app-router-view-leave-active {
2024-12-15 19:07:02 +08:00
transition: opacity 0.25s ease;
2024-06-05 18:02:15 +08:00
}
2024-12-12 18:03:40 +08:00
.app-router-view-enter-from,
.app-router-view-leave-to {
opacity: 0;
2024-04-09 17:57:51 +08:00
}
</style>
2024-12-12 18:03:40 +08:00
<script setup lang="ts">
2024-12-13 18:54:48 +08:00
import axiosInstance, { type RawResp } from '@/api/index';
2024-12-15 10:02:18 +08:00
import HeaderMenu from '@/components/app/HeaderMenu.vue';
import HeaderUser from '@/components/app/HeaderUser.vue';
2024-12-13 18:54:48 +08:00
import LoginRegisterDialog, {
loginImplKey,
registerImplKey,
2024-12-15 10:02:18 +08:00
} from '@/components/app/LoginRegisterDialog.vue';
import { useMediaStore } from '@/stores/media';
import { usePageStore } from '@/stores/page.js';
import { useUserStore } from '@/stores/user';
2024-12-12 18:03:40 +08:00
import { CloseBold } from '@element-plus/icons-vue';
import type { AxiosError } from 'axios';
import { ElMessage } from 'element-plus';
2024-12-13 13:00:56 +08:00
import { storeToRefs } from 'pinia';
import { provide, ref, watch } from 'vue';
2024-12-12 18:03:40 +08:00
import { loginResponseSchema, registerResponseSchema } from './schemas/response';
2024-12-15 21:12:21 +08:00
import { useMediaQuery } from '@vueuse/core';
2024-04-14 14:40:34 +08:00
const userStore = useUserStore();
const pageStore = usePageStore();
const { smLess, mdLess } = storeToRefs(useMediaStore());
2024-12-15 21:12:21 +08:00
const showAppTitle = useMediaQuery('(width >= 390px)');
2024-12-10 20:04:14 +08:00
const showLoginRegisterDialog = ref(false);
2024-12-12 18:03:40 +08:00
provide(loginImplKey, async (params) => {
2024-12-09 20:43:08 +08:00
const loginRespRaw = await axiosInstance
.post<RawResp>('/api/user/login', params)
.then((r) => r.data)
2024-12-12 18:03:40 +08:00
.catch((err: AxiosError) => {
ElMessage.error([err.code, err.message].join(':'));
2024-12-09 20:43:08 +08:00
});
if (!loginRespRaw) return false;
2024-12-12 18:03:40 +08:00
const resp = loginResponseSchema.parse(loginRespRaw);
if (resp.type === 'error') {
ElMessage.error([resp.code, resp.msg].join(':'));
2024-04-14 14:40:34 +08:00
return false;
}
2024-12-10 20:04:14 +08:00
return userStore.updateSelfUserInfo(true);
2024-12-12 18:03:40 +08:00
});
provide(registerImplKey, async (params) => {
2024-12-10 20:04:14 +08:00
const raw = await axiosInstance
.put<RawResp>('/api/user/create', params)
.then((r) => r.data)
.catch((err: AxiosError) => {
2024-12-12 18:03:40 +08:00
ElMessage.error([err.code, err.message].join(':'));
2024-12-10 20:04:14 +08:00
});
if (!raw) return false;
const resp = registerResponseSchema.parse(raw);
if (resp.type === 'error') {
2024-12-12 18:03:40 +08:00
ElMessage.error([resp.code, resp.msg].join(':'));
2024-04-14 14:40:34 +08:00
return false;
}
2024-12-10 20:04:14 +08:00
return userStore.updateSelfUserInfo(true);
2024-12-12 18:03:40 +08:00
});
2024-04-14 14:40:34 +08:00
async function logout() {
showVerticalHeaderMenu.value = false;
2024-12-15 21:12:21 +08:00
if (!(await userStore.logout())) return;
2024-12-09 20:43:08 +08:00
await userStore.updateSelfUserInfo(true);
2024-04-14 14:40:34 +08:00
}
const showVerticalHeaderMenu = ref(false);
watch(mdLess, (v) => {
2024-12-13 23:02:39 +08:00
if (v) return;
showVerticalHeaderMenu.value = false;
});
2024-12-15 10:02:18 +08:00
function onLoginButtonClick() {
showLoginRegisterDialog.value = true;
}
function onUserClick() {
showVerticalHeaderMenu.value = true;
}
2024-12-13 13:00:56 +08:00
// onMounted(() => {
// userStore.token = null;
// userStore.updateSelfUserInfo(true);
// });
</script>