Просмотр исходного кода

修不居中/排版差异: 门户内嵌 CSS(PortalSections.vue) 的 body{max-width:1440px} 等全局泄漏到工作台 => 在 styles.css 末尾加 !important 兜底(body max-width:none; main#root padding:0; header.top justify/wrap; .page-head padding/gap/align),计算样式与 v2.9.2 基线一致;新增 tools/layout_diff.mjs 排版对比工具

zhouyang.xie 1 неделя назад
Родитель
Сommit
17048821b1

+ 50 - 41
app_frontEnd/web/src/styles.css

@@ -1,41 +1,50 @@
-:root {
-  --ink: #16202c;
-  --muted: #6b7a8d;
-  --line: #d7dee8;
-  --bg: #f5f7fa;
-  --card: #ffffff;
-  --brand: #0b5fa5;
-  --bad: #b42318;
-}
-* { box-sizing: border-box; }
-body {
-  margin: 0;
-  background: var(--bg);
-  color: var(--ink);
-  font: 14px/1.6 "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
-}
-.top {
-  display: flex; align-items: center; justify-content: space-between;
-  padding: 10px 18px; background: var(--brand); color: #fff;
-}
-.top .brand { font-size: 16px; font-weight: 600; letter-spacing: .5px; }
-.top nav button {
-  margin-left: 8px; padding: 6px 12px; border: 1px solid rgba(255, 255, 255, .5);
-  background: transparent; color: #fff; border-radius: 4px; cursor: pointer;
-}
-.top nav button.on { background: #fff; color: var(--brand); }
-main { padding: 16px 18px 40px; }
-.card {
-  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
-  padding: 14px 16px; margin-bottom: 14px;
-}
-.card h2 { margin: 0 0 10px; font-size: 15px; }
-.card h2 small { color: var(--muted); font-weight: 400; }
-.hint { color: var(--muted); font-size: 12.5px; }
-table { width: 100%; border-collapse: collapse; font-size: 13px; }
-th, td { border-bottom: 1px solid var(--line); padding: 6px 8px; text-align: left; }
-th { background: #eef2f7; font-weight: 600; }
-tr.bad td { color: var(--bad); }
-code { font-family: Consolas, "Courier New", monospace; font-size: 12.5px; }
-button.re { margin-left: 10px; padding: 2px 10px; cursor: pointer; }
-ul { margin: 6px 0 0 18px; padding: 0; }
+:root {
+  --ink: #16202c;
+  --muted: #6b7a8d;
+  --line: #d7dee8;
+  --bg: #f5f7fa;
+  --card: #ffffff;
+  --brand: #0b5fa5;
+  --bad: #b42318;
+}
+* { box-sizing: border-box; }
+body {
+  margin: 0;
+  background: var(--bg);
+  color: var(--ink);
+  font: 14px/1.6 "Microsoft YaHei", "PingFang SC", system-ui, sans-serif;
+}
+.top {
+  display: flex; align-items: center; 
+  padding: 10px 18px; background: var(--brand); color: #fff;
+}
+.top .brand { font-size: 16px; font-weight: 600; letter-spacing: .5px; }
+.top nav button {
+  margin-left: 8px; padding: 6px 12px; border: 1px solid rgba(255, 255, 255, .5);
+  background: transparent; color: #fff; border-radius: 4px; cursor: pointer;
+}
+.top nav button.on { background: #fff; color: var(--brand); }
+main { padding: 0; }
+.card {
+  background: var(--card); border: 1px solid var(--line); border-radius: 6px;
+  padding: 14px 16px; margin-bottom: 14px;
+}
+.card h2 { margin: 0 0 10px; font-size: 15px; }
+.card h2 small { color: var(--muted); font-weight: 400; }
+.hint { color: var(--muted); font-size: 12.5px; }
+table { width: 100%; border-collapse: collapse; font-size: 13px; }
+th, td { border-bottom: 1px solid var(--line); padding: 6px 8px; text-align: left; }
+th { background: #eef2f7; font-weight: 600; }
+tr.bad td { color: var(--bad); }
+code { font-family: Consolas, "Courier New", monospace; font-size: 12.5px; }
+button.re { margin-left: 10px; padding: 2px 10px; cursor: pointer; }
+ul { margin: 6px 0 0 18px; padding: 0; }
+
+/* ★P61 与 v2.9.2 对齐的兜底覆盖:
+   `views/PortalSections.vue` 内嵌了门户整份 CSS(v2.9.2 原文,保真渲染所需),其中 `body{max-width:1440px}` 等
+   是**全局**的,会泄漏到工作台 ⇒ 页面被限宽左对齐(表现为"不居中")、main/page-head 多出内边距。
+   这里按 v2.9.2 基线的计算样式逐项覆盖(放在最后 + !important,保证优先于内嵌门户 CSS)。 */
+body { max-width: none !important; }
+main#root { padding: 0 !important; }
+header.top { justify-content: normal !important; flex-wrap: nowrap !important; }
+.page-head { padding: 0 !important; gap: 16px !important; align-items: center !important; }

+ 1 - 1
app_frontEnd/web/src/views/Workbench.vue

@@ -84,7 +84,7 @@ const pending = computed(() => !DONE.includes(props.tab))
 .wb-tabs button.on { background: var(--brand); border-color: var(--brand); color: #fff; }
 .todo { font-size: 10px; color: var(--muted); margin-left: 2px; }
 .wb-tabs button.on .todo { color: #ffe9a8; }
-.page-head { display: flex; align-items: baseline; gap: 12px; padding: 10px 18px 0; }
+.page-head { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding: 0; }
 .page-head h1 { font-size: 18px; margin: 0; }
 .window-badge { color: var(--muted); font-size: 12.5px; }
 .win-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

+ 50 - 0
app_frontEnd/web/tools/layout_diff.mjs

@@ -0,0 +1,50 @@
+// P61 排版计算样式对比:v2.9.2 原文页(工作台)↔ 新版 `/detail/v2#workbench`
+import { readFileSync } from 'node:fs'
+import { fileURLToPath } from 'node:url'
+import { dirname, resolve } from 'node:path'
+import { JSDOM, VirtualConsole } from 'jsdom'
+const HERE = dirname(fileURLToPath(import.meta.url))
+const GATEWAY = 'http://106.120.102.238:28084'
+const dist = resolve(HERE, '../../../release/web')
+const fleet = readFileSync(resolve(HERE, '_fleet_fixture.json'), 'utf8')
+const SEL = ['body', '#app', '.wrap', 'header.top', 'header.top > .right', 'nav.tabs', 'nav.wb-tabs', 'main#root', '.page-head']
+const PROPS = ['display', 'maxWidth', 'marginLeft', 'marginRight', 'padding', 'width', 'justifyContent', 'alignItems', 'gap', 'flexWrap']
+
+function report(tag, doc, win) {
+  console.log('==== ' + tag + ' ====')
+  for (const s of SEL) {
+    const el = doc.querySelector(s)
+    if (!el) { console.log(s + ' : 缺失'); continue }
+    const cs = win.getComputedStyle(el)
+    console.log(s + ' : ' + PROPS.map((p) => p + '=' + (cs[p] || '-')).join(' '))
+  }
+}
+
+// ① 基线(v2.9.2 原文页)
+const bdom = new JSDOM(readFileSync(dist + '/detail_v2.html', 'utf8'),
+  { url: GATEWAY + '/detail/v2', runScripts: 'dangerously', pretendToBeVisual: true, virtualConsole: new VirtualConsole(),
+    beforeParse: (w) => { w.fetch = async (u) => { const s = String(u)
+      const body = /fleet/.test(s) ? fleet : '{}'
+      return { ok: true, status: 200, headers: new Map(), text: async () => body, json: async () => JSON.parse(body) } } } })
+{
+  const d = bdom.window.document
+  for (let i = 0; i < 100; i++) { const r = d.getElementById('root'); if (r && r.querySelector('.page-head')) break; await new Promise((x) => setTimeout(x, 400)) }
+}
+report('BASE v2.9.2', bdom.window.document, bdom.window)
+
+// ② 新版
+const idx = readFileSync(dist + '/index.html', 'utf8')
+const jsFile = (idx.match(/src="([^"]+\.js)"/) || [])[1].replace(/^.*\//, '')
+const cssFile = (idx.match(/href="([^"]+\.css)"/) || [])[1].replace(/^.*\//, '')
+const code = readFileSync(dist + '/assets/' + jsFile, 'utf8')
+const css = readFileSync(dist + '/assets/' + cssFile, 'utf8')
+const ndom = new JSDOM(idx.replace('</head>', '<style>' + css + '</style></head>'),
+  { url: GATEWAY + '/detail/v2#workbench', runScripts: 'outside-only', pretendToBeVisual: true, virtualConsole: new VirtualConsole() })
+{
+  const w = ndom.window
+  w.fetch = async (u) => { const s = String(u); const body = /fleet/.test(s) ? fleet : '{}'
+    return { ok: true, status: 200, json: async () => JSON.parse(body), text: async () => body } }
+  try { w.eval(code) } catch (e) { console.log('EVAL_ERR ' + String(e).slice(0, 100)) }
+  for (let i = 0; i < 20; i++) { await new Promise((x) => setTimeout(x, 400)); if (w.document.querySelector('nav.tabs#tabs')) break }
+}
+report('NEW Vue', ndom.window.document, ndom.window)

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
release/web/assets/index-TecZ2KYe.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
release/web/assets/index-r8YOhGfl.css


+ 2 - 2
release/web/index.html

@@ -4,8 +4,8 @@
   <meta charset="utf-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1" />
   <title>观澜 · 风电数据分析与决策支持</title>
-  <script type="module" crossorigin src="/web/assets/index-B-A9wmEl.js"></script>
-  <link rel="stylesheet" crossorigin href="/web/assets/index-CaGxeZ59.css">
+  <script type="module" crossorigin src="/web/assets/index-TecZ2KYe.js"></script>
+  <link rel="stylesheet" crossorigin href="/web/assets/index-r8YOhGfl.css">
 </head>
 <body>
   <div id="app"></div>

Некоторые файлы не были показаны из-за большого количества измененных файлов