feat(query-tool): rewrite frontend with ECharts tree, multi-select, and modular composables
Replace the monolithic useQueryToolData composable and nested Vue component tree with a modular architecture: useLotResolve, useLotLineage, useLotDetail, and useEquipmentQuery. Introduce ECharts TreeChart (LR orthogonal layout) for lot lineage visualization with multi-select support, subtree expansion, zoom/pan, and serial number normalization. Add unified LineageEngine backend with split descendant traversal and leaf serial number queries. Archive the query-tool-rewrite openspec change and sync delta specs to main. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,64 +1,16 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: useTraceProgress composable SHALL orchestrate staged fetching with reactive state
|
||||
`useTraceProgress` SHALL provide a shared composable for sequential stage fetching with per-stage reactive state updates.
|
||||
|
||||
#### Scenario: Normal three-stage fetch sequence
|
||||
- **WHEN** `useTraceProgress` is invoked with profile and params
|
||||
- **THEN** it SHALL execute seed-resolve → lineage → events sequentially
|
||||
- **THEN** after each stage completes, `current_stage` and `completed_stages` reactive refs SHALL update immediately
|
||||
- **THEN** `stage_results` SHALL accumulate results from completed stages
|
||||
|
||||
#### Scenario: Stage failure does not block completed results
|
||||
- **WHEN** the lineage stage fails after seed-resolve has completed
|
||||
- **THEN** seed-resolve results SHALL remain visible and accessible
|
||||
- **THEN** the error SHALL be captured in stage-specific error state
|
||||
- **THEN** subsequent stages (events) SHALL NOT execute
|
||||
|
||||
### Requirement: mid-section-defect SHALL render progressively as stages complete
|
||||
The mid-section-defect page SHALL display partial results as each trace stage completes.
|
||||
|
||||
#### Scenario: Seed lots visible before lineage completes
|
||||
- **WHEN** seed-resolve stage completes (≤3s for ≥10 seed lots)
|
||||
- **THEN** the seed lots list SHALL be rendered immediately
|
||||
- **THEN** lineage and events sections SHALL show skeleton placeholders
|
||||
|
||||
#### Scenario: KPI/charts visible after events complete
|
||||
- **WHEN** lineage and events stages complete
|
||||
- **THEN** KPI cards and charts SHALL render with fade-in animation
|
||||
- **THEN** no layout shift SHALL occur (skeleton placeholders SHALL have matching dimensions)
|
||||
|
||||
#### Scenario: Detail table pagination unchanged
|
||||
- **WHEN** the user requests detail data
|
||||
- **THEN** the existing detail endpoint with pagination SHALL be used (not the staged API)
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: query-tool lineage tab SHALL load on-demand
|
||||
The query-tool lineage tab SHALL load lineage data for individual lots on user interaction, not batch-load all lots.
|
||||
The query-tool lineage tree SHALL auto-fire lineage API calls after lot resolution with concurrency-limited parallel requests and progressive rendering, while preserving on-demand expand/collapse for tree navigation.
|
||||
|
||||
#### Scenario: User clicks a lot to view lineage
|
||||
- **WHEN** the user clicks a lot card to expand lineage information
|
||||
- **THEN** lineage SHALL be fetched via `/api/trace/lineage` for that single lot's container IDs
|
||||
- **THEN** response time SHALL be ≤3s for the individual lot
|
||||
#### Scenario: Auto-fire lineage after resolve
|
||||
- **WHEN** lot resolution completes with N resolved lots
|
||||
- **THEN** lineage SHALL be fetched via `POST /api/trace/lineage` for each lot automatically
|
||||
- **THEN** concurrent requests SHALL be limited to 3 at a time to respect rate limits (10/60s)
|
||||
- **THEN** response time SHALL be ≤3s per individual lot
|
||||
|
||||
#### Scenario: Multiple lots expanded
|
||||
- **WHEN** the user expands lineage for multiple lots
|
||||
- **THEN** each lot's lineage SHALL be fetched independently (not batch)
|
||||
- **THEN** already-fetched lineage data SHALL be preserved (not re-fetched)
|
||||
|
||||
### Requirement: Both pages SHALL display a stage progress indicator
|
||||
Both mid-section-defect and query-tool SHALL display a progress indicator showing the current trace stage.
|
||||
|
||||
#### Scenario: Progress indicator during staged fetch
|
||||
- **WHEN** a trace query is in progress
|
||||
- **THEN** a progress indicator SHALL display the current stage (seed → lineage → events)
|
||||
- **THEN** completed stages SHALL be visually distinct from pending/active stages
|
||||
- **THEN** the indicator SHALL replace the existing single loading spinner
|
||||
|
||||
### Requirement: Legacy static query-tool.js SHALL be removed
|
||||
The pre-Vite static file `src/mes_dashboard/static/js/query-tool.js` (3056L, 126KB) SHALL be deleted as dead code.
|
||||
|
||||
#### Scenario: Dead code removal verification
|
||||
- **WHEN** `static/js/query-tool.js` is deleted
|
||||
- **THEN** grep for `static/js/query-tool.js` SHALL return zero results across the codebase
|
||||
- **THEN** `query_tool.html` template SHALL continue to function via `frontend_asset('query-tool.js')` which resolves to the Vite-built bundle
|
||||
- **THEN** `frontend/src/query-tool/main.js` (Vue 3 Vite entry) SHALL remain unaffected
|
||||
#### Scenario: Multiple lots lineage results cached
|
||||
- **WHEN** lineage data has been fetched for multiple lots
|
||||
- **THEN** each lot's lineage data SHALL be preserved independently (not re-fetched)
|
||||
- **WHEN** a new resolve query is executed
|
||||
- **THEN** all cached lineage data SHALL be cleared
|
||||
|
||||
72
openspec/specs/query-tool-equipment/spec.md
Normal file
72
openspec/specs/query-tool-equipment/spec.md
Normal file
@@ -0,0 +1,72 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Equipment tab SHALL provide equipment selection with date range filtering
|
||||
The equipment tab SHALL allow selecting multiple equipment and a date range for all sub-tab queries.
|
||||
|
||||
#### Scenario: Equipment and date selection
|
||||
- **WHEN** the user opens the equipment tab
|
||||
- **THEN** a MultiSelect dropdown SHALL list available equipment from `GET /api/query-tool/equipment-list`
|
||||
- **THEN** date inputs SHALL default to the last 30 days
|
||||
- **THEN** a query button SHALL trigger data loading for the active sub-tab
|
||||
|
||||
#### Scenario: Shared filter state across sub-tabs
|
||||
- **WHEN** the user selects equipment and date range then switches sub-tabs
|
||||
- **THEN** the filter values SHALL persist across all equipment sub-tabs
|
||||
- **THEN** switching to a new sub-tab with the same filters SHALL trigger a fresh query for that sub-tab's data type
|
||||
|
||||
### Requirement: Equipment Production Lots sub-tab SHALL display lots processed by selected equipment
|
||||
The Production Lots sub-tab SHALL show all lots processed on the selected equipment within the date range.
|
||||
|
||||
#### Scenario: Production lots query
|
||||
- **WHEN** the user queries with selected equipment and date range
|
||||
- **THEN** the system SHALL call `POST /api/query-tool/equipment-period` with `query_type: "lots"`
|
||||
- **THEN** results SHALL display in a table showing CONTAINERID, SPECNAME, TRACK_IN, TRACK_OUT, QTY, EQUIPMENTNAME
|
||||
|
||||
#### Scenario: Partial track-out handling
|
||||
- **WHEN** a lot has multiple track-out records (partial processing)
|
||||
- **THEN** all records SHALL be displayed (not deduplicated)
|
||||
|
||||
### Requirement: Equipment Maintenance sub-tab SHALL display maintenance job records with expandable detail
|
||||
The Maintenance sub-tab SHALL show maintenance jobs from `DW_MES_JOB` with cause/repair/symptom codes.
|
||||
|
||||
#### Scenario: Maintenance job list
|
||||
- **WHEN** the user queries maintenance records
|
||||
- **THEN** the system SHALL call `POST /api/query-tool/equipment-period` with `query_type: "jobs"`
|
||||
- **THEN** results SHALL display: JOBID, STATUS, CAUSECODENAME, REPAIRCODENAME, SYMPTOMCODENAME, CREATE/COMPLETE dates
|
||||
|
||||
#### Scenario: Job detail expansion
|
||||
- **WHEN** the user clicks on a maintenance job row
|
||||
- **THEN** the row SHALL expand to show full detail including employee names, secondary codes, and related lot IDs (CONTAINERNAMES)
|
||||
|
||||
### Requirement: Equipment Scrap sub-tab SHALL display reject/defect records
|
||||
The Scrap sub-tab SHALL show reject statistics grouped by loss reason for the selected equipment and date range.
|
||||
|
||||
#### Scenario: Scrap records query
|
||||
- **WHEN** the user queries scrap records
|
||||
- **THEN** the system SHALL call `POST /api/query-tool/equipment-period` with `query_type: "rejects"`
|
||||
- **THEN** results SHALL display: EQUIPMENTNAME, LOSSREASONNAME, TOTAL_REJECT_QTY, TOTAL_DEFECT_QTY, AFFECTED_LOT_COUNT
|
||||
|
||||
### Requirement: Equipment Timeline sub-tab SHALL visualize equipment activity over time
|
||||
The Timeline sub-tab SHALL render a Gantt-style timeline showing equipment status, lots processed, and maintenance events.
|
||||
|
||||
#### Scenario: Multi-layer timeline rendering
|
||||
- **WHEN** the user views the equipment timeline
|
||||
- **THEN** the timeline SHALL overlay three data layers: status bars (PRD/SBY/UDT/SDT), lot processing bars, and maintenance event markers
|
||||
- **THEN** each equipment SHALL appear as a separate track row
|
||||
|
||||
#### Scenario: Status color coding
|
||||
- **WHEN** the timeline renders status bars
|
||||
- **THEN** PRD SHALL be green, SBY SHALL be amber, UDT SHALL be red, SDT SHALL be blue-gray
|
||||
- **THEN** a legend SHALL be displayed showing the color mapping
|
||||
|
||||
#### Scenario: Maintenance marker interaction
|
||||
- **WHEN** the user hovers over or clicks a maintenance event marker on the timeline
|
||||
- **THEN** a tooltip or expanded panel SHALL show the job detail (CAUSECODENAME, REPAIRCODENAME, SYMPTOMCODENAME)
|
||||
|
||||
### Requirement: Each equipment sub-tab SHALL support CSV export
|
||||
Every equipment sub-tab SHALL have its own export button calling the existing export API.
|
||||
|
||||
#### Scenario: Equipment CSV export
|
||||
- **WHEN** the user clicks export on any equipment sub-tab
|
||||
- **THEN** the system SHALL call `POST /api/query-tool/export-csv` with the appropriate `export_type` (equipment_lots, equipment_jobs, equipment_rejects)
|
||||
- **THEN** the exported params SHALL include the current equipment_ids/equipment_names and date range
|
||||
152
openspec/specs/query-tool-lot-trace/spec.md
Normal file
152
openspec/specs/query-tool-lot-trace/spec.md
Normal file
@@ -0,0 +1,152 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Query-tool page SHALL use tab-based layout separating LOT tracing from equipment queries
|
||||
The query-tool page SHALL present two top-level tabs: "LOT 追蹤" and "設備查詢", each with independent state and UI.
|
||||
|
||||
#### Scenario: Tab switching preserves state
|
||||
- **WHEN** the user switches from LOT tab to Equipment tab and back
|
||||
- **THEN** the LOT tab SHALL retain its resolved lots, lineage tree state, and selected lot detail
|
||||
- **THEN** the Equipment tab SHALL retain its query results independently
|
||||
|
||||
#### Scenario: URL state reflects active tab
|
||||
- **WHEN** the user is on a specific tab
|
||||
- **THEN** the URL SHALL include a `tab` parameter (e.g., `?tab=lot` or `?tab=equipment`)
|
||||
- **THEN** reloading the page SHALL restore the active tab
|
||||
|
||||
### Requirement: QueryBar SHALL resolve LOT/Serial/WorkOrder inputs
|
||||
The query bar SHALL accept multi-value input (newline or comma-separated) with input type selection and resolve via `POST /api/query-tool/resolve`.
|
||||
|
||||
#### Scenario: Successful LOT resolution
|
||||
- **WHEN** the user enters lot IDs and clicks resolve
|
||||
- **THEN** the system SHALL call `POST /api/query-tool/resolve` with `input_type` and `values`
|
||||
- **THEN** resolved lots SHALL appear as root nodes in the lineage tree
|
||||
- **THEN** not-found values SHALL be displayed as warnings below the tree
|
||||
|
||||
#### Scenario: Work order expansion
|
||||
- **WHEN** the user enters work order IDs (max 10)
|
||||
- **THEN** each work order MAY expand to 100+ lots
|
||||
- **THEN** all expanded lots SHALL appear as root nodes in the lineage tree
|
||||
|
||||
#### Scenario: Input validation
|
||||
- **WHEN** the user submits empty input or exceeds limits (50 lot IDs, 50 serial numbers, 10 work orders)
|
||||
- **THEN** the system SHALL display a validation error without making an API call
|
||||
|
||||
### Requirement: LineageTree SHALL display as a decomposition tree with progressive growth animation
|
||||
After resolve completes, the lineage tree SHALL auto-fire lineage API calls for each resolved lot with concurrency control, rendering an animated tree that grows as results arrive.
|
||||
|
||||
#### Scenario: Auto-fire lineage after resolve
|
||||
- **WHEN** lot resolution completes with N resolved lots
|
||||
- **THEN** the system SHALL automatically call `POST /api/trace/lineage` for each lot
|
||||
- **THEN** concurrent lineage requests SHALL be limited to 3 at a time
|
||||
- **THEN** the lineage tree SHALL render root nodes immediately (resolved lots)
|
||||
|
||||
#### Scenario: Progressive tree growth animation
|
||||
- **WHEN** a lineage API response returns for a lot
|
||||
- **THEN** ancestor nodes SHALL animate into the tree (slide-in + fade, staggered 30-50ms per sibling)
|
||||
- **THEN** the animation SHALL give the visual impression of a tree "growing" its branches
|
||||
|
||||
#### Scenario: Tree node expand/collapse
|
||||
- **WHEN** the user clicks a tree node with children (ancestors)
|
||||
- **THEN** children SHALL toggle between expanded and collapsed state
|
||||
- **THEN** expand/collapse SHALL be a client-side operation (no additional API call)
|
||||
|
||||
#### Scenario: Expand-all and collapse-all
|
||||
- **WHEN** the user clicks "全部展開"
|
||||
- **THEN** all tree nodes at all levels SHALL expand with staggered animation
|
||||
- **WHEN** the user clicks "收合"
|
||||
- **THEN** all tree nodes SHALL collapse to show only root nodes
|
||||
|
||||
#### Scenario: Merge relationships visually distinct
|
||||
- **WHEN** the lineage data includes merge relationships
|
||||
- **THEN** merge nodes SHALL display a distinct icon and/or color to differentiate from direct ancestor relationships
|
||||
|
||||
#### Scenario: Leaf nodes without expand affordance
|
||||
- **WHEN** a tree node has no ancestors (leaf/terminal node)
|
||||
- **THEN** it SHALL NOT display an expand button or clickable expand area
|
||||
|
||||
#### Scenario: Lineage cache prevents duplicate fetches
|
||||
- **WHEN** lineage data has already been fetched for a lot
|
||||
- **THEN** subsequent interactions SHALL use cached data without re-fetching
|
||||
- **WHEN** a new resolve query is executed
|
||||
- **THEN** the lineage cache SHALL be cleared
|
||||
|
||||
### Requirement: Left-right master-detail layout SHALL show tree and LOT detail side by side
|
||||
The LOT tracing tab SHALL use a left-right split layout with the lineage tree on the left and LOT detail on the right.
|
||||
|
||||
#### Scenario: LOT selection from tree
|
||||
- **WHEN** the user clicks any node in the lineage tree (root lot or ancestor)
|
||||
- **THEN** the right panel SHALL load detail for that node's container ID
|
||||
- **THEN** the selected node SHALL be visually highlighted in the tree
|
||||
|
||||
#### Scenario: Right panel sub-tabs
|
||||
- **WHEN** a LOT is selected
|
||||
- **THEN** the right panel SHALL display sub-tabs: 歷程 (History), 物料 (Materials), 退貨 (Rejects), Hold, Split, Job
|
||||
- **THEN** each sub-tab SHALL load data on-demand when activated (not pre-fetched)
|
||||
|
||||
#### Scenario: Responsive behavior
|
||||
- **WHEN** the viewport width is below 1024px
|
||||
- **THEN** the layout SHALL stack vertically (tree above, detail below)
|
||||
|
||||
### Requirement: LOT History sub-tab SHALL display production history with workcenter filter
|
||||
The History sub-tab SHALL show production history data from `GET /api/query-tool/lot-history` with workcenter group filtering.
|
||||
|
||||
#### Scenario: History table display
|
||||
- **WHEN** the user selects the History sub-tab for a LOT
|
||||
- **THEN** the system SHALL call `GET /api/query-tool/lot-history?container_id=X`
|
||||
- **THEN** results SHALL display in a table with sticky headers and horizontal scroll
|
||||
|
||||
#### Scenario: Workcenter group filter
|
||||
- **WHEN** the user selects workcenter groups from the filter dropdown
|
||||
- **THEN** the history query SHALL include the selected groups as filter parameters
|
||||
- **THEN** the history table SHALL refresh with filtered results
|
||||
|
||||
### Requirement: LOT Production Timeline SHALL visualize station progression over time
|
||||
The History sub-tab SHALL include a timeline visualization showing the lot's journey through production stations.
|
||||
|
||||
#### Scenario: Timeline rendering
|
||||
- **WHEN** lot history data is loaded
|
||||
- **THEN** a horizontal Gantt-style timeline SHALL render with time on the X-axis
|
||||
- **THEN** each workcenter/station SHALL appear as a track with a colored bar from track-in to track-out time
|
||||
|
||||
#### Scenario: Workcenter filter affects timeline
|
||||
- **WHEN** the user filters by workcenter groups
|
||||
- **THEN** the timeline SHALL show only stations matching the selected groups
|
||||
- **THEN** filtered-out stations SHALL be hidden (not grayed out)
|
||||
|
||||
#### Scenario: Timeline event markers
|
||||
- **WHEN** hold events or material consumption events exist within the timeline range
|
||||
- **THEN** they SHALL be displayed as markers on the timeline with tooltip details on hover
|
||||
|
||||
### Requirement: LOT Association sub-tabs SHALL load data on-demand
|
||||
Each association sub-tab (Materials, Rejects, Holds, Splits, Jobs) SHALL fetch data independently when activated.
|
||||
|
||||
#### Scenario: Association data loading
|
||||
- **WHEN** the user activates a sub-tab (e.g., Materials)
|
||||
- **THEN** the system SHALL call `GET /api/query-tool/lot-associations?container_id=X&type=materials`
|
||||
- **THEN** results SHALL display in a table with dynamic columns
|
||||
|
||||
#### Scenario: Sub-tab data caching within session
|
||||
- **WHEN** the user switches between sub-tabs for the same LOT
|
||||
- **THEN** previously loaded sub-tab data SHALL be preserved (not re-fetched)
|
||||
- **WHEN** the user selects a different LOT
|
||||
- **THEN** all sub-tab caches SHALL be cleared
|
||||
|
||||
### Requirement: Each sub-tab SHALL support independent CSV export
|
||||
Every detail sub-tab SHALL have its own export button.
|
||||
|
||||
#### Scenario: Per-tab export
|
||||
- **WHEN** the user clicks export on the Materials sub-tab
|
||||
- **THEN** the system SHALL call `POST /api/query-tool/export-csv` with `export_type: "lot_materials"` and the current container_id
|
||||
- **THEN** a CSV file SHALL download with the appropriate filename
|
||||
|
||||
#### Scenario: Export disabled when no data
|
||||
- **WHEN** a sub-tab has no data loaded or the data is empty
|
||||
- **THEN** the export button SHALL be disabled
|
||||
|
||||
### Requirement: Legacy dead code SHALL be removed
|
||||
The legacy `frontend/src/query-tool/main.js` (448L vanilla JS) and `frontend/src/query-tool/style.css` SHALL be deleted.
|
||||
|
||||
#### Scenario: Dead code removal
|
||||
- **WHEN** the rewrite is complete
|
||||
- **THEN** `frontend/src/query-tool/main.js` SHALL contain only the Vite entry point (createApp + mount)
|
||||
- **THEN** `frontend/src/query-tool/style.css` SHALL be deleted (all styling via Tailwind)
|
||||
50
openspec/specs/timeline-chart/spec.md
Normal file
50
openspec/specs/timeline-chart/spec.md
Normal file
@@ -0,0 +1,50 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: TimelineChart component SHALL render configurable Gantt-style timelines
|
||||
A shared `TimelineChart` component SHALL accept structured track/event data and render a horizontal timeline with SVG/CSS.
|
||||
|
||||
#### Scenario: Basic track rendering
|
||||
- **WHEN** TimelineChart receives tracks with bars (each bar having start time, end time, type)
|
||||
- **THEN** it SHALL render a horizontal time axis and one row per track
|
||||
- **THEN** each bar SHALL be positioned proportionally along the time axis with width reflecting duration
|
||||
|
||||
#### Scenario: Color mapping
|
||||
- **WHEN** bars have different `type` values
|
||||
- **THEN** each type SHALL be rendered with a color from the provided `colorMap` prop
|
||||
- **THEN** a legend SHALL be displayed showing type-to-color mapping
|
||||
|
||||
#### Scenario: Event markers
|
||||
- **WHEN** the component receives events (point-in-time markers)
|
||||
- **THEN** each event SHALL render as a marker (diamond/triangle icon) at the corresponding time position on its track
|
||||
- **THEN** hovering over a marker SHALL display a tooltip with the event label and details
|
||||
|
||||
#### Scenario: Time axis adapts to data range
|
||||
- **WHEN** the timeline data spans hours
|
||||
- **THEN** the time axis SHALL show hour ticks (e.g., 06:00, 07:00, ...)
|
||||
- **WHEN** the timeline data spans days
|
||||
- **THEN** the time axis SHALL show date ticks (e.g., 02-10, 02-11, ...)
|
||||
|
||||
#### Scenario: Horizontal scroll for long timelines
|
||||
- **WHEN** the timeline data exceeds the visible width
|
||||
- **THEN** the component SHALL support horizontal scrolling
|
||||
- **THEN** track labels on the left SHALL remain fixed (sticky) during scroll
|
||||
|
||||
#### Scenario: Bar tooltip on hover
|
||||
- **WHEN** the user hovers over a bar segment
|
||||
- **THEN** a tooltip SHALL display the bar's label, start time, end time, and duration
|
||||
|
||||
### Requirement: TimelineChart SHALL support multi-layer overlapping tracks
|
||||
The component SHALL support rendering multiple bar layers on a single track row (e.g., status bars behind lot bars).
|
||||
|
||||
#### Scenario: Overlapping layers
|
||||
- **WHEN** a track has multiple layers (e.g., `statusBars` and `lotBars`)
|
||||
- **THEN** background layer bars SHALL render behind foreground layer bars
|
||||
- **THEN** both layers SHALL be visible (foreground bars shorter in height or semi-transparent)
|
||||
|
||||
### Requirement: TimelineChart SHALL have no external charting dependencies
|
||||
The component SHALL be implemented using only SVG elements and CSS, with no external charting library.
|
||||
|
||||
#### Scenario: Zero additional dependencies
|
||||
- **WHEN** the TimelineChart component is used
|
||||
- **THEN** it SHALL NOT require any npm package not already in the project
|
||||
- **THEN** rendering SHALL use inline SVG elements within the Vue template
|
||||
Reference in New Issue
Block a user