fix(WEB):수입검사 입력 모달 개선
- ImportInspectionInputModal: UI/로직 개선 - actions: API 호출 수정
This commit is contained in:
@@ -278,6 +278,28 @@ export function ImportInspectionInputModal({
|
||||
return map;
|
||||
}, [resolveData, template]);
|
||||
|
||||
// ===== Item → section/row mapping for normalized records =====
|
||||
const itemSectionMap = useMemo(() => {
|
||||
if (!resolveData) return new Map<string, { sectionId: number; rowIndex: number }>();
|
||||
const map = new Map<string, { sectionId: number; rowIndex: number }>();
|
||||
for (const section of resolveData.template.sections) {
|
||||
section.items.forEach((item, idx) => {
|
||||
map.set(String(item.id), { sectionId: section.id, rowIndex: idx });
|
||||
});
|
||||
}
|
||||
return map;
|
||||
}, [resolveData]);
|
||||
|
||||
// ===== Complex column ID (measurements) and result column ID (judgment) =====
|
||||
const { complexColumnId, resultColumnId } = useMemo(() => {
|
||||
if (!resolveData) return { complexColumnId: null as number | null, resultColumnId: null as number | null };
|
||||
const cols = resolveData.template.columns;
|
||||
const complex = cols.find(c => c.input_type === 'complex') ?? null;
|
||||
const result = cols.find(c => c.input_type === 'select' || c.input_type === 'check') ??
|
||||
cols.find(c => c.label.includes('판정')) ?? null;
|
||||
return { complexColumnId: complex?.id ?? null, resultColumnId: result?.id ?? null };
|
||||
}, [resolveData]);
|
||||
|
||||
// ===== Load template on modal open =====
|
||||
useEffect(() => {
|
||||
if (!open || !itemId) return;
|
||||
@@ -317,6 +339,14 @@ export function ImportInspectionInputModal({
|
||||
return;
|
||||
}
|
||||
|
||||
// Reverse map: (sectionId, rowIndex) → inspectionItem.id
|
||||
const reverseMap = new Map<string, string>();
|
||||
for (const section of resolve.template.sections) {
|
||||
section.items.forEach((item, idx) => {
|
||||
reverseMap.set(`${section.id}_${idx}`, String(item.id));
|
||||
});
|
||||
}
|
||||
|
||||
const meas: Record<string, Record<number, string>> = {};
|
||||
const okng: Record<string, Record<number, 'ok' | 'ng' | null>> = {};
|
||||
let savedRemark = '';
|
||||
@@ -326,28 +356,61 @@ export function ImportInspectionInputModal({
|
||||
const key = d.field_key;
|
||||
const val = d.field_value || '';
|
||||
|
||||
// {itemId}_n{index} - 숫자 측정값
|
||||
const nMatch = key.match(/^(\d+)_n(\d+)$/);
|
||||
if (nMatch) {
|
||||
const id = nMatch[1];
|
||||
const idx = parseInt(nMatch[2]) - 1;
|
||||
// Footer fields
|
||||
if (key === 'remark' || key === 'footer_remark') { savedRemark = val; continue; }
|
||||
if (key === 'overall_result' || key === 'footer_judgement') {
|
||||
savedOverall = (val === 'pass' || val === '적합') ? 'pass'
|
||||
: (val === 'fail' || val === '부적합') ? 'fail' : null;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 정규화 형식: section_id가 있으면 reverse map으로 item 찾기
|
||||
if (d.section_id != null) {
|
||||
const itemId = reverseMap.get(`${d.section_id}_${d.row_index}`);
|
||||
if (!itemId) continue;
|
||||
|
||||
const nMatch = key.match(/^n(\d+)$/);
|
||||
if (nMatch) {
|
||||
const idx = parseInt(nMatch[1]) - 1;
|
||||
if (!meas[itemId]) meas[itemId] = {};
|
||||
meas[itemId][idx] = val;
|
||||
continue;
|
||||
}
|
||||
const okMatch = key.match(/^n(\d+)_ok$/);
|
||||
if (okMatch && val === 'OK') {
|
||||
const idx = parseInt(okMatch[1]) - 1;
|
||||
if (!okng[itemId]) okng[itemId] = {};
|
||||
okng[itemId][idx] = 'ok';
|
||||
continue;
|
||||
}
|
||||
const ngMatch = key.match(/^n(\d+)_ng$/);
|
||||
if (ngMatch && val === 'NG') {
|
||||
const idx = parseInt(ngMatch[1]) - 1;
|
||||
if (!okng[itemId]) okng[itemId] = {};
|
||||
okng[itemId][idx] = 'ng';
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 레거시 형식 fallback: {itemId}_n{N}
|
||||
const nLegacy = key.match(/^(\d+)_n(\d+)$/);
|
||||
if (nLegacy) {
|
||||
const id = nLegacy[1];
|
||||
const idx = parseInt(nLegacy[2]) - 1;
|
||||
if (!meas[id]) meas[id] = {};
|
||||
meas[id][idx] = val;
|
||||
continue;
|
||||
}
|
||||
|
||||
// {itemId}_okng_n{index} - OK/NG 값
|
||||
const okngMatch = key.match(/^(\d+)_okng_n(\d+)$/);
|
||||
if (okngMatch) {
|
||||
const id = okngMatch[1];
|
||||
const idx = parseInt(okngMatch[2]) - 1;
|
||||
// 레거시: {itemId}_okng_n{N}
|
||||
const okngLegacy = key.match(/^(\d+)_okng_n(\d+)$/);
|
||||
if (okngLegacy) {
|
||||
const id = okngLegacy[1];
|
||||
const idx = parseInt(okngLegacy[2]) - 1;
|
||||
if (!okng[id]) okng[id] = {};
|
||||
okng[id][idx] = val === 'ok' ? 'ok' : val === 'ng' ? 'ng' : null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key === 'remark') savedRemark = val;
|
||||
if (key === 'overall_result') savedOverall = val === 'pass' ? 'pass' : val === 'fail' ? 'fail' : null;
|
||||
}
|
||||
|
||||
setMeasurements(meas);
|
||||
@@ -505,44 +568,61 @@ export function ImportInspectionInputModal({
|
||||
uploadedFileIds = (uploadResult.data || []).map((f) => f.id);
|
||||
}
|
||||
|
||||
// 2. field_key 기반 데이터 배열 생성
|
||||
// 2. 정규화 형식 데이터 배열 생성
|
||||
const data: Array<{
|
||||
section_id?: number | null;
|
||||
section_id: number | null;
|
||||
column_id: number | null;
|
||||
row_index: number;
|
||||
field_key: string;
|
||||
field_value: string | null;
|
||||
}> = [];
|
||||
|
||||
for (const item of template.inspectionItems) {
|
||||
const mapping = itemSectionMap.get(item.id);
|
||||
const sectionId = mapping?.sectionId ?? null;
|
||||
const rowIndex = mapping?.rowIndex ?? 0;
|
||||
const isOkng = item.measurementType === 'okng';
|
||||
|
||||
for (let n = 0; n < item.measurementCount; n++) {
|
||||
if (isOkng) {
|
||||
const val = okngValues[item.id]?.[n];
|
||||
data.push({
|
||||
row_index: 0,
|
||||
field_key: `${item.id}_okng_n${n + 1}`,
|
||||
field_value: okngValues[item.id]?.[n] || null,
|
||||
section_id: sectionId, column_id: complexColumnId, row_index: rowIndex,
|
||||
field_key: `n${n + 1}_ok`, field_value: val === 'ok' ? 'OK' : '',
|
||||
});
|
||||
data.push({
|
||||
section_id: sectionId, column_id: complexColumnId, row_index: rowIndex,
|
||||
field_key: `n${n + 1}_ng`, field_value: val === 'ng' ? 'NG' : '',
|
||||
});
|
||||
} else {
|
||||
data.push({
|
||||
row_index: 0,
|
||||
field_key: `${item.id}_n${n + 1}`,
|
||||
field_value: measurements[item.id]?.[n] || null,
|
||||
section_id: sectionId, column_id: complexColumnId, row_index: rowIndex,
|
||||
field_key: `n${n + 1}`, field_value: measurements[item.id]?.[n] || null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 항목별 판정
|
||||
data.push({
|
||||
row_index: 0,
|
||||
field_key: `${item.id}_result`,
|
||||
field_value: getItemResult(item),
|
||||
});
|
||||
// 항목별 판정 (판정 컬럼이 있을 때만)
|
||||
if (resultColumnId) {
|
||||
const itemResult = getItemResult(item);
|
||||
data.push({
|
||||
section_id: sectionId, column_id: resultColumnId, row_index: rowIndex,
|
||||
field_key: 'value',
|
||||
field_value: itemResult === 'ok' ? '적합' : itemResult === 'ng' ? '부적합' : null,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 종합판정 + 비고
|
||||
data.push({ row_index: 0, field_key: 'overall_result', field_value: overallResult });
|
||||
data.push({ row_index: 0, field_key: 'remark', field_value: remark || null });
|
||||
data.push({
|
||||
section_id: null, column_id: null, row_index: 0,
|
||||
field_key: 'overall_result',
|
||||
field_value: overallResult === 'pass' ? '적합' : overallResult === 'fail' ? '부적합' : null,
|
||||
});
|
||||
data.push({
|
||||
section_id: null, column_id: null, row_index: 0,
|
||||
field_key: 'remark', field_value: remark || null,
|
||||
});
|
||||
|
||||
// 3. 첨부파일 (기존 + 신규)
|
||||
const attachments = [
|
||||
|
||||
@@ -1900,7 +1900,7 @@ export async function saveInspectionData(params: {
|
||||
templateId: number;
|
||||
itemId: number;
|
||||
title?: string;
|
||||
data: Array<{ section_id?: number | null; row_index: number; field_key: string; field_value: string | null }>;
|
||||
data: Array<{ section_id?: number | null; column_id?: number | null; row_index: number; field_key: string; field_value: string | null }>;
|
||||
attachments?: Array<{ file_id: number; attachment_type: string; description?: string }>;
|
||||
receivingId: string;
|
||||
inspectionResult?: 'pass' | 'fail' | null;
|
||||
|
||||
Reference in New Issue
Block a user