Compare commits

...

2 Commits

Author SHA1 Message Date
5c1858d9e0 feat(layout): 添加用户列表视图并优化登出逻辑
- 新增 UserListView 组件
- 在 DefaultLayout 中添加登出时清除 token 的逻辑
2025-01-01 19:19:11 +08:00
d9f814ccfb feat(auth): 实现退出登录功能并优化登录状态验证
- 在 DefaultLayout 组件中添加退出登录按钮
- 实现 logout 函数,用于清除 token 并重定向到登录页
- 修改路由配置,增加 requiresAuth 元数据用于权限控制
- 优化 auth.js 中的 TokenKey 名称
- 移除 CustomCard、AboutView 和 TestApi 组件中的冗余样式
2025-01-01 17:33:57 +08:00
9 changed files with 57 additions and 51 deletions

View File

@ -28,39 +28,4 @@ defineProps({
</a-card> </a-card>
</template> </template>
<style scoped> <style scoped></style>
.card {
display: flex;
flex-direction: column;
text-align: center;
align-items: center;
box-sizing: border-box;
.avatar {
width: 50%;
img {
border-radius: 50%;
}
}
.name {
width: 50%;
}
.content {
width: 100%;
}
}
@media screen and (max-width: 800px) {
.card {
width: 160px;
}
}
@media screen and (min-width: 800px) {
.card {
width: 200px;
}
}
</style>

View File

@ -2,6 +2,7 @@
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue' import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
import { computed, reactive } from 'vue' import { computed, reactive } from 'vue'
import router from '@/router/index.js' import router from '@/router/index.js'
import { setToken } from '@/utils/auth.js'
const formState = reactive({ const formState = reactive({
account: '', account: '',
@ -22,8 +23,8 @@ const onfinish = async () => {
}) })
if (response.ok) { if (response.ok) {
const data = await response.json() console.log(`formState.account:${formState.account}`)
console.log(data) setToken(formState.account)
await router.push('/') await router.push('/')
} else { } else {
console.error('Login failed', response.statusText) console.error('Login failed', response.statusText)

View File

@ -22,7 +22,7 @@ export default defineComponent({
<template> <template>
<button @click="testapi">测试接口调用</button> <button @click="testapi">测试接口调用</button>
<p v-if="this.test != ''"> <p v-if="this.test !== ''">
{{ this.test[0].name }}<br /> {{ this.test[0].name }}<br />
{{ this.test[0].birth }}<br /> {{ this.test[0].birth }}<br />
{{ this.test[0].gender }}<br /> {{ this.test[0].gender }}<br />

View File

@ -3,6 +3,8 @@ import CustomCard from '@/components/CustomCard.vue'
import { RouterView } from 'vue-router' import { RouterView } from 'vue-router'
import { h, ref } from 'vue' import { h, ref } from 'vue'
import { AppstoreOutlined, MailOutlined } from '@ant-design/icons-vue' import { AppstoreOutlined, MailOutlined } from '@ant-design/icons-vue'
import router from '@/router/index.js'
import { removeToken } from '@/utils/auth.js'
const current = ref(['mail']) const current = ref(['mail'])
const items = ref([ const items = ref([
@ -25,6 +27,24 @@ const items = ref([
title: '工具' title: '工具'
} }
]) ])
const logout = async () => {
const response = await fetch('http://localhost:3000/logout', {
method: 'POST',
cache: 'default',
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
credentials: 'include'
})
if (response.ok) {
removeToken()
await router.push('/login')
} else {
console.error('Logout failed', response.statusText)
}
}
</script> </script>
<template> <template>
@ -52,6 +72,7 @@ const items = ref([
:defaultCollapsed="true" :defaultCollapsed="true"
> >
<CustomCard :name="'rsgl'" :style="{ margin: 'auto', padding: '10px' }" /> <CustomCard :name="'rsgl'" :style="{ margin: 'auto', padding: '10px' }" />
<a-button @click="logout">退出登录</a-button>
</a-layout-sider> </a-layout-sider>
</a-layout> </a-layout>
<a-layout-footer>footer</a-layout-footer> <a-layout-footer>footer</a-layout-footer>

View File

@ -6,6 +6,7 @@ import DefaultLayout from '../layouts/DefaultLayout.vue'
import LoginLayout from '@/layouts/LoginLayout.vue' import LoginLayout from '@/layouts/LoginLayout.vue'
import LoginView from '@/views/LoginView.vue' import LoginView from '@/views/LoginView.vue'
import HomeView from '@/views/HomeView.vue' import HomeView from '@/views/HomeView.vue'
import { getToken } from '@/utils/auth.js'
const router = createRouter({ const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), history: createWebHistory(import.meta.env.BASE_URL),
@ -43,11 +44,25 @@ const router = createRouter({
{ {
path: '', path: '',
name: 'Login', name: 'Login',
component: LoginView component: LoginView,
meta: {
requiresAuth: true
}
} }
] ]
} }
] ]
}) })
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some((record) => record.meta.requiresAuth)
if (!requiresAuth && !getToken()) {
next({ path: '/login' })
} else {
console.log('next')
next()
}
})
export default router export default router

View File

@ -1,6 +1,6 @@
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token' const TokenKey = 'account'
export function getToken() { export function getToken() {
return Cookies.get(TokenKey) return Cookies.get(TokenKey)

View File

@ -21,7 +21,7 @@ function dateTimeToTimestamp(pattern, datetime) {
} }
Date.prototype.Format = function (fmt) { Date.prototype.Format = function (fmt) {
var o = { const o = {
'M+': this.getMonth() + 1, //月份 'M+': this.getMonth() + 1, //月份
'd+': this.getDate(), //日 'd+': this.getDate(), //日
'h+': this.getHours(), //小时 'h+': this.getHours(), //小时
@ -32,7 +32,7 @@ Date.prototype.Format = function (fmt) {
} }
if (/(y+)/.test(fmt)) if (/(y+)/.test(fmt))
fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length))
for (var k in o) for (const k in o)
if (new RegExp('(' + k + ')').test(fmt)) if (new RegExp('(' + k + ')').test(fmt))
fmt = fmt.replace( fmt = fmt.replace(
RegExp.$1, RegExp.$1,

View File

@ -5,11 +5,4 @@ import CustomNews from '@/components/CustomNews.vue'
<CustomNews /> <CustomNews />
</template> </template>
<style> <style></style>
@media (min-width: 1024px) {
.about {
display: flex;
align-items: center;
}
}
</style>

View File

@ -0,0 +1,11 @@
<script setup>
</script>
<template>
</template>
<style scoped>
</style>