/**
* m-management.js — 관리함 모바일 페이지 로직
*/
var currentUser = null;
var issues = [];
var projects = [];
var filteredIssues = [];
var currentTab = 'in_progress';
var currentIssueId = null;
var rejectIssueId = null;
function cleanManagementComment(text) {
if (!text) return '';
return text.replace(/\[완료 반려[^\]]*\][^\n]*\n*/g, '').trim();
}
// ===== 초기화 =====
async function initialize() {
currentUser = await mCheckAuth();
if (!currentUser) return;
await loadProjects();
await loadIssues();
renderBottomNav('management');
hideLoading();
}
async function loadProjects() {
try {
var resp = await fetch(API_BASE_URL + '/projects/', {
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken() }
});
if (resp.ok) {
projects = await resp.json();
var sel = document.getElementById('projectFilter');
sel.innerHTML = '전체 프로젝트 ';
projects.forEach(function (p) {
sel.innerHTML += '' + escapeHtml(p.project_name) + ' ';
});
}
} catch (e) { console.error('프로젝트 로드 실패:', e); }
}
async function loadIssues() {
try {
var resp = await fetch(API_BASE_URL + '/issues/admin/all', {
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken() }
});
if (resp.ok) {
var all = await resp.json();
var filtered = all.filter(function (i) { return i.review_status === 'in_progress' || i.review_status === 'completed'; });
// 프로젝트별 순번
filtered.sort(function (a, b) { return new Date(a.reviewed_at) - new Date(b.reviewed_at); });
var groups = {};
filtered.forEach(function (issue) {
if (!groups[issue.project_id]) groups[issue.project_id] = [];
groups[issue.project_id].push(issue);
});
Object.keys(groups).forEach(function (pid) {
groups[pid].forEach(function (issue, idx) { issue.project_sequence_no = idx + 1; });
});
issues = filtered;
filterIssues();
}
} catch (e) { console.error('이슈 로드 실패:', e); }
}
// ===== 탭 전환 =====
function switchTab(tab) {
currentTab = tab;
document.getElementById('tabInProgress').classList.toggle('active', tab === 'in_progress');
document.getElementById('tabCompleted').classList.toggle('active', tab === 'completed');
document.getElementById('additionalInfoBtn').style.display = tab === 'in_progress' ? 'flex' : 'none';
filterIssues();
}
// ===== 통계 =====
function updateStatistics() {
var pid = document.getElementById('projectFilter').value;
var pi = pid ? issues.filter(function (i) { return i.project_id == pid; }) : issues;
document.getElementById('totalCount').textContent = pi.length;
document.getElementById('inProgressCount').textContent = pi.filter(function (i) { return i.review_status === 'in_progress' && !i.completion_requested_at; }).length;
document.getElementById('pendingCompletionCount').textContent = pi.filter(function (i) { return i.review_status === 'in_progress' && i.completion_requested_at; }).length;
document.getElementById('completedCount').textContent = pi.filter(function (i) { return i.review_status === 'completed'; }).length;
}
// ===== 필터 =====
function filterIssues() {
var pid = document.getElementById('projectFilter').value;
filteredIssues = issues.filter(function (i) {
if (i.review_status !== currentTab) return false;
if (pid && i.project_id != pid) return false;
return true;
});
filteredIssues.sort(function (a, b) { return new Date(b.report_date) - new Date(a.report_date); });
renderIssues();
updateStatistics();
}
// ===== 이슈 상태 =====
function getIssueStatus(issue) {
if (issue.review_status === 'completed') return 'completed';
if (issue.completion_requested_at) return 'pending_completion';
if (issue.expected_completion_date) {
var diff = (new Date(issue.expected_completion_date) - new Date()) / 86400000;
if (diff < 0) return 'overdue';
if (diff <= 3) return 'urgent';
}
return 'in_progress';
}
function getStatusBadgeHtml(status) {
var map = {
'in_progress': ' 진행 중 ',
'urgent': ' 긴급 ',
'overdue': ' 지연됨 ',
'pending_completion': ' 완료 대기 ',
'completed': ' 완료됨 '
};
return map[status] || map['in_progress'];
}
// ===== 렌더링 =====
function renderIssues() {
var container = document.getElementById('issuesList');
var empty = document.getElementById('emptyState');
if (!filteredIssues.length) { container.innerHTML = ''; empty.classList.remove('hidden'); return; }
empty.classList.add('hidden');
// 날짜별 그룹
var grouped = {};
var dateObjs = {};
filteredIssues.forEach(function (issue) {
var dateToUse = currentTab === 'completed' ? (issue.actual_completion_date || issue.report_date) : issue.report_date;
var d = new Date(dateToUse);
var key = d.toLocaleDateString('ko-KR');
if (!grouped[key]) { grouped[key] = []; dateObjs[key] = d; }
grouped[key].push(issue);
});
var html = Object.keys(grouped)
.sort(function (a, b) { return dateObjs[b] - dateObjs[a]; })
.map(function (dateKey) {
var issues = grouped[dateKey];
return '
' +
issues.map(function (issue) {
return currentTab === 'in_progress' ? renderInProgressCard(issue) : renderCompletedCard(issue);
}).join('') +
'
';
}).join('');
container.innerHTML = html;
}
function renderInProgressCard(issue) {
var project = projects.find(function (p) { return p.id === issue.project_id; });
var status = getIssueStatus(issue);
var isPending = status === 'pending_completion';
var photos = getPhotoPaths(issue);
// 관리 필드 표시
var mgmtHtml = '' +
'
해결방안: ' + escapeHtml(cleanManagementComment(issue.management_comment) || '-') + '
' +
'
담당부서: ' + getDepartmentText(issue.responsible_department) + '
' +
'
담당자: ' + escapeHtml(issue.responsible_person || '-') + '
' +
'
조치예상일: ' + (issue.expected_completion_date ? formatKSTDate(issue.expected_completion_date) : '-') + '
' +
'
';
// 완료 대기 정보
var completionInfoHtml = '';
if (isPending) {
var cPhotos = getCompletionPhotoPaths(issue);
completionInfoHtml = '' +
'
완료 신청 정보
' +
(cPhotos.length ? renderPhotoThumbs(cPhotos) : '') +
'
' + escapeHtml(issue.completion_comment || '코멘트 없음') + '
' +
'
신청: ' + formatKSTDateTime(issue.completion_requested_at) + '
' +
'
';
}
// 액션 버튼
var actionHtml = '';
if (isPending) {
actionHtml = '' +
' 반려 ' +
' 최종확인 ' +
'
';
} else {
actionHtml = '' +
' 편집 ' +
' 완료처리 ' +
'
';
}
return '' +
'' +
'
' + escapeHtml(getIssueTitle(issue)) + '
' +
'
' +
'
' + escapeHtml(getIssueDetail(issue)) + '
' +
'
' +
' ' + getCategoryText(issue.category || issue.final_category) + ' ' +
' ' + escapeHtml(issue.reporter?.full_name || issue.reporter?.username || '-') + ' ' +
'
' +
(photos.length ? renderPhotoThumbs(photos) : '') +
mgmtHtml +
completionInfoHtml +
'
' +
actionHtml +
'' +
'
';
}
function renderCompletedCard(issue) {
var project = projects.find(function (p) { return p.id === issue.project_id; });
var completedDate = issue.completed_at ? formatKSTDate(issue.completed_at) : '-';
return '' +
'' +
'
' + escapeHtml(getIssueTitle(issue)) + '
' +
'' +
'
';
}
// ===== 편집 시트 =====
function openEditMgmtSheet(issueId) {
currentIssueId = issueId;
var issue = issues.find(function (i) { return i.id === issueId; });
if (!issue) return;
// 프로젝트 셀렉트 채우기
var projSel = document.getElementById('editProject');
projSel.innerHTML = '선택하세요 ';
projects.forEach(function (p) {
projSel.innerHTML += '' + escapeHtml(p.project_name || p.job_no) + ' ';
});
projSel.disabled = (issue.review_status === 'completed');
document.getElementById('editManagementComment').value = cleanManagementComment(issue.management_comment) || '';
document.getElementById('editResponsibleDept').value = issue.responsible_department || '';
document.getElementById('editResponsiblePerson').value = issue.responsible_person || '';
document.getElementById('editExpectedDate').value = issue.expected_completion_date ? issue.expected_completion_date.split('T')[0] : '';
openSheet('editMgmt');
}
async function saveManagementEdit() {
if (!currentIssueId) return;
try {
var updates = {
management_comment: document.getElementById('editManagementComment').value.trim() || null,
responsible_department: document.getElementById('editResponsibleDept').value || null,
responsible_person: document.getElementById('editResponsiblePerson').value.trim() || null,
expected_completion_date: document.getElementById('editExpectedDate').value ? document.getElementById('editExpectedDate').value + 'T00:00:00' : null
};
// 프로젝트 변경 확인
var newProjectId = parseInt(document.getElementById('editProject').value);
var issue = issues.find(function (i) { return i.id === currentIssueId; });
if (newProjectId && issue && newProjectId !== issue.project_id) {
// 프로젝트 변경은 /issues/{id} PUT으로 별도 호출
var projResp = await fetch(API_BASE_URL + '/issues/' + currentIssueId, {
method: 'PUT',
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken(), 'Content-Type': 'application/json' },
body: JSON.stringify({ project_id: newProjectId })
});
if (!projResp.ok) {
var projErr = await projResp.json();
throw new Error(projErr.detail || '프로젝트 변경 실패');
}
}
var resp = await fetch(API_BASE_URL + '/issues/' + currentIssueId + '/management', {
method: 'PUT',
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken(), 'Content-Type': 'application/json' },
body: JSON.stringify(updates)
});
if (resp.ok) {
showToast('저장되었습니다.', 'success');
closeSheet('editMgmt');
await loadIssues();
} else {
var err = await resp.json();
throw new Error(err.detail || '저장 실패');
}
} catch (e) { showToast('오류: ' + e.message, 'error'); }
}
// ===== 완료 처리 =====
async function confirmCompletion(issueId) {
if (!confirm('완료 처리하시겠습니까?')) return;
try {
var resp = await fetch(API_BASE_URL + '/inbox/' + issueId + '/status', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken(), 'Content-Type': 'application/json' },
body: JSON.stringify({ review_status: 'completed' })
});
if (resp.ok) {
showToast('완료 처리되었습니다.', 'success');
await loadIssues();
} else {
var err = await resp.json();
throw new Error(err.detail || '완료 처리 실패');
}
} catch (e) { showToast('오류: ' + e.message, 'error'); }
}
// ===== 반려 =====
function openRejectSheet(issueId) {
rejectIssueId = issueId;
document.getElementById('rejectReason').value = '';
openSheet('reject');
}
async function submitReject() {
if (!rejectIssueId) return;
var reason = document.getElementById('rejectReason').value.trim();
if (!reason) { showToast('반려 사유를 입력해주세요.', 'warning'); return; }
try {
var resp = await fetch(API_BASE_URL + '/issues/' + rejectIssueId + '/reject-completion', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken(), 'Content-Type': 'application/json' },
body: JSON.stringify({ rejection_reason: reason })
});
if (resp.ok) {
showToast('반려 처리되었습니다.', 'success');
closeSheet('reject');
await loadIssues();
} else {
var err = await resp.json();
throw new Error(err.detail || '반려 실패');
}
} catch (e) { showToast('오류: ' + e.message, 'error'); }
}
// ===== 추가 정보 =====
function openAdditionalInfoSheet() {
var inProgressIssues = issues.filter(function (i) { return i.review_status === 'in_progress'; });
var sel = document.getElementById('additionalIssueSelect');
sel.innerHTML = '이슈 선택 ';
inProgressIssues.forEach(function (i) {
var p = projects.find(function (pr) { return pr.id === i.project_id; });
sel.innerHTML += 'No.' + (i.project_sequence_no || '-') + ' ' + escapeHtml(getIssueTitle(i)) + ' ';
});
document.getElementById('additionalCauseDept').value = '';
document.getElementById('additionalCausePerson').value = '';
document.getElementById('additionalCauseDetail').value = '';
openSheet('additional');
}
function loadAdditionalInfo() {
var id = parseInt(document.getElementById('additionalIssueSelect').value);
if (!id) return;
var issue = issues.find(function (i) { return i.id === id; });
if (!issue) return;
document.getElementById('additionalCauseDept').value = issue.cause_department || '';
document.getElementById('additionalCausePerson').value = issue.responsible_person_detail || '';
document.getElementById('additionalCauseDetail').value = issue.cause_detail || '';
}
async function saveAdditionalInfo() {
var id = parseInt(document.getElementById('additionalIssueSelect').value);
if (!id) { showToast('이슈를 선택해주세요.', 'warning'); return; }
try {
var resp = await fetch(API_BASE_URL + '/issues/' + id + '/management', {
method: 'PUT',
headers: { 'Authorization': 'Bearer ' + TokenManager.getToken(), 'Content-Type': 'application/json' },
body: JSON.stringify({
cause_department: document.getElementById('additionalCauseDept').value || null,
responsible_person_detail: document.getElementById('additionalCausePerson').value.trim() || null,
cause_detail: document.getElementById('additionalCauseDetail').value.trim() || null
})
});
if (resp.ok) {
showToast('추가 정보가 저장되었습니다.', 'success');
closeSheet('additional');
await loadIssues();
} else {
var err = await resp.json();
throw new Error(err.detail || '저장 실패');
}
} catch (e) { showToast('오류: ' + e.message, 'error'); }
}
// ===== 완료됨 상세보기 =====
function openDetailSheet(issueId) {
var issue = issues.find(function (i) { return i.id === issueId; });
if (!issue) return;
var project = projects.find(function (p) { return p.id === issue.project_id; });
var photos = getPhotoPaths(issue);
var cPhotos = getCompletionPhotoPaths(issue);
document.getElementById('detailSheetTitle').innerHTML =
'No.' + (issue.project_sequence_no || '-') + ' 상세 정보';
document.getElementById('detailSheetBody').innerHTML =
// 기본 정보
'' +
'
기본 정보
' +
'
프로젝트: ' + escapeHtml(project ? project.project_name : '-') + '
' +
'
부적합명: ' + escapeHtml(getIssueTitle(issue)) + '
' +
'
' + escapeHtml(getIssueDetail(issue)) + '
' +
'
분류: ' + getCategoryText(issue.final_category || issue.category) + '
' +
'
확인자: ' + escapeHtml(getReporterNames(issue)) + '
' +
(photos.length ? '
업로드 사진
' + renderPhotoThumbs(photos) + '
' : '') +
'
' +
// 관리 정보
'' +
'
관리 정보
' +
'
해결방안: ' + escapeHtml(cleanManagementComment(issue.management_comment) || '-') + '
' +
'
담당부서: ' + getDepartmentText(issue.responsible_department) + '
' +
'
담당자: ' + escapeHtml(issue.responsible_person || '-') + '
' +
'
원인부서: ' + getDepartmentText(issue.cause_department) + '
' +
'
' +
// 완료 정보
'' +
'
완료 정보
' +
(cPhotos.length ? '
완료 사진
' + renderPhotoThumbs(cPhotos) + '
' : '
완료 사진 없음
') +
'
완료 코멘트: ' + escapeHtml(issue.completion_comment || '-') + '
' +
(issue.completion_requested_at ? '
완료 신청일: ' + formatKSTDateTime(issue.completion_requested_at) + '
' : '') +
(issue.completed_at ? '
최종 완료일: ' + formatKSTDateTime(issue.completed_at) + '
' : '') +
'
';
openSheet('detail');
}
// ===== 시작 =====
document.addEventListener('DOMContentLoaded', initialize);