feat(proxy-input): 부적합 대분류/소분류 선택 추가

- 부적합 시간 > 0 → 대분류/소분류 드롭다운 표시
- issue_report_categories (nonconformity) + issue_report_items 연동
- 저장 시 work_report_defects에 category_id, item_id 포함

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-03-31 15:16:56 +09:00
parent c71286b52b
commit b855ac973a
3 changed files with 59 additions and 3 deletions

View File

@@ -137,8 +137,8 @@ const ProxyInputController = {
);
if (existingDefects.length === 0) {
await conn.query(
`INSERT INTO work_report_defects (report_id, defect_hours, note) VALUES (?, ?, '대리입력')`,
[reportId, defectHours]
`INSERT INTO work_report_defects (report_id, defect_hours, category_id, item_id, note) VALUES (?, ?, ?, ?, '대리입력')`,
[reportId, defectHours, entry.defect_category_id || null, entry.defect_item_id || null]
);
await conn.query(
'UPDATE daily_work_reports SET error_hours = ?, work_status_id = 2 WHERE id = ?',

View File

@@ -9,6 +9,7 @@ let allWorkers = [];
let selectedIds = new Set();
let projects = [];
let workTypes = [];
let defectCategories = []; // { category_id, category_name, items: [{ item_id, item_name }] }
// ===== Init =====
document.addEventListener('DOMContentLoaded', () => {
@@ -28,6 +29,18 @@ async function loadDropdownData() {
]);
projects = (pRes.data || pRes || []).filter(p => p.is_active !== 0);
workTypes = (wRes.data || wRes || []).map(w => ({ id: w.id || w.work_type_id, name: w.name || w.work_type_name, ...w }));
// 부적합 대분류/소분류 로드
const cRes = await window.apiCall('/work-issues/categories/type/nonconformity');
const cats = cRes.data || cRes || [];
for (const c of cats) {
const iRes = await window.apiCall('/work-issues/items/category/' + c.category_id);
defectCategories.push({
category_id: c.category_id,
category_name: c.category_name,
items: (iRes.data || iRes || [])
});
}
} catch (e) { console.warn('드롭다운 로드 실패:', e); }
}
@@ -174,6 +187,13 @@ async function saveAll() {
return;
}
const defectCategoryId = defect > 0 ? (parseInt(document.getElementById('bulkDefectCategory').value) || null) : null;
const defectItemId = defect > 0 ? (parseInt(document.getElementById('bulkDefectItem').value) || null) : null;
if (defect > 0 && !defectCategoryId) {
showToast('부적합 대분류를 선택하세요', 'error');
return;
}
const btn = document.getElementById('saveBtn');
btn.disabled = true;
document.getElementById('saveBtnText').textContent = '저장 중...';
@@ -184,6 +204,8 @@ async function saveAll() {
work_type_id: parseInt(wtypeId),
work_hours: hours,
defect_hours: defect,
defect_category_id: defectCategoryId,
defect_item_id: defectItemId,
note: note,
start_time: '08:00',
end_time: '17:00',
@@ -213,4 +235,28 @@ async function saveAll() {
document.getElementById('saveBtnText').textContent = '전체 저장';
}
// ===== Defect Category/Item =====
function onDefectChange() {
const val = parseFloat(document.getElementById('bulkDefect').value) || 0;
const row = document.getElementById('defectCategoryRow');
if (val > 0) {
row.classList.remove('hidden');
const catSel = document.getElementById('bulkDefectCategory');
if (catSel.options.length <= 1) {
catSel.innerHTML = '<option value="">부적합 대분류 *</option>' +
defectCategories.map(c => `<option value="${c.category_id}">${esc(c.category_name)}</option>`).join('');
}
} else {
row.classList.add('hidden');
}
}
function onDefectCategoryChange() {
const catId = parseInt(document.getElementById('bulkDefectCategory').value);
const itemSel = document.getElementById('bulkDefectItem');
const cat = defectCategories.find(c => c.category_id === catId);
itemSel.innerHTML = '<option value="">소분류 *</option>' +
(cat ? cat.items.map(i => `<option value="${i.item_id}">${esc(i.item_name)}</option>`).join('') : '');
}
function esc(s) { return (s || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }

View File

@@ -80,7 +80,17 @@
</div>
<div class="pi-edit-row">
<label class="pi-field"><span>시간</span><input type="number" id="bulkHours" value="8" step="0.5" min="0" max="24" class="pi-input"></label>
<label class="pi-field"><span>부적합</span><input type="number" id="bulkDefect" value="0" step="0.5" min="0" max="24" class="pi-input"></label>
<label class="pi-field"><span>부적합 시간</span><input type="number" id="bulkDefect" value="0" step="0.5" min="0" max="24" class="pi-input" onchange="onDefectChange()"></label>
</div>
<div id="defectCategoryRow" class="hidden">
<div class="pi-edit-row">
<select id="bulkDefectCategory" class="pi-select" onchange="onDefectCategoryChange()">
<option value="">부적합 대분류 *</option>
</select>
<select id="bulkDefectItem" class="pi-select">
<option value="">소분류 *</option>
</select>
</div>
</div>
<input type="text" id="bulkNote" placeholder="비고 (선택)" class="pi-note-input">
</div>