59-pagination-js-pagernav-vue.md 9.1 KB

前端执行票 —— 统一分页批次一:共享分页基建(pagination.js + PagerNav.vue)与设备详情三清单

Question

按 全局分页规范 落地批次一:把 domain/equipmentDetailView.js 的 pagedRows 升格为单源 domain/pagination.js(PAGE_SIZE = 10、pagedRows、页码窗口函数;HISTORY_PAGE_SIZE/pagedRows 原名保留导出兼容),新建共享 PagerNav.vue(上一页|页码直达|下一页 + 数字输入框跳页 + 计数行「第 X/Y 页 · 共 N 条」,一页不渲染、到边禁用保占位、aria-current="page"、总页数 >7 收缩「1 … c−1 c c+1 … Y」窗口);EquipmentDetailSections.vue 预警/报警迁移到共享 pager 并补页码直达,工单状态新接入分页(10/页)。

Acceptance

  • 页码窗口规则有纯函数闸门(≤7 全列;>7 收缩含首末与省略号;非法输入不抛错)。
  • 跳页(维护者 2026-10-19 追加,规范「跳页」节):pager 提供输入框 + 「跳转」按钮/Enter;非数字、0、超 pageCount 一律夹回 1..pageCount,不报错、不发请求;aria-label="跳转到指定页"、placeholder=当前页;跳页与页码/前后页共用同一翻页出口,不新增第二套页码状态;总页数 ≤1 时整块不渲染。
  • 预警/报警翻页行为与现状等价(分类变化回第 1 页、换设备全复位、越界夹回)+ 新增页码直达与跳页;t46 既有闸门按成例改写后全绿。
  • 工单状态每页 ≤10、一页不画控件、分类变化回第 1 页。
  • pager 控件唯一(PagerNav.vue),组件内不再有第二份翻页算术;data-pager/data-page-prev/data-page-next/data-page-state 断言面保留,跳页新增 data-page-jump/data-page-jump-input。
  • 新增闸门 + 变异打红;按 AGENTS.md 跳过 build/dev/浏览器验证。

Context

先例:domain/equipmentDetailView.js(pagedRows 纯函数)+ 票 46 实施记录。教训复用:票 43(视图状态必须用稳定标量键,不能用对象身份);复位触发器在组件 watch(deviceCode)。维护者裁定(2026-10-18 台账/事件、2026-10-19 跳页)见规范「维护者裁定」「跳页」「修订记录」节。

Related spec

../specs/2026-10-18-global-list-pagination.md

Status: resolved Assignees: Qoder Type: task Blocked by: Labels: wayfinder:task

Comments

  • 批次一开工说明:本票为纯执行票(ready-for-agent,无 needs-triage),无阻塞边,完成后解锁批次二~五(票 60–68 共 9 张 blocked by 本票)。仓内既有资料(规范 + 票 46 实施记录 + equipmentDetailView.pagedRows 先例)足以回答本次全部问题,未新开 research 笔记。

Answer

已实施、闸门 + 变异闭环并关闭(2026-10-19)。按 AGENTS.md 跳过 build/dev/浏览器验证。

交付物

文件 内容
src/modules/cockpit/domain/pagination.js(新) 翻页窗口计算单源:PAGE_SIZE = 10、PAGE_ELLIPSIS = '…'、pagedRows(自票 46 逐字升格,行为不变)、pageWindow(current, total)(≤7 全列;>7 收缩「1 … c−1 c c+1 … Y」,恒含首末+当前页+至少一个省略号;脏输入按最小安全形状回、不抛)、clampPage(value, pageCount)(跳页夹回 1..pageCount;非数字/空/null→1,绝不回 NaN;小数截断;脏 pageCount→1)
src/modules/cockpit/domain/equipmentDetailView.js pagedRows/HISTORY_PAGE_SIZE 改为原名兼容再导出 export { PAGE_SIZE as HISTORY_PAGE_SIZE, pagedRows } from './pagination.js'(同一函数引用,非复制实现),旧调用与 t46 闸门零改动可跑
src/modules/cockpit/components/PagerNav.vue(新) 全仓唯一共享 pager:上一页|页码直达|下一页 + 数字输入框跳页 + 计数行「第 X/Y 页 · 共 N 条」;pageCount<=1 整块不渲染;到边 disabled 保占位;当前页 aria-current="page" 且点击不跳;role="group" + 「列表名」分页 aria-label;跳页 aria-label="跳转到指定页"、:placeholder="String(page)"、Enter + 按钮双入口
src/modules/cockpit/components/EquipmentDetailSections.vue 预警/报警/工单三清单都接共享 PagerNav;内联 pager 与 .equipment-pager__* 样式退役;工单列表循环 visibleRows(panel) → pagedOf(panel).rows(新接入分页);pagedOf 收敛为单一委托(不再按 kind 分叉兜底形状)

