2991692032 3 weeks ago
parent dbc2480bad
commit 0dd026279b

@ -84,7 +84,7 @@ router.beforeEach((to) => {
return '/login'
}
if ((to.name === 'login' || to.name === 'register') && userStore.isLoggedIn) {
if (to.name === 'login' && userStore.isLoggedIn) {
return '/forum'
}
})

@ -31,7 +31,7 @@ export interface User {
}
export interface LoginRequest {
email: string
account: string // 支持用户名或邮箱
password: string
}

@ -52,24 +52,6 @@
了解更多
</a>
</div>
<!-- 用户统计 -->
<div class="stats-container animate-fade-in-up delay-500">
<div class="stat-item">
<div class="stat-number">1000+</div>
<div class="stat-label">活跃用户</div>
</div>
<div class="stat-divider"></div>
<div class="stat-item">
<div class="stat-number">500+</div>
<div class="stat-label">讨论话题</div>
</div>
<div class="stat-divider"></div>
<div class="stat-item">
<div class="stat-number">200+</div>
<div class="stat-label">学习资源</div>
</div>
</div>
</div>
<!-- Hero图片 -->
@ -168,28 +150,6 @@
</div>
<p class="footer-description">为大学生打造的综合性生活平台</p>
</div>
<div class="footer-links">
<div class="link-group">
<h4>产品</h4>
<a href="#">论坛</a>
<a href="#">资源库</a>
<a href="#">课程表</a>
<a href="#">日程管理</a>
</div>
<div class="link-group">
<h4>支持</h4>
<a href="#">帮助中心</a>
<a href="#">用户协议</a>
<a href="#">隐私政策</a>
</div>
<div class="link-group">
<h4>联系我们</h4>
<a href="#">反馈建议</a>
<a href="#">商务合作</a>
<a href="#">关于我们</a>
</div>
</div>
</div>
<div class="footer-bottom">
@ -520,42 +480,6 @@ const steps = ref([
font-size: 18px;
}
/* 统计数据 */
.stats-container {
display: flex;
align-items: center;
gap: 32px;
padding: 24px;
background: rgba(255, 255, 255, 0.8);
border-radius: 20px;
backdrop-filter: blur(20px);
border: 1px solid var(--gray-200);
box-shadow: var(--shadow-sm);
}
.stat-item {
text-align: center;
}
.stat-number {
font-size: 2rem;
font-weight: 700;
color: var(--primary-600);
margin-bottom: 4px;
}
.stat-label {
color: var(--gray-600);
font-size: 14px;
font-weight: 500;
}
.stat-divider {
width: 1px;
height: 40px;
background: var(--gray-200);
}
/* Hero Visual */
.hero-visual {
position: relative;
@ -896,16 +820,6 @@ const steps = ref([
align-items: center;
}
.stats-container {
flex-direction: column;
gap: 20px;
}
.stat-divider {
width: 80%;
height: 1px;
}
.features-grid {
grid-template-columns: 1fr;
}

@ -526,14 +526,14 @@ const sendMessage = async () => {
console.error('发送消息失败:', error)
//
if (streamingChatId.value === currentChatId.value) {
assistantMessage.content = '抱歉,发生了错误,请稍后重试。'
ElMessage.error('发送失败:' + (error.message || '网络错误'))
assistantMessage.content = '抱歉,发生了错误,请稍后重试。'
ElMessage.error('发送失败:' + (error.message || '网络错误'))
}
} finally {
//
if (streamingChatId.value === currentChatId.value) {
isStreaming.value = false
await scrollToBottom()
isStreaming.value = false
await scrollToBottom()
//
const delayTime = isFirstMessage ? 800 : 300 // 800ms300ms

@ -30,14 +30,13 @@
@submit.prevent="handleLogin"
class="form-container"
>
<!-- 邮箱输入 -->
<!-- 账号输入 -->
<div class="input-group animate-fade-in-up delay-100">
<label class="input-label">邮箱地址</label>
<el-form-item prop="email">
<label class="input-label">账号</label>
<el-form-item prop="account">
<el-input
v-model="loginForm.email"
placeholder="请输入您的邮箱地址"
type="email"
v-model="loginForm.account"
placeholder="请输入用户名或邮箱地址"
size="large"
class="modern-input"
>
@ -138,14 +137,14 @@ const loading = ref(false)
const rememberMe = ref(false)
const loginForm = reactive<LoginRequest>({
email: '',
account: '',
password: ''
})
const loginRules = {
email: [
{ required: true, message: '请输入邮箱地址', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱格式', trigger: 'blur' }
account: [
{ required: true, message: '请输入账号', trigger: 'blur' },
{ min: 3, message: '账号长度不能少于3位', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' },
@ -164,7 +163,7 @@ const handleLogin = async () => {
ElMessage.success('登录成功!欢迎回来 🎉')
router.push('/forum')
} catch (error: any) {
ElMessage.error(error.message || '登录失败,请检查邮箱和密码')
ElMessage.error(error.message || '登录失败,请检查账号和密码')
} finally {
loading.value = false
}

@ -106,7 +106,7 @@
<label class="input-label">确认密码</label>
<el-form-item prop="confirmPassword">
<el-input
v-model="confirmPassword"
v-model="registerForm.confirmPassword"
placeholder="请再次输入密码"
type="password"
size="large"
@ -265,7 +265,7 @@ const codeLoading = ref(false)
const countdown = ref(0)
const agreeTerms = ref(false)
const registerForm = reactive<RegisterRequest>({
const registerForm = reactive<RegisterRequest & { confirmPassword: string }>({
username: '',
email: '',
password: '',
@ -274,11 +274,10 @@ const registerForm = reactive<RegisterRequest>({
department: '',
major: '',
grade: '',
code: ''
code: '',
confirmPassword: ''
})
const confirmPassword = ref('')
//
const validateConfirmPassword = (rule: any, value: any, callback: any) => {
if (value !== registerForm.password) {
@ -369,7 +368,20 @@ const handleRegister = async () => {
loading.value = true
await userStore.userRegister(registerForm)
// confirmPassword
const registerData: RegisterRequest = {
username: registerForm.username,
email: registerForm.email,
password: registerForm.password,
nickname: registerForm.nickname,
studentId: registerForm.studentId,
department: registerForm.department,
major: registerForm.major,
grade: registerForm.grade,
code: registerForm.code
}
await userStore.userRegister(registerData)
ElMessage.success('注册成功欢迎加入UniLife 🎉')
router.push('/login')
} catch (error: any) {

@ -9,6 +9,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
public class LoginDTO {
private String email;
private String account; // 支持用户名或邮箱
private String password;
}

@ -45,7 +45,7 @@ public class AiServiceImpl implements AiService {
log.info("发送消息给AI: {}, 会话ID: {}", sendMessageDTO.getMessage(), sendMessageDTO.getSessionId());
String sessionId = sendMessageDTO.getSessionId();
// 确保会话元数据存在
sessionHistoryService.createOrUpdateSession(sessionId, BaseContext.getId(), "新对话");

@ -125,6 +125,12 @@ public class UserServiceImpl implements UserService {
String username = StringUtils.isNotEmpty(registerDTO.getUsername()) ? registerDTO.getUsername() : email.substring(0, Math.min(email.indexOf('@'), 10)) + "_" + RandomUtil.randomString(4);
user.setUsername(username);
// 设置学生信息
user.setStudentId(registerDTO.getStudentId());
user.setDepartment(registerDTO.getDepartment());
user.setMajor(registerDTO.getMajor());
user.setGrade(registerDTO.getGrade());
// 设置其他默认值
user.setRole((byte) 0); // 普通用户
user.setStatus((byte) 1); // 启用状态
@ -162,11 +168,22 @@ public class UserServiceImpl implements UserService {
@Override
public Result login(LoginDTO loginDTO,HttpServletRequest request) {
if(loginDTO==null|| StringUtils.isEmpty(loginDTO.getEmail())||StringUtils.isEmpty(loginDTO.getPassword())){
return Result.error(400,"邮箱或密码不能为空");
if(loginDTO==null|| StringUtils.isEmpty(loginDTO.getAccount())||StringUtils.isEmpty(loginDTO.getPassword())){
return Result.error(400,"账号或密码不能为空");
}
User user = userMapper.findByEmail(loginDTO.getEmail());
String account = loginDTO.getAccount();
User user = null;
// 判断输入的是邮箱还是用户名
if (RegexUtils.isEmailInvalid(account)) {
// 不是邮箱格式,按用户名查询
user = userMapper.findByUsername(account);
} else {
// 是邮箱格式,按邮箱查询
user = userMapper.findByEmail(account);
}
if (user == null) {
return Result.error(400, "账号或密码错误");
}
@ -179,7 +196,6 @@ public class UserServiceImpl implements UserService {
return Result.error(403, "账号已被禁用,请联系管理员");
}
String LastLogIpLocation = user.getLoginIp();
String currentIp = ipLocationService.getClientIP(request);
String ipLocation = ipLocationService.getIPLocation(currentIp);
@ -191,7 +207,6 @@ public class UserServiceImpl implements UserService {
BeanUtil.copyProperties(user,loginVO);
String message = StringUtils.isEmpty(LastLogIpLocation) ? "首次登录" : "上次登录IP归属地为" + LastLogIpLocation;
return Result.success(loginVO, message);
}
@Override

@ -1,6 +1,7 @@
package com.unilife.utils;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
@ -24,24 +25,45 @@ public class JwtUtil {
Map<String, Object> payload = new HashMap<>();
payload.put("userId", id);
payload.put("created",now.getTime());
return JWTUtil.createToken(payload,secret.getBytes());
payload.put("created", now.getTime());
payload.put("exp", expireTime.getTime() / 1000); // JWT标准过期时间字段
return JWTUtil.createToken(payload, secret.getBytes());
}
public boolean verifyToken(String token) {
try{
JWTUtil.verify(token,secret.getBytes());
try {
// 验证token签名
JWTUtil.verify(token, secret.getBytes());
// 验证过期时间
JWT jwt = JWTUtil.parseToken(token);
Object expObj = jwt.getPayload("exp");
if (expObj != null) {
long exp = Long.parseLong(expObj.toString());
long currentTime = System.currentTimeMillis() / 1000;
if (currentTime > exp) {
log.debug("Token已过期: exp={}, current={}", exp, currentTime);
return false;
}
}
return true;
}catch (Exception e){
} catch (Exception e) {
log.debug("Token验证失败: {}", e.getMessage());
return false;
}
}
public Long getUserIdFromToken(String token) {
try {
// 先验证token是否有效
if (!verifyToken(token)) {
return null;
}
return Long.valueOf(JWTUtil.parseToken(token).getPayload("userId").toString());
}catch (Exception e){
} catch (Exception e) {
log.debug("从Token获取用户ID失败: {}", e.getMessage());
return null;
}
}
}

@ -69,7 +69,7 @@ logging:
org.springframework.ai: debug
jwt:
secret: qwertyuiopasdfghjklzxcvbnm
expiration: 86400
expiration: 300 # 5分钟过期时间5 * 60 = 300秒用于测试
# 添加阿里云OSS配置
aliyun:
oss:

Loading…
Cancel
Save