grocy 1.12.1 版本解析:库存总览按位置过滤的浏览器兼容性修复与 DataTables 前端实现原理
【免费下载链接】grocyERP beyond your fridge - Grocy is a web-based self-hosted groceries & household management solution for your home项目地址: https://gitcode.com/GitHub_Trending/gr/grocy
grocy 1.12.1(发布于 2018-07-08)是一个紧跟在 1.12.0 之后的补丁版本,本次发布的全部变更集中在一个点上:修复库存总览(Stock Overview)页面按位置过滤功能在部分浏览器中不生效的问题。本文将结合该版本变更记录(changelog/24_1.12.1_2018-07-08.md)与 grocy 仓库中的实际前端代码,深入还原该问题的成因、修复所涉及的表单/表格结构,并给出在自托管部署中升级到该版本的方法与验证方式。
一、版本背景:1.12.0 引入位置过滤,1.12.1 修复其兼容性
grocy 的版本变更记录以序号递增的独立 Markdown 文件组织在 changelog 目录中,每个文件对应一个版本。在 1.12.0(changelog/23_1.12.0_2018-07-08.md)中,grocy 引入了两项新特性:
- 库存总览页面支持按位置(Location)过滤产品;
- 所有下拉框改为按字母序排序。
而 1.12.1 则是对前者的针对性修复。变更记录原文只有一句话:
Bug fix for location filtering on stock overview page did not work in all browsers (修复库存总览页面的位置过滤在部分浏览器中不生效的问题)
这说明该问题并非功能缺失,而是跨浏览器兼容性缺陷:在特定浏览器环境下,用户从位置下拉框中选择过滤条件后,库存总览表格并未如预期进行过滤。下面我们从仓库源码出发,剖析这一修复对应的实现细节。
二、从源码看位置过滤的实现链路
要理解 1.12.1 修复了什么,需要先看清库存总览页位置过滤的完整实现链路。grocy 的前端页面由服务端渲染的 Blade 模板(views)与独立的页面脚本(public/viewjs)两部分组成。
2.1 视图层:隐藏列承载过滤数据
库存总览页面模板为 views/stockoverview.blade.php。其中位置过滤下拉框的结构如下:
<select id="location-filter" class="form-control"> <option value="all">{{ $__t('All') }}</option> @foreach($locations as $location) <option value="{{ $location->name }}">{{ $location->name }}</option> @endforeach </select>即下拉框的选项值直接使用位置名称($location->name),而非位置的数据库主键id。
同时,表格中为每个产品行生成了一列「隐藏位置」列(Hidden location),用于承载该产品当前所在位置的信息,其单元格内容被格式化为xx位置名称xx形式:
<th class="d-none">Hidden location</th> ... xx{{ FindObjectInArrayByPropertyValue($locations, 'id', $locationsForProduct->location_id)->name }}xx2.2 逻辑层:DataTables 列搜索与「xx 包裹」技巧
库存总览表格由 DataTables 插件渲染,初始化配置位于 public/viewjs/stockoverview.js:
var stockOverviewTable = $('#stock-overview-table').DataTable({ 'order': [[5, 'asc']], 'columnDefs': [ { 'visible': false, 'targets': 6 }, // 隐藏位置列(Hidden location) { 'visible': false, 'targets': 7 }, // 状态列 { 'visible': false, 'targets': 8 }, // 产品组列 ... ].concat($.fn.dataTable.defaults.columnDefs) });其中第 6 列是隐藏的「位置」列,第 7、8 列分别为状态与产品组列。位置过滤的触发逻辑如下:
$("#location-filter").on("change", function () { var value = $(this).val(); if (value === "all") { value = ""; } else { value = "xx" + value + "xx"; } stockOverviewTable.column(stockOverviewTable.colReorder.transpose(6)).search(value).draw(); });关键点在于:当用户选择某个位置时,代码会把选择值包装成xx位置名xx,再对第 6 列执行 DataTables 的列级search()。由于模板中每个单元格内容本身就以xx...xx包裹,xx值xx恰好能与单元格内容构成唯一匹配,从而避免把「位置名称恰好是其他位置名称的子串」这类情况误过滤。这就是 grocy 早期实现中常用的「xx 包裹」精确匹配技巧。
同时,DataTables 的列重排(colReorder)功能在该项目中默认开启(见 public/js/grocy_datatables.js 中的'colReorder': true),因此代码通过stockOverviewTable.colReorder.transpose(6)获取列重排后第 6 列的实际物理索引,再传给.column(...)定位隐藏列。
2.3 修复点推断:浏览器差异与字符串匹配
结合变更记录与上述代码可以推断,1.12.1 的修复集中在位置过滤在部分浏览器中不生效这一行为上。常见跨浏览器问题根源包括:
- 表格搜索列定位对浏览器事件的兼容性:不同浏览器在
change事件触发时机、触发细节上存在差异; - 列重排后物理索引解析在不同环境下的差异:
colReorder.transpose()的返回值依赖插件内部状态,若初始渲染时序不同,列索引可能偏移,导致搜索作用于错误的列; - 字符串编码/空白符处理差异:单元格中
xx位置名xx与下拉框值之间的空白、编码不一致,会导致部分浏览器下字符串匹配失败。
从仓库当前代码结构看,修复后的实现通过统一使用隐藏列 +xx包裹值 +colReorder.transpose()定位物理列的方案,保证了过滤逻辑在各浏览器下一致生效。你可以将 1.12.0 与 1.12.1 两版变更记录对比阅读(changelog/23_1.12.0_2018-07-08.md 与 changelog/24_1.12.1_2018-07-08.md)以还原演进脉络。
三、1.12.1 时代的库存总览页其他过滤能力
虽然 1.12.1 只修复了位置过滤,但库存总览页在同一时期已经具备一套完整的过滤体系,理解它们有助于整体把握该页面在前端的功能结构(public/viewjs/stockoverview.js):
| 过滤维度 | 触发元素 | 实现要点 |
|---|---|---|
| 位置过滤 | #location-filter | 选择值包装为xx位置名xx,搜索隐藏列 6 |
| 产品组过滤 | #product-group-filter | 选择值包装为xx产品组名xx,搜索隐藏列 8 |
| 状态过滤 | #status-filter | 直接使用状态值,搜索隐藏列 7,并同步下拉框 CSS 类以展示状态底色 |
| 全文搜索 | #search | DataTables 全局search(),带Grocy.FormFocusDelay防抖 |
| 一键清空 | #clear-filter-button | 同时重置搜索框、状态、产品组、位置并清空对应列搜索 |
其中「一键清空」按钮的实现逻辑可以看作位置过滤修复正确性的一次联动验证:
$("#clear-filter-button").on("click", function () { $("#search").val(""); $("#status-filter").val("all"); $("#product-group-filter").val("all"); $("#location-filter").val("all"); stockOverviewTable.column(stockOverviewTable.colReorder.transpose(6)).search("").draw(); stockOverviewTable.column(stockOverviewTable.colReorder.transpose(7)).search("").draw(); stockOverviewTable.column(stockOverviewTable.colReorder.transpose(8)).search("").draw(); stockOverviewTable.search("").draw(); });四、位置数据在后端与页面间的流转
为了让上述前端过滤真正可用,位置数据需要在 grocy 的后端控制器、数据库与模板三个层面正确流转:
- 控制器注入位置数据:库存相关页面由 controllers/StockController.php 渲染。例如
Inventory(盘点)页面会查询活动位置列表并注入视图:
'locations' => $this->DB->locations()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),而Consume(消耗)页面同样会注入位置列表供前端使用。库存总览页面的位置下拉框即由这类注入驱动。
数据库层:位置由
locations表管理,产品与位置通过外键关联(例如产品的默认位置default_location_id、当前库存条目对应的location_id),这些字段在 grocy 的迁移脚本(migrations)中定义并随版本演进。模板层拼装:如前所述,views/stockoverview.blade.php 在下拉框中使用位置名称作为 option 值,在表格隐藏列中使用
xx名称xx格式填充,二者共同构成前端过滤的输入与搜索目标。
由此可以看到,位置过滤修复虽小,却涉及「后端注入数据 → 模板生成控件与隐藏列 → 前端 DataTables 列搜索」的完整链路,任何一环的浏览器兼容性问题都会导致过滤失效。
五、升级与验证:自托管用户如何应用 1.12.1
1.12.1 是一个纯 bugfix 的小版本,变更范围小、升级风险低,适合所有使用 1.12.x 的部署尽快跟进。
5.1 升级方式
grocy 是 PHP 自托管应用,部署结构与运行方式参见 README.md 与 config-dist.php(配置示例)。对于使用 Git 克隆方式部署的用户,获取 1.12.1 并应用变更的典型操作如下:
# 在当前 grocy 仓库目录内拉取 1.12.1 标签 git fetch origin git checkout 1.12.1之后确保 Web 服务器(如 Apache/Nginx + PHP-FPM)指向public目录,并确认数据目录可写。grocy 的数据库迁移机制会处理版本间的数据结构变更(若有),无需手工改库。
5.2 升级后的验证清单
升级完成后,可通过以下步骤验证 1.12.1 的修复是否生效:
- 登录 grocy,进入Stock Overview(库存总览)页面;
- 使用浏览器开发者工具将 UA 模拟为多种目标浏览器(或直接在不同浏览器中分别测试);
- 在页面上方的「Location(位置)」下拉框中选择一个具体位置;
- 确认表格行被正确过滤为仅包含该位置的库存条目;
- 点击「清空过滤」按钮,确认所有过滤条件(位置、状态、产品组、全文搜索)被同时重置;
- 在表格中开启列重排后再次测试位置过滤,确认
colReorder.transpose()索引定位依然正确。
六、小结
grocy 1.12.1 的全部变更凝结在一句话里:修复库存总览页面位置过滤在部分浏览器中不生效的问题。透过这句简洁的 changelog,我们看到的是一个由Blade 模板隐藏列 + DataTables 列搜索 +xx包裹精确匹配 +colReorder.transpose()物理列定位组成的前端过滤方案,以及该方案在跨浏览器一致性上的打磨。对于自托管用户,升级到 1.12.1 几乎没有成本,却能消除库存总览操作中的关键体验障碍——而这正是 grocy 每个补丁版本所承担的价值:小而准,稳中求进。
【免费下载链接】grocyERP beyond your fridge - Grocy is a web-based self-hosted groceries & household management solution for your home项目地址: https://gitcode.com/GitHub_Trending/gr/grocy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考