feat(resource): migrate resource-status and resource-history from Jinja2 to Vue 3 + Vite

Rewrite both resource pages (1,697 lines vanilla JS + 3,200 lines Jinja2 templates)
as Vue 3 SFC components. Extract resource-shared/ module with shared CSS, E10 status
constants, and HierarchyTable tree component. History page charts use vue-echarts,
Status page reuses useAutoRefresh composable with 5-minute interval.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
egg
2026-02-09 18:19:32 +08:00
parent a2653b8139
commit 720e190bc6
45 changed files with 5099 additions and 4993 deletions

View File

@@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-02-09

View File

@@ -0,0 +1,104 @@
## Context
設備即時概況與設備歷史績效是專案中最後一組使用三層階層樹表的 Jinja2 頁面。兩頁合計 1,697 行 vanilla JS + 3,200 行 Jinja2 模板(含 820 行重複 inline fallback script。已有 5 頁QC-GATE、Tables、WIP 三頁)成功遷移至 Vue 3 + Vite 純前端,模式穩定。
兩頁共享:
- 三層階層樹表workcenter group → family → resource
- E10 狀態碼集PRD/SBY/UDT/SDT/EGT/NST + 聚合規則 PM→UDT、ENG→EGT、OFF→NST
- OU%/Availability% KPI 計算(`core/compute.js`
- 樹狀展開/收合(`core/table-tree.js`
- 篩選模式workcenter groups、is_production/is_key/is_monitor
- CSS 變數系統(`:root` 色碼、卡片、表格樣式)
## Goals / Non-Goals
**Goals:**
- 兩頁完全脫離 Jinja2 + `_base.html`,改用 `send_from_directory` 靜態服務
- 抽取 `resource-shared/` 共用模組,消除兩頁間的重複邏輯
- History 頁 ECharts 改用 vue-echarts與 QC-GATE/WIP Overview 一致
- Status 頁複用 `useAutoRefresh` composable
- 移除 Jinja2 模板及 inline fallback script
**Non-Goals:**
- 不修改後端 API 端點或回傳結構
- 不新增 npm 依賴vue-echarts、echarts 已安裝)
- 不重構後端 cache 架構
- 不增加功能(如 History 頁新增自動刷新)
## Decisions
### D1: 抽取 `resource-shared/` 共用模組
**選擇**:建立 `frontend/src/resource-shared/` 放置兩頁共用的 CSS、常數、元件。
**替代方案**(a) 各頁獨立 — 大量重複;(b) 放入 `core/` — 太專屬設備頁面,不適合通用模組。
**理由**:與 `wip-shared/` 模式一致,語義清晰。
共用模組內容:
- `styles.css``:root` 變數、status 顏色、tree table 樣式、KPI 卡片樣式、loading overlay
- `constants.js``STATUS_DISPLAY_MAP`6 值中英對照)、`STATUS_AGGREGATION`PM→UDT 等聚合規則)、`STATUS_COLORS`6 色碼)、`OU_BADGE_THRESHOLDS`high≥80/medium≥50/low<50
- `components/HierarchyTable.vue`三層展開/收合樹表元件接收 `hierarchy` prop `columns` 定義兩頁共用
### D2: HierarchyTable.vue 設計
**選擇**單一 `<HierarchyTable>` 元件透過 `columns` prop 定義欄位`hierarchy` prop 傳入資料`@cell-click` 事件處理互動
**替代方案**(a) 遞迴 TreeNode 元件 過度設計三層固定深度不需遞迴(b) 各頁獨立表格 重複
**理由**三層結構固定group family resource `v-for` 嵌套即可不需泛用遞迴
### D3: vue-echarts 統一 ECharts 使用方式
**選擇**History 頁的 4 ECharts 圖表全部改用 `<VChart :option="..." autoresize />`
**替代方案**直接使用 ECharts API + `onMounted` 手動 init/dispose
**理由**vue-echarts 已用於 QC-GATE WIP Overview`autoresize` 解決 iframe 隱藏時 width=0 問題4 個圖表各自封裝為獨立元件
### D4: Status 頁 tooltip 實作
**選擇**自訂 `<FloatingTooltip>` 元件 + CSS fixed 定位移植現有邏輯)。
**替代方案**(a) Floating UI 新增依賴(b) 原生 `title` 太簡陋
**理由**現有 tooltip 邏輯已穩定viewport clamp + 點擊觸發Vue 化後更乾淨`<Teleport to="body">` + `v-if`無需新增依賴
### D5: Status 頁自動刷新複用
**選擇**直接 import `wip-shared/composables/useAutoRefresh.js` shared 目錄引用)。
**替代方案**(a) 複製到 resource-shared/ 重複(b) 移至 core/ 改動範圍大
**理由**composable WIP 特定邏輯路徑引用 `../../wip-shared/composables/useAutoRefresh.js` 可行intervalMs 設為 5 分鐘Status 頁用 5 分鐘而非 WIP 10 分鐘)。
### D6: 多選下拉元件History 頁)
**選擇**自訂 `<MultiSelect>` 元件移植現有邏輯)。
**替代方案**Element Plus Select 引入大型 UI
**理由**現有多選邏輯簡單checkbox list + click-outside-close + select all/clearVue 化後用 `v-model` 綁定即可無需外部庫
### D7: 元件拆分策略
**resource-status 元件結構**
```
App.vue
├── StatusHeader.vue (cache 狀態、最後更新時間)
├── FilterBar.vue (群組下拉 + 3 checkbox)
├── SummaryCards.vue (10 張 KPI 卡片)
├── MatrixSection.vue (expand/collapse toolbar + HierarchyTable)
├── EquipmentGrid.vue (設備卡片格 + 篩選指示器)
│ └── EquipmentCard.vue (單張設備卡片)
└── FloatingTooltip.vue (LOT/JOB 詳情 tooltip)
```
**resource-history 元件結構**
```
App.vue
├── FilterBar.vue (日期 + 粒度 + 多選 + checkbox)
│ └── MultiSelect.vue (多選下拉元件)
├── KpiCards.vue (9 張 KPI 卡片)
├── ChartSection.vue (2×2 圖表格)
│ ├── TrendChart.vue (OU%/AVAIL% 趨勢折線)
│ ├── StackedChart.vue (E10 狀態堆疊柱狀)
│ ├── ComparisonChart.vue (workcenter OU% 橫條)
│ └── HeatmapChart.vue (workcenter × 日期 熱圖)
├── DetailSection.vue (expand/collapse toolbar + HierarchyTable + CSV 匯出)
```
## Risks / Trade-offs
- **[R1] shared 目錄引用 useAutoRefresh** 路徑較長但可行未來若需可移至 `core/`不在此變更範圍內重構
- **[R2] HierarchyTable 通用性** 目前設計為兩頁共用欄位/格式差異透過 props slots 處理若未來新頁面需要完全不同的樹表可獨立元件
- **[R3] vue-echarts 4 圖同頁效能** History 頁同時渲染 4 個圖表資料量大時可能卡頓vue-echarts `autoresize` + `computed` option 已足夠不需 lazy loading
- **[R4] Status 250+ 設備卡片** 現有實作無虛擬滾動Vue 化後 `v-for` 渲染相同數量短期不加虛擬滾動 Non-Goal 但不在此範圍數量級可接受

