프로젝트 시스템 통합 및 전반적인 개선사항
- 솔루션 설정 및 프로젝트 파일 업데이트 - BaseController 최적화 (HtmlAgilityPack 의존성 제거) - CommonController 네비게이션 메뉴에 프로젝트 추가 - JobreportController 사용자 조회 기능 및 필터링 개선 - 모든 웹 화면 UI/UX 통합 및 일관성 개선 - 프로그램 시작 시 중복 실행 감지 개선 - 각종 폼 및 데이터셋 디자이너 업데이트 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -119,9 +119,28 @@
|
||||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
/* 셀렉트 박스 옵션 스타일링 */
|
||||
select option {
|
||||
background-color: #1f2937 !important;
|
||||
color: #f9fafb !important;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
select option:hover {
|
||||
background-color: #374151 !important;
|
||||
}
|
||||
|
||||
select option:checked {
|
||||
background-color: #3b82f6 !important;
|
||||
}
|
||||
|
||||
select option:focus {
|
||||
background-color: #374151 !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="gradient-bg min-h-screen">
|
||||
<body class="bg-gradient-to-br from-blue-900 via-purple-900 to-indigo-900 min-h-screen text-white">
|
||||
<!-- 네비게이션 메뉴 (동적으로 추가됨) -->
|
||||
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
@@ -189,46 +208,78 @@
|
||||
|
||||
<!-- 필터 및 검색 -->
|
||||
<div class="glass-effect rounded-lg mb-6 animate-slide-up">
|
||||
<div class="p-6">
|
||||
<div class="flex flex-col md:flex-row md:items-center md:justify-between space-y-4 md:space-y-0">
|
||||
<div class="flex flex-col sm:flex-row space-y-2 sm:space-y-0 sm:space-x-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-white/80 mb-1">조회기간</label>
|
||||
<div class="flex space-x-2">
|
||||
<input type="date" id="startDate" class="bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent text-sm">
|
||||
<span class="flex items-center text-white/60">~</span>
|
||||
<input type="date" id="endDate" class="bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent text-sm">
|
||||
<div class="p-4">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4">
|
||||
<!-- 좌측: 필터 컨트롤 -->
|
||||
<div class="lg:col-span-2 space-y-3">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-white/80 mb-1">조회기간</label>
|
||||
<div class="flex space-x-1">
|
||||
<input type="date" id="startDate" class="flex-1 bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
<span class="flex items-center text-white/60 text-xs">~</span>
|
||||
<input type="date" id="endDate" class="flex-1 bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-white/80 mb-1">상태</label>
|
||||
<select id="statusFilter" class="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
<option value="">전체</option>
|
||||
<option value="진행중">진행중</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-white/80 mb-1">타입</label>
|
||||
<select id="typeFilter" class="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
<option value="">전체</option>
|
||||
<option value="개발">개발</option>
|
||||
<option value="유지보수">유지보수</option>
|
||||
<option value="분석">분석</option>
|
||||
<option value="테스트">테스트</option>
|
||||
<option value="문서작업">문서작업</option>
|
||||
<option value="회의">회의</option>
|
||||
<option value="기타">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-white/80 mb-1">상태</label>
|
||||
<select id="statusFilter" class="bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent">
|
||||
<option value="">전체</option>
|
||||
<option value="진행중">진행중</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
</select>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-white/80 mb-1">사용자</label>
|
||||
<select id="userFilter" class="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
<option value="">전체</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-white/80 mb-1">프로젝트</label>
|
||||
<select id="projectFilter" class="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
<option value="">전체</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-white/80 mb-1">프로젝트</label>
|
||||
<select id="projectFilter" class="bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent">
|
||||
<option value="">전체</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-white/80 mb-1">검색</label>
|
||||
<input type="text" id="searchInput" placeholder="업무 내용 검색..." class="bg-white/20 border border-white/30 rounded-md px-3 py-2 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-white/50 focus:border-transparent">
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-white/80 mb-1">검색</label>
|
||||
<input type="text" id="searchInput" placeholder="업무 내용 검색..." class="w-full bg-white/20 border border-white/30 rounded-md px-2 py-1 text-white placeholder-white/60 focus:outline-none focus:ring-1 focus:ring-white/50 focus:border-transparent text-xs">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<button id="clearFilterBtn" class="glass-effect hover:bg-white/30 text-white px-4 py-2 rounded-md flex items-center transition-colors">
|
||||
<i data-feather="x" class="w-4 h-4 mr-2"></i>
|
||||
필터 초기화
|
||||
|
||||
<!-- 우측: 액션 버튼들 -->
|
||||
<div class="flex flex-col space-y-2 justify-center">
|
||||
<button id="addJobBtn" class="bg-primary-500 hover:bg-primary-600 text-white px-4 py-2 rounded-md flex items-center justify-center transition-colors" title="업무일지 추가">
|
||||
<i data-feather="plus" class="w-4 h-4 mr-2"></i>
|
||||
업무일지 추가
|
||||
</button>
|
||||
<button id="exportBtn" class="glass-effect hover:bg-white/30 text-white px-4 py-2 rounded-md flex items-center transition-colors">
|
||||
<button id="exportBtn" class="bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded-md flex items-center justify-center transition-colors" title="엑셀 다운로드">
|
||||
<i data-feather="download" class="w-4 h-4 mr-2"></i>
|
||||
엑셀 다운로드
|
||||
</button>
|
||||
<button id="clearFilterBtn" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-md flex items-center justify-center transition-colors" title="필터 초기화">
|
||||
<i data-feather="refresh-cw" class="w-4 h-4 mr-2"></i>
|
||||
필터 초기화
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -406,22 +457,33 @@
|
||||
return `
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<div class="flex items-center">
|
||||
<h2 class="text-xl font-bold text-white">GroupWare</h2>
|
||||
</div>
|
||||
<div class="hidden md:flex items-center space-x-8">
|
||||
${visibleItems.map(item => this.getMenuItemHTML(item)).join('')}
|
||||
</div>
|
||||
<div class="md:hidden">
|
||||
<button id="mobile-menu-button" class="text-white/80 hover:text-white transition-colors p-2">
|
||||
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
|
||||
<div class="flex items-center space-x-8">
|
||||
<div class="flex items-center space-x-2">
|
||||
<svg class="w-8 h-8 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<span class="text-xl font-bold text-white">GroupWare</span>
|
||||
</div>
|
||||
<nav class="hidden md:flex space-x-1">
|
||||
${visibleItems.map(item => `
|
||||
<a href="${item.url}" class="px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
||||
this.currentPage === item.key
|
||||
? 'bg-white/20 text-white'
|
||||
: 'text-white/60 hover:text-white hover:bg-white/10'
|
||||
}">
|
||||
<svg class="w-4 h-4 inline mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="${item.icon}"></path>
|
||||
</svg>
|
||||
${item.title}
|
||||
</a>
|
||||
`).join('')}
|
||||
</nav>
|
||||
</div>
|
||||
<div class="flex items-center space-x-4">
|
||||
<div class="text-sm text-white/60">
|
||||
<span id="currentUser">사용자</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mobile-menu" class="md:hidden hidden border-t border-white/10 pt-4 pb-4">
|
||||
${visibleItems.map(item => this.getMobileMenuItemHTML(item)).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -488,6 +550,19 @@
|
||||
initNavigation('jobreport');
|
||||
initializeApp();
|
||||
loadJobData();
|
||||
|
||||
// 새로운 위치의 버튼들에 이벤트 리스너 추가
|
||||
setTimeout(() => {
|
||||
const addJobBtn = document.getElementById('addJobBtn');
|
||||
const exportBtn = document.getElementById('exportBtn');
|
||||
|
||||
if (addJobBtn) {
|
||||
addJobBtn.addEventListener('click', showAddJobModal);
|
||||
}
|
||||
if (exportBtn) {
|
||||
exportBtn.addEventListener('click', exportToExcel);
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
|
||||
function initializeApp() {
|
||||
@@ -499,10 +574,16 @@
|
||||
document.getElementById('startDate').value = twoWeeksAgo;
|
||||
document.getElementById('endDate').value = today;
|
||||
|
||||
// 사용자 목록 로드
|
||||
console.log('사용자 목록 로드 시작...');
|
||||
loadUserList();
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
document.getElementById('startDate').addEventListener('change', loadJobData);
|
||||
document.getElementById('endDate').addEventListener('change', loadJobData);
|
||||
document.getElementById('statusFilter').addEventListener('change', filterData);
|
||||
document.getElementById('typeFilter').addEventListener('change', filterData);
|
||||
document.getElementById('userFilter').addEventListener('change', loadJobData);
|
||||
document.getElementById('projectFilter').addEventListener('change', filterData);
|
||||
document.getElementById('searchInput').addEventListener('input', filterData);
|
||||
document.getElementById('clearFilterBtn').addEventListener('click', clearFilters);
|
||||
@@ -524,7 +605,6 @@
|
||||
renderTable();
|
||||
}
|
||||
});
|
||||
document.getElementById('exportBtn').addEventListener('click', exportToExcel);
|
||||
document.getElementById('closeModal').addEventListener('click', closeModal);
|
||||
|
||||
// 정렬 이벤트 리스너
|
||||
@@ -561,12 +641,14 @@
|
||||
// 조회기간 파라미터 가져오기
|
||||
const startDate = document.getElementById('startDate').value;
|
||||
const endDate = document.getElementById('endDate').value;
|
||||
const selectedUser = document.getElementById('userFilter').value;
|
||||
|
||||
// API URL 구성 - 새로운 GetJobData API 사용
|
||||
let url = '/Jobreport/GetJobData';
|
||||
const params = new URLSearchParams();
|
||||
if (startDate) params.append('startDate', startDate);
|
||||
if (endDate) params.append('endDate', endDate);
|
||||
if (selectedUser) params.append('user', selectedUser);
|
||||
|
||||
if (params.toString()) {
|
||||
url += '?' + params.toString();
|
||||
@@ -684,20 +766,62 @@
|
||||
});
|
||||
}
|
||||
|
||||
function loadUserList() {
|
||||
const userSelect = document.getElementById('userFilter');
|
||||
|
||||
// 기존 옵션 제거 (전체 옵션 제외)
|
||||
while (userSelect.children.length > 1) {
|
||||
userSelect.removeChild(userSelect.lastChild);
|
||||
}
|
||||
|
||||
// 서버에서 사용자 목록 가져오기
|
||||
fetch('/Jobreport/GetUsers')
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: 사용자 목록을 불러오는데 실패했습니다.`);
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('사용자 목록 데이터:', data);
|
||||
if (data && Array.isArray(data)) {
|
||||
data.forEach(user => {
|
||||
const option = document.createElement('option');
|
||||
option.value = user.id;
|
||||
option.textContent = `${user.name} [${user.id}] ${user.process}`;
|
||||
userSelect.appendChild(option);
|
||||
});
|
||||
console.log('사용자 목록 로드 완료:', userSelect.children.length - 1, '명');
|
||||
} else {
|
||||
console.warn('사용자 목록 데이터가 배열이 아닙니다:', data);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('사용자 목록 로드 중 오류:', error);
|
||||
// 에러 시 기본 사용자 옵션 추가
|
||||
const option = document.createElement('option');
|
||||
option.value = FCOMMON?.info?.Login?.no || '';
|
||||
option.textContent = '현재 사용자';
|
||||
userSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
function filterData() {
|
||||
const statusFilter = document.getElementById('statusFilter').value;
|
||||
const typeFilter = document.getElementById('typeFilter').value;
|
||||
const projectFilter = document.getElementById('projectFilter').value;
|
||||
const searchTerm = document.getElementById('searchInput').value.toLowerCase();
|
||||
|
||||
filteredData = jobData.filter(item => {
|
||||
const statusMatch = !statusFilter || item.status === statusFilter;
|
||||
const typeMatch = !typeFilter || item.type === typeFilter;
|
||||
const projectMatch = !projectFilter || item.projectName === projectFilter;
|
||||
const searchMatch = !searchTerm ||
|
||||
(item.description && item.description.toLowerCase().includes(searchTerm)) ||
|
||||
(item.projectName && item.projectName.toLowerCase().includes(searchTerm)) ||
|
||||
(item.requestpart && item.requestpart.toLowerCase().includes(searchTerm));
|
||||
|
||||
return statusMatch && projectMatch && searchMatch;
|
||||
return statusMatch && typeMatch && projectMatch && searchMatch;
|
||||
});
|
||||
|
||||
currentPage = 1;
|
||||
@@ -862,6 +986,112 @@
|
||||
document.getElementById('nextPage').disabled = currentPage >= maxPage;
|
||||
}
|
||||
|
||||
function showAddJobModal() {
|
||||
const modal = document.getElementById('detailModal');
|
||||
const content = document.getElementById('modalContent');
|
||||
|
||||
// 오늘 날짜를 기본값으로 설정
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
|
||||
content.innerHTML = `
|
||||
<form id="editJobForm" class="space-y-6">
|
||||
<input type="hidden" id="editIdx" value="">
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-5 gap-8">
|
||||
<!-- 좌측: 기본 정보 (2열) -->
|
||||
<div class="lg:col-span-2">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">날짜 *</label>
|
||||
<input type="date" id="editPdate" value="${today}"
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">상태 *</label>
|
||||
<select id="editStatus" class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" required>
|
||||
<option value="">선택하세요</option>
|
||||
<option value="진행 중" selected>진행 중</option>
|
||||
<option value="완료">완료</option>
|
||||
<option value="대기">대기</option>
|
||||
<option value="보류">보류</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">요청부서</label>
|
||||
<input type="text" id="editRequestpart" value=""
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">타입</label>
|
||||
<select id="editType" class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all">
|
||||
<option value="">선택하세요</option>
|
||||
<option value="개발">개발</option>
|
||||
<option value="유지보수">유지보수</option>
|
||||
<option value="분석">분석</option>
|
||||
<option value="테스트">테스트</option>
|
||||
<option value="문서작업">문서작업</option>
|
||||
<option value="회의">회의</option>
|
||||
<option value="기타">기타</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">근무시간 (시간) *</label>
|
||||
<input type="number" id="editHrs" value="8" step="any"
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" required>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">초과근무 (시간)</label>
|
||||
<input type="number" id="editOt" value="" step="any"
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">초과근무 시작시간</label>
|
||||
<input type="time" id="editOtStart" value=""
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">초과근무 종료시간</label>
|
||||
<input type="time" id="editOtEnd" value=""
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 우측: 프로젝트명과 업무내용 -->
|
||||
<div class="lg:col-span-3 space-y-4">
|
||||
<div>
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">프로젝트명 *</label>
|
||||
<input type="text" id="editProjectName" value=""
|
||||
class="w-full bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all" required>
|
||||
</div>
|
||||
<div class="flex-grow">
|
||||
<label class="block text-white/70 text-sm font-medium mb-2">업무내용 *</label>
|
||||
<textarea id="editDescription" rows="15" required
|
||||
class="w-full h-full min-h-[360px] bg-white/20 backdrop-blur-sm border border-white/30 rounded-lg px-4 py-2 text-white placeholder-white/50 focus:outline-none focus:ring-2 focus:ring-primary-400 transition-all resize-vertical"
|
||||
placeholder="상세한 업무 내용을 입력하세요..."></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 모달 푸터 -->
|
||||
<div class="px-6 py-4 border-t border-white/10 flex justify-end space-x-3 bg-black/10 rounded-b-2xl">
|
||||
<button type="button" onclick="closeModal()" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button type="submit" form="editJobForm" class="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors">
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
feather.replace();
|
||||
|
||||
// 폼 제출 이벤트 리스너 추가
|
||||
document.getElementById('editJobForm').addEventListener('submit', handleAddSubmit);
|
||||
}
|
||||
|
||||
async function showDetailModal(item) {
|
||||
// 문자열로 전달된 경우 JSON 파싱
|
||||
if (typeof item === 'string') {
|
||||
@@ -970,16 +1200,18 @@
|
||||
</form>
|
||||
|
||||
<!-- 모달 푸터 -->
|
||||
<div class="px-6 py-4 border-t border-white/10 flex justify-end space-x-3 bg-black/10 rounded-b-2xl">
|
||||
<div class="px-6 py-4 border-t border-white/10 flex justify-between items-center bg-black/10 rounded-b-2xl">
|
||||
<button type="button" id="deleteJobBtn" class="bg-danger-500 hover:bg-danger-600 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
삭제
|
||||
</button>
|
||||
<button type="button" onclick="closeModal()" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button type="submit" form="editJobForm" class="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors">
|
||||
저장
|
||||
</button>
|
||||
<div class="flex space-x-3">
|
||||
<button type="button" onclick="closeModal()" class="bg-white/20 hover:bg-white/30 text-white px-4 py-2 rounded-lg transition-colors">
|
||||
취소
|
||||
</button>
|
||||
<button type="submit" form="editJobForm" class="bg-primary-500 hover:bg-primary-600 text-white px-6 py-2 rounded-lg transition-colors">
|
||||
저장
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -995,6 +1227,61 @@
|
||||
document.getElementById('detailModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
async function handleAddSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
// URLSearchParams 사용 (application/x-www-form-urlencoded)
|
||||
const formData = new URLSearchParams();
|
||||
formData.append('pdate', document.getElementById('editPdate').value);
|
||||
formData.append('status', document.getElementById('editStatus').value);
|
||||
formData.append('projectName', document.getElementById('editProjectName').value);
|
||||
formData.append('requestpart', document.getElementById('editRequestpart').value);
|
||||
formData.append('type', document.getElementById('editType').value);
|
||||
formData.append('hrs', document.getElementById('editHrs').value);
|
||||
formData.append('ot', document.getElementById('editOt').value);
|
||||
formData.append('otStart', document.getElementById('editOtStart').value);
|
||||
formData.append('otEnd', document.getElementById('editOtEnd').value);
|
||||
formData.append('description', document.getElementById('editDescription').value);
|
||||
|
||||
try {
|
||||
const response = await fetch('/Jobreport/Add', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: 추가에 실패했습니다.`);
|
||||
}
|
||||
|
||||
const result = await response.text();
|
||||
console.log('Add result:', result);
|
||||
|
||||
// JSON 응답인지 확인
|
||||
try {
|
||||
const jsonResult = JSON.parse(result);
|
||||
if (!jsonResult.success) {
|
||||
throw new Error(jsonResult.message || '추가에 실패했습니다.');
|
||||
}
|
||||
// 성공시 alert 없이 바로 진행
|
||||
} catch (parseError) {
|
||||
// JSON이 아닌 경우도 성공으로 처리 (alert 없음)
|
||||
}
|
||||
|
||||
// 모달 닫기
|
||||
closeModal();
|
||||
|
||||
// 데이터 새로고침
|
||||
await loadJobData();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error adding job:', error);
|
||||
alert('업무일지 추가 중 오류가 발생했습니다: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleEditSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -1202,6 +1489,8 @@
|
||||
|
||||
// 다른 필터들 초기화
|
||||
document.getElementById('statusFilter').value = '';
|
||||
document.getElementById('typeFilter').value = '';
|
||||
document.getElementById('userFilter').value = '';
|
||||
document.getElementById('projectFilter').value = '';
|
||||
document.getElementById('searchInput').value = '';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user