欢迎来到海上华帆的博客园子

记录一些学习过程中的心得体会,供自己和有缘人参考!

给表单增加筛选功能的通用实践二

模板+JS

筛选UI:直接在表头下方()为每一列加了 <input> <select>,实现了单号、门店、日期、状态、创建人等字段的筛选。
DataTables配置:
serverSide: true,即后端分页、排序、筛选。
通过 table.column(i).search(...) 实现每列的前端筛选交互,DataTables 会自动把这些搜索条件作为参数传给后端。
下拉选项是通过 DataTables 初始化后自动收集当前页数据的唯一值生成的。
优点:无需额外表单,筛选体验和 DataTables 原生风格一致,支持多列组合筛选。
缺点:如果后端API没有正确处理所有列的搜索参数,可能筛选不生效或只筛选当前页。


{% block content %}
<div class="container-fluid">
    <!-- <h1 class="h3 mb-4 text-gray-800">补货单列表</h1> -->

    <div class="card shadow mb-4">
        <div class="card-header py-3 d-flex flex-row align-items-center justify-content-start">
            <h3 class="m-0 font-weight-bold text-primary">补货单列表</h6>
            <a href="{% url 'store:store_replenishment_create' %}" class="btn btn-primary btn-sm ms-4">新建补货单</a>
        </div>
        <div class="card-body">
            <div class="table-responsive">
                <table class="table table-bordered table-sm align-middle" id="dataTable" style="font-size:14px;">
                    <thead>
                        <tr>
                            <th data-priority="1" style="min-width: 120px; width: 17%;">补货单号</th>
                            <th data-priority="5" style="min-width: 80px; width: 10%;">门店</th>
                            <th data-priority="3" style="min-width: 100px; width: 12%;">补货日期</th>
                            <th data-priority="1" style="min-width: 80px; width: 10%;">状态</th>
                            <th data-priority="4" style="min-width: 80px; width: 10%;">创建人</th>
                            <th data-priority="1" style="min-width: 90px; width: 10%;">总金额</th>
                            <th data-priority="1" style="min-width: 120px; width: 13%;">操作</th>
                        </tr>
                        <tr class="filter-row">
                            <th><input type="text" class="form-control form-control-sm" placeholder="筛选单号"></th>
                            <th><select class="form-select form-select-sm"><option value="">全部</option></select></th>
                            <th><input type="text" class="form-control form-control-sm" placeholder="筛选日期"></th>
                            <th><select class="form-select form-select-sm"><option value="">全部</option></select></th>
                            <th><input type="text" class="form-control form-control-sm" placeholder="筛选创建人"></th>
                            <th></th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        {% for order in replenishment_orders %}
                        <tr>
                            <td>{{ order.order_number }}</td>
                            <td>{{ order.store.name }}</td>
                            <!-- <td class="d-none d-md-table-cell" style="max-width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{{ order.warehouse.name }}</td> -->
                            <td>{{ order.order_date }}</td>
                            <td>
                                <span class="badge bg-{{ order.status|get_replenishment_status_style }}" style="font-size:0.95em;">
                                    {{ order.get_status_display }}
                                </span>
                            </td>
                            <td>{{ order.created_by.username }}</td>
                            <td>¥{{ order.total_amount|default:"0.00" }}</td>
                            <td>
                                <a href="{% url 'store:store_replenishment_detail' order.pk %}" class="btn btn-info btn-sm me-1">详情</a>
                                {% if order.status == 'draft' or order.status == 'pending_review' %}
                                    <a href="{% url 'store:store_replenishment_update' order.pk %}" class="btn btn-warning btn-sm me-1">编辑</a>
                                    <a href="{% url 'store:store_replenishment_delete' order.pk %}" class="btn btn-danger btn-sm">删除</a>
                                {% endif %}
                            </td>
                        </tr>
                        {% empty %}
                        <tr>
                            <td colspan="7" class="text-center">暂无补货单数据</td>
                        </tr>
                        {% endfor %}
                    </tbody>
                </table>
            </div>        
        </div>
    </div>
</div>
{% endblock %}

{% block store_js %}

