mobile app database models admin_contests admin_dashboard admin_exams admin_posts admin_teacher_applications admin_users apply_contest apply_teacher base chat contest_detail contest_list exam_result forum notifications profile themes
This commit is contained in:
@@ -4,31 +4,31 @@
|
||||
{% block content %}
|
||||
<div class="max-w-4xl mx-auto py-8 px-4 sm:px-6">
|
||||
<!-- 头部区域 -->
|
||||
<div class="bg-white rounded-3xl p-6 shadow-sm border border-slate-100 mb-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4 relative overflow-hidden group">
|
||||
<div class="absolute top-0 right-0 w-32 h-32 bg-indigo-50/50 rounded-bl-full -z-10 group-hover:scale-110 transition-transform duration-500"></div>
|
||||
<div class="futuristic-card p-6 mb-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4 relative overflow-hidden group">
|
||||
<div class="absolute top-0 right-0 w-32 h-32 bg-cyan-500/10 rounded-bl-full -z-10 group-hover:scale-110 transition-transform duration-500"></div>
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center text-white shadow-lg shadow-indigo-200 transform group-hover:rotate-12 transition-transform duration-300">
|
||||
<div class="w-12 h-12 bg-gradient-to-br from-cyan-500 to-blue-600 rounded-2xl flex items-center justify-center text-white shadow-lg shadow-cyan-500/30 transform group-hover:rotate-12 transition-transform duration-300">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-2xl font-extrabold text-slate-900 tracking-tight">通知中心</h1>
|
||||
<p class="text-sm text-slate-500 font-medium mt-0.5">查看系统通知、审核结果及最新公告</p>
|
||||
<h1 class="text-2xl font-extrabold bg-gradient-to-r from-cyan-400 to-blue-400 bg-clip-text text-transparent tracking-tight">通知中心</h1>
|
||||
<p class="text-sm text-slate-400 font-medium mt-0.5">查看系统通知、审核结果及最新公告</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="markAllRead()" class="px-5 py-2.5 text-sm font-bold text-slate-600 bg-slate-50 border border-slate-200 rounded-xl hover:bg-white hover:text-indigo-600 hover:border-indigo-200 hover:shadow-sm transition-all flex items-center gap-2 group/btn">
|
||||
<svg class="w-4 h-4 text-slate-400 group-hover/btn:text-indigo-500 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
||||
<button onclick="markAllRead()" class="btn-outline-futuristic px-5 py-2.5 text-sm font-bold flex items-center gap-2 group/btn">
|
||||
<svg class="w-4 h-4 text-slate-400 group-hover/btn:text-cyan-400 transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
|
||||
全部标为已读
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 标签切换 (玻璃拟物化) -->
|
||||
<div class="bg-white/80 backdrop-blur-md rounded-2xl p-1.5 shadow-sm border border-slate-100 mb-6 flex overflow-x-auto hide-scrollbar sticky top-4 z-10">
|
||||
<button onclick="switchTab('all')" id="tab-all" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-bold bg-white text-indigo-600 shadow-sm rounded-xl transition-all duration-300">全部</button>
|
||||
<button onclick="switchTab('system')" id="tab-system" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 rounded-xl transition-all duration-300">📢 系统公告</button>
|
||||
<button onclick="switchTab('teacher')" id="tab-teacher" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 rounded-xl transition-all duration-300">👨🏫 教师相关</button>
|
||||
<button onclick="switchTab('contest')" id="tab-contest" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 rounded-xl transition-all duration-300">🏆 杯赛相关</button>
|
||||
<button onclick="switchTab('friend')" id="tab-friend" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 rounded-xl transition-all duration-300">👤 好友</button>
|
||||
<button onclick="switchTab('exam')" id="tab-exam" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 rounded-xl transition-all duration-300">📝 考试相关</button>
|
||||
<div class="futuristic-card-dark backdrop-blur-md rounded-2xl p-1.5 mb-6 flex overflow-x-auto hide-scrollbar sticky top-4 z-10">
|
||||
<button onclick="switchTab('all')" id="tab-all" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-bold bg-gradient-to-r from-cyan-500 to-blue-500 text-white shadow-sm rounded-xl transition-all duration-300">全部</button>
|
||||
<button onclick="switchTab('system')" id="tab-system" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 rounded-xl transition-all duration-300">📢 系统公告</button>
|
||||
<button onclick="switchTab('teacher')" id="tab-teacher" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 rounded-xl transition-all duration-300">👨🏫 教师相关</button>
|
||||
<button onclick="switchTab('contest')" id="tab-contest" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 rounded-xl transition-all duration-300">🏆 杯赛相关</button>
|
||||
<button onclick="switchTab('friend')" id="tab-friend" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 rounded-xl transition-all duration-300">👤 好友</button>
|
||||
<button onclick="switchTab('exam')" id="tab-exam" class="flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 rounded-xl transition-all duration-300">📝 考试相关</button>
|
||||
</div>
|
||||
|
||||
<!-- 列表内容区 -->
|
||||
@@ -37,7 +37,7 @@
|
||||
<div id="announcements-section" class="hidden">
|
||||
<div class="flex items-center gap-2 mb-4 px-2">
|
||||
<span class="w-8 h-8 rounded-lg bg-amber-100 text-amber-600 flex items-center justify-center font-bold">📢</span>
|
||||
<h2 class="text-lg font-bold text-slate-800">系统公告</h2>
|
||||
<h2 class="text-lg font-bold text-slate-300">系统公告</h2>
|
||||
</div>
|
||||
<div id="announcements-list" class="space-y-4"></div>
|
||||
</div>
|
||||
@@ -70,10 +70,10 @@ function esc(s) { if(!s)return''; const d=document.createElement('div'); d.textC
|
||||
function switchTab(tab) {
|
||||
currentTab = tab;
|
||||
document.querySelectorAll('[id^="tab-"]').forEach(el => {
|
||||
el.className = 'flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-slate-50 rounded-xl transition-all duration-300';
|
||||
el.className = 'flex-1 min-w-[100px] px-4 py-2.5 text-sm font-medium text-slate-400 hover:text-slate-200 hover:bg-slate-700/50 rounded-xl transition-all duration-300';
|
||||
});
|
||||
const activeBtn = document.getElementById('tab-' + tab);
|
||||
activeBtn.className = 'flex-1 min-w-[100px] px-4 py-2.5 text-sm font-bold bg-white text-indigo-600 shadow-sm rounded-xl transition-all duration-300';
|
||||
activeBtn.className = 'flex-1 min-w-[100px] px-4 py-2.5 text-sm font-bold bg-gradient-to-r from-cyan-500 to-blue-500 text-white shadow-sm rounded-xl transition-all duration-300';
|
||||
renderNotifications();
|
||||
}
|
||||
|
||||
@@ -116,21 +116,21 @@ function renderNotifications() {
|
||||
if ((currentTab === 'all' || currentTab === 'system') && announcements.length > 0) {
|
||||
annSection.style.display = '';
|
||||
annList.innerHTML = announcements.map(a => `
|
||||
<div class="bg-white rounded-2xl p-5 shadow-sm border ${a.pinned ? 'border-amber-200 shadow-amber-100/50' : 'border-indigo-100 shadow-indigo-100/50'} relative overflow-hidden group hover:shadow-md transition-all duration-300">
|
||||
<div class="absolute top-0 right-0 w-24 h-24 ${a.pinned ? 'bg-amber-50' : 'bg-indigo-50'} rounded-bl-full -z-10 group-hover:scale-110 transition-transform duration-500"></div>
|
||||
<div class="futuristic-card p-5 border ${a.pinned ? 'border-amber-500/30' : 'border-cyan-500/30'} relative overflow-hidden group hover:shadow-lg transition-all duration-300">
|
||||
<div class="absolute top-0 right-0 w-24 h-24 ${a.pinned ? 'bg-amber-500/10' : 'bg-cyan-500/10'} rounded-bl-full -z-10 group-hover:scale-110 transition-transform duration-500"></div>
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center gap-2">
|
||||
${a.pinned ? '<span class="text-[10px] bg-gradient-to-r from-amber-400 to-orange-500 text-white px-2 py-0.5 rounded-full font-bold shadow-sm flex items-center gap-1"><svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"/></svg> 置顶</span>' : ''}
|
||||
<h3 class="text-lg font-bold text-slate-900 group-hover:text-indigo-600 transition-colors">${esc(a.title)}</h3>
|
||||
${a.pinned ? '<span class="badge-futuristic text-[10px] px-2 py-0.5 rounded-full font-bold shadow-sm flex items-center gap-1"><svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"/></svg> 置顶</span>' : ''}
|
||||
<h3 class="text-lg font-bold text-white group-hover:text-cyan-400 transition-colors">${esc(a.title)}</h3>
|
||||
</div>
|
||||
<p class="text-sm text-slate-600 mt-3 whitespace-pre-wrap leading-relaxed">${esc(a.content)}</p>
|
||||
<div class="flex items-center gap-3 mt-4 pt-4 border-t border-slate-100/60">
|
||||
<span class="flex items-center gap-1.5 text-xs font-medium text-slate-500 bg-slate-50 px-2.5 py-1 rounded-lg">
|
||||
<span class="w-4 h-4 rounded-full bg-slate-200 flex items-center justify-center text-[8px]">${esc(a.author_name)[0]}</span>
|
||||
<p class="text-sm text-slate-300 mt-3 whitespace-pre-wrap leading-relaxed">${esc(a.content)}</p>
|
||||
<div class="flex items-center gap-3 mt-4 pt-4 border-t border-slate-900/10">
|
||||
<span class="flex items-center gap-1.5 text-xs font-medium text-slate-400 bg-slate-800/50 px-2.5 py-1 rounded-lg">
|
||||
<span class="w-4 h-4 rounded-full bg-slate-700 flex items-center justify-center text-[8px] text-white">${esc(a.author_name)[0]}</span>
|
||||
${esc(a.author_name)}
|
||||
</span>
|
||||
<span class="text-xs font-medium text-slate-400 flex items-center gap-1">
|
||||
<span class="text-xs font-medium text-slate-500 flex items-center gap-1">
|
||||
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
||||
${a.created_at}
|
||||
</span>
|
||||
@@ -156,8 +156,8 @@ function renderNotifications() {
|
||||
|
||||
if (currentTab === 'system') {
|
||||
container.innerHTML = announcements.length === 0 ? `
|
||||
<div class="flex flex-col items-center justify-center py-16 text-slate-400 bg-white rounded-3xl border border-slate-100 border-dashed">
|
||||
<div class="w-16 h-16 bg-slate-50 rounded-full flex items-center justify-center text-3xl mb-4">📭</div>
|
||||
<div class="flex flex-col items-center justify-center py-16 text-slate-400 futuristic-card border-dashed">
|
||||
<div class="w-16 h-16 bg-slate-800/50 rounded-full flex items-center justify-center text-3xl mb-4">📭</div>
|
||||
<div class="font-medium">暂无系统公告</div>
|
||||
</div>` : '';
|
||||
return;
|
||||
@@ -165,8 +165,8 @@ function renderNotifications() {
|
||||
|
||||
if (filtered.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="flex flex-col items-center justify-center py-16 text-slate-400 bg-white rounded-3xl border border-slate-100 border-dashed">
|
||||
<div class="w-16 h-16 bg-slate-50 rounded-full flex items-center justify-center text-3xl mb-4">📭</div>
|
||||
<div class="flex flex-col items-center justify-center py-16 text-slate-400 futuristic-card border-dashed">
|
||||
<div class="w-16 h-16 bg-slate-800/50 rounded-full flex items-center justify-center text-3xl mb-4">📭</div>
|
||||
<div class="font-medium">暂无通知</div>
|
||||
</div>`;
|
||||
return;
|
||||
@@ -177,12 +177,12 @@ function renderNotifications() {
|
||||
const iconBgColor = {
|
||||
'teacher_application': 'bg-purple-100 text-purple-600', 'teacher_result': 'bg-fuchsia-100 text-fuchsia-600',
|
||||
'contest_application': 'bg-orange-100 text-orange-600', 'contest_result': 'bg-amber-100 text-amber-600',
|
||||
'contest_new_exam': 'bg-indigo-100 text-indigo-600', 'exam_graded': 'bg-emerald-100 text-emerald-600',
|
||||
'contest_new_exam': 'bg-indigo-100 text-cyan-400', 'exam_graded': 'bg-emerald-100 text-emerald-600',
|
||||
'system_announcement': 'bg-blue-100 text-blue-600', 'friend_request': 'bg-cyan-100 text-cyan-600'
|
||||
}[n.type] || 'bg-slate-100 text-slate-600';
|
||||
|
||||
return `<div class="bg-white border ${n.read ? 'border-slate-100' : 'border-indigo-200 shadow-md shadow-indigo-100/50 relative'} rounded-2xl p-4 sm:p-5 hover:border-indigo-300 hover:shadow-lg transition-all duration-300 cursor-pointer group" onclick="markSingleRead(${n.id}, this, ${JSON.stringify(n).replace(/"/g, '"')})">
|
||||
${!n.read ? '<div class="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full border-2 border-white animate-pulse"></div>' : ''}
|
||||
return `<div class="futuristic-card ${n.read ? 'border-slate-900/10' : 'border-cyan-500/30 shadow-md shadow-indigo-100/50 relative'} rounded-2xl p-4 sm:p-5 hover:border-cyan-500/50 hover:shadow-lg transition-all duration-300 cursor-pointer group" onclick="markSingleRead(${n.id}, this, ${JSON.stringify(n).replace(/"/g, '"')})">
|
||||
${!n.read ? '<div class="absolute -top-1 -right-1 w-3 h-3 bg-red-500 rounded-full border-2 border-slate-900 animate-pulse"></div>' : ''}
|
||||
<div class="flex items-start gap-4">
|
||||
<div class="w-12 h-12 rounded-2xl ${iconBgColor} flex items-center justify-center text-2xl flex-shrink-0 shadow-inner group-hover:scale-110 group-hover:rotate-6 transition-transform">
|
||||
${getTypeIcon(n.type)}
|
||||
@@ -196,7 +196,7 @@ function renderNotifications() {
|
||||
${n.created_at}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-sm font-medium text-slate-800 leading-relaxed ${!n.read ? 'font-bold' : ''}">${esc(n.content)}</div>
|
||||
<div class="text-sm font-medium text-slate-300 leading-relaxed ${!n.read ? 'font-bold' : ''}">${esc(n.content)}</div>
|
||||
${actions}
|
||||
</div>
|
||||
</div>
|
||||
@@ -208,31 +208,31 @@ function buildActions(n) {
|
||||
if (n.type === 'teacher_application' && n.application_status === 'pending' && n.application_id) {
|
||||
// 管理员显示快捷操作按钮
|
||||
if (currentUser.role === 'admin') {
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-100">
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-900/10">
|
||||
<button onclick="event.stopPropagation();approveTeacherN(${n.application_id})" class="px-4 py-1.5 text-xs font-bold bg-emerald-50 text-emerald-600 border border-emerald-200 rounded-lg hover:bg-emerald-500 hover:text-white hover:border-emerald-500 transition-colors shadow-sm">✅ 同意申请</button>
|
||||
<button onclick="event.stopPropagation();rejectTeacherN(${n.application_id})" class="px-4 py-1.5 text-xs font-bold bg-rose-50 text-rose-600 border border-rose-200 rounded-lg hover:bg-rose-500 hover:text-white hover:border-rose-500 transition-colors shadow-sm">❌ 拒绝申请</button>
|
||||
</div>`;
|
||||
}
|
||||
// 杯赛负责人显示查看按钮
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-100">
|
||||
<a href="/admin/teacher-applications" onclick="event.stopPropagation()" class="px-4 py-1.5 text-xs font-bold bg-indigo-50 text-indigo-600 border border-indigo-200 rounded-lg hover:bg-indigo-500 hover:text-white hover:border-indigo-500 transition-colors shadow-sm">👁️ 查看申请</a>
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-900/10">
|
||||
<a href="/admin/teacher-applications" onclick="event.stopPropagation()" class="px-4 py-1.5 text-xs font-bold bg-indigo-50 text-cyan-400 border border-cyan-500/30 rounded-lg hover:bg-indigo-500 hover:text-white hover:border-indigo-500 transition-colors shadow-sm">👁️ 查看申请</a>
|
||||
</div>`;
|
||||
}
|
||||
if (n.type === 'teacher_application' && n.application_status === 'approved') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-emerald-50 border border-emerald-100 text-emerald-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> 已同意</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
if (n.type === 'teacher_application' && n.application_status === 'rejected') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-rose-50 border border-rose-100 text-rose-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg> 已拒绝</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
if (n.type === 'teacher_application' && n.application_status === 'approved') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-emerald-50 border border-emerald-100 text-emerald-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> 已同意</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-800/50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
if (n.type === 'teacher_application' && n.application_status === 'rejected') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-rose-50 border border-rose-100 text-rose-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg> 已拒绝</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-800/50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
|
||||
if (n.type === 'contest_application' && n.application_status === 'pending' && n.post_id && currentUser.role === 'admin') {
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-100">
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-900/10">
|
||||
<button onclick="event.stopPropagation();approveContestN(${n.post_id})" class="px-4 py-1.5 text-xs font-bold bg-emerald-50 text-emerald-600 border border-emerald-200 rounded-lg hover:bg-emerald-500 hover:text-white hover:border-emerald-500 transition-colors shadow-sm">✅ 同意申请</button>
|
||||
<button onclick="event.stopPropagation();rejectContestN(${n.post_id})" class="px-4 py-1.5 text-xs font-bold bg-rose-50 text-rose-600 border border-rose-200 rounded-lg hover:bg-rose-500 hover:text-white hover:border-rose-500 transition-colors shadow-sm">❌ 拒绝申请</button>
|
||||
</div>`;
|
||||
}
|
||||
if (n.type === 'contest_application' && n.application_status === 'approved') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-emerald-50 border border-emerald-100 text-emerald-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> 已同意</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
if (n.type === 'contest_application' && n.application_status === 'rejected') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-rose-50 border border-rose-100 text-rose-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg> 已拒绝</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
if (n.type === 'contest_application' && n.application_status === 'approved') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-emerald-50 border border-emerald-100 text-emerald-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg> 已同意</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-800/50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
if (n.type === 'contest_application' && n.application_status === 'rejected') return '<div class="mt-3 flex items-center gap-2"><span class="inline-flex items-center gap-1.5 px-3 py-1 bg-rose-50 border border-rose-100 text-rose-600 text-xs font-bold rounded-lg"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg> 已拒绝</span>' + (currentUser.role === 'admin' ? `<button onclick="event.stopPropagation();deleteNotif(${n.id})" class="px-3 py-1 text-xs font-bold bg-slate-800/50 text-slate-500 border border-slate-200 rounded-lg hover:bg-red-50 hover:text-red-600 hover:border-red-200 transition-colors">删除</button>` : '') + '</div>';
|
||||
|
||||
// 好友申请处理
|
||||
if (n.type === 'friend_request' && n.application_status === 'pending' && n.friend_request_id) {
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-100">
|
||||
return `<div class="flex gap-3 mt-4 pt-3 border-t border-slate-900/10">
|
||||
<button onclick="event.stopPropagation();acceptFriendN(${n.friend_request_id})" class="px-4 py-1.5 text-xs font-bold bg-emerald-50 text-emerald-600 border border-emerald-200 rounded-lg hover:bg-emerald-500 hover:text-white hover:border-emerald-500 transition-colors shadow-sm">✅ 同意</button>
|
||||
<button onclick="event.stopPropagation();rejectFriendN(${n.friend_request_id})" class="px-4 py-1.5 text-xs font-bold bg-rose-50 text-rose-600 border border-rose-200 rounded-lg hover:bg-rose-500 hover:text-white hover:border-rose-500 transition-colors shadow-sm">❌ 拒绝</button>
|
||||
</div>`;
|
||||
@@ -242,7 +242,7 @@ function buildActions(n) {
|
||||
// 如果有考试关联的通知,添加快捷入口
|
||||
if (n.type === 'contest_new_exam' || n.type === 'exam_graded') {
|
||||
if(n.post_id) {
|
||||
return `<div class="mt-4 pt-3 border-t border-slate-100"><a href="/exams/${n.post_id}" class="inline-flex items-center gap-1.5 px-4 py-1.5 text-xs font-bold bg-indigo-50 text-indigo-600 border border-indigo-200 rounded-lg hover:bg-indigo-600 hover:text-white hover:border-indigo-600 transition-colors shadow-sm"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"/></svg> 查看考试</a></div>`;
|
||||
return `<div class="mt-4 pt-3 border-t border-slate-900/10"><a href="/exams/${n.post_id}" class="inline-flex items-center gap-1.5 px-4 py-1.5 text-xs font-bold bg-indigo-50 text-cyan-400 border border-cyan-500/30 rounded-lg hover:bg-indigo-600 hover:text-white hover:border-indigo-600 transition-colors shadow-sm"><svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7l5 5m0 0l-5 5m5-5H6"/></svg> 查看考试</a></div>`;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
@@ -304,8 +304,8 @@ async function rejectFriendN(reqId) {
|
||||
function markSingleRead(nid, el, notif) {
|
||||
fetch(`/api/notifications/${nid}/read`, {method:'POST'});
|
||||
// 移除未读的特定样式
|
||||
el.classList.remove('border-indigo-200', 'shadow-md', 'shadow-indigo-100/50');
|
||||
el.classList.add('border-slate-100');
|
||||
el.classList.remove('border-cyan-500/30', 'shadow-md', 'shadow-indigo-100/50');
|
||||
el.classList.add('border-slate-900/10');
|
||||
const content = el.querySelector('.font-bold.leading-relaxed');
|
||||
if(content) content.classList.remove('font-bold');
|
||||
const dot = el.querySelector('.bg-red-500.animate-pulse');
|
||||
|
||||
Reference in New Issue
Block a user