315 lines
7.3 KiB
Vue
315 lines
7.3 KiB
Vue
<template>
|
||
<div class="user-center">
|
||
<Navbar />
|
||
|
||
<div v-if="isLoading" class="loading-container">
|
||
<div class="loading-spinner">加载中...</div>
|
||
</div>
|
||
|
||
<div v-else-if="isAuthenticated" class="container">
|
||
<!-- 上部分(用户信息和东币记录) -->
|
||
<div class="upper-section">
|
||
<div class="user-info-container">
|
||
<UserInfo ref="userInfo" />
|
||
</div>
|
||
|
||
<div class="coin-container">
|
||
<Coin ref="coin" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 下部分(投稿记录) -->
|
||
<div class="lower-section">
|
||
<SubmissionList @manage-works="handleManageWorks" />
|
||
</div>
|
||
</div>
|
||
|
||
<div v-else class="login-required-container">
|
||
<div class="login-required-message">
|
||
<h2>请先登录!</h2>
|
||
<p>您需要登录后才能访问个人中心</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import Navbar from '@/components/NavBar.vue';
|
||
import UserInfo from '@/components/user_center/UserInfo.vue';
|
||
import Coin from '@/components/user_center/Coin.vue';
|
||
import SubmissionList from '@/components/user_center/SubmissionList.vue';
|
||
import Cookies from 'js-cookie';
|
||
import messageBox from '@/utils/messageBox.js';
|
||
import Login from '@/utils/login.js';
|
||
|
||
export default {
|
||
name: 'UserCenter',
|
||
components: {
|
||
Navbar,
|
||
UserInfo,
|
||
Coin,
|
||
SubmissionList
|
||
},
|
||
data() {
|
||
return {
|
||
isAuthenticated: false,
|
||
isLoading: true
|
||
};
|
||
},
|
||
created() {
|
||
document.title = '个人中心 - NEU小站';
|
||
},
|
||
mounted() {
|
||
this.checkAuthAndFetchUserInfo();
|
||
},
|
||
methods: {
|
||
async checkAuthAndFetchUserInfo() {
|
||
const token = Cookies.get('token');
|
||
|
||
if (!token) {
|
||
this.isLoading = false;
|
||
// 如果当前在user-center路径,但没有登录态,重定向到/login
|
||
if (this.$route.path === '/user-center') {
|
||
this.$router.replace('/login');
|
||
return;
|
||
}
|
||
// 如果是/login路由,自动弹出登录框
|
||
if (this.$route.path === '/login') {
|
||
this.showLoginDialog();
|
||
}
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 使用 /islogin 接口快速验证 token
|
||
const response = await fetch('https://newfront.xn--xhq44jb2fzpc.com/user/islogin', {
|
||
method: 'GET',
|
||
headers: {
|
||
'Authorization': token
|
||
}
|
||
});
|
||
|
||
if (!response.ok) {
|
||
// 如果状态码不是 2xx (例如 401 Unauthorized)
|
||
throw new Error('Token 验证失败');
|
||
}
|
||
|
||
// 验证成功
|
||
const data = await response.json();
|
||
if (data && data.isLoggedIn) {
|
||
this.isAuthenticated = true;
|
||
} else {
|
||
// 理论上如果 response.ok 为 true,这里不应该执行
|
||
// 但以防万一,处理逻辑上验证失败的情况
|
||
throw new Error('Token 验证成功但返回状态不正确');
|
||
}
|
||
|
||
this.isLoading = false;
|
||
|
||
// 如果登录成功且当前在/login路径,重定向到/user-center
|
||
if (this.$route.path === '/login') {
|
||
this.$router.replace('/user-center');
|
||
}
|
||
} catch (error) {
|
||
console.error('获取用户信息出错:', error);
|
||
this.isLoading = false;
|
||
// 清除可能存在的无效token
|
||
Cookies.remove('token');
|
||
|
||
// 如果当前在user-center路径,重定向到/login
|
||
if (this.$route.path === '/user-center') {
|
||
this.$router.replace('/login');
|
||
return;
|
||
}
|
||
|
||
// 如果是/login路由,自动弹出登录框
|
||
if (this.$route.path === '/login') {
|
||
this.showLoginDialog();
|
||
}
|
||
}
|
||
},
|
||
|
||
showLoginDialog() {
|
||
Login()
|
||
.then(userData => {
|
||
console.log('登录成功:', userData);
|
||
this.isAuthenticated = true;
|
||
// 登录成功后重定向到/user-center
|
||
this.$router.replace('/user-center');
|
||
})
|
||
.catch(reason => {
|
||
console.log('登录取消:', reason);
|
||
});
|
||
},
|
||
|
||
handleManageWorks() {
|
||
// 检测是否为移动设备
|
||
const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth < 768;
|
||
|
||
if (isMobile) {
|
||
// 移动设备显示确认对话框
|
||
messageBox.confirm("建议在电脑端进行投稿以获得最佳体验。仍要继续吗?", "提示")
|
||
.then(() => {
|
||
// 用户确认,跳转到投稿页面
|
||
this.$router.push('/submit');
|
||
})
|
||
.catch(() => {
|
||
// 用户取消,不执行任何操作
|
||
console.log("用户取消了在移动端投稿");
|
||
});
|
||
} else {
|
||
// 电脑端直接跳转到投稿页面
|
||
this.$router.push('/submit');
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.user-center {
|
||
min-height: 100vh;
|
||
background-color: #f4f7fa;
|
||
padding-top: 60px; /* 为导航栏留出空间 */
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 24px 16px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
|
||
/* 登录提示样式 */
|
||
.login-required-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: calc(100vh - 200px);
|
||
}
|
||
|
||
.login-required-message {
|
||
background-color: white;
|
||
padding: 30px 50px;
|
||
border-radius: 10px;
|
||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||
text-align: center;
|
||
}
|
||
|
||
.login-required-message h2 {
|
||
font-size: 24px;
|
||
color: #333;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.login-required-message p {
|
||
font-size: 16px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 上部分布局 */
|
||
.upper-section {
|
||
display: flex;
|
||
gap: 24px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.user-info-container,
|
||
.coin-container {
|
||
flex: 1;
|
||
min-width: 300px;
|
||
}
|
||
|
||
/* 调整高度统一 */
|
||
@media (min-width: 769px) {
|
||
.upper-section {
|
||
align-items: stretch;
|
||
}
|
||
|
||
.user-info-container,
|
||
.coin-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 350px; /* 固定高度 */
|
||
}
|
||
|
||
.coin-container > :first-child {
|
||
flex: 1;
|
||
overflow-y: auto; /* 允许内容滚动 */
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.coin-container ::-webkit-scrollbar {
|
||
width: 6px;
|
||
}
|
||
|
||
.coin-container ::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.coin-container ::-webkit-scrollbar-thumb {
|
||
background: #c1c1c1;
|
||
border-radius: 10px;
|
||
}
|
||
|
||
.coin-container ::-webkit-scrollbar-thumb:hover {
|
||
background: #a8a8a8;
|
||
}
|
||
}
|
||
|
||
/* 下部分布局 */
|
||
.lower-section {
|
||
width: 100%;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 768px) {
|
||
.upper-section {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.user-info-container,
|
||
.coin-container {
|
||
width: 100%;
|
||
height: auto;
|
||
}
|
||
|
||
.container {
|
||
padding: 16px 12px;
|
||
}
|
||
}
|
||
|
||
/* 加载状态样式 */
|
||
.loading-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: calc(100vh - 60px);
|
||
}
|
||
|
||
.loading-spinner {
|
||
padding: 20px;
|
||
background-color: white;
|
||
border-radius: 8px;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
font-size: 16px;
|
||
color: #3182ce;
|
||
}
|
||
|
||
/* 添加一些过渡效果 */
|
||
.user-center {
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
/* 确保在较小屏幕上内容不会溢出 */
|
||
@media (max-width: 480px) {
|
||
.container {
|
||
padding: 12px 8px;
|
||
}
|
||
}
|
||
</style>
|