fix: [production] 자재투입 모달 — bomGroupKey 그룹핑, 카테고리 순서 정렬, 번호 표시

- bomGroupKey 기반 그룹핑 (같은 item_id라도 category+partType별 분리)
- 카테고리 순서 정렬 (가이드레일→하단마감재→셔터박스→연기차단재)
- 카테고리 내 원형번호(①②③) 표시
- partType 배지 추가
- MaterialForItemInput에 bomGroupKey 필드 추가
This commit is contained in:
2026-03-03 20:58:10 +09:00
parent 5ff5093d7b
commit 8bcabafd08
2 changed files with 30 additions and 4 deletions

View File

@@ -99,16 +99,22 @@ export function MaterialInputModal({
const getLotKey = (material: MaterialForInput) =>
String(material.stockLotId ?? `item-${material.itemId}`);
// 품목별 그룹핑
// 품목별 그룹핑 (BOM 엔트리별 고유키 사용 — 같은 item_id라도 category+partType 다르면 별도 그룹)
const materialGroups: MaterialGroup[] = useMemo(() => {
// dynamic_bom 항목은 (itemId, workOrderItemId) 쌍으로 그룹핑
const groups = new Map<string, MaterialForInput[]>();
for (const m of materials) {
const groupKey = m.workOrderItemId ? `${m.itemId}_${m.workOrderItemId}` : String(m.itemId);
const itemInput = m as unknown as MaterialForItemInput;
const groupKey = itemInput.bomGroupKey
?? (m.workOrderItemId ? `${m.itemId}_${m.workOrderItemId}` : String(m.itemId));
const existing = groups.get(groupKey) || [];
existing.push(m);
groups.set(groupKey, existing);
}
// 작업일지와 동일한 카테고리 순서
const categoryOrder: Record<string, number> = {
guideRail: 0, bottomBar: 1, shutterBox: 2, smokeBarrier: 3,
};
return Array.from(groups.entries()).map(([groupKey, lots]) => {
const first = lots[0];
const itemInput = first as unknown as MaterialForItemInput;
@@ -129,6 +135,10 @@ export function MaterialInputModal({
partType: first.partType,
category: first.category,
};
}).sort((a, b) => {
const catA = categoryOrder[a.category ?? ''] ?? 99;
const catB = categoryOrder[b.category ?? ''] ?? 99;
return catA - catB;
});
}, [materials]);
@@ -344,7 +354,15 @@ export function MaterialInputModal({
</div>
) : (
<div className="space-y-4 flex-1 overflow-y-auto min-h-0">
{materialGroups.map((group) => {
{materialGroups.map((group, groupIdx) => {
// 같은 카테고리 내 순번 계산 (①②③...)
const categoryIndex = group.category
? materialGroups.slice(0, groupIdx).filter(g => g.category === group.category).length
: -1;
const circledNumbers = ['①','②','③','④','⑤','⑥','⑦','⑧','⑨','⑩'];
const circledNum = categoryIndex >= 0 && categoryIndex < circledNumbers.length
? circledNumbers[categoryIndex] : '';
const groupAllocated = group.lots.reduce(
(sum, lot) => sum + (allocations.get(getLotKey(lot)) || 0),
0
@@ -372,6 +390,11 @@ export function MaterialInputModal({
group.category}
</span>
)}
{group.partType && (
<span className="text-[10px] px-1.5 py-0.5 rounded bg-gray-200 text-gray-600 font-medium">
{circledNum}{group.partType}
</span>
)}
<span className="text-sm font-semibold text-gray-900">
{group.materialName}
</span>