280 lines
13 KiB
HTML
280 lines
13 KiB
HTML
{% extends "admin/base.html" %}
|
|
|
|
{% block title %}用户管理 - 太白购物商城管理后台{% endblock %}
|
|
|
|
{% block page_title %}用户管理{% endblock %}
|
|
{% block page_description %}管理系统用户,查看用户信息和状态{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<link href="{{ url_for('static', filename='css/admin_users.css') }}" rel="stylesheet">
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="admin-users">
|
|
<!-- 搜索和筛选 -->
|
|
<div class="card mb-4">
|
|
<div class="card-body">
|
|
<form method="GET" class="row g-3">
|
|
<div class="col-md-4">
|
|
<label for="search" class="form-label">搜索用户</label>
|
|
<input type="text" class="form-control" id="search" name="search"
|
|
value="{{ search }}" placeholder="用户名、邮箱、手机号、昵称">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label for="status" class="form-label">状态筛选</label>
|
|
<select class="form-select" id="status" name="status">
|
|
<option value="">全部状态</option>
|
|
<option value="1" {% if status == '1' %}selected{% endif %}>正常</option>
|
|
<option value="0" {% if status == '0' %}selected{% endif %}>禁用</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<label class="form-label"> </label>
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary">
|
|
<i class="bi bi-search"></i> 搜索
|
|
</button>
|
|
<a href="{{ url_for('admin.users') }}" class="btn btn-outline-secondary">
|
|
<i class="bi bi-arrow-clockwise"></i> 重置
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 用户统计 -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card stats-card">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h5 class="card-title">{{ users.total }}</h5>
|
|
<p class="card-text">总用户数</p>
|
|
</div>
|
|
<div class="icon-wrapper primary">
|
|
<i class="bi bi-people"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card stats-card">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h5 class="card-title">{{ users.items | selectattr('status', 'equalto', 1) | list | length }}</h5>
|
|
<p class="card-text">正常用户</p>
|
|
</div>
|
|
<div class="icon-wrapper success">
|
|
<i class="bi bi-person-check"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card stats-card">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h5 class="card-title">{{ users.items | selectattr('status', 'equalto', 0) | list | length }}</h5>
|
|
<p class="card-text">禁用用户</p>
|
|
</div>
|
|
<div class="icon-wrapper danger">
|
|
<i class="bi bi-person-x"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card stats-card">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="flex-grow-1">
|
|
<h5 class="card-title">{{ week_new_users }}</h5>
|
|
<p class="card-text">本周新增</p>
|
|
</div>
|
|
<div class="icon-wrapper info">
|
|
<i class="bi bi-person-plus"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 用户列表 -->
|
|
<div class="card">
|
|
<div class="card-header bg-white">
|
|
<h5 class="mb-0">
|
|
<i class="bi bi-people"></i>
|
|
用户列表
|
|
<small class="text-muted ms-2">共 {{ users.total }} 条记录</small>
|
|
</h5>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>用户ID</th>
|
|
<th>用户信息</th>
|
|
<th>联系方式</th>
|
|
<th>注册时间</th>
|
|
<th>状态</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% if users.items %}
|
|
{% for user in users.items %}
|
|
<tr>
|
|
<td>
|
|
<strong>#{{ user.id }}</strong>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="avatar-wrapper me-3">
|
|
{% if user.avatar_url %}
|
|
<img src="{{ user.avatar_url }}" alt="头像" class="user-avatar">
|
|
{% else %}
|
|
<div class="user-avatar-placeholder">
|
|
<i class="bi bi-person"></i>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<div>
|
|
<div class="fw-bold">{{ user.username }}</div>
|
|
{% if user.nickname %}
|
|
<small class="text-muted">{{ user.nickname }}</small>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>
|
|
{% if user.email %}
|
|
<div><i class="bi bi-envelope"></i> {{ user.email }}</div>
|
|
{% endif %}
|
|
{% if user.phone %}
|
|
<div><i class="bi bi-phone"></i> {{ user.phone }}</div>
|
|
{% endif %}
|
|
{% if not user.email and not user.phone %}
|
|
<span class="text-muted">未设置</span>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>{{ user.created_at.strftime('%Y-%m-%d') if user.created_at else '-' }}</div>
|
|
<small class="text-muted">{{ user.created_at.strftime('%H:%M:%S') if user.created_at else '' }}</small>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-{{ 'success' if user.status == 1 else 'danger' }}">
|
|
{{ '正常' if user.status == 1 else '禁用' }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<div class="btn-group" role="group">
|
|
<button type="button" class="btn btn-sm btn-outline-primary"
|
|
onclick="viewUser({{ user.id }})">
|
|
<i class="bi bi-eye"></i> 查看
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-outline-{{ 'warning' if user.status == 1 else 'success' }}"
|
|
onclick="toggleUserStatus({{ user.id }}, {{ user.status }})">
|
|
<i class="bi bi-{{ 'person-x' if user.status == 1 else 'person-check' }}"></i>
|
|
{{ '禁用' if user.status == 1 else '启用' }}
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% else %}
|
|
<tr>
|
|
<td colspan="6" class="text-center py-4">
|
|
<div class="empty-state">
|
|
<i class="bi bi-person-slash"></i>
|
|
<div>暂无用户数据</div>
|
|
{% if search or status %}
|
|
<small class="text-muted">尝试调整搜索条件</small>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- 分页 -->
|
|
{% if users.pages > 1 %}
|
|
<div class="card-footer bg-white">
|
|
<nav aria-label="用户列表分页">
|
|
<ul class="pagination justify-content-center mb-0">
|
|
{% if users.has_prev %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="{{ url_for('admin.users', page=users.prev_num, search=search, status=status) }}">
|
|
<i class="bi bi-chevron-left"></i>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
|
|
{% for page_num in users.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}
|
|
{% if page_num %}
|
|
{% if page_num != users.page %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="{{ url_for('admin.users', page=page_num, search=search, status=status) }}">
|
|
{{ page_num }}
|
|
</a>
|
|
</li>
|
|
{% else %}
|
|
<li class="page-item active">
|
|
<span class="page-link">{{ page_num }}</span>
|
|
</li>
|
|
{% endif %}
|
|
{% else %}
|
|
<li class="page-item disabled">
|
|
<span class="page-link">…</span>
|
|
</li>
|
|
{% endif %}
|
|
{% endfor %}
|
|
|
|
{% if users.has_next %}
|
|
<li class="page-item">
|
|
<a class="page-link" href="{{ url_for('admin.users', page=users.next_num, search=search, status=status) }}">
|
|
<i class="bi bi-chevron-right"></i>
|
|
</a>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 用户详情模态框 -->
|
|
<div class="modal fade" id="userDetailModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">用户详情</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div id="userDetailContent">
|
|
<!-- 用户详情内容将通过AJAX加载 -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script src="{{ url_for('static', filename='js/admin_users.js') }}"></script>
|
|
{% endblock %}
|