feat: 배치(로트) 추적 — batch_id 컬럼 + 카드 진행률 표시
- work_order_process에 batch_id 컬럼 자동 추가 (ALTER TABLE IF NOT EXISTS) - 접수 시 batch_id 자동 생성 (BATCH-timestamp-random) - 다음 공정 접수 시 batch_id 전달 가능 (이어받기) - 완료 카드: 같은 batch_id의 SPLIT 추적으로 정확한 진행률 표시 - 예: seq1만 완료 → ✓○○ (1/3), 전체 완료 → ✓✓✓ (전체 완료)
This commit is contained in:
@@ -292,11 +292,15 @@ function CompressedProcessSteps({
|
||||
currentSeqNo,
|
||||
status,
|
||||
onClick,
|
||||
batchId,
|
||||
allProcesses,
|
||||
}: {
|
||||
processes: WorkOrderProcess[];
|
||||
currentSeqNo: string;
|
||||
status: string;
|
||||
onClick?: () => void;
|
||||
batchId?: string;
|
||||
allProcesses?: WorkOrderProcess[];
|
||||
}) {
|
||||
const sorted = [...processes]
|
||||
.filter((p) => !p.parent_process_id)
|
||||
@@ -307,10 +311,24 @@ function CompressedProcessSteps({
|
||||
const currentIdx = sorted.findIndex((p) => p.seq_no === currentSeqNo);
|
||||
if (currentIdx < 0) return null;
|
||||
|
||||
// For completed status: show progress up to current card's seq position
|
||||
// For completed status: batch_id 기반 진행률 표시
|
||||
if (status === "completed") {
|
||||
const currentSeqNum = parseInt(currentSeqNo, 10);
|
||||
const allDone = currentIdx === sorted.length - 1; // 마지막 공정이면 전체 완료
|
||||
// 같은 batch_id를 가진 SPLIT들이 어느 seq까지 완료했는지 추적
|
||||
let maxCompletedSeq = parseInt(currentSeqNo, 10); // 최소한 현재 seq까지는 완료
|
||||
|
||||
if (batchId && allProcesses) {
|
||||
const batchSplits = allProcesses.filter(
|
||||
(p) => (p as Record<string, unknown>).batch_id === batchId && p.parent_process_id && p.status === "completed"
|
||||
);
|
||||
for (const s of batchSplits) {
|
||||
const sSeq = parseInt(s.seq_no, 10);
|
||||
if (sSeq > maxCompletedSeq) maxCompletedSeq = sSeq;
|
||||
}
|
||||
}
|
||||
|
||||
const completedCount = sorted.filter((p) => parseInt(p.seq_no, 10) <= maxCompletedSeq).length;
|
||||
const allDone = completedCount === sorted.length;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-center justify-center gap-0.5 mb-3 py-2 px-3 bg-green-50 rounded-xl cursor-pointer hover:bg-green-100 transition"
|
||||
@@ -318,7 +336,7 @@ function CompressedProcessSteps({
|
||||
>
|
||||
{sorted.map((proc, idx) => {
|
||||
const seqNum = parseInt(proc.seq_no, 10);
|
||||
const isDone = seqNum <= currentSeqNum; // 현재 카드 seq 이하만 완료
|
||||
const isDone = seqNum <= maxCompletedSeq;
|
||||
return (
|
||||
<React.Fragment key={proc.id}>
|
||||
{idx > 0 && <span className={`w-3 h-0.5 ${isDone ? "bg-green-400" : "bg-gray-300"} shrink-0`} />}
|
||||
@@ -336,7 +354,7 @@ function CompressedProcessSteps({
|
||||
);
|
||||
})}
|
||||
<span className="text-[10px] text-green-600 font-bold ml-2">
|
||||
{allDone ? "전체 완료" : `${currentIdx + 1}/${sorted.length} 완료`}
|
||||
{allDone ? "전체 완료" : `${completedCount}/${sorted.length} 완료`}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
@@ -1305,6 +1323,8 @@ export function WorkOrderList() {
|
||||
currentSeqNo={proc.seq_no}
|
||||
status={proc.status}
|
||||
onClick={() => openDetailModal(proc)}
|
||||
batchId={(proc as Record<string, unknown>).batch_id as string | undefined}
|
||||
allProcesses={allProcesses}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user