feat: 권한 탭 분리 + 부서 인원 표시 + 다수 시스템 개선

- tkuser: 권한 관리를 별도 탭으로 분리, 부서 클릭 시 소속 인원 목록 표시
- system1: 모바일 UI 개선, nginx 권한 보정, 신고 카테고리 타입 마이그레이션
- system2: 신고 상세/보고서 개선, 내 보고서 페이지 추가
- system3: 이슈 뷰/수신함/관리함 개선
- gateway: 포털 라우팅 수정
- user-management API: 부서별 권한 벌크 설정 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Hyungi Ahn
2026-02-23 14:12:57 +09:00
parent bf4000c4ae
commit 3cc29c03a8
37 changed files with 1751 additions and 233 deletions

View File

@@ -20,7 +20,8 @@ const statusNames = {
// 유형 한글명
const typeNames = {
nonconformity: '부적합',
safety: '안전'
safety: '안전',
facility: '시설설비'
};
// 심각도 한글명
@@ -146,7 +147,7 @@ function renderBasicInfo(d) {
});
};
const validTypes = ['nonconformity', 'safety'];
const validTypes = ['nonconformity', 'safety', 'facility'];
const safeType = validTypes.includes(d.category_type) ? d.category_type : '';
const reporterName = escapeHtml(d.reporter_full_name || d.reporter_name || '-');
const locationText = escapeHtml(d.custom_location || d.workplace_name || '-');
@@ -358,6 +359,11 @@ function renderActionButtons(d) {
}
}
// 유형 이관 버튼 (admin/support_team/담당자, closed 아닐 때)
if ((isAdmin || isAssignee) && d.status !== 'closed') {
buttons.push(`<button class="action-btn" onclick="openTransferModal()">유형 이관</button>`);
}
// 신고자 버튼 (수정/삭제는 reported 상태에서만)
if (isOwner && d.status === 'reported') {
buttons.push(`<button class="action-btn danger" onclick="deleteReport()">삭제</button>`);
@@ -635,6 +641,62 @@ async function submitComplete() {
}
}
// ==================== 유형 이관 모달 ====================
function openTransferModal() {
const select = document.getElementById('transferCategoryType');
// 현재 유형은 선택 불가 처리
for (const option of select.options) {
option.disabled = (option.value === reportData.category_type);
}
select.value = '';
document.getElementById('transferModal').classList.add('visible');
}
function closeTransferModal() {
document.getElementById('transferModal').classList.remove('visible');
}
async function submitTransfer() {
const newType = document.getElementById('transferCategoryType').value;
if (!newType) {
alert('이관할 유형을 선택해주세요.');
return;
}
if (newType === reportData.category_type) {
alert('현재 유형과 동일합니다.');
return;
}
const typeName = typeNames[newType] || newType;
if (!confirm(`이 신고를 "${typeName}" 유형으로 이관하시겠습니까?`)) return;
try {
const response = await fetch(`${API_BASE}/work-issues/${reportId}/transfer`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${(window.getSSOToken ? window.getSSOToken() : localStorage.getItem('sso_token'))}`
},
body: JSON.stringify({ category_type: newType })
});
const data = await response.json();
if (data.success) {
alert('유형이 이관되었습니다.');
closeTransferModal();
location.reload();
} else {
throw new Error(data.error || '이관 실패');
}
} catch (error) {
alert('유형 이관 실패: ' + error.message);
}
}
// ==================== 사진 모달 ====================
function openPhotoModal(src) {
@@ -665,11 +727,13 @@ function goBackToList() {
window.location.href = '/pages/work/nonconformity.html';
} else if (from === 'safety') {
window.location.href = '/pages/safety/report-status.html';
} else if (from === 'my-reports') {
window.location.href = '/pages/safety/my-reports.html';
} else {
if (window.history.length > 1) {
window.history.back();
} else {
window.location.href = '/pages/safety/report-status.html';
window.location.href = '/pages/safety/my-reports.html';
}
}
}
@@ -686,5 +750,8 @@ window.submitAssign = submitAssign;
window.openCompleteModal = openCompleteModal;
window.closeCompleteModal = closeCompleteModal;
window.submitComplete = submitComplete;
window.openTransferModal = openTransferModal;
window.closeTransferModal = closeTransferModal;
window.submitTransfer = submitTransfer;
window.openPhotoModal = openPhotoModal;
window.closePhotoModal = closePhotoModal;