Files
MIS-Contro-Tower/lib/recap/types.ts
2026-05-02 01:35:27 +00:00

242 lines
5.2 KiB
TypeScript

export type RecapSkuRow = {
machineName: string;
sku: string;
good: number;
scrap: number;
target: number | null;
progressPct: number | null;
};
export type RecapMachine = {
machineId: string;
machineName: string;
location: string | null;
production: {
goodParts: number;
scrapParts: number;
totalCycles: number;
bySku: RecapSkuRow[];
};
oee: {
avg: number | null;
availability: number | null;
performance: number | null;
quality: number | null;
};
downtime: {
totalMin: number;
stopsCount: number;
topReasons: Array<{
reasonLabel: string;
minutes: number;
count: number;
}>;
ongoingStopMin: number | null;
};
workOrders: {
completed: Array<{
id: string;
sku: string | null;
goodParts: number;
durationHrs: number;
}>;
active: {
id: string;
sku: string | null;
progressPct: number | null;
startedAt: string | null;
} | null;
moldChangeInProgress: boolean;
moldChangeStartMs: number | null;
};
heartbeat: {
lastSeenAt: string | null;
uptimePct: number | null;
};
};
export type RecapTimelineSegment =
| {
type: "production";
startMs: number;
endMs: number;
durationSec: number;
workOrderId: string | null;
sku: string | null;
label: string;
}
| {
type: "mold-change";
startMs: number;
endMs: number;
fromMoldId: string | null;
toMoldId: string | null;
durationSec: number;
label: string;
}
| {
type: "macrostop" | "microstop" | "slow-cycle";
startMs: number;
endMs: number;
reason: string | null;
reasonLabel?: string | null;
durationSec: number;
label: string;
}
| {
type: "idle";
startMs: number;
endMs: number;
durationSec: number;
label: string;
};
export type RecapTimelineResponse = {
range: {
start: string;
end: string;
};
segments: RecapTimelineSegment[];
hasData: boolean;
generatedAt: string;
};
export type RecapResponse = {
range: {
start: string;
end: string;
};
availableShifts: Array<{
id: string;
name: string;
}>;
machines: RecapMachine[];
};
export type RecapQuery = {
orgId: string;
machineId?: string;
start?: Date;
end?: Date;
shift?: string;
};
export type RecapMachineStatus = "running" | "mold-change" | "stopped" | "data-loss" | "offline" | "idle";
export type RecapStoppedReason = "machine_fault" | "not_started";
export type RecapDataLossReason = "untracked";
/**
* Reason context for STOPPED and DATA_LOSS states.
* - When status is "stopped": stoppedReason is set, dataLossReason is null.
* - When status is "data-loss": dataLossReason is set, stoppedReason is null.
* - All other states: both are null.
*/
export type RecapStateContext = {
stoppedReason: RecapStoppedReason | null;
dataLossReason: RecapDataLossReason | null;
/** For data-loss: how many untracked cycles have been detected so far. */
untrackedCycleCount: number | null;
};
export type RecapSummaryMachine = {
machineId: string;
name: string;
location: string | null;
status: RecapMachineStatus;
oee: number | null;
goodParts: number;
scrap: number;
stopsCount: number;
lastSeenMs: number | null;
lastActivityMin: number | null;
offlineForMin: number | null;
ongoingStopMin: number | null;
stateContext: RecapStateContext;
activeWorkOrderId: string | null;
moldChange: {
active: boolean;
startMs: number | null;
elapsedMin: number | null;
} | null;
miniTimeline: RecapTimelineSegment[];
};
export type RecapSummaryResponse = {
generatedAt: string;
range: {
start: string;
end: string;
hours: number;
};
machines: RecapSummaryMachine[];
};
export type RecapRangeMode = "24h" | "shift" | "yesterday" | "custom";
export type RecapDowntimeTopRow = {
reasonLabel: string;
minutes: number;
count: number;
percent: number;
};
export type RecapWorkOrders = {
completed: Array<{
id: string;
sku: string | null;
goodParts: number;
durationHrs: number;
}>;
active: {
id: string;
sku: string | null;
progressPct: number | null;
startedAt: string | null;
} | null;
};
export type RecapMachineDetail = {
machineId: string;
name: string;
location: string | null;
status: RecapMachineStatus;
oee: number | null;
goodParts: number;
scrap: number;
stopsCount: number;
stopMinutes: number;
activeWorkOrderId: string | null;
lastSeenMs: number | null;
offlineForMin: number | null;
ongoingStopMin: number | null;
stateContext: RecapStateContext;
moldChange: {
active: boolean;
startMs: number | null;
} | null;
timeline: RecapTimelineSegment[];
productionBySku: RecapSkuRow[];
downtimeTop: RecapDowntimeTopRow[];
workOrders: RecapWorkOrders;
heartbeat: {
lastSeenAt: string | null;
uptimePct: number | null;
connectionStatus: "online" | "offline";
};
};
export type RecapDetailResponse = {
generatedAt: string;
range: {
requestedMode?: RecapRangeMode;
mode: RecapRangeMode;
start: string;
end: string;
shiftAvailable?: boolean;
fallbackReason?: "shift-unavailable" | "shift-inactive";
};
machine: RecapMachineDetail;
};