feat: implement frontend-only mock for production lines and runs
- Add ProductionTemplatesPage component for managing production templates with a visual representation using React Flow. - Create LineHeaderNode and LineStageNode components for rendering production line nodes. - Introduce RunStageNode and RunHeaderNode components for displaying run stages and headers. - Implement StageProgressStrip for visualizing stage progress in runs. - Create mock data for production runs and templates to simulate backend functionality. - Define types for production templates and runs to structure mock data. - Document frontend Phase 2 specifications for manufacturing processes, including screens, dialogs, and validation posture.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// Frontend-only mock run registry — no Dtos/Production backend exists yet
|
||||
// (docs/21-FRONTEND-PHASE2.md). Shared by the Runs board and the run detail page so both
|
||||
// read the same seed data (each page still keeps its own local edits — there's no backend
|
||||
// to persist an advance/start-run action back to the other screen).
|
||||
import { ProductionRun } from "@/types/production"
|
||||
import { MOCK_TEMPLATE_INFO } from "@/lib/production-mock-templates"
|
||||
import { STAGE_STATUS_ORDER, type StageStatus } from "@/lib/production-status-colors"
|
||||
|
||||
export const INITIAL_RUNS: ProductionRun[] = [
|
||||
{
|
||||
runId: 1, docNo: "PRD-2026-00001", templateName: "Steel Bracket Assembly", targetQty: 500,
|
||||
finishedItemName: "Steel Bracket A", uom: "PCS", warehouseName: "Main Warehouse", status: "InProgress",
|
||||
reworkCount: 0, createdAt: "2026-07-26", completedAt: null,
|
||||
stageSummary: { waiting: 1, ready: 0, inProgress: 1, done: 1, approved: 0 },
|
||||
},
|
||||
{
|
||||
runId: 2, docNo: "PRD-2026-00002", templateName: "PCB Soldering Line", targetQty: 200,
|
||||
finishedItemName: "PCB Board X", uom: "PCS", warehouseName: "Colombo Warehouse", status: "InProgress",
|
||||
reworkCount: 1, createdAt: "2026-07-25", completedAt: null,
|
||||
stageSummary: { waiting: 0, ready: 1, inProgress: 2, done: 1, approved: 1 },
|
||||
},
|
||||
{
|
||||
runId: 3, docNo: "PRD-2026-00003", templateName: "Wooden Pallet Build", targetQty: 1000,
|
||||
finishedItemName: "Pallet Standard", uom: "PCS", warehouseName: "Main Warehouse", status: "Completed",
|
||||
reworkCount: 0, createdAt: "2026-07-20", completedAt: "2026-07-24",
|
||||
stageSummary: { waiting: 0, ready: 0, inProgress: 0, done: 0, approved: 2 },
|
||||
},
|
||||
{
|
||||
runId: 4, docNo: "PRD-2026-00004", templateName: "Cable Harness Kit", targetQty: 300,
|
||||
finishedItemName: "Harness Kit B", uom: "PCS", warehouseName: "Main Warehouse", status: "InProgress",
|
||||
reworkCount: 0, createdAt: "2026-07-27", completedAt: null,
|
||||
stageSummary: { waiting: 2, ready: 1, inProgress: 0, done: 0, approved: 0 },
|
||||
},
|
||||
{
|
||||
runId: 5, docNo: "PRD-2026-00005", templateName: "Steel Bracket Assembly", targetQty: 150,
|
||||
finishedItemName: "Steel Bracket A", uom: "PCS", warehouseName: "Colombo Warehouse", status: "Cancelled",
|
||||
reworkCount: 0, createdAt: "2026-07-15", completedAt: null,
|
||||
stageSummary: { waiting: 0, ready: 0, inProgress: 1, done: 0, approved: 0 },
|
||||
},
|
||||
{
|
||||
runId: 6, docNo: "PRD-2026-00006", templateName: "PCB Soldering Line", targetQty: 400,
|
||||
finishedItemName: "PCB Board X", uom: "PCS", warehouseName: "Main Warehouse", status: "InProgress",
|
||||
reworkCount: 0, createdAt: "2026-07-23", completedAt: null,
|
||||
stageSummary: { waiting: 1, ready: 2, inProgress: 1, done: 1, approved: 0 },
|
||||
},
|
||||
]
|
||||
|
||||
// Active templates only (docs/21-FRONTEND-PHASE2.md §4 "Template picker (Active only)") —
|
||||
// mirrors the 4 Active rows on the Template list page ("Plastic Injection Mold" is Inactive
|
||||
// there, so it's excluded here too. `nominalBatchQty` backs the scaled-preview calculation;
|
||||
// there's no real per-template formula graph shared across routes to scale properly (each
|
||||
// builder page's stage data is local, unsaved state — see templates/[id]/page.tsx), so this
|
||||
// is a simplified stand-in for the doc's full per-stage scaled preview.
|
||||
export interface StartableTemplate {
|
||||
templateId: number
|
||||
name: string
|
||||
finishedItemName: string
|
||||
uom: string
|
||||
nominalBatchQty: number
|
||||
stageCount: number
|
||||
}
|
||||
|
||||
export const STARTABLE_TEMPLATES: StartableTemplate[] = [
|
||||
{ templateId: 1, name: "Steel Bracket Assembly", finishedItemName: "Steel Bracket A", uom: "PCS", nominalBatchQty: 100, stageCount: 3 },
|
||||
{ templateId: 2, name: "PCB Soldering Line", finishedItemName: "PCB Board X", uom: "PCS", nominalBatchQty: 50, stageCount: 5 },
|
||||
{ templateId: 3, name: "Wooden Pallet Build", finishedItemName: "Pallet Standard", uom: "PCS", nominalBatchQty: 200, stageCount: 2 },
|
||||
{ templateId: 5, name: "Cable Harness Kit", finishedItemName: "Harness Kit B", uom: "SET", nominalBatchQty: 75, stageCount: 3 },
|
||||
]
|
||||
|
||||
export interface RunStagePlanItem {
|
||||
name: string
|
||||
state: StageStatus
|
||||
}
|
||||
|
||||
const SUMMARY_KEY_BY_STATUS: Record<StageStatus, keyof ProductionRun["stageSummary"]> = {
|
||||
Waiting: "waiting",
|
||||
Ready: "ready",
|
||||
InProgress: "inProgress",
|
||||
Done: "done",
|
||||
Approved: "approved",
|
||||
}
|
||||
|
||||
/**
|
||||
* `stageSummary` only carries counts per status, not which named stage each count belongs
|
||||
* to. Reconstruct a per-stage breakdown by looking up the template's real stage names (via
|
||||
* MOCK_TEMPLATE_INFO) and allocating the counts across them most-complete-first — stages
|
||||
* run left to right, so the furthest-along stages are assumed to be the earliest ones in
|
||||
* the list. Pad with "Waiting" (and truncate) when the counts don't add up to the template's
|
||||
* actual stage count — e.g. the Cancelled mock run stops partway through its stage list.
|
||||
*/
|
||||
export function buildStagePlan(templateName: string, summary: ProductionRun["stageSummary"]): RunStagePlanItem[] {
|
||||
const info = Object.values(MOCK_TEMPLATE_INFO).find((t) => t.name === templateName)
|
||||
const totalCount = Object.values(summary).reduce((sum, n) => sum + n, 0)
|
||||
const stageNames = info?.stages ?? Array.from({ length: Math.max(totalCount, 1) }, (_, i) => `Stage ${i + 1}`)
|
||||
|
||||
const statuses: StageStatus[] = []
|
||||
for (const s of [...STAGE_STATUS_ORDER].reverse()) {
|
||||
const count = summary[SUMMARY_KEY_BY_STATUS[s]]
|
||||
for (let i = 0; i < count; i++) statuses.push(s)
|
||||
}
|
||||
while (statuses.length < stageNames.length) statuses.push("Waiting")
|
||||
statuses.length = stageNames.length
|
||||
|
||||
return stageNames.map((name, i) => ({ name, state: statuses[i] }))
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Frontend-only mock template registry — no Dtos/Production backend exists yet
|
||||
// (docs/21-FRONTEND-PHASE2.md). Shared by the Template list page (production-line preview
|
||||
// per card) and the canvas builder page (initial graph + edit-lock), so the two never drift.
|
||||
export interface MockTemplateInfo {
|
||||
name: string
|
||||
activeRunCount: number
|
||||
stages: string[]
|
||||
}
|
||||
|
||||
export const MOCK_TEMPLATE_INFO: Record<string, MockTemplateInfo> = {
|
||||
"1": { name: "Steel Bracket Assembly", activeRunCount: 2, stages: ["Cutting", "Welding", "QA Inspection"] },
|
||||
"2": { name: "PCB Soldering Line", activeRunCount: 0, stages: ["Component Placement", "Soldering", "Inspection", "Cleaning", "Final Test"] },
|
||||
"3": { name: "Wooden Pallet Build", activeRunCount: 1, stages: ["Assembly", "Quality Check"] },
|
||||
"4": { name: "Plastic Injection Mold", activeRunCount: 0, stages: ["Mold Prep", "Injection", "Cooling", "Trimming"] },
|
||||
"5": { name: "Cable Harness Kit", activeRunCount: 0, stages: ["Wire Cutting", "Crimping", "Bundling"] },
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Single source of truth for stage-status coloring (docs/21-FRONTEND-PHASE2.md §3):
|
||||
// "These colors are the single source for status coloring everywhere (board, run graph,
|
||||
// drawers, legend)." Every screen that renders a stage status imports from here.
|
||||
|
||||
export type StageStatus = "Waiting" | "Ready" | "InProgress" | "Done" | "Approved"
|
||||
|
||||
export const STAGE_STATUS_ORDER: StageStatus[] = ["Waiting", "Ready", "InProgress", "Done", "Approved"]
|
||||
|
||||
export const STAGE_STATUS_COLOR: Record<StageStatus, string> = {
|
||||
Waiting: "#9CA3AF",
|
||||
Ready: "#3B82F6",
|
||||
InProgress: "#F59E0B",
|
||||
Done: "#22C55E",
|
||||
Approved: "#14B8A6",
|
||||
}
|
||||
|
||||
export const STAGE_STATUS_LABEL: Record<StageStatus, string> = {
|
||||
Waiting: "Waiting",
|
||||
Ready: "Ready",
|
||||
InProgress: "In Progress",
|
||||
Done: "Done",
|
||||
Approved: "Approved",
|
||||
}
|
||||
|
||||
/** Run-level (not stage-level) colors, per the same table. */
|
||||
export const RUN_CANCELLED_COLOR = "#EF4444"
|
||||
export const RUN_COMPLETED_COLOR = "#14B8A6"
|
||||
Reference in New Issue
Block a user