news 2026/9/11 6:22:45

Filament Tables 汇总行(Summaries)完全指南:在 Laravel 表格中实现平均值、计数、范围与求和统计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Filament Tables 汇总行(Summaries)完全指南:在 Laravel 表格中实现平均值、计数、范围与求和统计

Filament Tables 汇总行(Summaries)完全指南:在 Laravel 表格中实现平均值、计数、范围与求和统计

【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament

Filament 的 Tables 包允许你在表格内容下方渲染一个"汇总(summary)"区域,用于展示当前数据集的计算结果,例如平均值、总和、计数和范围。本指南以 packages/tables/docs/06-summaries.md 为核心,结合 packages/tables/src/Columns/Summarizers 目录下的源码实现,系统讲解内置四类汇总器(Average / Count / Range / Sum)的用法、格式化能力、作用域控制、自定义汇总器,以及配合分组(grouping)实现报表级汇总的实战方案。读完本文,你将能够为任意表格列快速接入统计汇总,并精确控制其展示形式与计算范围。

汇总(Summaries)是什么

默认情况下,Filament 表格会在数据下方渲染一个汇总区域,包含:

  • 当前页数据(this page)的汇总行;
  • 当存在多页数据时,额外渲染全部数据(all data)的总计汇总行。

此外,如果表格启用了分组(grouping),你还可以为每个分组单独渲染汇总,详见下文"汇总分组行"一节。

汇总器(Summarizer)对象可以通过任意表格列的summarize()方法挂载。该方法定义在 packages/tables/src/Columns/Concerns/CanBeSummarized.php,它接收单个汇总器或汇总器数组,并将每个汇总器与当前列进行绑定($summarizer->column($this))。单个列可以同时挂载多个汇总器:

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\Summarizers\Range; use Filament\Tables\Columns\TextColumn; TextColumn::make('rating') ->numeric() ->summarize([ Average::make(), Range::make(), ])

注意:表格的第一列不能使用汇总器,因为该列被专门用于渲染汇总区域的标题(heading)与副标题(subheading)。

内置汇总器一览

Filament 默认提供四类汇总器,均继承自抽象基类 Summarizer,类文件位于packages/tables/src/Columns/Summarizers/目录:

汇总器类名说明底层查询
平均值 AverageAverage计算数据集中所有值的平均值avg($attribute)
计数 CountCount统计数据集中的值(行)总数count($attribute)
范围 RangeRange计算数据集中的最小值与最大值min()/max()
求和 SumSum计算数据集中所有值的总和sum($attribute)

在 Average.php、Sum.php、Count.php、Range.php 的summarize()方法中可以看到,每个汇总器最终都是基于Illuminate\Database\Query\Builder执行对应的 SQL 聚合函数,因此统计完全在数据库端完成,不会把全量数据加载到内存。

你也可以创建自定义汇总器,以任意方式展示数据。

平均值(Average)

使用Average计算数据集中所有值的平均值——例如将所有评分相加后除以评分数量:

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\TextColumn; TextColumn::make('rating') ->summarize(Average::make())

从源码可以看出,AveragesetUp()中会自动调用$this->numeric()(见 Average.php),即平均值默认按数字格式展示。

计数(Count)

使用Count统计数据集中的值(行)总数。如果只是统计行数,直接使用即可;若需要统计满足特定条件的记录数,通常需要配合作用域(scoping)使用:

use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\Summarizers\Count; use Illuminate\Database\Query\Builder; IconColumn::make('is_published') ->boolean() ->summarize( Count::make()->query(fn (Builder $query) => $query->where('is_published', true)), ),

上述示例会计算"已发布文章"的数量。

统计图标的出现次数

当 Count 作用于图标列(IconColumn)时,可以使用icons()方法,以图形化方式向用户展示表格中每种图标分别出现了多少次:

use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\Summarizers\Count; use Illuminate\Database\Query\Builder; IconColumn::make('is_published') ->boolean() ->summarize(Count::make()->icons()),

从源码 Count.php 可以看到,icons()模式下的计数逻辑是:对列中出现的每个去重取值,结合图标列的getIcon()/getColor()解析出对应的图标与颜色,然后统计每个图标组合出现的次数,最终渲染为一个「次数 + 图标」的列表(渲染逻辑见toEmbeddedHtml(),Count.php)。需要注意的是,若对非IconColumn列调用icons(),会抛出LogicException(Count.php)。

