fix(web): 窄屏布局三处根因 + 页面滚动塌陷

在 375/320 屏上实机取证(三节点集群 192.168.2.{30,106,60}),修掉四个
独立缺陷。前三个是布局根因,第四个是被前三个掩盖的真 bug。

1. 全站没有 box-sizing 重置
   content-box 下 `.sidebar { width:100%; padding:10px 12px }` 在 375 视口
   实算 399px(320 屏 344px)。顶栏主题色块右缘 332 > 320,被
   `.sidebar{overflow-x:hidden}` 静默裁掉 ⇒ 主题切换在手机上点不到。
   桌面侧栏同样是 274px 而非声明的 246px。
   注:已有两个「窄屏顶栏右侧溢出」commit(64d3359 用 flex min-width/vw
   限宽、0559cc5 改 backdrop-filter)都在治症状,真因是盒模型。

2. fit-view-on-init 把画布缩到不可读
   画布用绝对图形坐标(x=60/760,两列随转发数向下增长),bbox 远大于
   手机视口。实测合成缩放 375 屏 0.3135 ⇒ 248px 的卡片渲成 85px、
   有效字号 4.39px;**1280 桌面也只有 0.6011 / 8.42px**(5 条转发即
   触发),所以这不只是窄屏问题。
   改为删掉 fit-view-on-init 自己接管:MIN_ZOOM=0.65 下限 +
   frameCanvas() 把最左上节点重贴到内边距边缘(fitView 是居中的,窄屏
   下会把两列接缝摆在视口正中,两边各看一半)。duration:0 保证量 rect
   时动画已停;初始 frame 只认一次,避免后续 add 节点把正在平移的用户
   拽走。挂 @init + @nodes-initialized(store 与节点分先后到达,任一
   单独触发都会 fit 空画布)。

3. el-dialog 固定宽度超出手机视口
   Element Plus 把 width 写成内联 --el-dialog-width。375 屏实测
   left=0 right=420,右上关闭按钮在屏外,只能横向滚 overlay 才够得到。
   窄屏下 clamp 到 calc(100vw - 24px)。

4. 【滚动塌陷】状态页在手机上完全无法滑动
   `.status-page` 是 height:100% + overflow:hidden 的 flex 列,内层
   `.status-body` 靠 flex:1 + overflow-y:auto 自己滚。375 屏下可用高度
   651px,而两个不可压缩子元素 topbar(122) + kpis(565) 已占 687px ⇒
   `.status-body` 被分到 **0px**,其中却有 1682px 内容。同时外层
   `.content` scrollHeight==clientHeight(无可滚内容)⇒ 整页没有任何
   可滚动元素,手势完全无响应。
   修法:让 `.content`(App.vue 已声明 flex:1 + overflow-y:auto)做唯一
   滚动容器,页面自身不再 height:100%/overflow。ClusterView /
   SettingsView 同类嵌套一并去掉,从根上消灭「按剩余空间算高度」这类
   算术错误。另把 ≤380px 的 KPI 单列改回两列(单列四张全宽卡自身就
   565px,超过整个视口,是塌陷的起因)。

验证(构建产物挂反代打真后端 + 共享 Chromium CDP):
- 缩放 0.31→0.65、卡片 85→177px、有效字号 4.39→9.1px(320/375/414/1280 一致)
- bodyScrollW 344→320(320 屏),横向溢出清零;主题色块全部落回屏内
- 对话框 left 12 / right 363(完全在屏内,关闭键可达)
- 9 种视口 × 5 个页面 = 45 格全部「末块可达 + 无横向滚动」,console 零报错
  修复前:状态页 375/320/414 全部无滚动;1280 桌面状态/设置同样中招
- 三节点滚动重启部署,集群收敛 pending=0 / topo=4,owner 与实际
  worker 进程一一对应,journal 无 panic/fatal,reclaimed=2 各节点自愈
This commit is contained in:
JianFeeeee
2026-09-18 11:00:35 +08:00
parent 64d3359981
commit f4fb964734
6 changed files with 170 additions and 18 deletions

View File

@ -496,11 +496,22 @@ onBeforeUnmount(() => {
</script>
<style scoped lang="scss">
/* The pages inside .content must NOT be their own scrollers.
*
* App.vue already designates `.content` as the app's single scroll container
* (`flex:1; overflow-y:auto`). These pages were also `height:100%` +
* `overflow-y:auto`, producing a nested scroller whose height is the leftover
* space of a flex column. On a 375px phone the status page's fixed-height
* header (122px) plus the single-column KPI stack (565px) exceed the available
* 651px, so the inner `.status-body` was handed 0px while holding 1682px of
* content — the page looked completely frozen, since neither `.content` (which
* had nothing to scroll) nor the 0-height inner box could be swiped.
*
* Letting the page grow naturally and scroll in `.content` removes the whole
* class of bug: there is no leftover-space arithmetic left to get wrong. */
.status-page {
height: 100%;
display: flex;
flex-direction: column;
overflow: hidden;
gap: 14px;
}
@ -527,12 +538,9 @@ onBeforeUnmount(() => {
}
.status-body {
flex: 1;
display: flex;
flex-direction: column;
gap: 18px;
overflow-y: auto;
padding-right: 4px;
}
.section { display: flex; flex-direction: column; }
@ -720,8 +728,13 @@ onBeforeUnmount(() => {
}
@media (max-width: 380px) {
/* 极窄:KPI 也降为单列,否则数字会被压断 */
.kpis { grid-template-columns: minmax(0, 1fr); }
/* Keep the KPI grid at TWO columns even on the narrowest phones.
* Dropping to one column made four full-width cards ~565px tall, which on its
* own exceeded the whole viewport and (with the page-level scroller of the
* day) collapsed the content area to zero height. Two columns keeps each card
* ~160px wide — enough for the 27px number + 11.5px caption, which is all a
* KPI card holds. */
.kpis { gap: 8px; }
.fwd-route { font-size: 12.5px; }
.page-title { font-size: 16px; }
}