You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取material-react-table中已应用的筛选器并在PDF中展示

问题描述

使用material-react-table创建了支持行选择与PDF导出的表格,希望在数据被筛选(例如数量大于5000)时,获取当前应用的筛选器信息(包含筛选列名称与筛选值)并展示在导出的PDF中,提升数据上下文可读性。目前已通过columnFilters状态和onColumnFiltersChange方法获取筛选值,但无法获取对应的筛选列名称。

解决方案

columnFilters数组中的每个筛选对象都包含id字段,该字段对应你定义的列的id。你可以通过这个id在columns配置中找到对应的列标题,然后将筛选条件渲染到PDF中。

具体步骤:

  1. 编写辅助函数,将columnFilters转换为包含列标题和筛选值的数组
  2. 在PDF导出函数中,先渲染筛选条件文本,再渲染数据表格
修改后的完整代码
import React, { useEffect, useState } from "react";

import { Delete } from "@mui/icons-material";
import FileDownloadIcon from '@mui/icons-material/FileDownload';
import { Box, Button, ListItemIcon, MenuItem, lighten } from "@mui/material";
import { jsPDF } from 'jspdf';
import autoTable from 'jspdf-autotable';
import {
  MRT_GlobalFilterTextField,
  MRT_ToggleFiltersButton,
  MaterialReactTable,
  useMaterialReactTable,
} from "material-react-table";
import { MRT_Localization_ES } from "material-react-table/locales/es";