关键设计(唯一翻页出口)

规范「跳页」节要求「跳页与页码/前后页共用同一个翻页出口,不新增第二套页码状态」。落地形态:PagerNav 是受控组件——本地只有跳页输入缓冲(jumpValue),页码一律从 props.page 进;defineEmits(['page']) 单一事件,所有交互(前后页/页码直达/跳页)统一 emit 绝对目标页码(1 起),由 go() 一处出口发出。

第一版草稿曾用相对增量(emit('change', -1|1|target)),点第 1 页(当前 2 页)emit -1 与「上一页」撞车、父组件必须靠 !== -1 && !== 1 猜意图——那不是同一出口,是两套状态挤在一个通道里。改为绝对页码后父侧只需 gotoPage(panel, target) 存状态,越界夹回由 pagedRows 下一帧渲染时做(条文 6),组件内零 Math.min/max。

跳页同值不 emit(不发请求、不清列表);输入经 clampPage 后走同一 go()。复位规则不变:toggleCategory 回第 1 页、watch(deviceCode) 全复位。

验证

  • 新增闸门 t59-shared-pager.mjs 37/37:P 单源与兼容(P2 判同一函数引用、P3 判旧模块无残留实现、P5 越界夹回);W 页码窗口九条(含 7 页阈值边界、8 页起步收缩、贴左不出现假省略号、恒含首末与当前页、数字升序无重复、脏输入不抛);J 跳页夹回五条;S PagerNav 静态守卫九条(按绑定判不按字样判);C 消费方七条(C4 判组件零 Math.ceil/trunc/floor、零 .slice(、零内联 pager、零 hasPrev/hasNext——第二份算术即红);K 两份 .vue 用 @vue/compiler-sfc 真实编译过(票 41 教训:拼错的绑定只有加载层判得出)。
  • 变异闸 t59-mutations.mjs 13/13 打红并按字节还原:M1 阈值 7→5 / M2 右侧省略号不推 / M3 夹回放 NaN 过 / M4 只夹下不夹上 / M5 一页也画控件 / M6 出口改名出第二个事件 / M7 到边不再禁用 / M8 丢 aria-current / M9 跳页绕过 clampPage / M10 兼容导出改名(崩溃式抓住)/ M11 组件重长翻页算术 / M12 工单退回全量直渲 / M13 换分类不再回第 1 页。
  • t46 既有闸门按成例改写后全绿(54/54 + 变异 12/12):E3 的「工单走过滤行」改为「工单也走分页行」;E3b 从「内联按钮按 hasPrev/hasNext 置灰」改判「内联 pager 退役 + 接共享 PagerNav + 唯一 @page→gotoPage 出口」;M5/M8 变异锚点随升格从 equipmentDetailView.js 移到 pagination.js(G 节测的仍是兼容再导出,同一份实现)。
  • 回归与 HEAD 基线对照(本票 diff 只 5 个文件,余为并行在制品):t41 SSR 9/9、t23、t15 11/11 全绿;t12 由基线 51/52 保持 51/52(E8 经 worktree 基线证实为改前既有红,与本票零交集)。
  • t12 扫描器假红修正:F11 把事件处理器里的箭头形参 target 误报成未绑定标识符(与本文件既有「v-for 局部名」同类的判据过宽,注释里已记三次同类实测)。按成例把 ([^)]*)\s*=> 的形参收进模板局部名,不改组件写法迁就守卫。

验收对照

  1. ✅ 窗口纯函数闸门 W1–W9 + 变异 M1/M2。
  2. ✅ 跳页:输入框 + 按钮/Enter;非数字/0/超界夹回不报错不发请求(J1–J5、M3/M4);aria-label/placeholder(S5);同一出口不新增第二套状态(S2/S6/S8、M6/M9);≤1 页整块不渲染(S1、M5)。
  3. ✅ 预警/报警行为等价(C5 复位规则、P5 越界夹回)+ 页码直达与跳页;t46 改写后 54/54。
  4. ✅ 工单 ≤10/页(C3、M12)、一页不画控件(S1)、分类变化回第 1 页(C5、M13)。
  5. ✅ pager 唯一 + 组件无第二份算术(C4、M11);data-pager/prev/next/state 保留、新增 data-page-jump/data-page-jump-input(S9)。
  6. ✅ 新增闸门 + 变异打红;按 AGENTS.md 跳过 build/dev/浏览器验证。

状态与下一步

批次一收口,票 60–68 九张批次的共享前置已就位(pagination.js 单源 + PagerNav.vue 唯一控件可直接接入;服务端分页与渐进装载批次另需按规范三分法扩参)。两点如实留档:① 改动未提交(工作树混票 46/50/51 等并行在制品,入库须按票 33/36/37 纪律单独裁剪本票 5 个文件的 hunks);② 浏览器走查按项目规则未自动执行,真机验收归票 18/17 联调窗口。