分页条初始化

分页查询API

python 复制代码
@user_activity_bp.route('/api/activity_list')
def activity_list():
    """获取活动日志列表"""
    try:
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)
        # 将user_id作为字符串处理
        user_id = request.args.get('user_id', type=str)
        days = request.args.get('days', 7, type=int)

        start_date = datetime.now() - timedelta(days=days)

        # 修改:关联用户表获取用户信息
        base_query = """
            SELECT 
                ual.id, ual.user_id, ual.request_path, ual.request_method, ual.user_agent,
                ual.ip_address, ual.access_time, ual.duration_ms, ual.status_code,
                u.real_name, u.mobile
            FROM user_activity_log ual
            LEFT JOIN user u ON ual.user_id = u.id
            WHERE ual.access_time >= %s
        """
        params = [start_date]

        # 用户筛选
        if user_id and user_id != '' and user_id != 'null':
            base_query += " AND ual.user_id = %s"
            params.append(user_id)

        # 搜索条件
        search = request.args.get('search', '')
        if search:
            base_query += " AND (ual.request_path LIKE %s OR ual.request_method LIKE %s)"
            params.extend([f"%{search}%", f"%{search}%"])

        # 排序
        sort_field = request.args.get('sort_field', 'access_time')
        sort_order = request.args.get('sort_order', 'desc')

        if sort_field == 'access_time':
            order_by = "ual.access_time DESC" if sort_order == 'desc' else "ual.access_time ASC"
        elif sort_field == 'duration_ms':
            order_by = "ual.duration_ms DESC" if sort_order == 'desc' else "ual.duration_ms ASC"
        else:
            order_by = "ual.access_time DESC"

        base_query += f" ORDER BY {order_by}"

        # 使用分页工具
        return Paginator.paginate_template(
            template_path='user_activity/activity_list.html',
            data_key='activities',
            query=base_query,
            base_params=params
        )
    except Exception as e:
        print(f"获取活动日志列表错误: {str(e)}")
        return f"<div class='alert alert-danger'>加载数据失败: {str(e)}</div>", 500

分页条容器

html 复制代码
<div class="table-responsive">
    <table class="table table-hover table-sm">
        <thead>
            <tr>
                <th>用户ID</th>
                <th>姓名</th>
                <th>手机号</th>
                <th>请求路径</th>
                <th>方法</th>
                <th>IP地址</th>
                <th>访问时间</th>
                <th>耗时(ms)</th>
                <th>状态码</th>
            </tr>
        </thead>
        <tbody>
            {% if activities and activities|length > 0 %}
                {% for activity in activities %}
                <tr>
                    <td>{{ activity.user_id or '匿名' }}</td>
                    <td>{{ activity.real_name or '-' }}</td>
                    <td>{{ activity.mobile or '-' }}</td>
                    <td title="{{ activity.request_path }}">{{ activity.request_path[:40] }}{% if activity.request_path|length > 40 %}...{% endif %}</td>
                    <td><span class="badge bg-secondary">{{ activity.request_method }}</span></td>
                    <td>{{ activity.ip_address }}</td>
                    <td>{{ activity.access_time.strftime('%Y-%m-%d %H:%M:%S') }}</td>
                    <td>{{ activity.duration_ms or '-' }}</td>
                    <td>
                        {% if activity.status_code %}
                            {% if activity.status_code >= 200 and activity.status_code < 300 %}
                                <span class="badge badge-success">{{ activity.status_code }}</span>
                            {% elif activity.status_code >= 400 and activity.status_code < 500 %}
                                <span class="badge badge-warning">{{ activity.status_code }}</span>
                            {% else %}
                                <span class="badge badge-danger">{{ activity.status_code }}</span>
                            {% endif %}
                        {% else %}
                            <span class="badge bg-secondary">-</span>
                        {% endif %}
                    </td>
                </tr>
                {% endfor %}
            {% else %}
                <tr>
                    <td colspan="9" class="text-center py-4">
                        <i class="fas fa-inbox fa-2x text-muted mb-2"></i>
                        <p class="text-muted">暂无活动日志数据</p>
                    </td>
                </tr>
            {% endif %}
        </tbody>
    </table>
</div>

<!-- 分页信息 -->
{% if total_pages is defined %}
<div id="pageInfo"
     data-total="{{ total }}"
     data-page="{{ page }}"
     data-per-page="{{ per_page }}"
     data-total-pages="{{ total_pages }}">
</div>
{% endif %}

分页条初始化

