分页条初始化

分页查询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
        )
相关推荐
lancyu1 小时前
关于多轮对话机器人的上下文Token优化和解决方案
人工智能·python·深度学习·机器学习·chatgpt·机器人·prompt
草莓橙子碗1 小时前
Claude 使用指南
开发语言·python
工具分享1 小时前
陪跑跟品爆单AI选品助手,高效跟品会赔本吗?
人工智能·python
COOLMO研究AI2 小时前
Python 如何实现 AI API 的提示词(Prompt)版本管理与热更新
人工智能·python·prompt
老郑聊AI业财智造2 小时前
Transformer 技术架构与源码分析
人工智能·python·深度学习·语言模型·架构·transformer·软件工程
程序员三藏2 小时前
自动化测试用例编写详解
自动化测试·软件测试·python·功能测试·测试工具·职场和发展·测试用例
230万光年的思念3 小时前
分子动力学模拟参考文献
python
HongXu_CaiYi3 小时前
0103-python相关-函数、文件
python
vortex54 小时前
从Conda到UV:Python项目依赖管理的现代演进
python·conda·uv
何以解忧,唯有..4 小时前
Python time 模块详解:时间处理与日期操作指南
开发语言·python