范围(Range)

使用Range计算数据集中的最小值和最大值:

use Filament\Tables\Columns\Summarizers\Range; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Range::make())

上述示例会找出表格中的最低价和最高价。从源码看,Range.php 的summarize()会执行一条selectRaw("min(...) as ..., max(...) as ...")的查询并返回[最小值, 最大值]二元组。

日期范围

使用minimalDateTimeDifference()可以将范围格式化为日期,并以"最小差异"方式展示:

use Filament\Tables\Columns\Summarizers\Range; use Filament\Tables\Columns\TextColumn; TextColumn::make('created_at') ->dateTime() ->summarize(Range::make()->minimalDateTimeDifference())

该方法会呈现最小值与最大值之间的最小差异(实现见 Range.php),具体规则:

  • 如果最小、最大日期不是同一天,只显示日期;
  • 如果最小、最大日期在同一天但时间不同,日期和时间都显示;
  • 如果最小、最大日期时间完全相同,只显示一次。

文本范围

使用minimalTextualDifference()将范围格式化为文本:

use Filament\Tables\Columns\Summarizers\Range; use Filament\Tables\Columns\TextColumn; TextColumn::make('sku') ->summarize(Range::make()->minimalTextualDifference())

该方法呈现两个值之间的最小差异(实现见 Range.php):

  • 如果最小、最大值首字母不同,只显示第一个字母;
  • 如果首字母相同,则持续追加字符直到出现差异为止(大小写不敏感比较);
  • 如果两个值完全相同,只显示一次。

范围中是否包含 null 值

默认情况下,Range会从计算中排除 null 值(源码中$shouldExcludeNull默认为true,并在查询中自动追加whereNotNull($attribute),见 Range.php)。如需包含 null 值,可以使用excludeNull(false)

use Filament\Tables\Columns\Summarizers\Range; use Filament\Tables\Columns\TextColumn; TextColumn::make('sku') ->summarize(Range::make()->excludeNull(false))

求和(Sum)

使用Sum计算数据集中所有值的总和:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make())

上述示例会将表中所有价格相加。与Average相同,Sum也会在setUp()中默认启用数字格式化(见 Sum.php)。

设置标签

使用label()方法为汇总器设置标签:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->label('Total'))

不设置时,会回退到各汇总器getDefaultLabel()返回的翻译字符串(如filament-tables::table.summary.summarizers.sum.label,见 Sum.php)。label()也可以传入闭包进行动态求值,并支持translateLabel()开启翻译(见 HasLabel.php)。

隐藏标签

不建议通过将标签设置为空字符串来"隐藏"它:虽然视觉上达到了隐藏效果,但屏幕阅读器(screen readers)将无法感知该汇总器的用途。正确做法是使用hiddenLabel(),它在视觉上隐藏标签的同时,仍将其保留在无障碍树中(渲染时给标签追加fi-sr-onlyclass,见 Summarizer.php):

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->hiddenLabel())

hiddenLabel()也支持传入布尔值或闭包进行条件隐藏:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->hiddenLabel(FeatureFlag::active()))

作用域(Scoping the dataset)

使用query()方法可以为汇总器的数据集施加数据库查询作用域。query()既接受闭包(作为查询修改器,保存在modifyQueryUsing),也接受查询构建器实例(见 InteractsWithTableQuery.php):

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\TextColumn; use Illuminate\Database\Query\Builder; TextColumn::make('rating') ->summarize( Average::make()->query(fn (Builder $query) => $query->where('is_published', true)), ),

上述示例中,只有is_publishedtrue的行才会参与平均值计算。

该特性与计数汇总器配合尤为实用——可以统计数据集中通过某项测试的记录数:

use Filament\Tables\Columns\IconColumn; use Filament\Tables\Columns\Summarizers\Count; use Illuminate\Database\Query\Builder; IconColumn::make('is_published') ->boolean() ->summarize( Count::make()->query(fn (Builder $query) => $query->where('is_published', true)), ),

在底层,Summarizer::getState()会对传入的查询clone()一份再进行计算(见 Summarizer.php),因此作用域修改不会污染表格主查询;同时源码中还处理了关联关系列(通过whereHas反向关联统计)与多对多中间表列(pivot.xxx)等复杂场景。