python 复制代码
// 初始化分页(优化版)
function initPagination(data) {
    const container = $('#paginationContainer');
    container.empty();

    // 如果总页数小于等于1,不显示分页
    if (data.totalPages <= 1) return;

    // 生成需要显示的页码数组(当前页前后各2页,加上首尾页)
    const pageNumbers = [];
    const currentPage = data.page;
    const totalPages = data.totalPages;

    // 添加首页
    pageNumbers.push(1);

    // 计算显示范围
    let startPage = Math.max(2, currentPage - 2);
    let endPage = Math.min(totalPages - 1, currentPage + 2);

    // 如果当前页附近与首页有间隔,添加省略号
    if (startPage > 2) {
        pageNumbers.push('...');
    }

    // 添加当前页附近的页码
    for (let i = startPage; i <= endPage; i++) {
        pageNumbers.push(i);
    }

    // 如果当前页附近与末页有间隔,添加省略号
    if (endPage < totalPages - 1) {
        pageNumbers.push('...');
    }

    // 添加末页(如果总页数大于1)
    if (totalPages > 1) {
        pageNumbers.push(totalPages);
    }

    // 生成分页HTML
    const pagination = `
        <nav>
            <ul class="pagination pagination-sm justify-content-center">
                <li class="page-item ${currentPage === 1 ? 'disabled' : ''}">
                    <a class="page-link" href="javascript:void(0)" onclick="loadActivityList(${currentPage - 1})">上一页</a>
                </li>

                ${pageNumbers.map(p => {
                    // 处理省略号
                    if (p === '...') {
                        return `<li class="page-item disabled"><span class="page-link">...</span></li>`;
                    }
                    // 处理正常页码
                    return `
                        <li class="page-item ${p === currentPage ? 'active' : ''}">
                            <a class="page-link" href="javascript:void(0)" onclick="loadActivityList(${p})">${p}</a>
                        </li>
                    `;
                }).join('')}

                <li class="page-item ${currentPage === totalPages ? 'disabled' : ''}">
                    <a class="page-link" href="javascript:void(0)" onclick="loadActivityList(${currentPage + 1})">下一页</a>
                </li>
            </ul>
        </nav>
    `;

    container.html(pagination);
}

后端通用分页工具

python 复制代码
from flask import request, render_template
from utils import db

class Paginator:
    @staticmethod
    def paginate_query(query, base_params=[], count_query=None, default_per_page=50):
        """
        通用分页方法
        :param query: 基础查询语句
        :param base_params: 基础查询的参数列表
        :param count_query: 计数查询语句(可选)
        :param default_per_page: 默认每页数量
        :return: 包含分页结果的字典
        """
        # 获取分页参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', default_per_page, type=int)

        # 计算偏移量
        offset = (page - 1) * per_page

        # 执行分页查询 - 合并基础参数和分页参数
        data_query = f"{query} LIMIT %s OFFSET %s"
        data_params = base_params + [per_page, offset]
        data = db.fetch_all(data_query, data_params)

        # 执行计数查询
        if count_query:
            count_result = db.fetch_one(count_query, base_params)
            total = count_result['total'] if count_result else 0
        else:
            # 如果没有提供计数查询,尝试从基础查询生成
            count_query = f"SELECT COUNT(*) AS total FROM ({query}) AS subquery"
            count_result = db.fetch_one(count_query, base_params)
            total = count_result['total'] if count_result else 0

        # 计算总页数
        total_pages = (total + per_page - 1) // per_page if per_page > 0 else 1

        return {
            'data': data,
            'page': page,
            'per_page': per_page,
            'total': total,
            'total_pages': total_pages
        }

    @staticmethod
    def paginate_template(template_path, data_key, query, base_params=[], **kwargs):
        """
        分页并渲染模板
        :param template_path: 模板路径
        :param data_key: 模板中数据的变量名
        :param query: 基础查询语句
        :param base_params: 基础查询的参数列表
        :param kwargs: 传递给模板的额外参数
        :return: 渲染后的模板
        """
        result = Paginator.paginate_query(query, base_params, default_per_page=50)
        return render_template(
            template_path,
            **{
                data_key: result['data'],
                'page': result['page'],
                'per_page': result['per_page'],
                'total': result['total'],
                'total_pages': result['total_pages']
            },
            **kwargs
        )
相关推荐
NewsMash2 小时前
PyTorch之父发离职长文,告别Meta
人工智能·pytorch·python
硅农深芯2 小时前
如何使用ptqt5实现进度条的动态显示
开发语言·python·qt
程序员杰哥3 小时前
软件测试之压力测试详解
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·压力测试
今天没有盐3 小时前
Pandas完全指南:从Series到DataFrame,掌握数据分析核心技能
python·pycharm·编程语言
暴风鱼划水3 小时前
算法题(Python)数组篇 | 4.长度最小的子数组
python·算法·力扣
B站计算机毕业设计之家3 小时前
大数据python招聘数据分析预测系统 招聘数据平台 +爬虫+可视化 +django框架+vue框架 大数据技术✅
大数据·爬虫·python·机器学习·数据挖掘·数据分析
新手村领路人4 小时前
python打包成exe
python·打包
胡桃不是夹子4 小时前
torch和torchvision对应版本匹配官网下载
人工智能·python·深度学习