New independent report page based on DWH.DW_MES_HOLDRELEASEHISTORY providing historical hold/release performance analysis. Includes daily trend with Redis caching, reason Pareto with click-to-filter, duration distribution with click-to-filter, multi-select record type filter (new/on_hold/released), workcenter-group mapping via memory cache, and server-side paginated detail table. All 32 backend tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.1 KiB
Context
Hold Overview (DW_MES_LOT_V, Redis cache) 提供即時快照;Hold Detail 深入單一 Reason。但主管缺乏歷史視角——趨勢、時長分析、部門績效都只能透過 BI 工具 (PJMES043) 手動操作。
本設計在既有 Dashboard 架構上新增一個歷史績效頁面,直接查詢 DWH.DW_MES_HOLDRELEASEHISTORY 表 (~310K rows),搭配 Redis 快取加速近期資料。
Goals / Non-Goals
Goals:
- 提供自由日期區間的 Hold 歷史每日趨勢圖(On Hold/新增/解除/Future Hold)
- 提供 Reason Pareto、Duration 分布、負責人統計(部門+個人)分析
- 提供 paginated Hold/Release 明細表
- Reason Pareto 點擊可 cascade filter 負責人統計與明細表
- 近二月資料使用 Redis 快取(12hr TTL),前端切換 Hold Type 免 re-call
Non-Goals:
- 不替代既有 Hold Overview / Hold Detail 的即時功能
- 不引入即時 WebSocket 推送
- 不做跨頁面的 drill-through(本頁面自成體系)
- 不修改 HOLDRELEASEHISTORY 表結構或新增 index
Decisions
1. 資料來源:直接查詢 HOLDRELEASEHISTORY vs. 預建聚合表
選擇: 直接查詢 + Redis 快取聚合結果
理由: 310K 行規模適中,calendar-spine cross-join 月級查詢在秒級內完成。預建聚合表增加 ETL 複雜度,且歷史數據變動低頻,12hr 快取已足夠。
替代方案: 在 DWH 建立物化視圖 → 拒絕,因需 DBA 協調且 Dashboard 應盡量自包含。
2. 快取策略:近二月 Redis vs. 全量快取 vs. 無快取
選擇: 近二月(當月 + 前一月)Redis 快取,12hr TTL
理由: 多數使用者查看近期資料。近二月快取命中率高,超過二月的查詢較少且可接受直接 Oracle 查詢的延遲。全量快取浪費記憶體且過期管理複雜。
Redis key: hold_history:daily:{YYYY-MM}
結構: 一份快取包含 quality / non_quality / all 三種 hold_type 的每日聚合,前端切換免 API re-call。
跨月查詢: 後端從多個月快取中切出需要的日期範圍後合併回傳。
3. trend API 回傳三種 hold_type vs. 按需查詢
選擇: trend API 一次回傳三種 hold_type 的每日資料
理由: 趨勢是最常操作的圖表,切換 hold_type 應即時響應。三種 hold_type 資料已在同一份 Redis 快取中,回傳全部不增加 I/O,但大幅改善 UX。其餘 4 支 API (pareto/duration/department/list) 按 hold_type 過濾,因為它們的 payload 可能很大。
4. SQL 集中管理:sql/hold_history/ 目錄
選擇: SQL 檔案放在 src/mes_dashboard/sql/hold_history/ 目錄
理由: 遵循既有 sql/query_tool/、sql/dashboard/、sql/resource/、sql/wip/ 的集中管理模式。SQL 與 Python 分離便於 review 和維護。
檔案規劃:
trend.sql— calendar-spine cross-join 每日聚合(翻譯自 hold_history.md)reason_pareto.sql— GROUP BY HOLDREASONNAMEduration.sql— 已 release 的 hold 時長分布department.sql— GROUP BY HOLDEMPDEPTNAME / HOLDEMPlist.sql— paginated 明細查詢
5. 商業邏輯:07:30 班別邊界
選擇: 忠實保留 hold_history.md 的班別邊界邏輯
理由: 這是工廠既有的日報定義,07:30 後的交易歸入隔天。偏離此定義會導致 Dashboard 數字與既有 BI 報表不一致。
實作: 在 SQL 層處理 (CASE WHEN TO_CHAR(HOLDTXNDATE,'HH24MI') >= '0730' THEN TRUNC(HOLDTXNDATE) + 1 ELSE TRUNC(HOLDTXNDATE) END)。
6. 前端架構
選擇: 獨立 Vue 3 SFC 頁面,複用 wip-shared composables
元件規劃:
App.vue— 頁面主容器、狀態管理、API 呼叫FilterBar.vue— DatePicker + Hold Type radioSummaryCards.vue— 6 張 KPI 卡片DailyTrend.vue— ECharts 折線+柱狀混合圖ReasonPareto.vue— ECharts Pareto 圖(可點擊)DurationChart.vue— ECharts 橫向柱狀圖DepartmentTable.vue— 可展開的部門/個人統計表DetailTable.vue— paginated 明細表
7. Duration 分布的計算範圍
選擇: 僅計算已 Release 的 hold(RELEASETXNDATE IS NOT NULL)
理由: 仍在 hold 中的無法確定最終時長,納入會扭曲分布。明細表中仍顯示未 release 的 hold(以 SYSDATE 計算到目前時長)。
Risks / Trade-offs
- [HOLDTXNDATE 無 index] → HOLDRELEASEHISTORY 僅有 HISTORYMAINLINEID 和 CONTAINERID 的 index。日期範圍查詢走 full table scan (~310K rows)。緩解:12hr Redis 快取 + 月級查詢粒度限制。若未來資料量成長,可考慮請 DBA 加 HOLDTXNDATE index。
- [Calendar-spine cross-join 效能] → 月曆骨幹 × 全表 cross join 是最重的查詢。緩解:Redis 快取近二月,超過二月直接查詢但接受較長 loading。
- [Redis 快取一致性] → 12hr TTL 意味資料最多延遲 12 小時。緩解:歷史資料本身就是 T-1 更新,12hr 延遲對管理決策無影響。
- [明細表回傳 HOLDCOMMENTS/RELEASECOMMENTS] → 文字欄位可能很長。緩解:前端 truncate 顯示,hover 看全文。