fix(tkfb): project_code → job_no 컬럼명 수정 (500 에러 해결)
projects 테이블에 project_code 컬럼이 없고 job_no가 올바른 컬럼명. 백엔드 SQL에서는 pr.job_no AS project_code alias 사용, 프론트 드롭다운에서는 p.job_no로 직접 참조. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -57,7 +57,7 @@ const MeetingModel = {
|
|||||||
|
|
||||||
// 안건
|
// 안건
|
||||||
const [items] = await db.query(`
|
const [items] = await db.query(`
|
||||||
SELECT ai.*, pr.project_name, pr.project_code,
|
SELECT ai.*, pr.project_name, pr.job_no AS project_code,
|
||||||
ms.milestone_name, ms.milestone_date,
|
ms.milestone_name, ms.milestone_date,
|
||||||
su.name AS responsible_name
|
su.name AS responsible_name
|
||||||
FROM meeting_agenda_items ai
|
FROM meeting_agenda_items ai
|
||||||
@@ -185,7 +185,7 @@ const MeetingModel = {
|
|||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
let sql = `
|
let sql = `
|
||||||
SELECT ai.*, m.title AS meeting_title, m.meeting_date,
|
SELECT ai.*, m.title AS meeting_title, m.meeting_date,
|
||||||
pr.project_name, pr.project_code,
|
pr.project_name, pr.job_no AS project_code,
|
||||||
su.name AS responsible_name
|
su.name AS responsible_name
|
||||||
FROM meeting_agenda_items ai
|
FROM meeting_agenda_items ai
|
||||||
JOIN meeting_minutes m ON ai.meeting_id = m.meeting_id
|
JOIN meeting_minutes m ON ai.meeting_id = m.meeting_id
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const ScheduleModel = {
|
|||||||
async getEntries(filters = {}) {
|
async getEntries(filters = {}) {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
let sql = `
|
let sql = `
|
||||||
SELECT e.*, p.phase_name, p.color AS phase_color, pr.project_name, pr.project_code,
|
SELECT e.*, p.phase_name, p.color AS phase_color, pr.project_name, pr.job_no AS project_code,
|
||||||
su.name AS created_by_name
|
su.name AS created_by_name
|
||||||
FROM schedule_entries e
|
FROM schedule_entries e
|
||||||
JOIN schedule_phases p ON e.phase_id = p.phase_id
|
JOIN schedule_phases p ON e.phase_id = p.phase_id
|
||||||
@@ -66,7 +66,7 @@ const ScheduleModel = {
|
|||||||
sql += ' AND ((YEAR(e.start_date) = ? AND MONTH(e.start_date) = ?) OR (YEAR(e.end_date) = ? AND MONTH(e.end_date) = ?))';
|
sql += ' AND ((YEAR(e.start_date) = ? AND MONTH(e.start_date) = ?) OR (YEAR(e.end_date) = ? AND MONTH(e.end_date) = ?))';
|
||||||
params.push(filters.year, filters.month, filters.year, filters.month);
|
params.push(filters.year, filters.month, filters.year, filters.month);
|
||||||
}
|
}
|
||||||
sql += ' ORDER BY pr.project_code, p.display_order, e.display_order';
|
sql += ' ORDER BY pr.job_no, p.display_order, e.display_order';
|
||||||
const [rows] = await db.query(sql, params);
|
const [rows] = await db.query(sql, params);
|
||||||
return rows;
|
return rows;
|
||||||
},
|
},
|
||||||
@@ -76,13 +76,13 @@ const ScheduleModel = {
|
|||||||
// 해당 연도에 걸치는 모든 항목
|
// 해당 연도에 걸치는 모든 항목
|
||||||
const [entries] = await db.query(`
|
const [entries] = await db.query(`
|
||||||
SELECT e.*, p.phase_name, p.color AS phase_color, p.display_order AS phase_order,
|
SELECT e.*, p.phase_name, p.color AS phase_color, p.display_order AS phase_order,
|
||||||
pr.project_name, pr.project_code
|
pr.project_name, pr.job_no AS project_code
|
||||||
FROM schedule_entries e
|
FROM schedule_entries e
|
||||||
JOIN schedule_phases p ON e.phase_id = p.phase_id
|
JOIN schedule_phases p ON e.phase_id = p.phase_id
|
||||||
JOIN projects pr ON e.project_id = pr.project_id
|
JOIN projects pr ON e.project_id = pr.project_id
|
||||||
WHERE (YEAR(e.start_date) <= ? AND YEAR(e.end_date) >= ?)
|
WHERE (YEAR(e.start_date) <= ? AND YEAR(e.end_date) >= ?)
|
||||||
AND e.status != 'cancelled'
|
AND e.status != 'cancelled'
|
||||||
ORDER BY pr.project_code, p.display_order, e.display_order
|
ORDER BY pr.job_no, p.display_order, e.display_order
|
||||||
`, [year, year]);
|
`, [year, year]);
|
||||||
|
|
||||||
// 의존관계
|
// 의존관계
|
||||||
@@ -98,7 +98,7 @@ const ScheduleModel = {
|
|||||||
|
|
||||||
// 마일스톤
|
// 마일스톤
|
||||||
const [milestones] = await db.query(`
|
const [milestones] = await db.query(`
|
||||||
SELECT m.*, pr.project_name, pr.project_code
|
SELECT m.*, pr.project_name, pr.job_no AS project_code
|
||||||
FROM schedule_milestones m
|
FROM schedule_milestones m
|
||||||
JOIN projects pr ON m.project_id = pr.project_id
|
JOIN projects pr ON m.project_id = pr.project_id
|
||||||
WHERE YEAR(m.milestone_date) = ?
|
WHERE YEAR(m.milestone_date) = ?
|
||||||
@@ -200,7 +200,7 @@ const ScheduleModel = {
|
|||||||
async getMilestones(filters = {}) {
|
async getMilestones(filters = {}) {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
let sql = `
|
let sql = `
|
||||||
SELECT m.*, pr.project_name, pr.project_code, e.task_name AS entry_task_name,
|
SELECT m.*, pr.project_name, pr.job_no AS project_code, e.task_name AS entry_task_name,
|
||||||
su.name AS created_by_name
|
su.name AS created_by_name
|
||||||
FROM schedule_milestones m
|
FROM schedule_milestones m
|
||||||
JOIN projects pr ON m.project_id = pr.project_id
|
JOIN projects pr ON m.project_id = pr.project_id
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
// Populate project select in item modal
|
// Populate project select in item modal
|
||||||
const projSel = document.getElementById('itemProject');
|
const projSel = document.getElementById('itemProject');
|
||||||
projects.forEach(p => {
|
projects.forEach(p => {
|
||||||
projSel.innerHTML += `<option value="${p.project_id}">${escapeHtml(p.project_code)} ${escapeHtml(p.project_name)}</option>`;
|
projSel.innerHTML += `<option value="${p.project_id}">${escapeHtml(p.job_no)} ${escapeHtml(p.project_name)}</option>`;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Populate responsible user select
|
// Populate responsible user select
|
||||||
|
|||||||
@@ -374,7 +374,7 @@ function showMilestoneDetail(milestoneId) {
|
|||||||
function showNcPopup(projectId) {
|
function showNcPopup(projectId) {
|
||||||
const list = ncCache[projectId] || [];
|
const list = ncCache[projectId] || [];
|
||||||
const proj = projects.find(p => p.project_id === projectId);
|
const proj = projects.find(p => p.project_id === projectId);
|
||||||
document.getElementById('ncPopupTitle').textContent = `부적합 현황 - ${proj ? proj.project_code : ''}`;
|
document.getElementById('ncPopupTitle').textContent = `부적합 현황 - ${proj ? proj.job_no : ''}`;
|
||||||
const statusLabels = { reported: '신고', received: '접수', reviewing: '검토중', in_progress: '처리중', completed: '완료' };
|
const statusLabels = { reported: '신고', received: '접수', reviewing: '검토중', in_progress: '처리중', completed: '완료' };
|
||||||
let html = '';
|
let html = '';
|
||||||
if (list.length === 0) {
|
if (list.length === 0) {
|
||||||
@@ -402,7 +402,7 @@ function openEntryModal(editId) {
|
|||||||
document.getElementById('entryModalTitle').textContent = isEdit ? '공정표 항목 수정' : '공정표 항목 추가';
|
document.getElementById('entryModalTitle').textContent = isEdit ? '공정표 항목 수정' : '공정표 항목 추가';
|
||||||
|
|
||||||
// Populate dropdowns
|
// Populate dropdowns
|
||||||
populateSelect('entryProject', projects, 'project_id', p => `${p.project_code} ${p.project_name}`);
|
populateSelect('entryProject', projects, 'project_id', p => `${p.job_no} ${p.project_name}`);
|
||||||
populateSelect('entryPhase', phases, 'phase_id', p => p.phase_name);
|
populateSelect('entryPhase', phases, 'phase_id', p => p.phase_name);
|
||||||
|
|
||||||
// Template select (populated on phase change)
|
// Template select (populated on phase change)
|
||||||
@@ -530,7 +530,7 @@ async function saveEntry() {
|
|||||||
|
|
||||||
/* ===== Batch Modal ===== */
|
/* ===== Batch Modal ===== */
|
||||||
function openBatchModal() {
|
function openBatchModal() {
|
||||||
populateSelect('batchProject', projects, 'project_id', p => `${p.project_code} ${p.project_name}`);
|
populateSelect('batchProject', projects, 'project_id', p => `${p.job_no} ${p.project_name}`);
|
||||||
populateSelect('batchPhase', phases, 'phase_id', p => p.phase_name);
|
populateSelect('batchPhase', phases, 'phase_id', p => p.phase_name);
|
||||||
document.getElementById('batchStartDate').value = '';
|
document.getElementById('batchStartDate').value = '';
|
||||||
document.getElementById('batchTemplateList').innerHTML = '';
|
document.getElementById('batchTemplateList').innerHTML = '';
|
||||||
@@ -610,7 +610,7 @@ function openMilestoneModal(editId) {
|
|||||||
const isEdit = !!editId;
|
const isEdit = !!editId;
|
||||||
document.getElementById('milestoneModalTitle').textContent = isEdit ? '마일스톤 수정' : '마일스톤 추가';
|
document.getElementById('milestoneModalTitle').textContent = isEdit ? '마일스톤 수정' : '마일스톤 추가';
|
||||||
|
|
||||||
populateSelect('milestoneProject', projects, 'project_id', p => `${p.project_code} ${p.project_name}`);
|
populateSelect('milestoneProject', projects, 'project_id', p => `${p.job_no} ${p.project_name}`);
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
const m = ganttData.milestones.find(ms => ms.milestone_id === editId);
|
const m = ganttData.milestones.find(ms => ms.milestone_id === editId);
|
||||||
|
|||||||
Reference in New Issue
Block a user