格式化(Formatting)

数字格式化

numeric()方法将汇总值格式化为数字:

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\TextColumn; TextColumn::make('rating') ->summarize(Average::make()->numeric())

可以通过decimalPlaces参数自定义小数位数:

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\TextColumn; TextColumn::make('rating') ->summarize(Average::make()->numeric( decimalPlaces: 0, ))

默认使用应用(app)的 locale 进行格式化;也可以传入locale参数指定:

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\TextColumn; TextColumn::make('rating') ->summarize(Average::make()->numeric( locale: 'nl', ))

从源码看,CanFormatState.php 中的numeric()最终调用Illuminate\Support\Number::format()完成本地化数字格式化;同时它还支持decimalSeparatorthousandsSeparatormaxDecimalPlaces等参数,且locale未指定时优先回退到$summarizer->getTable()->getDefaultNumberLocale(),其次才是config('app.locale')

货币格式化

money()方法可以方便地以任意货币格式化金额:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->money('EUR'))

money()还提供divideBy参数,在格式化之前先将原始值除以指定数。例如数据库中以"分"存储价格时:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->money('EUR', divideBy: 100))

默认使用应用的 locale 格式化货币;同样可以传入locale参数:

use Filament\Tables\Columns\Summarizers\Average; use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->money('EUR', locale: 'nl'))

还可以通过decimalPlaces参数自定义小数位数:

use Filament\Tables\Columns\TextColumn; TextColumn::make('price') ->summarize(Sum::make()->money('EUR', decimalPlaces: 3))

底层实现见 CanFormatState.php:货币未指定时回退到表格的getDefaultCurrency(),最终通过Number::currency()格式化。

限制文本长度

使用limit()限制汇总值的显示长度:

use Filament\Tables\Columns\Summarizers\Range; use Filament\Tables\Columns\TextColumn; TextColumn::make('sku') ->summarize(Range::make()->limit(5))

limit(int $length = 100, ?string $end = '...')内部通过Str::limit()截断文本(见 CanFormatState.php),end参数可自定义省略后缀。

添加前缀或后缀

使用prefix()/suffix()为汇总值添加前缀或后缀,二者都支持Htmlable(如HtmlString),便于插入上标等富文本内容:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; use Illuminate\Support\HtmlString; TextColumn::make('volume') ->summarize(Sum::make() ->prefix('Total volume: ') ->suffix(new HtmlString(' m³')) )

从 CanFormatState.php 的formatState()可以看出:当前缀/后缀是Htmlable时,渲染会自动切换为 HTML 输出模式;该 trait 还提供placeholder()html()markdown()等格式化辅助方法。

自定义汇总器(Custom Summaries)

通过using()方法可以直接返回自定义计算值,无需新建类:

use Filament\Tables\Columns\Summarizers\Summarizer; use Filament\Tables\Columns\TextColumn; use Illuminate\Database\Query\Builder; TextColumn::make('name') ->summarize(Summarizer::make() ->label('First last name') ->using(fn (Builder $query): string => $query->min('last_name')))

回调可以访问数据库$query构建器实例进行任意计算,并返回要在表格中显示的值。底层using()将闭包保存在$using属性中,getState()优先执行该闭包(见 Summarizer.php)。

如果希望复用一段自定义汇总逻辑,更规范的做法是继承Summarizer基类并重写summarize(Builder $query, string $attribute)方法(基类默认返回null,见 Summarizer.php),同时可以像内置汇总器一样覆写getDefaultLabel()提供默认标签。

条件隐藏汇总(Conditionally hiding the summary)

hidden()方法传入布尔值或返回布尔值的函数即可隐藏汇总。闭包可以通过$query参数访问该汇总器的 Eloquent 查询构建器实例:

use Filament\Tables\Columns\Summarizers\Summarizer; use Filament\Tables\Columns\TextColumn; use Illuminate\Database\Eloquent\Builder; TextColumn::make('sku') ->summarize(Summarizer::make() ->hidden(fn (Builder $query): bool => ! $query->exists()))

visible()方法则达到相反效果:

