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:
2026-03-03 16:02:23 +08:00
parent 0764566742
commit 9a08140623
30 changed files with 1531 additions and 834 deletions

View File

@@ -2,8 +2,8 @@
{% block title %}个人中心 - 智联青云{% endblock %}
{% block content %}
<div class="max-w-6xl mx-auto space-y-6">
<!-- 顶部横幅与头像:高级游戏化设计 -->
<div class="bg-white rounded-3xl shadow-xl border border-slate-100 overflow-hidden relative group">
<!-- 顶部横幅与头像:科幻未来风格 -->
<div class="futuristic-card-dark overflow-hidden relative group transition-all duration-300 hover:shadow-2xl hover:shadow-cyan-500/20">
<div class="h-48 bg-gradient-to-r from-indigo-600 via-purple-600 to-blue-600 relative overflow-hidden">
<!-- 高级光影动画背景 -->
<div class="absolute inset-0 bg-[url('data:image/svg+xml,%3Csvg width=\'40\' height=\'40\' viewBox=\'0 0 40 40\' xmlns=\'http://www.w3.org/2000/svg\'%3E%3Cpath d=\'M20 20.5V18H0v-2h20v-2H0v-2h20v-2H0V8h20V6H0V4h20V2H0V0h22v20h2V0h2v20h2V0h2v20h2V0h2v20h2V0h2v20h2v2H20v-1.5zM0 20h2v20H0V20zm4 0h2v20H4V20zm4 0h2v20H8V20zm4 0h2v20h-2V20zm4 0h2v20h-2V20zm4 4h20v2H20v-2zm0 4h20v2H20v-2zm0 4h20v2H20v-2zm0 4h20v2H20v-2z\' fill=\'%23ffffff\' fill-opacity=\'0.05\' fill-rule=\'evenodd\'/%3E%3C/svg%3E')] opacity-50"></div>
@@ -13,10 +13,10 @@
<div class="px-6 pb-8 sm:px-12 relative">
<div class="flex flex-col sm:flex-row items-center sm:items-end -mt-20 sm:-mt-24 sm:space-x-8">
<!-- 头像区域(呼吸发光效果 -->
<!-- 头像区域(科幻未来风格 -->
<div class="relative group/avatar">
<div class="absolute inset-0 bg-gradient-to-br from-indigo-500 to-purple-500 rounded-full blur-md opacity-40 group-hover/avatar:opacity-60 animate-pulse transition-opacity"></div>
<div id="avatar-display" class="relative w-36 h-36 rounded-full overflow-hidden border-4 border-white shadow-xl flex items-center justify-center bg-gradient-to-br from-indigo-50 to-blue-50 text-indigo-600 text-5xl font-black cursor-pointer transform group-hover/avatar:scale-105 group-hover/avatar:rotate-3 transition-all duration-300 z-10" onclick="uploadAvatar()">
<div class="absolute inset-0 bg-gradient-to-br from-cyan-500 to-blue-500 rounded-full blur-md opacity-40 group-hover/avatar:opacity-60 animate-pulse transition-opacity"></div>
<div id="avatar-display" class="avatar-futuristic relative w-36 h-36 rounded-full overflow-hidden border-4 border-cyan-400/30 shadow-xl flex items-center justify-center bg-gradient-to-br from-slate-900 to-slate-800 text-cyan-400 text-5xl font-black cursor-pointer transform group-hover/avatar:scale-105 group-hover/avatar:rotate-3 transition-all duration-300 z-10" onclick="uploadAvatar()">
{% if profile_user.avatar %}
<img src="{{ profile_user.avatar }}" class="w-full h-full object-cover" id="avatar-img">
{% else %}
@@ -24,38 +24,38 @@
{% endif %}
</div>
{% if profile_user.id == user.id %}
<div class="absolute bottom-1 right-1 bg-white p-2.5 rounded-full shadow-lg border-2 border-slate-100 cursor-pointer text-slate-500 hover:text-indigo-600 hover:border-indigo-200 transition-all z-20 transform hover:scale-110" onclick="uploadAvatar()">
<div class="absolute bottom-1 right-1 bg-slate-900/90 p-2.5 rounded-full shadow-lg border-2 border-cyan-400/30 cursor-pointer text-cyan-400 hover:text-cyan-300 hover:border-cyan-300 transition-all z-20 transform hover:scale-110" onclick="uploadAvatar()">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
</div>
{% endif %}
<!-- 浮动等级徽章 -->
<div class="absolute -top-2 -right-2 bg-slate-900 text-white text-xs font-black px-3 py-1.5 rounded-full shadow-lg border-2 border-white z-20 transform -rotate-12 group-hover/avatar:rotate-0 transition-transform">
<div class="badge-futuristic absolute -top-2 -right-2 text-xs font-black px-3 py-1.5 rounded-full shadow-lg border-2 border-cyan-400/50 z-20 transform -rotate-12 group-hover/avatar:rotate-0 transition-transform">
Lv.{{ level }}
</div>
</div>
<!-- 个人信息 -->
<div class="mt-5 sm:mt-0 text-center sm:text-left flex-1 pb-2">
<h1 class="text-4xl font-extrabold text-slate-900 flex items-center justify-center sm:justify-start gap-4 tracking-tight drop-shadow-sm">
<h1 class="text-4xl font-extrabold flex items-center justify-center sm:justify-start gap-4 tracking-tight drop-shadow-sm bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent">
{{ get_display_name(profile_user.id, profile_user.name) if profile_user.id == user.id else profile_user.name }}
{% if profile_user.role == 'admin' %}
<span class="px-3 py-1 rounded-xl text-xs font-bold bg-gradient-to-r from-red-500 to-rose-600 text-white shadow-sm shadow-red-200 transform hover:scale-105 transition-transform">管理员</span>
<span class="badge-futuristic px-3 py-1 rounded-xl text-xs font-bold bg-gradient-to-r from-red-500 to-rose-600 text-white shadow-sm shadow-red-200 transform hover:scale-105 transition-transform">管理员</span>
{% elif profile_user.role == 'teacher' %}
<span class="px-3 py-1 rounded-xl text-xs font-bold bg-gradient-to-r from-blue-500 to-indigo-600 text-white shadow-sm shadow-blue-200 transform hover:scale-105 transition-transform flex items-center gap-1">👨‍🏫 认证教师</span>
<span class="badge-futuristic px-3 py-1 rounded-xl text-xs font-bold bg-gradient-to-r from-blue-500 to-indigo-600 text-white shadow-sm shadow-blue-200 transform hover:scale-105 transition-transform flex items-center gap-1">👨‍🏫 认证教师</span>
{% else %}
<span class="px-3 py-1 rounded-xl text-xs font-bold bg-gradient-to-r from-emerald-400 to-teal-500 text-white shadow-sm shadow-emerald-200 transform hover:scale-105 transition-transform flex items-center gap-1">🎓 学生</span>
<span class="badge-futuristic px-3 py-1 rounded-xl text-xs font-bold bg-gradient-to-r from-emerald-400 to-teal-500 text-white shadow-sm shadow-emerald-200 transform hover:scale-105 transition-transform flex items-center gap-1">🎓 学生</span>
{% endif %}
</h1>
<div class="flex flex-wrap items-center justify-center sm:justify-start gap-5 mt-4 text-sm font-medium text-slate-500">
<div class="flex flex-wrap items-center justify-center sm:justify-start gap-5 mt-4 text-sm font-medium text-slate-400">
{% if profile_user.email %}
<span class="flex items-center gap-1.5 bg-slate-50 px-3 py-1.5 rounded-lg border border-slate-100 hover:bg-slate-100 transition-colors"><svg class="w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>{{ profile_user.email }}</span>
<span class="flex items-center gap-1.5 bg-slate-800/50 px-3 py-1.5 rounded-lg border border-cyan-500/30 hover:bg-slate-700/50 transition-colors"><svg class="w-4 h-4 text-cyan-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"/></svg>{{ profile_user.email }}</span>
{% endif %}
{% if profile_user.phone %}
<span class="flex items-center gap-1.5 bg-slate-50 px-3 py-1.5 rounded-lg border border-slate-100 hover:bg-slate-100 transition-colors"><svg class="w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/></svg>{{ profile_user.phone }}</span>
<span class="flex items-center gap-1.5 bg-slate-800/50 px-3 py-1.5 rounded-lg border border-cyan-500/30 hover:bg-slate-700/50 transition-colors"><svg class="w-4 h-4 text-cyan-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 5a2 2 0 012-2h3.28a1 1 0 01.948.684l1.498 4.493a1 1 0 01-.502 1.21l-2.257 1.13a11.042 11.042 0 005.516 5.516l1.13-2.257a1 1 0 011.21-.502l4.493 1.498a1 1 0 01.684.949V19a2 2 0 01-2 2h-1C9.716 21 3 14.284 3 6V5z"/></svg>{{ profile_user.phone }}</span>
{% endif %}
<span class="flex items-center gap-1.5 bg-indigo-50 text-indigo-600 px-3 py-1.5 rounded-lg border border-indigo-100"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>加入于 {{ profile_user.created_at.strftime('%Y-%m-%d') }}</span>
<span class="flex items-center gap-1.5 bg-indigo-500/20 text-indigo-400 px-3 py-1.5 rounded-lg border border-indigo-500/30"><svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"/></svg>加入于 {{ profile_user.created_at.strftime('%Y-%m-%d') }}</span>
</div>
</div>
</div>
@@ -65,21 +65,21 @@
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- 左侧:统计与信息 -->
<div class="space-y-6 lg:col-span-1">
<!-- 游戏化数据统计(Bento 风格) -->
<div class="bg-white rounded-3xl p-6 shadow-sm border border-slate-100 relative overflow-hidden group">
<div class="absolute top-0 right-0 w-32 h-32 bg-indigo-50 rounded-bl-full -z-10 group-hover:scale-110 transition-transform duration-500"></div>
<h3 class="text-xl font-extrabold text-slate-900 mb-5 flex items-center">
<span class="w-8 h-8 bg-indigo-100 text-indigo-600 rounded-xl flex items-center justify-center mr-3 shadow-sm">📊</span>
<!-- 游戏化数据统计(科幻未来风格) -->
<div class="futuristic-card-dark relative overflow-hidden group transition-all duration-300 hover:scale-105">
<div class="absolute top-0 right-0 w-32 h-32 bg-indigo-500/10 rounded-bl-full -z-10 group-hover:scale-110 transition-transform duration-500"></div>
<h3 class="text-xl font-extrabold mb-5 flex items-center bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent">
<span class="w-8 h-8 bg-indigo-500/20 text-indigo-400 rounded-xl flex items-center justify-center mr-3 shadow-sm border border-indigo-500/30">📊</span>
活跃数据
</h3>
<!-- 积分进度条 -->
<div class="mb-6 bg-slate-50 rounded-2xl p-4 border border-slate-100">
<div class="flex justify-between text-xs font-bold text-slate-600 mb-2">
<div class="mb-6 bg-slate-900/50 rounded-2xl p-4 border border-cyan-500/30">
<div class="flex justify-between text-xs font-bold text-slate-400 mb-2">
<span>当前等级进度</span>
<span class="text-indigo-600">{{ points }} / {{ (level * 100) }} XP</span>
<span class="text-indigo-400">{{ points }} / {{ (level * 100) }} XP</span>
</div>
<div class="h-3 w-full bg-slate-200 rounded-full overflow-hidden shadow-inner relative">
<div class="h-3 w-full bg-slate-800/50 rounded-full overflow-hidden shadow-inner relative border border-cyan-500/30">
{% set progress = (points / (level * 100) * 100) | int %}
{% set p_width = progress if progress <= 100 else 100 %}
<div class="absolute top-0 left-0 h-full bg-gradient-to-r from-indigo-500 to-purple-500 rounded-full transition-all duration-1000 ease-out overflow-hidden" style="width: {{ p_width }}%;">
@@ -89,56 +89,56 @@
</div>
<div class="grid grid-cols-2 gap-4">
<div class="bg-gradient-to-br from-indigo-50 to-blue-50 rounded-2xl p-4 text-center border border-indigo-100/50 hover:shadow-md hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-indigo-600 drop-shadow-sm">{{ points }}</div>
<div class="text-[11px] font-bold text-indigo-400 uppercase tracking-widest mt-1">总积分</div>
<div class="bg-gradient-to-br from-indigo-500/20 to-blue-500/20 rounded-2xl p-4 text-center border border-indigo-500/30 hover:shadow-md hover:shadow-indigo-500/20 hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-indigo-400 drop-shadow-sm">{{ points }}</div>
<div class="text-[11px] font-bold text-indigo-300 uppercase tracking-widest mt-1">总积分</div>
</div>
<div class="bg-gradient-to-br from-emerald-50 to-teal-50 rounded-2xl p-4 text-center border border-emerald-100/50 hover:shadow-md hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-emerald-600 drop-shadow-sm">{{ post_count }}</div>
<div class="text-[11px] font-bold text-emerald-500 uppercase tracking-widest mt-1">发帖数</div>
<div class="bg-gradient-to-br from-emerald-500/20 to-teal-500/20 rounded-2xl p-4 text-center border border-emerald-500/30 hover:shadow-md hover:shadow-emerald-500/20 hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-emerald-400 drop-shadow-sm">{{ post_count }}</div>
<div class="text-[11px] font-bold text-emerald-300 uppercase tracking-widest mt-1">发帖数</div>
</div>
<div class="bg-gradient-to-br from-amber-50 to-orange-50 rounded-2xl p-4 text-center border border-amber-100/50 hover:shadow-md hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-amber-600 drop-shadow-sm">{{ reply_count }}</div>
<div class="text-[11px] font-bold text-amber-500 uppercase tracking-widest mt-1">回复数</div>
<div class="bg-gradient-to-br from-amber-500/20 to-orange-500/20 rounded-2xl p-4 text-center border border-amber-500/30 hover:shadow-md hover:shadow-amber-500/20 hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-amber-400 drop-shadow-sm">{{ reply_count }}</div>
<div class="text-[11px] font-bold text-amber-300 uppercase tracking-widest mt-1">回复数</div>
</div>
<div class="bg-gradient-to-br from-rose-50 to-pink-50 rounded-2xl p-4 text-center border border-rose-100/50 hover:shadow-md hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-rose-500 drop-shadow-sm">{{ likes_received }}</div>
<div class="text-[11px] font-bold text-rose-400 uppercase tracking-widest mt-1">获赞数</div>
<div class="bg-gradient-to-br from-rose-500/20 to-pink-500/20 rounded-2xl p-4 text-center border border-rose-500/30 hover:shadow-md hover:shadow-rose-500/20 hover:-translate-y-1 transition-all duration-300">
<div class="text-3xl font-black text-rose-400 drop-shadow-sm">{{ likes_received }}</div>
<div class="text-[11px] font-bold text-rose-300 uppercase tracking-widest mt-1">获赞数</div>
</div>
</div>
</div>
<!-- 账号设置 -->
{% if profile_user.id == user.id %}
<div class="bg-white rounded-2xl p-6 shadow-sm border border-slate-100">
<h3 class="text-lg font-bold text-slate-900 mb-4 flex items-center">
<svg class="w-5 h-5 mr-2 text-primary" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
<div class="futuristic-card-dark transition-all duration-300 hover:scale-105">
<h3 class="text-lg font-bold mb-4 flex items-center bg-gradient-to-r from-blue-600 via-purple-600 to-pink-600 bg-clip-text text-transparent">
<svg class="w-5 h-5 mr-2 text-cyan-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/></svg>
账号设置
</h3>
<div class="space-y-4">
<div class="flex items-center justify-between p-3 bg-slate-50 rounded-xl">
<div class="flex items-center justify-between p-3 bg-slate-900/50 rounded-xl border border-cyan-500/30">
<div>
<div class="text-sm font-medium text-slate-900">用户名</div>
<div class="text-xs text-slate-500 mt-0.5" id="display-username">{{ profile_user.name }}</div>
<div class="text-sm font-medium text-slate-200">用户名</div>
<div class="text-xs text-slate-400 mt-0.5" id="display-username">{{ profile_user.name }}</div>
</div>
<button onclick="changeName()" class="px-3 py-1.5 text-xs font-medium text-primary bg-blue-50 hover:bg-blue-100 rounded-lg transition-colors">修改</button>
<button onclick="changeName()" class="btn-futuristic px-3 py-1.5 text-xs font-medium rounded-lg transition-colors">修改</button>
</div>
{% if user.role == 'student' %}
<a href="/apply-teacher" class="flex items-center justify-between p-3 bg-slate-50 rounded-xl hover:bg-slate-100 transition-colors group">
<a href="/apply-teacher" class="flex items-center justify-between p-3 bg-slate-900/50 rounded-xl hover:bg-slate-800/50 border border-blue-500/30 hover:border-blue-500/50 transition-all group">
<div>
<div class="text-sm font-medium text-slate-900 group-hover:text-primary transition-colors">申请成为老师</div>
<div class="text-xs text-slate-500 mt-0.5">获取发布赛事和考试的权限</div>
<div class="text-sm font-medium text-slate-200 group-hover:text-cyan-400 transition-colors">申请成为老师</div>
<div class="text-xs text-slate-400 mt-0.5">获取发布赛事和考试的权限</div>
</div>
<svg class="w-5 h-5 text-slate-400 group-hover:text-primary transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
<svg class="w-5 h-5 text-slate-400 group-hover: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="M9 5l7 7-7 7"/></svg>
</a>
{% endif %}
{% if user.role == 'admin' or user.role == 'teacher' %}
<a href="/admin" class="flex items-center justify-between p-3 bg-slate-50 rounded-xl hover:bg-slate-100 transition-colors group">
<a href="/admin" class="flex items-center justify-between p-3 bg-slate-900/50 rounded-xl hover:bg-slate-800/50 border border-purple-500/30 hover:border-purple-500/50 transition-all group">
<div>
<div class="text-sm font-medium text-slate-900 group-hover:text-primary transition-colors">进入管理后台</div>
<div class="text-xs text-slate-500 mt-0.5">管理系统各项数据</div>
<div class="text-sm font-medium text-slate-200 group-hover:text-cyan-400 transition-colors">进入管理后台</div>
<div class="text-xs text-slate-400 mt-0.5">管理系统各项数据</div>
</div>
<svg class="w-5 h-5 text-slate-400 group-hover:text-primary transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
<svg class="w-5 h-5 text-slate-400 group-hover: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="M9 5l7 7-7 7"/></svg>
</a>
{% endif %}
</div>
@@ -148,45 +148,45 @@
<!-- 右侧:主要内容 -->
<div class="space-y-6 lg:col-span-2">
<!-- 快捷入口(玻璃拟物化卡片 -->
<!-- 快捷入口(科幻未来风格 -->
{% if profile_user.id == user.id %}
<div class="grid grid-cols-2 sm:grid-cols-4 gap-4">
<a href="/notifications" class="bg-white rounded-2xl p-5 shadow-sm border border-slate-100 hover:shadow-lg hover:border-blue-200 hover:-translate-y-1 transition-all duration-300 text-center group">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-blue-100 to-indigo-100 rounded-2xl flex items-center justify-center text-blue-600 shadow-inner group-hover:scale-110 group-hover:rotate-6 transition-transform mb-3">
<a href="/notifications" class="futuristic-card-dark text-center group transition-all duration-300 hover:scale-105">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-cyan-500/20 to-blue-500/20 rounded-2xl flex items-center justify-center text-cyan-400 shadow-inner group-hover:scale-110 group-hover:rotate-6 transition-transform mb-3 border border-cyan-500/30">
<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 class="text-sm font-bold text-slate-700 group-hover:text-blue-600 transition-colors">通知中心</div>
<div class="text-sm font-bold text-slate-300 group-hover:text-cyan-400 transition-colors">通知中心</div>
</a>
<a href="/chat" class="bg-white rounded-2xl p-5 shadow-sm border border-slate-100 hover:shadow-lg hover:border-emerald-200 hover:-translate-y-1 transition-all duration-300 text-center group">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-emerald-100 to-teal-100 rounded-2xl flex items-center justify-center text-emerald-600 shadow-inner group-hover:scale-110 group-hover:-rotate-6 transition-transform mb-3">
<a href="/chat" class="futuristic-card-dark text-center group transition-all duration-300 hover:scale-105">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-emerald-500/20 to-teal-500/20 rounded-2xl flex items-center justify-center text-emerald-400 shadow-inner group-hover:scale-110 group-hover:-rotate-6 transition-transform mb-3 border border-emerald-500/30">
<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="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"/></svg>
</div>
<div class="text-sm font-bold text-slate-700 group-hover:text-emerald-600 transition-colors">我的消息</div>
<div class="text-sm font-bold text-slate-300 group-hover:text-emerald-400 transition-colors">我的消息</div>
</a>
<div class="bg-white rounded-2xl p-5 shadow-sm border border-slate-100 hover:shadow-lg hover:border-purple-200 hover:-translate-y-1 transition-all duration-300 text-center group cursor-pointer" onclick="document.getElementById('exam-history-tab').scrollIntoView({behavior:'smooth'})">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-purple-100 to-fuchsia-100 rounded-2xl flex items-center justify-center text-purple-600 shadow-inner group-hover:scale-110 group-hover:rotate-6 transition-transform mb-3">
<div class="futuristic-card-dark text-center group cursor-pointer transition-all duration-300 hover:scale-105" onclick="document.getElementById('exam-history-tab').scrollIntoView({behavior:'smooth'})">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-purple-500/20 to-fuchsia-500/20 rounded-2xl flex items-center justify-center text-purple-400 shadow-inner group-hover:scale-110 group-hover:rotate-6 transition-transform mb-3 border border-purple-500/30">
<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="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/></svg>
</div>
<div class="text-sm font-bold text-slate-700 group-hover:text-purple-600 transition-colors">考试记录</div>
<div class="text-sm font-bold text-slate-300 group-hover:text-purple-400 transition-colors">考试记录</div>
</div>
<div class="bg-white rounded-2xl p-5 shadow-sm border border-slate-100 hover:shadow-lg hover:border-amber-200 hover:-translate-y-1 transition-all duration-300 text-center group cursor-pointer" onclick="document.getElementById('bookmarks-tab').scrollIntoView({behavior:'smooth'})">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-amber-100 to-orange-100 rounded-2xl flex items-center justify-center text-amber-600 shadow-inner group-hover:scale-110 group-hover:-rotate-6 transition-transform mb-3">
<div class="futuristic-card-dark text-center group cursor-pointer transition-all duration-300 hover:scale-105" onclick="document.getElementById('bookmarks-tab').scrollIntoView({behavior:'smooth'})">
<div class="w-12 h-12 mx-auto bg-gradient-to-br from-amber-500/20 to-orange-500/20 rounded-2xl flex items-center justify-center text-amber-400 shadow-inner group-hover:scale-110 group-hover:-rotate-6 transition-transform mb-3 border border-amber-500/30">
<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="M5 5a2 2 0 012-2h10a2 2 0 012 2v16l-7-3.5L5 21V5z"/></svg>
</div>
<div class="text-sm font-bold text-slate-700 group-hover:text-amber-600 transition-colors">我的收藏</div>
<div class="text-sm font-bold text-slate-300 group-hover:text-amber-400 transition-colors">我的收藏</div>
</div>
</div>
{% endif %}
<!-- 高级选项卡内容区 -->
<div class="bg-white shadow-sm rounded-3xl border border-slate-100 overflow-hidden">
<!-- 游戏化标签栏 -->
<div class="p-2 bg-slate-50/80 border-b border-slate-100">
<div class="futuristic-card-dark overflow-hidden">
<!-- 科幻未来标签栏 -->
<div class="p-2 bg-slate-900/50 border-b border-cyan-500/20">
<div class="flex gap-2 overflow-x-auto hide-scrollbar">
<button class="flex-1 min-w-[120px] px-6 py-3.5 text-sm font-bold text-indigo-600 bg-white rounded-xl shadow-sm transition-all duration-300 whitespace-nowrap" id="tab-btn-history" onclick="switchTab('history')">📜 考试经历</button>
<button class="flex-1 min-w-[120px] px-6 py-3.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-white/60 bg-transparent rounded-xl transition-all duration-300 whitespace-nowrap" id="tab-btn-posts" onclick="switchTab('posts')">📝 我的帖子</button>
<button class="flex-1 min-w-[120px] px-6 py-3.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-white/60 bg-transparent rounded-xl transition-all duration-300 whitespace-nowrap" id="tab-btn-bookmarks" onclick="switchTab('bookmarks')">⭐ 收藏试卷</button>
<button class="flex-1 min-w-[120px] px-6 py-3.5 text-sm font-medium text-slate-500 hover:text-slate-800 hover:bg-white/60 bg-transparent rounded-xl transition-all duration-300 whitespace-nowrap" id="tab-btn-friends" onclick="switchTab('friends')">👥 好友列表</button>
<button class="btn-futuristic flex-1 min-w-[120px] px-6 py-3.5 text-sm font-bold rounded-xl shadow-sm transition-all duration-300 whitespace-nowrap" id="tab-btn-history" onclick="switchTab('history')">📜 考试经历</button>
<button class="btn-outline-futuristic flex-1 min-w-[120px] px-6 py-3.5 text-sm font-medium rounded-xl transition-all duration-300 whitespace-nowrap" id="tab-btn-posts" onclick="switchTab('posts')">📝 我的帖子</button>
<button class="btn-outline-futuristic flex-1 min-w-[120px] px-6 py-3.5 text-sm font-medium rounded-xl transition-all duration-300 whitespace-nowrap" id="tab-btn-bookmarks" onclick="switchTab('bookmarks')">⭐ 收藏试卷</button>
<button class="btn-outline-futuristic flex-1 min-w-[120px] px-6 py-3.5 text-sm font-medium rounded-xl transition-all duration-300 whitespace-nowrap" id="tab-btn-friends" onclick="switchTab('friends')">👥 好友列表</button>
</div>
</div>
@@ -219,7 +219,7 @@
<h4 class="text-sm font-bold text-slate-700">搜索用户</h4>
<div class="flex gap-2">
<input id="friend-search-input" type="text" placeholder="输入用户名搜索..." class="flex-1 px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary/30 focus:border-primary">
<button onclick="searchUsers()" class="px-4 py-2 bg-primary text-white text-sm rounded-lg hover:bg-blue-600 transition-colors">搜索</button>
<button onclick="searchUsers()" class="btn-futuristic px-4 py-2 text-sm rounded-lg transition-colors">搜索</button>
</div>
<div id="search-results"></div>
</div>
@@ -290,7 +290,7 @@ async function loadFriends() {
<div class="text-sm font-medium text-slate-900 truncate">${f.name}</div>
<div class="text-xs text-slate-400">好友 · ${f.created_at}</div>
</div>
<a href="/chat?dm=${f.id}" class="px-3 py-1.5 text-xs bg-primary/10 text-primary rounded-lg hover:bg-primary/20 transition-colors font-medium">私聊</a>
<a href="/chat?dm=${f.id}" class="btn-futuristic px-3 py-1.5 text-xs rounded-lg transition-colors font-medium">私聊</a>
</div>`;
});
container.innerHTML = html;
@@ -319,7 +319,7 @@ async function searchUsers() {
} else if (u.friend_status === 'pending') {
actionBtn = '<span class="text-xs text-amber-600 font-medium">已申请</span>';
} else {
actionBtn = `<button onclick="addFriend(${u.id}, this)" class="px-3 py-1 text-xs bg-primary text-white rounded-lg hover:bg-blue-600 transition-colors">加好友</button>`;
actionBtn = `<button onclick="addFriend(${u.id}, this)" class="btn-futuristic px-3 py-1 text-xs rounded-lg transition-colors">加好友</button>`;
}
html += `
<div class="flex items-center space-x-3 p-2 rounded-lg hover:bg-white transition-colors">
@@ -362,8 +362,8 @@ async function loadFriendRequests() {
${r.avatar ? `<img src="${r.avatar}" class="w-full h-full object-cover">` : r.name.charAt(0).toUpperCase()}
</div>
<div class="flex-1 min-w-0"><div class="text-sm font-medium text-slate-800 truncate">${r.name}</div></div>
<button onclick="acceptFriend(${r.id})" class="px-2.5 py-1 text-xs bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors">同意</button>
<button onclick="rejectFriend(${r.id})" class="px-2.5 py-1 text-xs bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors">拒绝</button>
<button onclick="acceptFriend(${r.id})" class="btn-futuristic px-2.5 py-1 text-xs rounded-lg transition-colors">同意</button>
<button onclick="rejectFriend(${r.id})" class="btn-outline-futuristic px-2.5 py-1 text-xs rounded-lg transition-colors">拒绝</button>
</div>`;
});
container.innerHTML = html;
@@ -500,14 +500,14 @@ function switchTab(tabName) {
content.classList.add('hidden');
content.style.animation = 'none';
}
const btn = document.getElementById(`tab-btn-${t}`);
if(btn) {
btn.classList.remove('text-indigo-600', 'bg-white', 'shadow-sm', 'font-bold');
btn.classList.add('text-slate-500', 'bg-transparent', 'hover:bg-white/60', 'font-medium');
btn.classList.remove('btn-futuristic');
btn.classList.add('btn-outline-futuristic');
}
});
// 显示选中内容并添加动画
const activeContent = document.getElementById(`tab-content-${tabName}`);
if(activeContent) {
@@ -515,12 +515,12 @@ function switchTab(tabName) {
void activeContent.offsetWidth; // 触发重绘
activeContent.style.animation = 'fadeIn 0.3s ease-out';
}
// 激活按钮样式
const activeBtn = document.getElementById(`tab-btn-${tabName}`);
if(activeBtn) {
activeBtn.classList.remove('text-slate-500', 'bg-transparent', 'hover:bg-white/60', 'font-medium');
activeBtn.classList.add('text-indigo-600', 'bg-white', 'shadow-sm', 'font-bold');
activeBtn.classList.remove('btn-outline-futuristic');
activeBtn.classList.add('btn-futuristic');
}
}