View File

@@ -0,0 +1,30 @@
## Why
設備即時概況(`/resource-status`853 行 JS + 1,669 行模板)與設備歷史績效(`/resource-history`844 行 JS + 1,531 行模板)仍為 Jinja2 + vanilla JS 架構,是最後一組使用三層階層樹表的 Jinja2 頁面。兩頁共享 E10 狀態碼集、OU%/Availability% KPI 計算、workcenter group/family/resource 三層結構、以及相同的篩選模式,適合成對遷移並抽取共用模組。
## What Changes
-`/resource-status` 從 Jinja2 + vanilla JS 遷移至 Vue 3 SFC + Vite 純前端架構
-`/resource-history` 從 Jinja2 + vanilla JS 遷移至 Vue 3 SFC + Vite 純前端架構
- History 頁的 4 個 ECharts 圖表改用 vue-echarts與 QC-GATE、WIP Overview 一致)
- 抽取 `resource-shared/` 共用模組CSS 基底、狀態常數、HierarchyTable 元件
- 兩頁 Vite entry 從 `main.js` 改為 `index.html`Flask route 改為 `send_from_directory`
- 移除兩份 Jinja2 模板(`resource_status.html``resource_history.html`
- Status 頁模板內 820 行 inline fallback script 遷移後一併移除
- 複用已建立的 `useAutoRefresh` composable`wip-shared/` 移至或引用)
## Capabilities
### New Capabilities
- `resource-status-page`: 設備即時概況頁面需求 — 即時矩陣、設備卡片、LOT/JOB tooltip、狀態篩選、5 分鐘自動刷新
- `resource-history-page`: 設備歷史績效頁面需求 — 日期區間查詢、4 個 ECharts 圖表、三層階層明細表、多選篩選、CSV 匯出
### Modified Capabilities
- `vue-vite-page-architecture`: 新增 Shared CSS import 跨 resource-shared/ 的場景,與 wip-shared/ 模式一致
## Impact
- **前端**:新增 `frontend/src/resource-shared/`、修改 `frontend/src/resource-status/``frontend/src/resource-history/``frontend/vite.config.js``frontend/package.json`
- **後端**`app.py` 兩條 route 改為 `send_from_directory`API 端點不變
- **移除**`templates/resource_status.html``templates/resource_history.html`
- **依賴**:無新增 npm 依賴vue-echarts、echarts 已安裝)