use Filament\Tables\Columns\Summarizers\Summarizer; use Filament\Tables\Columns\TextColumn; use Illuminate\Database\Eloquent\Builder; TextColumn::make('sku') ->summarize(Summarizer::make() ->visible(fn (Builder $query): bool => $query->exists()))

从 CanBeHidden.php 的源码可以看到,可见性判断会基于当前查询 SQL 做结果缓存(visibilityCache),且当传入query()查询时,getSummarizers($query)只会返回可见的汇总器(见 CanBeSummarized.php),即不可见的汇总器连查询都不会执行。

汇总分组行(Summarising groups of rows)

汇总可以配合分组(grouping)使用:只要在分组表格的列上添加汇总器,Filament 会自动为每个分组内部的记录渲染汇总,无需额外配置。

仅显示分组汇总、隐藏分组明细行

使用groupsOnly()方法可以隐藏分组内的数据行、只展示每个分组的汇总结果,这在报表类场景中非常实用:

use Filament\Tables\Columns\Summarizers\Sum; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Table; public function table(Table $table): Table { return $table ->columns([ TextColumn::make('views_count') ->summarize(Sum::make()), TextColumn::make('likes_count') ->summarize(Sum::make()), ]) ->defaultGroup('category') ->groupsOnly(); }

上述示例会按category分组,并仅显示每个分类下views_countlikes_count的求和结果。

隐藏汇总行(Hiding summary rows)

默认情况下,只要列上存在汇总器,当前页汇总行全表总计汇总行都会显示。你可以通过表格的summaries()方法控制哪些汇总行出现(该方法定义在 packages/tables/src/Table/Concerns/CanSummarizeRecords.php):

use Filament\Tables\Table; public function table(Table $table): Table { return $table ->summaries( pageCondition: false, allTableCondition: false ); }
  • pageCondition控制"当前页(this page)"汇总行是否显示;
  • allTableCondition控制"全表总计(all data)"汇总行是否显示。

这在以下场景中很有价值:使用分组汇总时只想按组展示汇总;或者当前页汇总冗余、只需全量总计时。

小结

Filament 的汇总机制以"列为中心":通过summarize()AverageCountRangeSum四类内置汇总器(或自定义Summarizer)挂载到任意列上,所有聚合计算均下沉到数据库执行,并自动区分当前页与全表两个统计层级。配合query()作用域、numeric()/money()/limit()/prefix()/suffix()等格式化能力,以及分组汇总与summaries()行级开关,开发者可以快速构建从简单求和到复杂报表的各类统计场景。

进一步阅读:表格列基础用法见 packages/tables/docs/01-overview.md,分组功能见 packages/tables/docs/07-grouping.md,图标列与icons()计数的配合见 packages/tables/docs/02-columns/09-icon.md,汇总器全部源码位于 packages/tables/src/Columns/Summarizers。

【免费下载链接】filamentA powerful open-source UI framework for Laravel • Build and ship apps & admin panels fast with Livewire项目地址: https://gitcode.com/GitHub_Trending/fi/filament

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 6:20:38

Docker镜像构建优化与前后端部署实践

1. Docker镜像构建基础概念解析 在现代化应用部署流程中,Docker镜像已成为软件交付的标准单元。对于前后端分离架构的项目,合理的镜像构建策略直接影响着部署效率和运行稳定性。我经历过数十个企业级项目的容器化改造,发现90%的构建问题都源于…

作者头像 李华
网站建设 2026/9/11 6:20:34

Mojo 贡献区域指南:编译器与标准库的贡献边界与实操路径

Mojo 贡献区域指南:编译器与标准库的贡献边界与实操路径 【免费下载链接】mojo The Modular Platform (includes MAX & Mojo) 项目地址: https://gitcode.com/GitHub_Trending/mo/mojo 本文档基于 Mojo 开源仓库的 contribution-areas.md 编写&#xff0c…

作者头像 李华
网站建设 2026/9/11 6:20:16

Java Getter/Setter 方法详解:从基础到高级应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:18:58

多租户酒店小程序系统架构设计与实践

1. 多用户酒店小程序系统的核心价值与市场定位在移动互联网深度渗透酒店行业的今天,传统单体酒店小程序已无法满足连锁品牌、加盟集团和区域酒店联盟的运营需求。我去年为某东南亚连锁酒店集团设计多租户系统时,发现他们最头疼的问题是:旗下1…

作者头像 李华