Files
egg 8225863a85 feat(hold-overview): add Hold Lot Overview page with TreeMap, Matrix, and cascade filtering
Provide managers with a dedicated page to analyze hold lots across all stations.
Extends existing service functions (get_hold_detail_summary, get_hold_detail_lots,
get_wip_matrix) with optional parameters for backward compatibility, adds one new
function (get_hold_overview_treemap), and registers the page in the portal navigation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 13:02:24 +08:00

7.2 KiB
Raw Permalink Blame History

1. Backend — 擴充現有 Service 函數

  • 1.1 擴充 get_hold_detail_summary() 簽名:reason 改為 Optional[str] = None,新增 hold_type: Optional[str] = None 參數reason=None 時聚合所有 HOLD lotshold_type 過濾品質/非品質cache path 和 Oracle fallback 都需支援;確保現有 Hold Detail 呼叫 get_hold_detail_summary(reason='xxx') 行為不變
  • 1.2 擴充 get_hold_detail_lots() 簽名:reason 改為 Optional[str] = None,新增 hold_type: Optional[str] = Nonetreemap_reason: Optional[str] = None 參數reason=None 時返回所有 HOLD lotstreemap_reason 作為額外 HOLDREASONNAME 過濾TreeMap 點擊篩選用);增加 holdReason 欄位到 lot 回傳資料中;確保現有 Hold Detail 呼叫不受影響
  • 1.3 擴充 get_wip_matrix() 簽名:新增 reason: Optional[str] = None 參數,過濾 HOLDREASONNAMEcache path 用 DataFrame filterOracle fallback 用 QueryBuilderreason=None 時行為不變,確保 WIP Overview 呼叫不受影響
  • 1.4 新增 get_hold_overview_treemap() 函數(唯一全新函數):使用 _select_with_snapshot_indexes(status='HOLD', hold_type=...) 取得 HOLD DataFrame按 (WORKCENTER_GROUP, HOLDREASONNAME) groupBy 聚合,回傳 [{ workcenter, reason, lots, qty, avgAge }];接受 hold_type, reason, workcenter, package 參數;含 Oracle fallback

2. Backend — 路由

  • 2.1 建立 src/mes_dashboard/routes/hold_overview_routes.pyFlask Blueprint hold_overview_bp;頁面路由 GET /hold-overviewsend_from_directory 提供 static Vite HTML含 fallback HTML
  • 2.2 實作 GET /api/hold-overview/summary:解析 hold_type(預設 quality)和 reason query params委派給擴充後的 get_hold_detail_summary(reason=reason, hold_type=hold_type)
  • 2.3 實作 GET /api/hold-overview/matrix:委派給現有 get_wip_matrix(status='HOLD', hold_type=..., reason=...);套用 rate limiting (120 req/60s)
  • 2.4 實作 GET /api/hold-overview/treemap:解析 hold_type, reason, workcenter, package params委派給 get_hold_overview_treemap()
  • 2.5 實作 GET /api/hold-overview/lots:解析所有 filter params + 分頁,委派給擴充後的 get_hold_detail_lots(reason=reason, hold_type=hold_type, treemap_reason=treemap_reason, ...);套用 rate limiting (90 req/60s)per_page 上限 200
  • 2.6 在 Flask app factoryroutes/__init__.py)中註冊 hold_overview_bp

3. Backend — 向後相容驗證

  • 3.1 驗證 Hold Detail 頁面現有 3 支 APIsummary/distribution/lots在擴充後行為不變get_hold_detail_summary(reason='xxx')get_hold_detail_lots(reason='xxx', ...) 結果與擴充前一致
  • 3.2 驗證 WIP Overview 的 get_wip_matrix() 呼叫在新增 reason 參數後行為不變reason=None 預設值)

4. Frontend — 腳手架

  • 4.1 建立 frontend/src/hold-overview/ 目錄結構:index.html, main.js, App.vue, style.css, components/
  • 4.2 在 vite.config.js 的 input 加入 'hold-overview': resolve(__dirname, 'src/hold-overview/index.html')
  • 4.3 建立 index.htmlVue 3 mount pointmain.jscreateApp(App).mount('#app')import style.csswip-shared/styles.css