const MovementsTable = ({ movements, commodities, handleOpenDeleteModal }) => {
  const [columnFilters, setColumnFilters] = useState([]);
  const columns = [
    {
      id: "created_at",
      header: "Fecha",
      columns: [
        {
          accessorFn: (row) =>
            new Date(row.created_at).toLocaleDateString("es-ES", {
              year: "numeric",
              month: "2-digit",
              day: "2-digit",
              hour: "2-digit",
              minute: "2-digit",
              second: "2-digit",
            }),
          id: "created_at",
          header: "Fecha",
          size: 250,
        },
      ],
    },
    {
      id: "movement_id",
      header: "Movimiento Nº",
      columns: [
        {
          accessorFn: (row) => `${row.movement_id}`,
          id: "movement_id",
          header: "Movimiento Nº",
          size: 250,
        },
      ],
    },
    {
      id: "form_number",
      header: "Formulario Nº",
      columns: [
        {
          accessorFn: (row) => `${row.form_number}`,
          id: "form_number",
          header: "Formulario Nº",
          size: 250,
        },
      ],
    },
    {
      id: "commodity",
      header: "Producto",
      columns: [
        {
          accessorFn: (row) =>
            `${commodities[row.commodity] || "Producto Desconocido"}`,
          id: "commodity",
          header: "Producto",
          size: 250,
        },
      ],
    },
    {
      id: "quantity",
      header: "Cantidad [kg]",
      columns: [
        {
          accessorFn: (row) => `${row.quantity}`,
          id: "quantity",
          header: "Cantidad [kg]",
          size: 250,
        },
      ],
    },
    {
      id: "origin_destination",
      header: "Origen/Destino",
      columns: [
        {
          accessorFn: (row) =>
            `${row.movement_type === "input" ? "Ingreso desde " + row.origin : "Salida hacia " + row.destination}`,
          id: "origin_destination",
          header: "Origen/Destino",
          size: 250,
        },
      ],
    },
    {
      id: "observations",
      header: "Observaciones",
      columns: [
        {
          accessorFn: (row) => `${row.observations}`,
          id: "observations",
          header: "Observaciones",
          size: 250,
        },
      ],
    },
  ];

  // 辅助函数:将columnFilters转换为带列标题的筛选条件
  const getFilterConditions = () => {
    return columnFilters.map(filter => {
      // 找到对应列的标题
      const column = columns.find(col => col.id === filter.id);
      const columnHeader = column?.columns[0].header || filter.id;
      // 根据筛选类型格式化值(处理范围筛选)
      let filterValue = filter.value;
      if (typeof filterValue === 'object') {
        filterValue = Object.entries(filterValue)
          .map(([key, val]) => `${key === 'gte' ? '≥' : '≤'} ${val}`)
          .join(' ');
      }
      return { column: columnHeader, value: filterValue };
    });
  };

  const handleExportRows = (rows) => {
    const doc = new jsPDF('landscape');
    const filterConditions = getFilterConditions();
    let tableStartY = 20;

    // 添加筛选条件到PDF顶部
    if (filterConditions.length > 0) {
      doc.setFontSize(14);
      doc.text('Filtrado aplicado:', 20, tableStartY);
      tableStartY += 15;
      doc.setFontSize(12);
      filterConditions.forEach((condition, index) => {
        doc.text(`${condition.column}: ${condition.value}`, 30, tableStartY + index * 15);
      });
      tableStartY += filterConditions.length * 15 + 10;
    }

    // 处理表格数据
    const tableData = rows.map((row) => {
      return columns.map((column) => {
        return column.columns[0].accessorFn(row.original) || '';
      })
    });
  
    const tableHeaders = columns.map((column) => {
      return column.columns[0].header;
    });
  
    // 渲染数据表格
    autoTable(doc, {
      startY: tableStartY,
      head: [tableHeaders],
      body: tableData,
      theme: 'grid',
      headStyles: {
        fillColor: [2, 129, 67],
        textColor: [255],
      },
    });
  
    // 保存PDF
    const now = new Date().toLocaleDateString('es-ES', {
      year: 'numeric',
      month: '2-digit',
      day: '2-digit',
    }).replace(/\//g, '-');
    doc.save(`oilcan-movements-report-${now}.pdf`);
  };

  useEffect(() => {
    console.log(columnFilters);
  }, [columnFilters]);

  const table = useMaterialReactTable({
    columns,
    data: movements,
    enableColumnFilterModes: true,
    enableColumnOrdering: true,
    enableGrouping: true,
    enableColumnPinning: true,
    enableFacetedValues: true,
    enableRowActions: true,
    onColumnFiltersChange: setColumnFilters,
    state: { columnFilters },
    enableRowSelection: true,
    localization: MRT_Localization_ES,
    initialState: {
      showColumnFilters: true,
      showGlobalFilter: true,
      columnPinning: {
        right: ["mrt-row-actions"],
      },
    },
    paginationDisplayMode: "pages",
    positionToolbarAlertBanner: "bottom",
    muiTableBodyRowProps: ({ row }) => ({
      sx: {
        backgroundColor:
          row.original.movement_type === "input" ? "#00800075" : "#ff000078",
      },
    }),
    muiSearchTextFieldProps: {
      size: "small",
      variant: "outlined",
    },
    muiPaginationProps: {
      color: "secondary",
      rowsPerPageOptions: [10, 20, 30],
      shape: "rounded",
      variant: "outlined",
    },
    renderRowActionMenuItems: ({ row, closeMenu }) => [
      <MenuItem
        key={0}
        onClick={() => {
          handleOpenDeleteModal(row.original.movement_id);
          closeMenu();
        }}
        sx={{ m: 0 }}
      >
        <ListItemIcon>
          <Delete />
        </ListItemIcon>
        Eliminar Movimiento
      </MenuItem>,
    ],
    renderTopToolbar: ({ table }) => {
      return (
        <Box
          sx={(theme) => ({
            backgroundColor: lighten(theme.palette.background.default, 0.05),
            display: "flex",
            gap: "0.5rem",
            p: "8px",
            justifyContent: "space-between",
          })}
        >
          <Box sx={{ display: "flex", gap: "0.5rem", alignItems: "center" }}>
            <MRT_GlobalFilterTextField table={table} />
            <MRT_ToggleFiltersButton table={table} />
          </Box>
        <Button
          disabled={
            !table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()
          }
          onClick={() => handleExportRows(table.getSelectedRowModel().rows)}
          startIcon={<FileDownloadIcon />}
        >
          Exportar Filas Seleccionadas
        </Button>
        </Box>
      );
    },
    renderTopToolbarCustomActions: ({ table }) => (
      <Box
        sx={{
          display: 'flex',
          gap: '16px',
          padding: '8px',
          flexWrap: 'wrap',
        }}
      >
        <Button
          disabled={table.getPrePaginationRowModel().rows.length === 0}
          onClick={() =>
            handleExportRows(table.getPrePaginationRowModel().rows)
          }
          startIcon={<FileDownloadIcon />}
        >
          Export All Rows
        </Button>
        <Button
          disabled={table.getRowModel().rows.length === 0}
          onClick={() => handleExportRows(table.getRowModel().rows)}
          startIcon={<FileDownloadIcon />}
        >
          Export Page Rows
        </Button>
        <Button
          disabled={
            !table.getIsSomeRowsSelected() && !table.getIsAllRowsSelected()
          }
          onClick={() => handleExportRows(table.getSelectedRowModel().rows)}
          startIcon={<FileDownloadIcon />}
        >
          Export Selected Rows
        </Button>
      </Box>
    ),
  });
  return <MaterialReactTable table={table} />;
};

export default MovementsTable;
关键修改说明
  • 添加getFilterConditions辅助函数:通过筛选对象的id匹配列配置中的标题,同时格式化范围筛选的显示文本
  • 调整handleExportRows函数:动态在PDF顶部添加筛选条件,根据筛选数量调整数据表格的起始位置,避免内容重叠
  • 保留原有导出逻辑,确保数据表格的样式和功能不受影响

内容的提问来源于stack exchange,提问作者Alejo Nuñez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 07:59:51