列表分页
TanzCMS 官方文档示例,展示模板标签、开放 API、内容管理和部署说明。
前台列表搜索筛选分页规范
本文记录前台、会员中心和插件前台列表类页面的统一查询规范。目标是让搜索、筛选和分页从一开始就按同一套边界实现,避免每个页面慢了以后再专项补丁。
一、适用范围
适用于以下页面:
- 前台首页内容区、栏目页、列表页、搜索页、标签页、归档页。
- 会员中心列表,例如投稿、订单、收藏、资产流水。
- 插件前台列表,例如订单查询、充值记录、下载记录。
- 后台列表另有后台 CRUD 和后台性能规范,但索引、分页和搜索原则保持一致。
不适用于:
- 详情页正文读取。
- 后台编辑页完整表单数据。
- 导入、迁移、索引重建、批处理命令。
二、基本原则
列表页默认只查当前页需要展示的轻字段,不默认读取正文、大 JSON、大附件列表或完整模型扩展数据。需要详情数据时进入详情页或显式批量读取当前页数据。
搜索和筛选必须先明确作用域:
- 内容模型列表走
ContentQuery、content_search_idx和content_field_idx。 - 会员自身列表先限定
member_id、seller_member_id或当前会员可见范围。 - 插件业务列表优先使用插件自身快照字段和业务索引,不为了显示内容标题而回查核心内容表。
能用索引表达的条件必须走索引。缺字段索引、缺搜索索引、缺业务索引时,处理方式是补迁移、重建索引或修复测试数据,不在业务代码里退回全表模糊查询。
三、搜索规范
内容搜索:
- 标题、摘要、关键词、正文摘要走
content_search_idx。 - 中文模糊搜索优先使用已验证的 FULLTEXT ngram 单列组合索引。
- ID、slug、订单号、手机号、邮箱等精确模式走 BTree 或业务专用索引。
- 搜索参数不得传 SQL 片段,只能传声明式参数。
- 前台搜索结果数量以
content_search_idx为准,不直接以content_items的LIKE结果作为页面结果。线上排查“原表有 15 条、搜索页只有 5 条”时,必须同时检查content_search_idx是否同步;索引不一致时先执行tanzcms:search-rebuild,不要把所有差异都归因到页面缓存。 - 中文关键词如“合击”应走可控的 LIKE/索引搜索路径,避免被 MySQL 全文分词差异截断。修改搜索逻辑后,必须用原表计数、搜索索引计数和前台页面结果三者对照。
搜索与筛选边界:
- 搜索框提交的是关键词搜索,例如
/search/合击.html表示标题或指定搜索字段包含“合击”。 - 筛选按钮提交的是字段筛选,例如
/search?version_type=392表示“版本类型字段等于合击”。 - 两者不是同一个条件。筛选按钮不应默认继承当前搜索关键词,否则会变成“标题包含合击 AND 版本类型等于合击”,导致结果看起来被错误缩小。
- 官方
xin001这类筛选区应只保留筛选项之间的联动参数,如buy_type、engine、version_type;不要在筛选链接里写keyword=$keyword,除非需求明确要求组合搜索。
会员中心订单搜索:
- 会员订单页已经限定当前买家或卖家,不走全站内容搜索。
- 订单号类关键词走
order_no/payment_order_no前缀匹配。 - 普通关键词在当前会员范围内匹配订单快照
subject/order_no/payment_order_no。 - 不在会员中心订单列表里 join 正文表或核心内容表补搜索条件。
会员投稿搜索:
- 当前阶段会员投稿页没有搜索框,默认只验收分页。
- 后续如新增投稿搜索,应先限定当前会员,再按标题前缀、状态、栏目等索引字段筛选。
- 需要搜索正文时应另建搜索索引或进入内容搜索体系,不直接扫
member_post_data。
四、筛选规范
内容字段筛选:
- 字段必须在模型字段中声明可筛选,并写入
content_field_idx。 - 多字段组合筛选由查询服务解析字段元数据后生成索引查询。
- 未命中字段索引定义时直接报结构问题,不 join 模型数据表兜底。
- 高频稳定字段可以进入热字段升级候选,但必须走 IndexAdvisor、DDL 预览、审计和
EXPLAIN ANALYZE验收。
业务表筛选:
- 会员、订单、资产、充值、下载等插件业务表应按真实业务查询建立组合索引。
- 列表筛选应尽量使用状态、会员、时间、订单号、业务类型这类低成本字段。
- 任意文本模糊筛选必须先限定可控范围,例如当前会员、当前商家、当前时间窗口。
五、分页规范
普通列表第一页可以使用精确总数。第一页返回数量小于每页数量时,可以直接判定总数,避免额外 COUNT(*)。
深分页按页面类型处理:
- 后台管理列表:优先优化,不轻易拦截用户;使用轻字段、覆盖索引、降序索引和延迟关联。
- 前台栏目、标签、归档:属于有限参数空间,可保留较深页,配合缓存、sitemap、
noindex或软限制。 - 前台搜索、组合筛选、任意参数页:属于无限参数空间,必须有预算、缓存、告警或限制。
- RSS、API、批量接口:优先使用游标、时间范围或 ID 边界。
- 会员中心列表:先限定当前会员或卖家,再按
member_id,id、seller_member_id,id等复合索引分页。
大表深分页推荐模式:
- 用覆盖索引按当前筛选条件取当前页 ID。
- 再按 ID 读取当前页展示字段。
- 按 ID 结果恢复排序。
这适用于后台内容列表、会员订单、会员投稿等“当前页展示字段多于索引字段”的场景。
首页、栏目页和搜索页可以用懒加载改善首屏和滚动体验,但分页口径与每次加载数量要分开:
pagesize决定分页总页数和{$pages}。limit或num决定单次查询返回多少条。chunk可用于同一页内分批加载,例如首页按pagesize=300计算分页,但首屏limit=50,下拉时继续请求chunk=2、3...每批 50 条。- 这种场景仍然请求完整页面模板,由前端从完整页面里取
data-infinite-list,不要为了每批 50 条新建 rows 片段模板。
六、rows 片段边界
fragment=rows、list_rows.html、search_rows.html 这类片段不是主题必备项,也不是性能验收默认项。
默认规则:不要新增 rows 片段。首页、栏目页、列表页和搜索页本身已经能通过 {content}、{search}、page、pagesize、chunk 和主题 JS 完成分页、筛选和懒加载。
只有用户明确要求“单独的局部片段接口”或插件明确需要局部刷新端点时,才允许设计 fragment=rows。默认主题不保留 index_rows.html、list_rows.html、search_rows.html、partials/*_rows.html 这类历史片段;不能因为懒加载、无限滚动或性能担忧,就主动新增 rows 模板或控制器里的 rows 分支。
默认性能探针不请求 rows 片段,避免把一个未启用的交互当成性能问题。主题没有 rows 片段时,不应因为探针访问 fragment=rows 而被判失败。
不允许的做法:
- 在
HomeController、CategoryController、SearchController中为单个主题硬编码fragment=rows分支。 - 在主题里新增
*_rows.html后再让完整页面依赖它。 - 为了少传头尾而绕过正常模板渲染、栏目模板配置或权限边界。
- 把 rows 片段缺失当作线上性能、缓存或模板错误。
如果主题启用了 rows 片段,则该片段应:
- 只输出当前页行内容,不输出完整头尾和整页布局。
- 默认不做精确总数统计,除非交互确实需要。
- 使用与完整页面一致的查询参数和权限边界。
- 由主题自身或交互功能提供测试,不作为所有主题的通用必测项。
上线排查时要区分这些缓存和索引:
- 页面响应头
X-TanzCMS-Page-Cache: HIT/MISS只说明页面响应缓存是否命中。 - 模板源文件已更新但页面仍输出旧 HTML 时,检查
storage/framework/tanzcms/templates、template-tags、template-controls、template-expressions,并考虑 PHP-FPM OPcache。 - 搜索结果数量不对时,先对照
content_items和content_search_idx,必要时重建搜索索引;字段筛选结果不对时,对照content_field_idx,必要时重建字段索引。 - 后台“清所有缓存”不能替代 PHP-FPM/OPcache 重启,也不能修复未同步的搜索索引。
目标站点排查时,应先核对模板源文件、搜索索引、字段索引和模板缓存。需要执行命令时,应在目标站点根目录使用当前站点实际 PHP CLI,并按站点实际主题名、模型和关键词调整参数。不要把示例路径或服务管理命令照搬到不同服务器。
七、验收方式
默认前台性能验收覆盖:
- 首页。
- 栏目第一页和栏目深分页。
- 搜索页。
- 搜索 + 筛选组合页。
- 详情页。
- 会员登录、注册、会员中心。
- 会员投稿列表和深分页。
- 会员订单列表、深分页、搜索。
- 插件前台关键页面。
rows 片段、特殊筛选页、特殊插件页面只在功能启用时加入专项探针。
验收时可使用:
php artisan tanzcms:frontend-hotpath-probe --json
php artisan tanzcms:performance-baseline --after-id=日志ID --fail-on-warning
php artisan tanzcms:performance-assert --after-id=日志ID --min-samples=1
验收结论必须基于真实日志、真实 SQL 和实际响应大小,不使用“估计、预估、大概”作为性能判断。