fix: 부적합 제출 버그 수정 및 UI 개선

- 부적합 API 호출 형식 수정 (카테고리/아이템 추가 시)
- 부적합 저장 시 내부 플래그 제거 후 백엔드 전송
- 기본 부적합 객체 구조 수정 (category_id, item_id 추가)
- 날씨 API 시간대 수정 (UTC → KST 변환)
- 신고 카테고리 관리 페이지 추가 (/pages/admin/issue-categories.html)
- 부적합 입력 UI 개선 (대분류→소분류 캐스케이딩 선택)
- 저장된 부적합 분리 표시 및 수정/삭제 기능
- 디버깅 로그 추가

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-02-03 09:31:26 +09:00
parent 4b158de1eb
commit c42c9f4fa3
29 changed files with 7042 additions and 809 deletions

View File

@@ -274,6 +274,7 @@ const getSummaryService = async (year, month) => {
/**
* 작업 보고서의 부적합 원인 목록 조회
* - error_type_id 또는 issue_report_id 중 하나로 연결
*/
const getReportDefectsService = async (reportId) => {
const db = await getDb();
@@ -283,13 +284,22 @@ const getReportDefectsService = async (reportId) => {
d.defect_id,
d.report_id,
d.error_type_id,
d.issue_report_id,
d.defect_hours,
d.note,
d.created_at,
et.name as error_type_name,
et.severity
et.severity as error_severity,
ir.content as issue_content,
ir.status as issue_status,
irc.category_name as issue_category_name,
irc.severity as issue_severity,
iri.item_name as issue_item_name
FROM work_report_defects d
JOIN error_types et ON d.error_type_id = et.id
LEFT JOIN error_types et ON d.error_type_id = et.id
LEFT JOIN work_issue_reports ir ON d.issue_report_id = ir.report_id
LEFT JOIN issue_report_categories irc ON ir.category_id = irc.category_id
LEFT JOIN issue_report_items iri ON ir.item_id = iri.item_id
WHERE d.report_id = ?
ORDER BY d.created_at
`, [reportId]);
@@ -303,6 +313,9 @@ const getReportDefectsService = async (reportId) => {
/**
* 부적합 원인 저장 (전체 교체)
* - error_type_id 또는 issue_report_id 중 하나 사용 가능
* - issue_report_id: 신고된 이슈와 연결
* - error_type_id: 기존 오류 유형 (레거시)
*/
const saveReportDefectsService = async (reportId, defects) => {
const db = await getDb();
@@ -315,10 +328,19 @@ const saveReportDefectsService = async (reportId, defects) => {
// 새 부적합 원인 추가
if (defects && defects.length > 0) {
for (const defect of defects) {
// issue_report_id > category_id/item_id > error_type_id 순으로 우선
await db.execute(`
INSERT INTO work_report_defects (report_id, error_type_id, defect_hours, note)
VALUES (?, ?, ?, ?)
`, [reportId, defect.error_type_id, defect.defect_hours || 0, defect.note || null]);
INSERT INTO work_report_defects (report_id, error_type_id, issue_report_id, category_id, item_id, defect_hours, note)
VALUES (?, ?, ?, ?, ?, ?, ?)
`, [
reportId,
(defect.issue_report_id || defect.category_id) ? null : (defect.error_type_id || null),
defect.issue_report_id || null,
defect.category_id || null,
defect.item_id || null,
defect.defect_hours || 0,
defect.note || null
]);
}
}
@@ -327,6 +349,11 @@ const saveReportDefectsService = async (reportId, defects) => {
? defects.reduce((sum, d) => sum + (parseFloat(d.defect_hours) || 0), 0)
: 0;
// 첫 번째 defect의 error_type_id를 대표값으로 (레거시 호환)
const firstErrorTypeId = defects && defects.length > 0
? (defects.find(d => d.error_type_id)?.error_type_id || null)
: null;
await db.execute(`
UPDATE daily_work_reports
SET error_hours = ?,
@@ -335,7 +362,7 @@ const saveReportDefectsService = async (reportId, defects) => {
WHERE id = ?
`, [
totalErrorHours,
defects && defects.length > 0 ? defects[0].error_type_id : null,
firstErrorTypeId,
totalErrorHours > 0 ? 2 : 1,
reportId
]);
@@ -353,14 +380,21 @@ const saveReportDefectsService = async (reportId, defects) => {
/**
* 부적합 원인 추가 (단일)
* - issue_report_id 또는 error_type_id 중 하나 사용
*/
const addReportDefectService = async (reportId, defectData) => {
const db = await getDb();
try {
const [result] = await db.execute(`
INSERT INTO work_report_defects (report_id, error_type_id, defect_hours, note)
VALUES (?, ?, ?, ?)
`, [reportId, defectData.error_type_id, defectData.defect_hours || 0, defectData.note || null]);
INSERT INTO work_report_defects (report_id, error_type_id, issue_report_id, defect_hours, note)
VALUES (?, ?, ?, ?, ?)
`, [
reportId,
defectData.issue_report_id ? null : (defectData.error_type_id || null),
defectData.issue_report_id || null,
defectData.defect_hours || 0,
defectData.note || null
]);
// 총 부적합 시간 업데이트
await updateTotalErrorHours(reportId);
@@ -404,6 +438,7 @@ const removeReportDefectService = async (defectId) => {
/**
* 총 부적합 시간 업데이트 헬퍼
* - issue_report_id가 있는 경우도 고려
*/
const updateTotalErrorHours = async (reportId) => {
const db = await getDb();
@@ -415,9 +450,12 @@ const updateTotalErrorHours = async (reportId) => {
const totalErrorHours = result[0].total || 0;
// 첫 번째 부적합 원인의 error_type_id를 대표값으로 사용
// 첫 번째 부적합 원인의 error_type_id를 대표값으로 사용 (레거시 호환)
// issue_report_id만 있는 경우 error_type_id는 null
const [firstDefect] = await db.execute(`
SELECT error_type_id FROM work_report_defects WHERE report_id = ? ORDER BY created_at LIMIT 1
SELECT error_type_id FROM work_report_defects
WHERE report_id = ? AND error_type_id IS NOT NULL
ORDER BY created_at LIMIT 1
`, [reportId]);
await db.execute(`