ui: 导航圆润与用户信息展示;详情页作者与关注;主页粉丝/关注与卡片网格

This commit is contained in:
2025-12-07 11:25:50 +08:00
parent b497fe97f3
commit a60d9d1e54
5 changed files with 78 additions and 29 deletions

View File

@@ -1,14 +1,23 @@
from flask import Blueprint, render_template, request, redirect, url_for
from flask_login import login_required, current_user
from ..extensions import db
from ..models import User, Profile, Notification
from ..models import User, Profile, Notification, Follow
bp = Blueprint("users", __name__, url_prefix="/users")
@bp.route("/<int:user_id>")
def profile(user_id):
user = User.query.get_or_404(user_id)
return render_template("users/profile.html", user=user)
followers_count = Follow.query.filter_by(followee_id=user.id).count()
following_count = Follow.query.filter_by(follower_id=user.id).count()
is_following = False
try:
from flask_login import current_user
if current_user.is_authenticated:
is_following = Follow.query.filter_by(follower_id=current_user.id, followee_id=user.id).first() is not None
except Exception:
pass
return render_template("users/profile.html", user=user, followers_count=followers_count, following_count=following_count, is_following=is_following)
@bp.route("/me/edit", methods=["GET", "POST"])
@login_required

View File

@@ -9,6 +9,10 @@
body { background: #f8fafc; }
.container { max-width: 1100px; }
.navbar { border-radius: var(--radius); box-shadow: var(--shadow); }
.nav-menu a { padding: 8px 14px; border-radius: 999px; }
.nav-menu a:hover { background: #f1f5ff; }
.nav-user { display:flex; align-items:center; gap:12px; }
.avatar { width: 32px; height: 32px; border-radius: 50%; background: #e5e7eb; display:inline-flex; align-items:center; justify-content:center; font-weight:600; color:#4b5563; }
.card { border: 0; border-radius: var(--radius); box-shadow: var(--shadow); }
.btn { border-radius: var(--radius-sm); }
.form-control, .form-select, textarea { border-radius: var(--radius-sm); }

View File

@@ -11,22 +11,29 @@
<nav class="navbar navbar-expand-lg navbar-light bg-white mb-3 mt-2 px-3">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('feed.discover') }}">摄影社</a>
<div>
<a class="btn btn-link" href="{{ url_for('feed.discover') }}">发现</a>
{% if current_user.is_authenticated %}
<a class="btn btn-link" href="{{ url_for('feed.following') }}">关注</a>
<a class="btn btn-link" href="{{ url_for('users.profile', user_id=current_user.id) }}">我的主页</a>
<a class="btn btn-link" href="{{ url_for('users.notifications') }}">通知</a>
<a class="btn btn-link" href="{{ url_for('posts.create') }}">发布作品</a>
<a class="btn btn-link" href="{{ url_for('activities.list_activities') }}">活动</a>
{% if current_user.role == 'admin' %}
<a class="btn btn-link" href="{{ url_for('admin.dashboard') }}">管理员</a>
{% endif %}
<a class="btn btn-link" href="{{ url_for('auth.logout') }}">退出</a>
{% else %}
<a class="btn btn-link" href="{{ url_for('auth.login') }}">登录</a>
<a class="btn btn-brand" href="{{ url_for('auth.register') }}">注册</a>
{% endif %}
<div class="d-flex justify-content-between align-items-center w-100">
<div class="nav-menu">
<a class="btn btn-link" href="{{ url_for('feed.discover') }}">发现</a>
{% if current_user.is_authenticated %}
<a class="btn btn-link" href="{{ url_for('feed.following') }}">关注</a>
<a class="btn btn-link" href="{{ url_for('activities.list_activities') }}">活动</a>
{% if current_user.role in ['admin','sub_admin','checker'] %}
<a class="btn btn-link" href="{{ url_for('admin.dashboard') }}">后台</a>
{% endif %}
<a class="btn btn-brand" href="{{ url_for('posts.create') }}">发布作品</a>
{% else %}
<a class="btn btn-link" href="{{ url_for('auth.login') }}">登录</a>
<a class="btn btn-brand" href="{{ url_for('auth.register') }}">注册</a>
{% endif %}
</div>
<div class="nav-user">
{% if current_user.is_authenticated %}
<span class="avatar">{{ current_user.username[:1]|upper }}</span>
<a class="btn btn-link" href="{{ url_for('users.profile', user_id=current_user.id) }}">{{ current_user.username }}</a>
<a class="btn btn-link" href="{{ url_for('users.notifications') }}">通知</a>
<a class="btn btn-link" href="{{ url_for('auth.logout') }}">退出</a>
{% endif %}
</div>
</div>
</div>
</nav>

View File

@@ -3,7 +3,18 @@
{% block content %}
<div class="card mb-3">
<div class="p-3">
<h3 class="mb-2">{{ post.title }}</h3>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="d-flex align-items-center gap-3">
<span class="avatar">{{ post.user.username[:1]|upper }}</span>
<div>
<h3 class="mb-1">{{ post.title }}</h3>
<a class="text-decoration-none" href="{{ url_for('users.profile', user_id=post.user.id) }}">{{ post.user.username }}</a>
</div>
</div>
{% if current_user.is_authenticated and current_user.id != post.user.id %}
<a class="btn btn-brand" href="{{ url_for('follows.follow', user_id=post.user.id) }}">关注作者</a>
{% endif %}
</div>
<p class="text-secondary">{{ post.description }}</p>
<span class="badge bg-light text-dark">{{ post.visibility.value }}</span>
</div>

View File

@@ -1,19 +1,37 @@
{% extends 'base.html' %}
{% block title %}主页{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-center">
<h3>{{ user.username }}</h3>
{% if current_user.is_authenticated and current_user.id != user.id %}
<a class="btn btn-outline-primary" href="{{ url_for('follows.follow', user_id=user.id) }}">关注</a>
{% endif %}
<div class="card p-3 mb-3">
<div class="d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center gap-3">
<span class="avatar">{{ user.username[:1]|upper }}</span>
<h3 class="m-0">{{ user.username }}</h3>
</div>
{% if current_user.is_authenticated and current_user.id != user.id %}
{% if is_following %}
<a class="btn btn-secondary" href="{{ url_for('follows.unfollow', user_id=user.id) }}">已关注</a>
{% else %}
<a class="btn btn-brand" href="{{ url_for('follows.follow', user_id=user.id) }}">关注</a>
{% endif %}
{% endif %}
</div>
<div class="text-secondary mt-2">粉丝 {{ followers_count }} · 关注 {{ following_count }}</div>
<p class="mt-2">{{ user.profile.bio }}</p>
</div>
<p>{{ user.profile.bio }}</p>
<hr>
<h5>作品</h5>
<div class="row">
<h5 class="mb-2">作品</h5>
<div class="card-grid">
{% for p in user.posts %}
<div class="col-md-4">
<a href="{{ url_for('posts.detail', post_id=p.id) }}">{{ p.title }}</a>
<div class="card">
{% set first = p.images[0] if p.images %}
{% if first %}
<a href="{{ url_for('posts.detail', post_id=p.id) }}">
<img class="photo-thumb" src="{{ url_for('main.uploads', filename=first.web_path) }}" alt="{{ p.title }}" />
</a>
{% endif %}
<div class="p-3">
<a class="text-decoration-none" href="{{ url_for('posts.detail', post_id=p.id) }}">{{ p.title }}</a>
</div>
</div>
{% endfor %}
</div>