5. Frontend — FilterBar全新

  • 5.1 建立 components/FilterBar.vueHold Type radio group品質異常 default, 非品質異常, 全部)+ Reason dropdown全部 + dynamic reasonsemit change 事件帶 { holdType, reason }

6. Frontend — SummaryCards直接 import

  • 6.1 在 App.vue 中直接 import SummaryCards from '../hold-detail/components/SummaryCards.vue'props 形狀 { totalLots, totalQty, avgAge, maxAge, workcenterCount } 完全相容,無需新建元件

7. Frontend — HoldMatrix基於 MatrixTable 新建)

  • 7.1 建立 components/HoldMatrix.vue,以 wip-overview/MatrixTable.vue 為基礎:保留 matrix 渲染邏輯sticky 首欄、Total row/column、"-" 零值、zh-TW 格式化)
  • 7.2 擴充互動cell click → emit { workcenter, package }、workcenter name/row total click → emit { workcenter }、package header/column total click → emit { package }active cell/row/column highlighttoggle logic再次點擊同一項 = 清除)

8. Frontend — HoldTreeMap全新

  • 8.1 建立 components/HoldTreeMap.vueECharts TreeMapimport { TreemapChart } from 'echarts/charts'兩層結構WC parent → Reason child面積=QTYvisualMap 色階 for avgAge綠<1天, 黃1-3天, 橙3-7天, 紅>7天
  • 8.2 實作 tooltipworkcenter, reason, lots, qty, avgAge和 click handler → emit { workcenter, reason }toggle logic"目前無 Hold 資料" empty state
  • 8.3 實作 autoresize 和 responsive height

9. Frontend — LotTable基於 hold-detail/LotTable 新建)

  • 9.1 建立 components/LotTable.vue,以 hold-detail/LotTable.vue 為基礎:保留分頁邏輯(已 import wip-shared/Pagination.vue、loading/error/empty 狀態、filter indicator替換欄位移除 Spec新增 Hold Reason 欄位holdReason

10. Frontend — FilterIndicator全新

  • 10.1 建立 components/FilterIndicator.vue:顯示 active matrixFilter 和/或 treemapFilter 標籤,含 ✕ 清除按鈕;任一 cascade filter 啟用時顯示「清除所有篩選」按鈕

11. Frontend — App.vue 整合

  • 11.1 串接 App.vueimport 所有元件SummaryCards 從 hold-detail import、其餘從 local components設定 reactive state for filterBar, matrixFilter, treemapFilter, page
  • 11.2 實作資料載入:loadAllData() 平行呼叫 4 支 APIloadTreemapAndLots() for matrix filter 變更;loadLots() for treemap filter 變更;使用 useAutoRefresh composablewip-shared/composables/useAutoRefresh.js import
  • 11.3 實作 filter cascadefilter bar 變更 → 清除 matrixFilter + treemapFilter → loadAllData()matrix click → set matrixFilter, 清除 treemapFilter → loadTreemapAndLots()treemap click → set treemapFilter → loadLots()
  • 11.4 實作 loading statesinitialLoading overlay、refreshing indicator、refresh success/error、error handling、手動重新整理按鈕、AbortController request cancellation
  • 11.5 從 treemap 資料的 distinct reasons 填充 Reason dropdown

12. Frontend — 樣式

  • 12.1 建立 style.css,沿用 wip-overview/style.csshold-detail/style.css 的 pattern包含 header、summary cards、matrix table、treemap section、lot table、filter indicator、filter bar、loading overlay、error banner 樣式

13. Build & 驗證

  • 13.1 執行 npm --prefix frontend run build,確認 static/dist/ 生成 hold-overview.html, hold-overview.js, hold-overview.css
  • 13.2 驗證 Flask serve /hold-overview 正常4 支 API endpoint 回應正確
  • 13.3 端對端測試filter bar toggle → matrix click → treemap click → lot table cascade驗證每層正確回應
  • 13.4 回歸測試:確認 Hold Detail 頁面(/hold-detail?reason=xxx)功能正常不受影響;確認 WIP Overview Matrix 功能正常不受影響