View File

@@ -0,0 +1,127 @@
## ADDED Requirements
### Requirement: Resource History page SHALL display KPI summary cards
The page SHALL show 9 KPI cards with aggregated performance metrics for the queried period.
#### Scenario: KPI cards rendering
- **WHEN** summary data is loaded from `GET /api/resource/history/summary`
- **THEN** 9 cards SHALL display: OU%, AVAIL%, PRD, SBY, UDT, SDT, EGT, NST, Machine Count
- **THEN** hour values SHALL format with "K" suffix for large numbers (e.g., 2.5K)
- **THEN** percentage values SHALL use `buildResourceKpiFromHours()` from `core/compute.js`
### Requirement: Resource History page SHALL display trend chart
The page SHALL show OU% and Availability% trends over time.
#### Scenario: Trend chart rendering
- **WHEN** summary data is loaded
- **THEN** a line chart with area fill SHALL display OU% and AVAIL% time series
- **THEN** the chart SHALL use vue-echarts with `autoresize` prop
- **THEN** smooth curves with 0.2 opacity area style SHALL render
### Requirement: Resource History page SHALL display stacked status distribution chart
The page SHALL show E10 status hour distribution over time.
#### Scenario: Stacked bar chart rendering
- **WHEN** summary data is loaded
- **THEN** a stacked bar chart SHALL display PRD, SBY, UDT, SDT, EGT, NST hours per period
- **THEN** each status SHALL use its designated color (PRD=green, SBY=blue, UDT=red, SDT=yellow, EGT=purple, NST=gray)
- **THEN** tooltips SHALL show percentages calculated dynamically
### Requirement: Resource History page SHALL display workcenter comparison chart
The page SHALL show top workcenters ranked by OU%.
#### Scenario: Comparison chart rendering
- **WHEN** summary data is loaded
- **THEN** a horizontal bar chart SHALL display top 15 workcenters by OU%
- **THEN** bars SHALL be color-coded: green (≥80%), yellow (≥50%), red (<50%)
- **THEN** data SHALL display in descending OU% order (top to bottom)
### Requirement: Resource History page SHALL display OU% heatmap
The page SHALL show a heatmap of OU% by workcenter and date.
#### Scenario: Heatmap chart rendering
- **WHEN** summary data is loaded
- **THEN** a 2D heatmap SHALL display: workcenters (Y-axis) × dates (X-axis)
- **THEN** color scale SHALL range from red (low OU%) through yellow to green (high OU%)
- **THEN** workcenters SHALL sort by `workcenter_seq` for consistent ordering
### Requirement: Resource History page SHALL display hierarchical detail table
The page SHALL show a three-level expandable table with per-resource performance metrics.
#### Scenario: Detail table rendering
- **WHEN** detail data is loaded from `GET /api/resource/history/detail`
- **THEN** a tree table SHALL display with columns: Name, OU%, AVAIL%, PRD, SBY, UDT, SDT, EGT, NST, Count
- **THEN** Level 0 rows SHALL show workcenter groups with aggregated metrics
- **THEN** Level 1 rows SHALL show resource families with aggregated metrics
- **THEN** Level 2 rows SHALL show individual resources
#### Scenario: Hour and percentage display
- **WHEN** detail data renders
- **THEN** status columns SHALL display hours with percentage: "10.5h (25%)"
- **THEN** KPI values SHALL be computed using `buildResourceKpiFromHours()` from `core/compute.js`
#### Scenario: Tree expand and collapse
- **WHEN** user clicks the expand button on a row
- **THEN** child rows SHALL toggle visibility
- **WHEN** user clicks "Expand All" or "Collapse All"
- **THEN** all rows SHALL expand or collapse accordingly
### Requirement: Resource History page SHALL support date range and granularity selection
The page SHALL allow users to specify time range and aggregation granularity.
#### Scenario: Date range selection
- **WHEN** the page loads
- **THEN** date inputs SHALL default to last 7 days (yesterday minus 6 days)
- **THEN** date range SHALL NOT exceed 730 days (2 years)
#### Scenario: Granularity buttons
- **WHEN** user clicks a granularity button (///)
- **THEN** the active button SHALL highlight
- **THEN** the next query SHALL use the selected granularity (day/week/month/year)
#### Scenario: Query execution
- **WHEN** user clicks the query button
- **THEN** summary and detail APIs SHALL be called in parallel
- **THEN** all 4 charts, KPI cards, and detail table SHALL update with results
### Requirement: Resource History page SHALL support multi-select filtering
The page SHALL provide multi-select dropdown filters for workcenter groups and families.
#### Scenario: Multi-select dropdown
- **WHEN** user clicks a multi-select dropdown trigger
- **THEN** a dropdown SHALL display with checkboxes for each option
- **THEN** "Select All" and "Clear All" buttons SHALL be available
- **THEN** clicking outside the dropdown SHALL close it
#### Scenario: Filter options loading
- **WHEN** the page loads
- **THEN** workcenter groups and families SHALL load from `GET /api/resource/history/options`
#### Scenario: Equipment type checkboxes
- **WHEN** user toggles a checkbox (生產設備, 重點設備, 監控設備)
- **THEN** the next query SHALL include the corresponding filter parameter
### Requirement: Resource History page SHALL support CSV export
The page SHALL allow users to export the current query results as CSV.
#### Scenario: CSV export
- **WHEN** user clicks the "匯出 CSV" button
- **THEN** the browser SHALL download a CSV file from `GET /api/resource/history/export` with current filters
- **THEN** the filename SHALL be `resource_history_{start_date}_to_{end_date}.csv`
### Requirement: Resource History page SHALL handle loading and error states
The page SHALL display appropriate feedback during API calls and on errors.
#### Scenario: Query loading state
- **WHEN** a query is executing
- **THEN** the query button SHALL be disabled
- **THEN** a loading indicator SHALL display
#### Scenario: API error handling
- **WHEN** an API call fails
- **THEN** a toast notification SHALL display the error message
- **THEN** the page SHALL NOT crash or become unresponsive
#### Scenario: No data placeholder
- **WHEN** query returns empty results
- **THEN** charts and table SHALL display "No data" placeholders

View File

@@ -0,0 +1,121 @@
## ADDED Requirements
### Requirement: Resource Status page SHALL display summary KPI cards
The page SHALL show 10 summary cards with aggregated equipment status statistics.
#### Scenario: Summary cards rendering
- **WHEN** equipment data is loaded from `GET /api/resource/status/summary`
- **THEN** 10 cards SHALL display: Total, PRD, SBY, UDT, SDT, EGT, NST, OTHER, OU%, Availability%
- **THEN** each status card SHALL show count and percentage
- **THEN** OU% card SHALL use color coding: green (≥80%), yellow (≥50%), red (<50%)
#### Scenario: Status card click filters equipment
- **WHEN** user clicks a status card (PRD, SBY, UDT, SDT, EGT, NST)
- **THEN** the equipment grid SHALL filter to show only equipment in that status
- **THEN** the clicked card SHALL show an active visual state
- **THEN** clicking the same card again SHALL remove the filter
### Requirement: Resource Status page SHALL display hierarchical matrix table
The page SHALL show a three-level expandable matrix of workcenter group, family, and resource with status columns.
#### Scenario: Matrix table rendering
- **WHEN** equipment data is loaded from `GET /api/resource/status`
- **THEN** a matrix table SHALL display with columns: Name, Total, PRD, SBY, UDT, SDT, EGT, NST, OTHER, OU%
- **THEN** Level 0 rows SHALL show workcenter groups with aggregated counts
- **THEN** Level 1 rows SHALL show resource families with aggregated counts
- **THEN** Level 2 rows SHALL show individual equipment with status indicator
#### Scenario: Status code aggregation
- **WHEN** equipment has status PM or BKD
- **THEN** the status SHALL be aggregated under UDT column
- **WHEN** equipment has status ENG
- **THEN** the status SHALL be aggregated under EGT column
- **WHEN** equipment has status OFF
- **THEN** the status SHALL be aggregated under NST column
#### Scenario: Tree expand and collapse
- **WHEN** user clicks the expand button on a Level 0 row
- **THEN** Level 1 rows (families) for that group SHALL toggle visibility
- **WHEN** user clicks the expand button on a Level 1 row
- **THEN** Level 2 rows (equipment) for that family SHALL toggle visibility
- **WHEN** user clicks "Expand All" or "Collapse All" in the toolbar
- **THEN** all tree rows SHALL expand or collapse accordingly
#### Scenario: Matrix cell click filters equipment
- **WHEN** user clicks a status count cell in the matrix (e.g., PRD count for a workcenter group)
- **THEN** the equipment grid SHALL filter to that workcenter group and status
- **THEN** the clicked cell SHALL show a selected visual state
- **THEN** a filter indicator banner SHALL display showing active filters
- **THEN** clicking the same cell again SHALL remove the filter
### Requirement: Resource Status page SHALL display equipment card grid
The page SHALL show filterable equipment cards with status information.
#### Scenario: Equipment card rendering
- **WHEN** equipment data is loaded
- **THEN** cards SHALL display in a responsive grid (auto-fill, min 280px)
- **THEN** each card SHALL show: resource name, status badge, workcenter, group, family, location
- **THEN** each card SHALL have a colored left border matching its status category
#### Scenario: LOT information tooltip
- **WHEN** user clicks the LOT count indicator on an equipment card
- **THEN** a floating tooltip SHALL display with LOT details: LOTID, QTY, track-in time, employee
- **THEN** the tooltip SHALL be positioned within the viewport (clamp to edges)
- **THEN** clicking outside the tooltip SHALL close it
#### Scenario: JOB information tooltip
- **WHEN** user clicks the JOB indicator on an equipment card
- **THEN** a floating tooltip SHALL display with JOB details: order, status, model, stage, technician, symptom/cause/repair codes
- **THEN** the tooltip SHALL use the same positioning logic as the LOT tooltip
### Requirement: Resource Status page SHALL support workcenter and equipment type filtering
The page SHALL provide filter controls to narrow the displayed equipment.
#### Scenario: Workcenter group filter
- **WHEN** user selects a workcenter group from the dropdown
- **THEN** all data (summary, matrix, equipment) SHALL reload filtered to that group
- **THEN** the dropdown options SHALL be loaded from `GET /api/resource/status/options`
#### Scenario: Equipment type checkboxes
- **WHEN** user toggles a checkbox (生產設備, 重點設備, 監控設備)
- **THEN** all data SHALL reload with the corresponding filter (is_production, is_key, is_monitor)
- **THEN** multiple checkboxes can be active simultaneously
### Requirement: Resource Status page SHALL display cache status
The page SHALL show the real-time cache health and last update time.
#### Scenario: Cache status indicator
- **WHEN** the page loads
- **THEN** the page SHALL call `GET /health` to check cache status
- **THEN** a green dot SHALL display when cache is loaded and enabled
- **THEN** a yellow dot SHALL display when cache is loading
- **THEN** a red dot SHALL display when cache is not enabled
- **THEN** the last update timestamp SHALL display from equipment status cache metadata
### Requirement: Resource Status page SHALL auto-refresh and handle request cancellation
The page SHALL automatically refresh data and prevent stale request pile-up.
#### Scenario: Auto-refresh interval
- **WHEN** the page is loaded
- **THEN** data SHALL auto-refresh every 5 minutes
- **THEN** auto-refresh SHALL be skipped when the tab is hidden
#### Scenario: Visibility change refresh
- **WHEN** the tab becomes visible after being hidden
- **THEN** data SHALL refresh immediately
#### Scenario: Manual refresh
- **WHEN** user clicks the refresh button
- **THEN** data SHALL reload and the auto-refresh timer SHALL reset
### Requirement: Resource Status page SHALL handle loading and error states
The page SHALL display appropriate feedback during API calls and on errors.
#### Scenario: Initial loading overlay
- **WHEN** the page first loads
- **THEN** a loading overlay SHALL display until all data is loaded
#### Scenario: API error handling
- **WHEN** an API call fails
- **THEN** the affected section SHALL display an error message
- **THEN** the page SHALL NOT crash or become unresponsive

View File

@@ -0,0 +1,35 @@
## MODIFIED Requirements
### Requirement: Vite config SHALL support Vue SFC and HTML entry points
The Vite build configuration SHALL support Vue Single File Components alongside existing vanilla JS entries.
#### Scenario: Vue plugin coexistence
- **WHEN** `vite build` is executed
- **THEN** Vue SFC (`.vue` files) SHALL be compiled by `@vitejs/plugin-vue`
- **THEN** existing vanilla JS entry points SHALL continue to build without modification
#### Scenario: HTML entry point
- **WHEN** a page uses an HTML file as its Vite entry point
- **THEN** Vite SHALL process the HTML and its referenced JS/CSS into `static/dist/`
- **THEN** the output SHALL include `<page-name>.html`, `<page-name>.js`, and `<page-name>.css`
#### Scenario: Chunk splitting
- **WHEN** Vite builds the project
- **THEN** Vue runtime SHALL be split into a `vendor-vue` chunk
- **THEN** ECharts modules SHALL be split into the existing `vendor-echarts` chunk
- **THEN** chunk splitting SHALL NOT affect existing page bundles
#### Scenario: Migrated page entry replacement
- **WHEN** a vanilla JS page is migrated to Vue 3
- **THEN** its Vite entry SHALL change from JS file to HTML file (e.g., `src/resource-status/main.js``src/resource-status/index.html`)
- **THEN** the original JS entry SHALL be replaced, not kept alongside
#### Scenario: Shared CSS import across migrated pages
- **WHEN** multiple migrated pages import a shared CSS module (e.g., `resource-shared/styles.css`)
- **THEN** Vite SHALL bundle the shared CSS into each page's output CSS
- **THEN** shared CSS SHALL NOT create a separate shared chunk that requires additional HTTP requests
#### Scenario: Shared composable import across module boundaries
- **WHEN** a migrated page imports a composable from another shared module (e.g., `resource-status` imports `useAutoRefresh` from `wip-shared/`)
- **THEN** the composable SHALL be bundled into the importing page's JS output
- **THEN** cross-module imports SHALL NOT create unexpected shared chunks

View File

@@ -0,0 +1,44 @@
## 1. resource-shared 共用模組
- [x] 1.1 建立 `frontend/src/resource-shared/styles.css` — 從兩頁 Jinja2 模板抽取共用 CSS`:root` 變數、status 顏色類別(`.col-prd`/`.col-sby`/...、tree table 樣式(`.row-level-0`/`.row-level-1`/`.row-level-2``.indent-1`/`.indent-2``.expand-btn`、KPI 卡片樣式、OU badge 色碼(`.ou-badge.high/medium/low`、loading overlay、filter indicator
- [x] 1.2 建立 `frontend/src/resource-shared/constants.js` — STATUS_DISPLAY_MAPPRD→生產中 等 6+值、STATUS_AGGREGATIONPM/BKD→UDT、ENG→EGT、OFF→NST、STATUS_COLORSPRD=#22c55e 等 6 色、OU_BADGE_THRESHOLDShigh≥80、medium≥50、low<50)、MATRIX_STATUS_COLUMNS 順序定義
- [x] 1.3 建立 `frontend/src/resource-shared/components/HierarchyTable.vue` 三層展開/收合樹表元件props: `hierarchy`三層資料)、`columns`欄位定義陣列)、`expandedState`reactive 物件events: `@cell-click``@toggle-row``@toggle-all`支援 Level 0/1/2 行樣式和縮排
## 2. resource-status Vue 3 遷移
- [x] 2.1 建立 `frontend/src/resource-status/index.html` HTML entry point引用 main.js設定 `<title>設備即時概況</title>`
- [x] 2.2 建立 `frontend/src/resource-status/App.vue` 頂層元件整合所有子元件管理全域狀態allEquipmentmatrixFilterhierarchyState呼叫 loadData/loadOptions/loadSummary
- [x] 2.3 建立 `frontend/src/resource-status/components/StatusHeader.vue` cache 狀態指示green/yellow/red dot)、最後更新時間手動刷新按鈕
- [x] 2.4 建立 `frontend/src/resource-status/components/FilterBar.vue` workcenter group 下拉GET /api/resource/status/options+ 3 checkbox生產設備/重點設備/監控設備
- [x] 2.5 建立 `frontend/src/resource-status/components/SummaryCards.vue` 10 KPI 卡片Total/PRD/SBY/UDT/SDT/EGT/NST/OTHER/OU%/AVAIL% click 篩選active 狀態百分比顯示
- [x] 2.6 建立 `frontend/src/resource-status/components/MatrixSection.vue` 使用 resource-shared/HierarchyTablebuildMatrixHierarchy 邏輯3 層聚合 + 狀態歸類toolbarexpand/collapse allcell click 篩選設備
- [x] 2.7 建立 `frontend/src/resource-status/components/EquipmentGrid.vue` + `EquipmentCard.vue` 設備卡片格auto-fill grid, min 280px每卡顯示 resource name/status badge/workcenter/group/family/location/LOT count/JOB indicator狀態色邊框篩選指示器
- [x] 2.8 建立 `frontend/src/resource-status/components/FloatingTooltip.vue` `<Teleport to="body">` + `v-if`LOT 詳情LOTID/QTY/track-in time/employee JOB 詳情order/status/model/technician/codesviewport clamp 定位邏輯
- [x] 2.9 整合 useAutoRefresh import `wip-shared/composables/useAutoRefresh.js`intervalMs 設為 5 分鐘5 * 60 * 1000接入 loadData 作為 onRefresh
## 3. resource-history Vue 3 遷移
- [x] 3.1 建立 `frontend/src/resource-history/index.html` HTML entry point設定 `<title>設備歷史績效</title>`
- [x] 3.2 建立 `frontend/src/resource-history/App.vue` 頂層元件管理 summaryData/detailData/hierarchyState/filters 狀態executeQuery 整合 parallel API calls
- [x] 3.3 建立 `frontend/src/resource-history/components/FilterBar.vue` 日期區間預設 last 7 days+ 粒度按鈕///+ 查詢按鈕
- [x] 3.4 建立 `frontend/src/resource-history/components/MultiSelect.vue` 多選下拉元件checkbox list + click-outside-close + select all/clearv-model 綁定 selectedItems 陣列 workcenter groups families 使用
- [x] 3.5 建立 `frontend/src/resource-history/components/KpiCards.vue` 9 KPI 卡片OU%/AVAIL%/PRD/SBY/UDT/SDT/EGT/NST/Machine Count使用 buildResourceKpiFromHours() 計算大數值用 K 格式
- [x] 3.6 建立 `frontend/src/resource-history/components/TrendChart.vue` vue-echarts 折線圖OU%+AVAIL% 雙線smooth area fill 0.2 opacity`<VChart :option="chartOption" autoresize />`
- [x] 3.7 建立 `frontend/src/resource-history/components/StackedChart.vue` vue-echarts 堆疊柱狀圖6 狀態 hours per period使用 resource-shared STATUS_COLORS
- [x] 3.8 建立 `frontend/src/resource-history/components/ComparisonChart.vue` vue-echarts 橫向柱狀圖top 15 workcenters by OU%色碼 green/yellow/red OU badge 閾值
- [x] 3.9 建立 `frontend/src/resource-history/components/HeatmapChart.vue` vue-echarts 2D 熱圖workcenters × datesvisualMap redyellowgreenworkcenter_seq 排序
- [x] 3.10 建立 `frontend/src/resource-history/components/DetailSection.vue` 使用 resource-shared/HierarchyTablebuildHierarchy 邏輯3 層聚合 + hours 計算toolbarexpand/collapse all + CSV export 按鈕
- [x] 3.11 實作 CSV 匯出 點擊按鈕建立臨時 `<a>` 導向 `/api/resource/history/export?...` 下載
## 4. Vite 建置與 Flask 路由
- [x] 4.1 更新 `frontend/vite.config.js` resource-status resource-history entry `main.js` 改為 `index.html`
- [x] 4.2 更新 `frontend/package.json` build script 新增 resource-status.html resource-history.html copy 指令
- [x] 4.3 更新 `src/mes_dashboard/app.py` `/resource` route 改為 `send_from_directory(dist_dir, 'resource-status.html')``/resource-history` route 改為 `send_from_directory(dist_dir, 'resource-history.html')`
## 5. 清理與驗證
- [x] 5.1 刪除 Jinja2 模板 `templates/resource_status.html` `templates/resource_history.html`
- [x] 5.2 刪除 resource-status/main.js resource-history/main.js 中的舊 vanilla JS 程式碼替換為 Vue 3 createApp 入口
- [x] 5.3 執行 `npm run build` 確認建置成功確認 `static/dist/` 產出 resource-status.html/js/css resource-history.html/js/css
- [x] 5.4 驗證兩頁在 portal iframe 中正常載入CSP frame-ancestors 'self' 允許嵌入