<script>
$(document).ready(function() {
    var table = $('#dataTable').DataTable({
        serverSide: true,
        processing: true,
        ajax: {
            url: "{% url 'store:store_replenishment_list_api' %}",
            type: 'POST',
            data: function(d) {
                d.csrfmiddlewaretoken = '{{ csrf_token }}';
            }
        },
        language: {
            url: '/static/js/datatables.zh-cn.json'
        },
        orderCellsTop: true,
        fixedHeader: true,
        pageLength: 10,
        columns: [
            { title: '补货单号' },
            { title: '门店' },
            { title: '补货日期' },
            { title: '状态' },
            { title: '创建人' },
            { title: '总金额' },
            { title: '操作', orderable: false, searchable: false }
        ]
    });
    // 下拉筛选列索引
    var selectColumns = [1, 2, 4];
    table.on('init', function() {
        selectColumns.forEach(function(colIdx) {
            var column = table.column(colIdx);
            var select = $(column.header()).closest('table').find('thead tr.filter-row th').eq(colIdx).find('select');
            var uniqueData = column.data().unique().sort();
            select.empty().append('<option value="">全部</option>');
            uniqueData.each(function(d) {
                var val = $('<div>').html(d).text().trim();
                // 对状态列(4)特殊处理,提取纯文本
                if (colIdx === 4) {
                    val = $(d).text().trim();
                }
                if (val && select.find('option[value="'+val+'"]').length === 0) {
                    select.append('<option value="'+val+'">'+val+'</option>');
                }
            });
        });
    });
    // 每列筛选
    $('#dataTable thead tr.filter-row th').each(function(i) {
        var input = $(this).find('input');
        var select = $(this).find('select');
        if (input.length) {
            input.on('keyup change', function() {
                if (table.column(i).search() !== this.value) {
                    table.column(i).search(this.value).draw();
                }
            });
        }
        if (select.length) {
            select.on('change', function() {
                var val = $(this).val();
                if (i === 4) {
                    // 状态列筛选,匹配纯文本
                    table.column(i).search(val ? val : '', false, false).draw();
                } else {
                    table.column(i).search(val ? '^'+$.fn.dataTable.util.escapeRegex(val)+'$' : '', true, false).draw();
                }
            });
        }
    });
});
</script>
{% endblock %} 

模板+JS

  • 筛选UI:直接在表头下方(<tr class="filter-row">)为每一列加了 <input><select>,实现了“单号、门店、日期、状态、创建人”等字段的筛选。
  • DataTables配置
    • serverSide: true,即后端分页、排序、筛选。
    • 通过 table.column(i).search(...) 实现每列的前端筛选交互,DataTables 会自动把这些搜索条件作为参数传给后端。
    • 下拉选项是通过 DataTables 初始化后自动收集当前页数据的唯一值生成的。
  • 优点:无需额外表单,筛选体验和 DataTables 原生风格一致,支持多列组合筛选。
  • 缺点:如果后端API没有正确处理所有列的搜索参数,可能筛选不生效或只筛选当前页。

筛选UI

  • 筛选UI:在表格上方单独放一个 <form>,每个字段一个输入框或下拉,点击“筛选”按钮后刷新表格。
  • DataTables配置
    • 通过 ajax.data 显式将表单的值作为参数传递给后端API。
    • 可以自定义筛选字段、类型、交互方式。
  • 优点:筛选参数传递更直观,后端API处理更灵活,适合复杂筛选和自定义表单。
  • 缺点:不如表头筛选那样“所见即所得”,但更适合复杂业务。

主要区别

表头筛选 表单筛选
UI位置 表头下方每列 表格上方单独表单
参数传递 DataTables自动处理每列search 手动将表单值加到ajax.data
适用场景 简单、列筛选为主 复杂、多条件、跨列筛选
后端API 需支持DataTables的search参数 需支持自定义参数名

方法是否足够?

  • 如果表头筛选已经能满足业务需求(如所有字段都能正确筛选,后端API能正确处理DataTables的search参数),可以继续用你的方法,无需切换。
  • 如果需要更复杂的筛选逻辑(如跨列、范围、模糊、组合等),推荐用表单+自定义参数的方式,后端处理更灵活。
posted @ 2025-07-21 16:26  海上华帆  阅读(45)  评论(0)    收藏  举报