Complete project files including setup.sh
This commit is contained in:
43
templates/admin/create_admin.html
Normal file
43
templates/admin/create_admin.html
Normal file
@@ -0,0 +1,43 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}创建管理员 - 管理面板{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container admin-container">
|
||||
<div class="page-header">
|
||||
<h1>👤 创建新管理员</h1>
|
||||
<a href="{{ url_for('admin.dashboard') }}" class="btn btn-secondary">返回面板</a>
|
||||
</div>
|
||||
|
||||
<div class="auth-card" style="max-width: 600px; margin: 0 auto;">
|
||||
<form method="POST" class="auth-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" id="username" name="username" required placeholder="请输入用户名" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">邮箱</label>
|
||||
<input type="email" id="email" name="email" required placeholder="请输入邮箱" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" id="password" name="password" required placeholder="至少6位" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required placeholder="再次输入密码"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>提示:</strong>新管理员将拥有完整的管理权限,包括审核用户、帖子和创建其他管理员。</p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block">创建管理员</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
49
templates/admin/dashboard.html
Normal file
49
templates/admin/dashboard.html
Normal file
@@ -0,0 +1,49 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}管理面板 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container admin-container">
|
||||
<div class="page-header">
|
||||
<h1>🛡️ 管理面板</h1>
|
||||
</div>
|
||||
|
||||
<div class="admin-stats">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">👥</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-number">{{ pending_users }}</div>
|
||||
<div class="stat-label">待审核用户</div>
|
||||
</div>
|
||||
<a href="{{ url_for('admin.users') }}" class="stat-link">查看</a>
|
||||
</div>
|
||||
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">📝</div>
|
||||
<div class="stat-info">
|
||||
<div class="stat-number">{{ pending_posts }}</div>
|
||||
<div class="stat-label">待审核帖子</div>
|
||||
</div>
|
||||
<a href="{{ url_for('admin.posts') }}" class="stat-link">查看</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-quick-links">
|
||||
<h2>快速链接</h2>
|
||||
<div class="quick-links-grid">
|
||||
<a href="{{ url_for('admin.users') }}" class="quick-link-card">
|
||||
<span class="quick-link-icon">👤</span>
|
||||
<span class="quick-link-text">用户审核</span>
|
||||
</a>
|
||||
<a href="{{ url_for('admin.posts') }}" class="quick-link-card">
|
||||
<span class="quick-link-icon">📸</span>
|
||||
<span class="quick-link-text">帖子审核</span>
|
||||
</a>
|
||||
<a href="{{ url_for('admin.create_admin') }}" class="quick-link-card">
|
||||
<span class="quick-link-icon">➕</span>
|
||||
<span class="quick-link-text">创建管理员</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
84
templates/admin/posts.html
Normal file
84
templates/admin/posts.html
Normal file
@@ -0,0 +1,84 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}帖子审核 - 管理面板{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container admin-container">
|
||||
<div class="page-header">
|
||||
<h1>📝 帖子审核</h1>
|
||||
<a href="{{ url_for('admin.dashboard') }}" class="btn btn-secondary">返回面板</a>
|
||||
</div>
|
||||
|
||||
<!-- Pending Posts -->
|
||||
<section class="admin-section">
|
||||
<h2 class="section-title">待审核帖子 ({{ pending_posts|length }})</h2>
|
||||
|
||||
{% if pending_posts %}
|
||||
<div class="admin-posts-grid">
|
||||
{% for post in pending_posts %}
|
||||
<div class="admin-post-card">
|
||||
<img src="{{ url_for('uploaded_file', filename=post.image_path) }}" alt="Post image"
|
||||
class="admin-post-image">
|
||||
|
||||
<div class="admin-post-info">
|
||||
<div class="admin-post-author">
|
||||
<a href="{{ url_for('users.profile', username=post.author.username) }}">
|
||||
{{ post.author.username }}
|
||||
</a>
|
||||
<span class="post-time">{{ post.created_at.strftime('%Y-%m-%d %H:%M') }}</span>
|
||||
</div>
|
||||
|
||||
{% if post.description %}
|
||||
<div class="admin-post-description">
|
||||
{{ post.description }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="admin-actions">
|
||||
<form method="POST" action="{{ url_for('admin.approve_post', post_id=post.id) }}"
|
||||
style="display: inline;">
|
||||
<button type="submit" class="btn btn-success">✓ 批准</button>
|
||||
</form>
|
||||
<form method="POST" action="{{ url_for('admin.reject_post', post_id=post.id) }}"
|
||||
style="display: inline;" onsubmit="return confirm('确定要拒绝该帖子吗?');">
|
||||
<button type="submit" class="btn btn-danger">✗ 拒绝</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>暂无待审核帖子</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<!-- Recently Approved Posts -->
|
||||
<section class="admin-section">
|
||||
<h2 class="section-title">最近批准的帖子</h2>
|
||||
|
||||
{% if approved_posts %}
|
||||
<div class="posts-grid">
|
||||
{% for post in approved_posts %}
|
||||
<div class="post-card">
|
||||
<a href="{{ url_for('posts.post_detail', post_id=post.id) }}" class="post-image-link">
|
||||
<img src="{{ url_for('uploaded_file', filename=post.image_path) }}" alt="Post image"
|
||||
class="post-image" loading="lazy">
|
||||
</a>
|
||||
<div class="post-footer">
|
||||
<span>{{ post.author.username }}</span>
|
||||
<span class="badge badge-success">已批准</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>暂无已批准帖子</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
85
templates/admin/users.html
Normal file
85
templates/admin/users.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}用户审核 - 管理面板{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container admin-container">
|
||||
<div class="page-header">
|
||||
<h1>👥 用户审核</h1>
|
||||
<a href="{{ url_for('admin.dashboard') }}" class="btn btn-secondary">返回面板</a>
|
||||
</div>
|
||||
|
||||
<!-- Pending Users -->
|
||||
<section class="admin-section">
|
||||
<h2 class="section-title">待审核用户 ({{ pending_users|length }})</h2>
|
||||
|
||||
{% if pending_users %}
|
||||
<div class="admin-list">
|
||||
{% for user in pending_users %}
|
||||
<div class="admin-item">
|
||||
<div class="admin-item-header">
|
||||
<div class="user-info">
|
||||
<div class="user-avatar">{{ user.username[0].upper() }}</div>
|
||||
<div>
|
||||
<div class="username">{{ user.username }}</div>
|
||||
<div class="user-email">{{ user.email }}</div>
|
||||
<div class="user-time">注册于 {{ user.created_at.strftime('%Y-%m-%d %H:%M') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Student ID Photo -->
|
||||
<div class="student-id-preview">
|
||||
<p><strong>学生证照片:</strong></p>
|
||||
<img src="{{ url_for('uploaded_file', filename=user.student_id_photo) }}" alt="Student ID"
|
||||
class="student-id-image">
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="admin-actions">
|
||||
<form method="POST" action="{{ url_for('admin.approve_user', user_id=user.id) }}"
|
||||
style="display: inline;">
|
||||
<button type="submit" class="btn btn-success">✓ 批准</button>
|
||||
</form>
|
||||
<form method="POST" action="{{ url_for('admin.reject_user', user_id=user.id) }}"
|
||||
style="display: inline;" onsubmit="return confirm('确定要拒绝该用户的注册吗?');">
|
||||
<button type="submit" class="btn btn-danger">✗ 拒绝</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>暂无待审核用户</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<!-- Recently Approved Users -->
|
||||
<section class="admin-section">
|
||||
<h2 class="section-title">最近批准的用户</h2>
|
||||
|
||||
{% if approved_users %}
|
||||
<div class="users-list">
|
||||
{% for user in approved_users %}
|
||||
<div class="user-list-item">
|
||||
<div class="user-avatar">{{ user.username[0].upper() }}</div>
|
||||
<div class="user-list-info">
|
||||
<a href="{{ url_for('users.profile', username=user.username) }}" class="username">
|
||||
{{ user.username }}
|
||||
</a>
|
||||
<p class="user-stats">{{ user.email }} · 加入于 {{ user.created_at.strftime('%Y-%m-%d') }}</p>
|
||||
</div>
|
||||
<span class="badge badge-success">已批准</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>暂无已批准用户</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
67
templates/base.html
Normal file
67
templates/base.html
Normal file
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}泸州高中摄影社论坛{% endblock %}</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<!-- 导航栏 -->
|
||||
<nav class="navbar">
|
||||
<div class="container">
|
||||
<div class="nav-brand">
|
||||
<a href="{{ url_for('posts.index') }}">📷 泸州高中摄影社</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-menu">
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="{{ url_for('posts.index') }}" class="nav-link">首页</a>
|
||||
<a href="{{ url_for('posts.create_post') }}" class="nav-link">发帖</a>
|
||||
<a href="{{ url_for('users.profile', username=current_user.username) }}" class="nav-link">我的主页</a>
|
||||
{% if current_user.is_admin %}
|
||||
<a href="{{ url_for('admin.dashboard') }}" class="nav-link admin">管理面板</a>
|
||||
{% endif %}
|
||||
<a href="{{ url_for('auth.logout') }}" class="nav-link">退出</a>
|
||||
<span class="nav-user">@{{ current_user.username }}</span>
|
||||
{% else %}
|
||||
<a href="{{ url_for('posts.index') }}" class="nav-link">首页</a>
|
||||
<a href="{{ url_for('auth.login') }}" class="nav-link">登录</a>
|
||||
<a href="{{ url_for('auth.register') }}" class="nav-link btn-primary">注册</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Flash 消息 -->
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<div class="flash-container">
|
||||
{% for category, message in messages %}
|
||||
<div class="flash flash-{{ category }}">
|
||||
{{ message }}
|
||||
<button class="flash-close" onclick="this.parentElement.remove()">×</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- 主内容 -->
|
||||
<main class="main-content">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- 页脚 -->
|
||||
<footer class="footer">
|
||||
<div class="container">
|
||||
<p>© 2026 泸州高中摄影社 | 分享精彩瞬间</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
40
templates/change_password.html
Normal file
40
templates/change_password.html
Normal file
@@ -0,0 +1,40 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}修改密码 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="auth-container">
|
||||
<div class="auth-card">
|
||||
<div class="auth-header">
|
||||
<h1>🔐 修改密码</h1>
|
||||
{% if current_user.is_admin and not current_user.password_changed %}
|
||||
<p style="color: var(--warning-color);">首次登录,请修改默认密码以确保账号安全</p>
|
||||
{% else %}
|
||||
<p>修改您的登录密码</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form method="POST" class="auth-form">
|
||||
<div class="form-group">
|
||||
<label for="current_password">当前密码</label>
|
||||
<input type="password" id="current_password" name="current_password" required placeholder="请输入当前密码"
|
||||
class="form-control" autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="new_password">新密码</label>
|
||||
<input type="password" id="new_password" name="new_password" required placeholder="至少6位"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认新密码</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required placeholder="再次输入新密码"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block">确认修改</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
44
templates/create_post.html
Normal file
44
templates/create_post.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}发布作品 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container create-post-container">
|
||||
<div class="page-header">
|
||||
<h1>📸 发布摄影作品</h1>
|
||||
<p class="subtitle">分享你的精彩瞬间</p>
|
||||
</div>
|
||||
|
||||
<div class="create-post-card">
|
||||
<form method="POST" enctype="multipart/form-data" class="create-post-form">
|
||||
<div class="form-group">
|
||||
<label for="image">照片 <span class="required">*</span></label>
|
||||
<div class="file-upload-area large" id="postImageUploadArea">
|
||||
<input type="file" id="image" name="image" accept="image/*" required class="file-input">
|
||||
<div class="file-upload-text">
|
||||
<span class="upload-icon">🖼️</span>
|
||||
<p>点击或拖拽上传照片</p>
|
||||
<p class="file-hint">支持 PNG, JPG, JPEG, GIF, WEBP(最大 16MB)</p>
|
||||
</div>
|
||||
<img id="postImagePreview" class="image-preview large" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">描述</label>
|
||||
<textarea id="description" name="description" rows="5" placeholder="说说这张照片的故事..."
|
||||
class="form-control"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>提示:</strong>您的作品将在管理员审核通过后展示给所有用户。</p>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<a href="{{ url_for('posts.index') }}" class="btn btn-secondary">取消</a>
|
||||
<button type="submit" class="btn btn-primary">发布作品</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
15
templates/errors/404.html
Normal file
15
templates/errors/404.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}页面未找到 - 404{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">🔍</div>
|
||||
<h1 style="font-size: 3rem; margin-bottom: 1rem;">404</h1>
|
||||
<h2>页面未找到</h2>
|
||||
<p>抱歉,您访问的页面不存在。</p>
|
||||
<a href="{{ url_for('posts.index') }}" class="btn btn-primary" style="margin-top: 2rem;">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
15
templates/errors/500.html
Normal file
15
templates/errors/500.html
Normal file
@@ -0,0 +1,15 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}服务器错误 - 500{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">⚠️</div>
|
||||
<h1 style="font-size: 3rem; margin-bottom: 1rem;">500</h1>
|
||||
<h2>服务器内部错误</h2>
|
||||
<p>抱歉,服务器遇到了一个错误。我们会尽快修复。</p>
|
||||
<a href="{{ url_for('posts.index') }}" class="btn btn-primary" style="margin-top: 2rem;">返回首页</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
34
templates/followers.html
Normal file
34
templates/followers.html
Normal file
@@ -0,0 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ user.username }} 的粉丝 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>{{ user.username }} 的粉丝</h1>
|
||||
<a href="{{ url_for('users.profile', username=user.username) }}" class="btn btn-secondary">返回主页</a>
|
||||
</div>
|
||||
|
||||
{% if followers %}
|
||||
<div class="users-list">
|
||||
{% for follower in followers %}
|
||||
<div class="user-list-item">
|
||||
<a href="{{ url_for('users.profile', username=follower.username) }}" class="user-avatar">
|
||||
{{ follower.username[0].upper() }}
|
||||
</a>
|
||||
<div class="user-list-info">
|
||||
<a href="{{ url_for('users.profile', username=follower.username) }}" class="username">
|
||||
{{ follower.username }}
|
||||
</a>
|
||||
<p class="user-stats">{{ follower.get_follower_count() }} 粉丝 · {{ follower.posts.count() }} 作品</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>还没有粉丝</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
35
templates/following.html
Normal file
35
templates/following.html
Normal file
@@ -0,0 +1,35 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ user.username }} 关注的人 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>{{ user.username }} 关注的人</h1>
|
||||
<a href="{{ url_for('users.profile', username=user.username) }}" class="btn btn-secondary">返回主页</a>
|
||||
</div>
|
||||
|
||||
{% if following %}
|
||||
<div class="users-list">
|
||||
{% for followed_user in following %}
|
||||
<div class="user-list-item">
|
||||
<a href="{{ url_for('users.profile', username=followed_user.username) }}" class="user-avatar">
|
||||
{{ followed_user.username[0].upper() }}
|
||||
</a>
|
||||
<div class="user-list-info">
|
||||
<a href="{{ url_for('users.profile', username=followed_user.username) }}" class="username">
|
||||
{{ followed_user.username }}
|
||||
</a>
|
||||
<p class="user-stats">{{ followed_user.get_follower_count() }} 粉丝 · {{ followed_user.posts.count() }} 作品
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<p>还没有关注任何人</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
87
templates/index.html
Normal file
87
templates/index.html
Normal file
@@ -0,0 +1,87 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}首页 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div class="page-header">
|
||||
<h1>📸 摄影作品分享</h1>
|
||||
<p class="subtitle">发现精彩瞬间</p>
|
||||
</div>
|
||||
|
||||
{% if posts %}
|
||||
<div class="posts-grid">
|
||||
{% for post in posts %}
|
||||
<div class="post-card">
|
||||
<div class="post-header">
|
||||
<div class="user-info">
|
||||
<a href="{{ url_for('users.profile', username=post.author.username) }}" class="user-avatar">
|
||||
{{ post.author.username[0].upper() }}
|
||||
</a>
|
||||
<div>
|
||||
<a href="{{ url_for('users.profile', username=post.author.username) }}" class="username">
|
||||
{{ post.author.username }}
|
||||
</a>
|
||||
<span class="post-time">{{ post.created_at.strftime('%Y-%m-%d %H:%M') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a href="{{ url_for('posts.post_detail', post_id=post.id) }}" class="post-image-link">
|
||||
<img src="{{ url_for('uploaded_file', filename=post.image_path) }}" alt="Post image" class="post-image"
|
||||
loading="lazy">
|
||||
</a>
|
||||
|
||||
{% if post.description %}
|
||||
<div class="post-description">
|
||||
{{ post.description }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="post-footer">
|
||||
<a href="{{ url_for('posts.post_detail', post_id=post.id) }}" class="comment-count">
|
||||
💬 {{ post.get_comment_count() }} 条评论
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
{% if pagination.pages > 1 %}
|
||||
<div class="pagination">
|
||||
{% if pagination.has_prev %}
|
||||
<a href="{{ url_for('posts.index', page=pagination.prev_num) }}" class="page-link">上一页</a>
|
||||
{% endif %}
|
||||
|
||||
{% for page_num in pagination.iter_pages(left_edge=1, right_edge=1, left_current=2, right_current=2) %}
|
||||
{% if page_num %}
|
||||
{% if page_num == pagination.page %}
|
||||
<span class="page-link active">{{ page_num }}</span>
|
||||
{% else %}
|
||||
<a href="{{ url_for('posts.index', page=page_num) }}" class="page-link">{{ page_num }}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<span class="page-link">...</span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if pagination.has_next %}
|
||||
<a href="{{ url_for('posts.index', page=pagination.next_num) }}" class="page-link">下一页</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">📷</div>
|
||||
<h2>还没有帖子</h2>
|
||||
<p>成为第一个分享摄影作品的人吧!</p>
|
||||
{% if current_user.is_authenticated %}
|
||||
<a href="{{ url_for('posts.create_post') }}" class="btn btn-primary">发布作品</a>
|
||||
{% else %}
|
||||
<a href="{{ url_for('auth.register') }}" class="btn btn-primary">立即注册</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
38
templates/login.html
Normal file
38
templates/login.html
Normal file
@@ -0,0 +1,38 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}登录 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="auth-container">
|
||||
<div class="auth-card">
|
||||
<div class="auth-header">
|
||||
<h1>🔐 欢迎回来</h1>
|
||||
<p>登录查看更多精彩作品</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" class="auth-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" id="username" name="username" required placeholder="请输入用户名" class="form-control"
|
||||
autofocus>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" id="password" name="password" required placeholder="请输入密码" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-check">
|
||||
<input type="checkbox" id="remember" name="remember" class="form-checkbox">
|
||||
<label for="remember">记住我</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block">登录</button>
|
||||
</form>
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>还没有账号?<a href="{{ url_for('auth.register') }}">立即注册</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
81
templates/post_detail.html
Normal file
81
templates/post_detail.html
Normal file
@@ -0,0 +1,81 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ post.author.username }} 的作品 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container post-detail-container">
|
||||
<div class="post-detail-card">
|
||||
<!-- Post Header -->
|
||||
<div class="post-detail-header">
|
||||
<a href="{{ url_for('users.profile', username=post.author.username) }}" class="user-info-large">
|
||||
<div class="user-avatar-large">
|
||||
{{ post.author.username[0].upper() }}
|
||||
</div>
|
||||
<div>
|
||||
<div class="username-large">{{ post.author.username }}</div>
|
||||
<div class="post-time">{{ post.created_at.strftime('%Y年%m月%d日 %H:%M') }}</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{% if not post.is_approved %}
|
||||
<div class="badge badge-warning">等待审核</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Post Image -->
|
||||
<div class="post-detail-image">
|
||||
<img src="{{ url_for('uploaded_file', filename=post.image_path) }}" alt="Post image" class="detail-image">
|
||||
</div>
|
||||
|
||||
<!-- Post Description -->
|
||||
{% if post.description %}
|
||||
<div class="post-detail-description">
|
||||
{{ post.description }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Comments Section -->
|
||||
<div class="comments-section">
|
||||
<h2 class="comments-title">💬 评论 ({{ comments|length }})</h2>
|
||||
|
||||
{% if current_user.is_authenticated and current_user.is_approved and post.is_approved %}
|
||||
<form method="POST" action="{{ url_for('posts.add_comment', post_id=post.id) }}" class="comment-form">
|
||||
<textarea name="content" placeholder="发表你的想法..." required class="comment-input"></textarea>
|
||||
<button type="submit" class="btn btn-primary">发表评论</button>
|
||||
</form>
|
||||
{% elif not current_user.is_authenticated %}
|
||||
<div class="info-box">
|
||||
<p><a href="{{ url_for('auth.login') }}">登录</a> 后可以发表评论</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- Comments List -->
|
||||
<div class="comments-list">
|
||||
{% for comment in comments %}
|
||||
<div class="comment-item">
|
||||
<a href="{{ url_for('users.profile', username=comment.author.username) }}" class="comment-avatar">
|
||||
{{ comment.author.username[0].upper() }}
|
||||
</a>
|
||||
<div class="comment-content">
|
||||
<div class="comment-header">
|
||||
<a href="{{ url_for('users.profile', username=comment.author.username) }}"
|
||||
class="comment-username">
|
||||
{{ comment.author.username }}
|
||||
</a>
|
||||
<span class="comment-time">{{ comment.created_at.strftime('%Y-%m-%d %H:%M') }}</span>
|
||||
</div>
|
||||
<div class="comment-text">{{ comment.content }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if not comments %}
|
||||
<div class="empty-comments">
|
||||
<p>还没有评论,快来抢沙发吧!</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
87
templates/profile.html
Normal file
87
templates/profile.html
Normal file
@@ -0,0 +1,87 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ user.username }} - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container profile-container">
|
||||
<!-- Profile Header -->
|
||||
<div class="profile-header">
|
||||
<div class="profile-avatar-large">
|
||||
{{ user.username[0].upper() }}
|
||||
</div>
|
||||
<div class="profile-info">
|
||||
<h1 class="profile-username">{{ user.username }}</h1>
|
||||
|
||||
{% if not user.is_approved %}
|
||||
<div class="badge badge-warning">等待审核</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="profile-stats">
|
||||
<div class="stat-item">
|
||||
<span class="stat-number">{{ posts|length }}</span>
|
||||
<span class="stat-label">作品</span>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<a href="{{ url_for('users.followers', username=user.username) }}">
|
||||
<span class="stat-number">{{ follower_count }}</span>
|
||||
<span class="stat-label">粉丝</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<a href="{{ url_for('users.following', username=user.username) }}">
|
||||
<span class="stat-number">{{ following_count }}</span>
|
||||
<span class="stat-label">关注</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if user.bio %}
|
||||
<p class="profile-bio">{{ user.bio }}</p>
|
||||
{% endif %}
|
||||
|
||||
<!-- Follow Button -->
|
||||
{% if current_user.is_authenticated and current_user.id != user.id %}
|
||||
{% if is_following %}
|
||||
<form method="POST" action="{{ url_for('users.unfollow', username=user.username) }}"
|
||||
style="display: inline;">
|
||||
<button type="submit" class="btn btn-secondary">已关注</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<form method="POST" action="{{ url_for('users.follow', username=user.username) }}" style="display: inline;">
|
||||
<button type="submit" class="btn btn-primary">关注</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Posts -->
|
||||
<div class="profile-posts">
|
||||
<h2 class="section-title">📸 作品集</h2>
|
||||
|
||||
{% if posts %}
|
||||
<div class="posts-grid">
|
||||
{% for post in posts %}
|
||||
<div class="post-card">
|
||||
<a href="{{ url_for('posts.post_detail', post_id=post.id) }}" class="post-image-link">
|
||||
<img src="{{ url_for('uploaded_file', filename=post.image_path) }}" alt="Post image"
|
||||
class="post-image" loading="lazy">
|
||||
{% if not post.is_approved %}
|
||||
<div class="badge badge-overlay">审核中</div>
|
||||
{% endif %}
|
||||
</a>
|
||||
<div class="post-footer">
|
||||
<span class="comment-count">💬 {{ post.get_comment_count() }}</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="empty-icon">📷</div>
|
||||
<p>该用户还没有发布作品</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
61
templates/register.html
Normal file
61
templates/register.html
Normal file
@@ -0,0 +1,61 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}注册 - 泸州高中摄影社论坛{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="auth-container">
|
||||
<div class="auth-card">
|
||||
<div class="auth-header">
|
||||
<h1>📷 加入摄影社</h1>
|
||||
<p>分享你的摄影作品,发现更多精彩</p>
|
||||
</div>
|
||||
|
||||
<form method="POST" enctype="multipart/form-data" class="auth-form">
|
||||
<div class="form-group">
|
||||
<label for="username">用户名</label>
|
||||
<input type="text" id="username" name="username" required placeholder="请输入用户名" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">邮箱</label>
|
||||
<input type="email" id="email" name="email" required placeholder="请输入邮箱" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password">密码</label>
|
||||
<input type="password" id="password" name="password" required placeholder="至少6位" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="confirm_password">确认密码</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required placeholder="再次输入密码"
|
||||
class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="student_id_photo">学生证照片 <span class="required">*</span></label>
|
||||
<div class="file-upload-area" id="fileUploadArea">
|
||||
<input type="file" id="student_id_photo" name="student_id_photo" accept="image/*" required
|
||||
class="file-input">
|
||||
<div class="file-upload-text">
|
||||
<span class="upload-icon">📤</span>
|
||||
<p>点击或拖拽上传学生证照片</p>
|
||||
<p class="file-hint">支持 PNG, JPG, JPEG, GIF, WEBP</p>
|
||||
</div>
|
||||
<img id="imagePreview" class="image-preview" style="display: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>注意:</strong>您上传的学生证照片将用于身份验证,管理员审核通过后才能使用论坛功能。</p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block">提交注册</button>
|
||||
</form>
|
||||
|
||||
<div class="auth-footer">
|
||||
<p>已有账号?<a href="{{ url_for('auth.login') }}">立即登录</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user