Label: ready-for-agent Category: frontend-execution
承接票37收口时维护者反馈第1、2条。
Status: claimed)→ 诊断(范围 1)→ 实施(范围 2/3)→ 离线闸门 + 变异测试 + 回归 → 收口。AGENTS.md 项目规则:不自动运行 dev/build/截图);走查入口 http://127.0.0.1:8000/#/cockpit,判据见「验收对照」第 2 条。Status: claimed Type: task Blocked by: Labels: ready-for-agent, wayfinder:task
小间隔=绘制缺陷(像素舍入),不是设计语义。 判定过程没有把视觉现象当设计:
components/PanelBlocks.vue 的堆叠段样式原先对 left 与 width 各自独立取整 —— left: Math.round(row.start*100)%、width: Math.round(row.ratio*100)%。相邻段之间露出的底色缝 = round(nextStart*100) − (round(start*100) + round(ratio*100)),该值可为 ±1 个百分点(取决于两段各自的小数部分)。[0,1,2,1,1,3,1,0](mocks/contractMocks.js:2419 alarmWorkOrderStates,total=9)逐段复算,「待验收→已结案」边界 left+width=55 而下一段 left=56,实测 1 个百分点缝,与维护者所见一致(预警效率/报警族两处堆叠条同一算法,同一缺陷)。.panel-stacked__seg 无 margin、条容器无 gap/分隔声明,分段色由 barTone 逐态给(八态八色相)——若真要表达语义边界,应当是显式的分隔样式,而不是随数据总数随机出现在某些边界上的缝。同一对类别是否露缝取决于计数(待派单/待接单边界 0→0 不露,待验收/已结案露 1),这正是舍入噪声的特征,不是语义设计的特征。domain/panelBlocks.js stackedBlock() 每行新增 startPct / widthPct:由同一个累加器取整接力(endPct = round(acc/total*100),下一段 startPct = 上一段 endPct),末段终点恒为 100。无缝不是运气舍入的结果,而是代码结构保证(每段起点定义上就是上一段终点)。components/PanelBlocks.vue 堆叠段样式改消费这两个整数百分比,删除段内的 Math.round(...) 独立取整。total / start / ratio 原样保留未取整的精确占比,只改绘制边界;后端统计字段与工单状态码一字未动。tabindex="0" + role="img" + 每片自己的可访问名称 :aria-label="`${slice.label}:${slice.count}`"(类别与数量都在名称里,读屏可达)。@focus/@blur 接同一个共享详情浮层 showChartTip/hideChartTip(票 37 走查扩展立的浮层),CSS :focus-visible 与 :hover 同一档放大(饼 1.05 / 环 1.06)+ 增亮 + 一圈白色描边让焦点位置可见。交互风格与已验收横条统计一致(横条用 :hover/:focus-visible 同档反馈,见 .panel-bar--button)。<svg> 由 role="img" 改 role="group":img 会把整棵子树对辅助技术隐藏,扇区的名称与焦点根本读不到 —— 这是「可访问名称」真正生效的前提。<title>(原生提示有 ~1s 延迟、样式不可控,且与自绘浮层双重叠加)。这与票 37 给趋势点定的成例一致(「趋势点改用无延迟的 aria-label 详情入口,避免与自绘浮层叠加原生 title」)。barTone 八态八色相,未新增含义不明的视觉元素。tabindex + aria-label)。真实浏览器走查未执行(项目规则),走查判据:Tab 进入扇区应见描边与浮层、四类扇区逐一可读、堆叠条各类别边界不再露底色缝。total/start/ratio 保持精确值;闸门 S4 钉住这一点。新闸门 t43(13/13,全离线):S 组堆叠连续(接力构造、旧缺陷实证复现 + 新公式缝=0、宽度和=100、0 计数行保留、口径不变、渲染层消费接力值);P 组交互(两图扇区 tabindex/aria-label/focus-blur、原生 title 已清、svg role=group、:focus-visible 与 :hover 同档、环形图图例浮层对齐);D 组 donutBlock 形状与可点接缝不回归。
变异测试证明守卫有牙(3 处全部打红):
tabindex → P1-pie 红(证明逐元素正则用 (?:(?!</path>)[\s\S])*? 锚定,不会从环形图那片借断言假绿)。<title> → P2 红。回归(离线可跑的 10 组全绿):t43 13/13、t50 30/30(此前被跳过的 pinia store 断言本轮环境已恢复并实跑)、t42、t15 11/11、t23、t27、t16-stores、t16-alarm-order、t22、t19 16/16。另用仓库自带 @vue/compiler-sfc 对 PanelBlocks.vue 做结构校验(parse + compileTemplate 零错误,票 43 的 9 处接线在编译产物中逐条命中)。
既有红闸门归因:t20-overview-panels 60/66,6 条红为 B4/C2/D2b/D3/E2/F3(片区端点、载荷引用、store 裸字段),与票 42 收口时记录的 HEAD 基线同 6 条,且与本票 diff(堆叠/饼/环)零交集 —— 非本票引入。
事故与修复(如实记录):归因实验期间用 git stash push -- <两个文件> 往返,domain/panelBlocks.js 被写坏(内容变成 .vue 的模板、后被压成单行)。已恢复并逐层验证:① 从票 37 会话留下的 dangling stash blob 取回一份 js,核对后发现它是票 37 之前的旧版(旧图标名、无 KPI_ICON_COLORS、barsBlock 无 hint)——没有采用,否则会回退并行在制品;② 按本会话内已完整读过的原文(604 行)+ 本票那一处编辑重建,逐段核对;③ 结构校验:619 行 = 604 + 本票 15 行,导出符号 29 个齐全,EllipsisText 用点 15 处、text-overflow 声明 0 处(票 37 的单一口径未被破坏),role 用法逐处核对(2 个 svg group、2 个扇区 img、趋势/堆叠的 role="img" 原样保留);④ 行尾改回仓库的 CRLF(避免整文件行尾噪声污染维护者的裁剪提交);⑤ 上述全部闸门在重建后的文件上复跑转绿。git stash list 已空,未遗留 stash。
domain/panelBlocks.js(stackedBlock 接力取整 + 注释)、components/PanelBlocks.vue(堆叠段样式、饼/环扇区 tabindex+aria-label+focus/blur、svg role、删 <title>、环形图图例浮层、:focus-visible CSS)、verify/t43-stacked-gap-and-pie-interactions.mjs(新闸门)。入库按票 33/36/42 的裁剪纪律单独摘取。诊断+实施完成(2026-10-15):① 间隔根因=绘制缺陷——堆叠段 left/width 各自独立取整露出底色缝(mock 报警向量 [0,1,2,1,1,3,1,0] 实测「待验收→已结案」边界 1 个百分点,反证非语义设计:CSS 无任何分隔声明、露缝与否随计数变化)。修复=domain 单累加器接力取整(startPct/widthPct),连续由构造保证;total/start/ratio 口径原样保留。② 饼/环交互补齐:扇区 tabindex=0 + 每片 aria-label(类别:数量)、focus/blur 接同一共享浮层、:focus-visible 与 :hover 同档放大+描边、外层 svg role=img→group(img 会藏子树使名称不可达)、删原生