From 7976f11cf4f03c84a030d1d9dd62d29e1dc04a83 Mon Sep 17 00:00:00 2001 From: unknown <1251316345@qq.com> Date: Fri, 27 Feb 2026 14:48:37 +0800 Subject: [PATCH] modified app chat forum theme --- app.py | 8 +++++++- templates/chat.html | 44 ++++++++++++++++++++++++++++++++++++++++---- templates/forum.html | 24 +++++++++++++++++++++++- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/app.py b/app.py index b0c883f..1185e3f 100644 --- a/app.py +++ b/app.py @@ -704,9 +704,10 @@ def api_add_friend(): return jsonify({'success': False, 'message': '已经是好友或已发送请求'}), 400 friend_req = Friend(user_id=user_id, friend_id=friend_id, status='pending') db.session.add(friend_req) + db.session.flush() # 发送通知给对方 sender_name = session['user'].get('name', '未知用户') - notif = Notification(user_id=friend_id, type='friend_request', content=f'{sender_name} 请求添加你为好友', from_user=sender_name) + notif = Notification(user_id=friend_id, type='friend_request', content=f'{sender_name} 请求添加你为好友', from_user=sender_name, post_id=friend_req.id) db.session.add(notif) db.session.commit() return jsonify({'success': True, 'message': '好友请求已发送'}) @@ -1104,6 +1105,11 @@ def api_notifications(): item['contest_name'] = contest.name if contest else '' applicant = User.query.get(ta.user_id) item['applicant_name'] = applicant.name if applicant else '' + if n.type == 'friend_request' and n.post_id: + fr = Friend.query.get(n.post_id) + if fr: + item['application_status'] = fr.status + item['friend_request_id'] = fr.id result.append(item) return jsonify({'success': True, 'notifications': result}) diff --git a/templates/chat.html b/templates/chat.html index c787e7e..226dcd4 100644 --- a/templates/chat.html +++ b/templates/chat.html @@ -384,17 +384,20 @@ function renderNotifications() { list.innerHTML = notifData.map(n => { const isContestApp = n.type === 'contest_application'; const isTeacherApp = n.type === 'teacher_application'; + const isFriendReq = n.type === 'friend_request'; const isResult = n.type === 'contest_result' || n.type === 'teacher_result'; const isNewExam = n.type === 'contest_new_exam'; const isGraded = n.type === 'exam_graded'; const isSystem = n.type === 'system_announcement'; const isPendingContest = isContestApp && n.application_status === 'pending'; const isPendingTeacher = isTeacherApp && n.application_status === 'pending'; + const isPendingFriend = isFriendReq && n.application_status === 'pending'; let statusHtml = ''; if ((isContestApp || isTeacherApp) && n.application_status === 'approved') statusHtml = '已批准'; else if ((isContestApp || isTeacherApp) && n.application_status === 'rejected') statusHtml = '已拒绝'; - const icon = isContestApp ? '📋' : isTeacherApp ? '👨‍🏫' : isResult ? '📢' : isNewExam ? '📝' : isGraded ? '✅' : isSystem ? '📢' : '🔔'; - const iconBg = isContestApp ? 'bg-orange-100' : isTeacherApp ? 'bg-purple-100' : isResult ? 'bg-green-100' : isNewExam ? 'bg-indigo-100' : isGraded ? 'bg-emerald-100' : isSystem ? 'bg-amber-100' : 'bg-blue-100'; + else if (isFriendReq && n.application_status === 'accepted') statusHtml = '已同意'; + const icon = isContestApp ? '📋' : isTeacherApp ? '👨‍🏫' : isFriendReq ? '👤' : isResult ? '📢' : isNewExam ? '📝' : isGraded ? '✅' : isSystem ? '📢' : '🔔'; + const iconBg = isContestApp ? 'bg-orange-100' : isTeacherApp ? 'bg-purple-100' : isFriendReq ? 'bg-blue-100' : isResult ? 'bg-green-100' : isNewExam ? 'bg-indigo-100' : isGraded ? 'bg-emerald-100' : isSystem ? 'bg-amber-100' : 'bg-blue-100'; const clickAction = `showNotifDetail(${n.id})`; let actionsHtml = ''; if (isPendingContest && currentUser.role === 'admin') { @@ -409,6 +412,12 @@ function renderNotifications() { `; } + if (isPendingFriend && n.friend_request_id) { + actionsHtml = `
+ + +
`; + } return `
@@ -479,6 +488,26 @@ async function rejectTeacher(appId) { } } +async function acceptFriendReq(reqId, notifId) { + const res = await fetch(`/api/friend/accept/${reqId}`, { method: 'POST' }); + const data = await res.json(); + if (data.success) { + loadNotifications(); + } else { + alert(data.message || '操作失败'); + } +} + +async function rejectFriendReq(reqId, notifId) { + const res = await fetch(`/api/friend/reject/${reqId}`, { method: 'POST' }); + const data = await res.json(); + if (data.success) { + loadNotifications(); + } else { + alert(data.message || '操作失败'); + } +} + async function checkUnreadNotifs() { const res = await fetch('/api/notifications/unread-count'); const data = await res.json(); @@ -517,13 +546,13 @@ function showNotifDetail(nid) { 'teacher_application': '教师申请', 'teacher_result': '教师审核结果', 'contest_application': '杯赛申请', 'contest_result': '杯赛通知', 'contest_new_exam': '新考试', 'exam_graded': '成绩通知', - 'system_announcement': '系统通知' + 'system_announcement': '系统通知', 'friend_request': '好友申请' }; const typeIcons = { 'teacher_application': '👨‍🏫', 'teacher_result': '🎓', 'contest_application': '📋', 'contest_result': '🏅', 'contest_new_exam': '📝', 'exam_graded': '✅', - 'system_announcement': '📢' + 'system_announcement': '📢', 'friend_request': '👤' }; document.getElementById('notifDetailIcon').textContent = typeIcons[n.type] || '🔔'; @@ -546,6 +575,13 @@ function showNotifDetail(nid) {
`; } else if (n.type === 'contest_new_exam' || n.type === 'exam_graded') { actHtml = `查看考试`; + } else if (n.type === 'friend_request' && n.application_status === 'pending' && n.friend_request_id) { + actHtml = `
+ + +
`; + } else if (n.type === 'friend_request' && n.application_status === 'accepted') { + actHtml = '✅ 已同意'; } else if ((n.type === 'contest_application' || n.type === 'teacher_application') && n.application_status === 'approved') { actHtml = '✅ 已批准'; } else if ((n.type === 'contest_application' || n.type === 'teacher_application') && n.application_status === 'rejected') { diff --git a/templates/forum.html b/templates/forum.html index 1c6ea91..36fc51a 100644 --- a/templates/forum.html +++ b/templates/forum.html @@ -838,12 +838,19 @@ async function showProfile(uid) { const p = d.profile; let badges = p.badges.map(b => `${b.icon} ${b.name}`).join(''); let posts = p.recent_posts.map(pp => `
${esc(pp.title)}
`).join(''); + let friendBtn = ''; + if (CU && CU.id !== parseInt(uid)) { + friendBtn = ``; + } document.getElementById('profile-content').innerHTML = `
${esc(p.name.charAt(0))}
${esc(p.name)}Lv.${p.level} ${p.level_title}
${p.points} 积分
- +
+ ${friendBtn} + +
${p.posts_count}
帖子
@@ -854,6 +861,21 @@ async function showProfile(uid) { ${posts?`
📝 最近帖子
${posts}
`:''}`; } +async function forumAddFriend(userId, btn) { + try { + const res = await fetch('/api/friend/add', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({friend_id: userId})}); + const data = await res.json(); + if (data.success) { + btn.textContent = '已发送'; + btn.disabled = true; + btn.classList.replace('bg-primary', 'bg-slate-400'); + btn.classList.remove('hover:bg-blue-600'); + } else { + alert(data.message || '操作失败'); + } + } catch(e) { alert('操作失败'); } +} + // ===== 侧边栏 ===== async function loadSidebar() { // 热门帖子