Ver Fonte

外壳对齐(步骤1-3): 品牌区 span.mark+span.brand+small; 页头加 div.right(返回门户/重选/时间窗/起止+应用, 照 v2.9.2 app.js:126-135); 删除 Workbench 里重复的时间窗控件

zhouyang.xie há 6 dias atrás
pai
commit
1bd87e458a

+ 35 - 2
app_frontEnd/web/src/App.vue

@@ -8,9 +8,10 @@
  *
  * 迁移纪律(用户令 2026-09-29):页签逐个搬,**与重构前页面对拍通过后**才删对应 Python 前端源码。
  */
-import { onMounted, ref, watch } from 'vue'
+import { computed, onMounted, ref, watch } from 'vue'
 import ContractSmoke from './views/ContractSmoke.vue'
 import Workbench from './views/Workbench.vue'
+import { t } from './i18n/zh'
 import PortalView from './views/PortalView.vue'
 import { callApi } from './api/contract'
 
@@ -29,6 +30,15 @@ if (_tabInHash) tab.value = _tabInHash
 const sub = ref<string | null>(null)
 const d = ref<any>(null)
 const win = ref<string>('')
+const WIN_PRESETS: [string, string][] = [['近30日', 'win.30d'], ['近90日', 'win.90d'], ['2026年', 'win.2026'], ['2026H1', 'win.2026H1'], ['2025H2', 'win.2025H2'], ['全程', 'win.all']]
+const WIN_SLUG: Record<string, string> = {'近30日': '30d', '近90日': '90d', '2026年': '2026', '2026H1': '2026H1', '2025H2': '2025H2', '全程': 'all'}
+const winSel = computed<string>(() => win.value || '')
+const isCustomWin = computed<boolean>(() => /^\d{4}-\d{2}-\d{2}~\d{4}-\d{2}-\d{2}$/.test(winSel.value))
+const mon = computed<string[]>(() => (((d.value || {}).all_months) || []).slice().reverse())
+const wa = ref<string>('')
+const wb2 = ref<string>('')
+function pickWin(ev: Event) { const v = (ev.target as HTMLSelectElement).value; win.value = WIN_SLUG[v] || v }
+function applyRange() { if (wa.value && wb2.value) win.value = wa.value + '~' + wb2.value }
 const loading = ref(false)
 const err = ref('')
 
@@ -74,7 +84,30 @@ onMounted(() => {
   <PortalView v-if="mode === 'portal'" />
   <div v-else class="wrap">
   <header class="top">
-    <div class="brand">观澜 · 风电数据分析与决策支持</div>
+    <span class="mark">≋</span>
+    <span class="brand">观澜<small>WIND ASSET INTELLIGENCE</small></span>
+    <div class="right">
+      <a class="back-portal" href="#" :title="t('ui.back_portal')" @click.prevent="go('portal')">{{ t('ui.back_portal') }}</a>
+      <button type="button" class="reselect" :title="t('ui.reselect')" @click="reselect">{{ t('ui.reselect') }}</button>
+      <label class="small muted" for="win">{{ t('win.label') }}</label>
+      <select id="win" :aria-label="t('win.label')" :value="winSel" @change="pickWin">
+        <optgroup :label="t('win.presets')">
+          <option v-for="[w2, k] in WIN_PRESETS" :key="w2" :value="w2">{{ t(k) }}</option>
+        </optgroup>
+        <optgroup v-if="isCustomWin" :label="t('win.custom')">
+          <option :value="winSel">{{ t('win.custom_sel', { a: winSel.split('~')[0], b: winSel.split('~')[1] }) }}</option>
+        </optgroup>
+        <optgroup v-if="mon.length" :label="t('win.months')">
+          <option v-for="m in mon" :key="m" :value="m">{{ m }}</option>
+        </optgroup>
+      </select>
+      <span class="winrng" :title="t('win.custom_hint')">
+        <input type="date" :aria-label="t('win.from')" v-model="wa">
+        <span class="muted">~</span>
+        <input type="date" :aria-label="t('win.to')" v-model="wb2">
+        <button type="button" @click="applyRange">{{ t('win.apply') }}</button>
+      </span>
+    </div>
     <nav class="tabs">
       <button :class="{ on: mode === 'workbench' }" @click="go('workbench')">工作台</button>
       <button :class="{ on: mode === 'smoke' }" @click="go('smoke')">契约自检</button>

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

@@ -54,29 +54,7 @@ const pending = computed(() => !DONE.includes(props.tab))
   <div class="page-head">
     <h1>{{ t('tab.' + tab) }}</h1>
     <!-- 与旧 app.js:1066 逐字一致:`${t('win.label')} · ${winName(WIN)}`(对拍实逮:写成 win.l 第 1 项就错位) -->
-    <span class="win-bar">
-      <button type="button" class="reselect" @click="emit('reselect')" :title="t('ui.reselect')">{{ t('ui.reselect') }}</button>
-      <label class="small muted" for="win">{{ t('win.label') }}</label>
-      <select id="win" class="win-select" :aria-label="t('win.label')" :value="sel" @change="pickWin">
-        <optgroup :label="t('win.presets')">
-          <option v-for="[w, k] in WIN_PRESETS" :key="w" :value="w">{{ t(k) }}</option>
-        </optgroup>
-        <optgroup v-if="isCustom" :label="t('win.custom')">
-          <option :value="sel">{{ t('win.custom_sel', { a: sel.split('~')[0], b: sel.split('~')[1] }) }}</option>
-        </optgroup>
-        <optgroup v-if="months.length" :label="t('win.months')">
-          <option v-for="m in months" :key="m" :value="m">{{ m }}</option>
-        </optgroup>
-      </select>
-      <span class="winrng" :title="t('win.custom_hint')">
-        <input type="date" :aria-label="t('win.from')" v-model="wa">
-        <span class="muted">~</span>
-        <input type="date" :aria-label="t('win.to')" v-model="wb2">
-        <button type="button" @click="applyRange">{{ t('win.apply') }}</button>
-      </span>
-      <span class="window-badge">{{ t('win.label') }} · {{ winName(d?.win) }}</span>
-    </span>
-  </div>
+    </div>
   <Overview v-if="tab === 'overview'" :d="d" />
   <Energy v-else-if="tab === 'energy'" :d="d" />
   <Component v-else-if="tab === 'component'" :d="d" :sys="sys" />

Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 0
release/web/assets/index-B0oni8dy.css


Diff do ficheiro suprimidas por serem muito extensas
+ 4 - 0
release/web/assets/index-C6eKPw1d.js


Diff do ficheiro suprimidas por serem muito extensas
+ 0 - 4
release/web/assets/index-CWQ0LsbW.js


+ 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-CWQ0LsbW.js"></script>
-  <link rel="stylesheet" crossorigin href="/web/assets/index-C63KWLu1.css">
+  <script type="module" crossorigin src="/web/assets/index-C6eKPw1d.js"></script>
+  <link rel="stylesheet" crossorigin href="/web/assets/index-B0oni8dy.css">
 </head>
 <body>
   <div id="app"></div>

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff