feat: field-only INSERT + pop-field key 수정 + 모달 접근성 개선
- popActionRoutes.ts: 카드리스트 없이 필드만으로 INSERT 가능 (field-only 분기) - PopFieldComponent.tsx: React duplicate key 에러 수정 (staticOptions 문자열 변환 + key fallback) - pop-field/index.tsx: preview nested map key fallback - PopViewerWithModals.tsx: 모달 제목 없을 때 sr-only 접근성 처리 - PopWorkDetailComponent.tsx: 모달 내부 헤더 중복 제거 + isInModal 자동 감지
This commit is contained in:
@@ -183,7 +183,8 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
||||
const cardMapping = mappings?.cardList;
|
||||
const fieldMapping = mappings?.field;
|
||||
|
||||
if (cardMapping?.targetTable && Object.keys(cardMapping.columnMapping).length > 0) {
|
||||
if (cardMapping?.targetTable && Object.keys(cardMapping.columnMapping).length > 0 && items.length > 0) {
|
||||
// ── 카드리스트 기반 INSERT (기존: items 반복) ──
|
||||
if (!isSafeIdentifier(cardMapping.targetTable)) {
|
||||
throw new Error(`유효하지 않은 테이블명: ${cardMapping.targetTable}`);
|
||||
}
|
||||
@@ -300,6 +301,84 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
||||
insertedCount++;
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
// ── 필드 단독 INSERT (카드리스트 없이 pop-field만으로 저장) ──
|
||||
items.length === 0 &&
|
||||
fieldMapping?.targetTable &&
|
||||
Object.keys(fieldMapping.columnMapping).length > 0 &&
|
||||
Object.keys(fieldValues).length > 0
|
||||
) {
|
||||
if (!isSafeIdentifier(fieldMapping.targetTable)) {
|
||||
throw new Error(`유효하지 않은 테이블명: ${fieldMapping.targetTable}`);
|
||||
}
|
||||
|
||||
const columns: string[] = ["company_code"];
|
||||
const values: unknown[] = [companyCode];
|
||||
|
||||
// 필드 매핑 값 추가
|
||||
for (const [sourceField, targetColumn] of Object.entries(fieldMapping.columnMapping)) {
|
||||
if (!isSafeIdentifier(targetColumn)) continue;
|
||||
columns.push(`"${targetColumn}"`);
|
||||
values.push(fieldValues[sourceField] ?? null);
|
||||
}
|
||||
|
||||
// hiddenMappings 처리
|
||||
for (const hm of (fieldMapping.hiddenMappings ?? [])) {
|
||||
if (!hm.targetColumn || !isSafeIdentifier(hm.targetColumn)) continue;
|
||||
if (columns.includes(`"${hm.targetColumn}"`)) continue;
|
||||
let value: unknown = null;
|
||||
if (hm.valueSource === "static") {
|
||||
value = hm.staticValue ?? null;
|
||||
} else if (hm.valueSource === "db_column" && hm.sourceDbColumn) {
|
||||
value = fieldValues[hm.sourceDbColumn] ?? null;
|
||||
}
|
||||
columns.push(`"${hm.targetColumn}"`);
|
||||
values.push(value);
|
||||
}
|
||||
|
||||
// autoGenMappings 채번 처리
|
||||
for (const ag of (fieldMapping.autoGenMappings ?? [])) {
|
||||
if (!ag.numberingRuleId || !ag.targetColumn) continue;
|
||||
if (!isSafeIdentifier(ag.targetColumn)) continue;
|
||||
if (columns.includes(`"${ag.targetColumn}"`)) continue;
|
||||
try {
|
||||
const generatedCode = await numberingRuleService.allocateCode(
|
||||
ag.numberingRuleId, companyCode, fieldValues,
|
||||
);
|
||||
columns.push(`"${ag.targetColumn}"`);
|
||||
values.push(generatedCode);
|
||||
generatedCodes.push({ targetColumn: ag.targetColumn, code: generatedCode, showResultModal: ag.showResultModal ?? false });
|
||||
} catch (err: any) {
|
||||
logger.error("[pop/execute-action] 필드 단독 채번 실패", { ruleId: ag.numberingRuleId, error: err.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 자동 필드 추가 (created_date, updated_date, writer)
|
||||
if (!columns.includes('"created_date"')) {
|
||||
columns.push('"created_date"');
|
||||
values.push(new Date().toISOString());
|
||||
}
|
||||
if (!columns.includes('"updated_date"')) {
|
||||
columns.push('"updated_date"');
|
||||
values.push(new Date().toISOString());
|
||||
}
|
||||
if (!columns.includes('"writer"') && userId) {
|
||||
columns.push('"writer"');
|
||||
values.push(userId);
|
||||
}
|
||||
|
||||
if (columns.length > 1) {
|
||||
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
||||
await client.query(
|
||||
`INSERT INTO "${fieldMapping.targetTable}" (${columns.join(", ")}) VALUES (${placeholders})`,
|
||||
values,
|
||||
);
|
||||
insertedCount++;
|
||||
logger.info("[pop/execute-action] 필드 단독 INSERT 실행", {
|
||||
table: fieldMapping.targetTable,
|
||||
columnCount: columns.length,
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user