| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788 |
- <script setup lang="ts">
- /**
- * 工作台(P11):页签容器。页签清单与重构前 `app.js` 的 `TABS` **完全一致**(9 个)。
- *
- * 已迁移:overview(总览)。其余页签先如实标"迁移中",不做假界面 ——
- * 用户令要求"逐页签迁移、对拍通过再删 Python 源码",所以未迁移的页签必须一眼可见。
- */
- import { computed, ref, watch } from 'vue'
- import { t } from '../i18n/zh'
- import { DONE, TABS } from '../lib/tabs'
- import Documents from './Documents.vue'
- import PortalView from './PortalView.vue'
- import { winName } from '../lib/render'
- import Component from './Component.vue'
- import Energy from './Energy.vue'
- import Fault from './Fault.vue'
- import Vibration from './Vibration.vue'
- import Generation from './Generation.vue'
- import Decision from './Decision.vue'
- import Assistant from './Assistant.vue'
- import System from './System.vue'
- import Report from './Report.vue'
- import Overview from './Overview.vue'
- const props = defineProps<{ d: any; tab: string; sys?: string | null; sub?: string | null; cms?: any; curves?: any; apis?: any; win?: string }>()
- const emit = defineEmits<{ (e: 'tab', id: string): void; (e: 'sub', id: string): void; (e: 'win', w: string): void; (e: 'reselect'): void; (e: 'refresh'): void }>()
- /** 旧 app.js:60-70 —— 预设与 slug 映射(照抄) */
- 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 winSlug = (v: string): string => WIN_SLUG[v] || v
- const sel = ref<string>('')
- const wa = ref<string>('')
- const wb2 = ref<string>('')
- const months = computed<string[]>(() => ((props.d && props.d.all_months) || []).slice().reverse())
- const isCustom = computed(() => /^\d{4}-\d{2}-\d{2}~\d{4}-\d{2}-\d{2}$/.test(sel.value))
- watch(() => props.win, (w) => { sel.value = w || ''; const p = String(w || '').split('~'); if (p.length === 2) { wa.value = p[0]; wb2.value = p[1] } }, { immediate: true })
- function pickWin(ev: Event) { const v = (ev.target as HTMLSelectElement).value; sel.value = v; emit('win', winSlug(v)) }
- function applyRange() { if (wa.value && wb2.value) emit('win', wa.value + '~' + wb2.value) }
- const pending = computed(() => !DONE.includes(props.tab))
- </script>
- <template>
- <div class="page-head">
- <h1>{{ t('tab.' + tab) }}</h1>
- <!-- 与旧 app.js:1066 逐字一致:`${t('win.label')} · ${winName(WIN)}`(对拍实逮:写成 win.l 第 1 项就错位) -->
- </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" />
- <Fault v-else-if="tab === 'fault'" :d="d" />
- <Vibration v-else-if="tab === 'vibration'" :d="d" :sub="sub" :cms="cms" @sub="emit('sub', $event)" />
- <Generation v-else-if="tab === 'generation'" :d="d" :curves="curves" :pending="!!d.m9_pending" />
- <Decision v-else-if="tab === 'decision'" :d="d" :apis="apis" />
- <Assistant v-else-if="tab === 'assistant'" :d="d" />
- <System v-else-if="tab === 'system'" :apis="apis" @refresh="emit('refresh')" />
- <Report v-else-if="tab === 'report'" :d="d" :apis="apis" />
- <Documents v-else-if="tab === 'documents'" />
- <PortalView v-else-if="tab === 'portal_src'" />
- <section v-else-if="pending" class="card">
- <h2>{{ t('tab.' + tab) }} <small>(本页签尚未迁移到 Vue)</small></h2>
- <p class="hint">
- 迁移纪律:页签逐个搬,每搬一个就用 <code>tools/render_parity.mjs</code> 与重构前页面
- (现网 <code>/detail/v2</code>)对拍文案/数值/类名序列,**通过后**才删对应的 Python 前端源码。
- 当前已迁移:{{ DONE.join('、') }}。
- </p>
- </section>
- </template>
- <style scoped>
- .wb-tabs { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px 18px 0; }
- .wb-tabs button {
- padding: 6px 12px; border: 1px solid var(--line); background: #fff; border-radius: 4px 4px 0 0;
- cursor: pointer; color: var(--ink);
- }
- .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; 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; }
- .win-select { max-width: 220px; }
- .winrng { display: inline-flex; align-items: center; gap: 4px; }
- .winrng input[type=date] { width: 132px; }
- </style>
|