- partials/favicon.ejs로 icon·apple-touch-icon 링크 - 전 페이지 head에 include, /favicon.ico는 동일 PNG 제공 - 인라인 403 HTML에도 favicon 링크 Made-with: Cursor
481 lines
29 KiB
Plaintext
481 lines
29 KiB
Plaintext
<!doctype html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<%- include('partials/favicon') %>
|
|
<title>AX 과제 신청 - XAVIS</title>
|
|
<link rel="stylesheet" href="/public/styles.css" />
|
|
</head>
|
|
<body
|
|
data-ax-admin-mode="<%= (typeof adminMode !== 'undefined' && adminMode) ? '1' : '0' %>"
|
|
data-ax-apply-download-submit-allowed="<%= (typeof axApplyDownloadSubmitAllowed !== 'undefined' && axApplyDownloadSubmitAllowed) ? '1' : '0' %>"
|
|
>
|
|
<% var axDlSubmitOk = typeof axApplyDownloadSubmitAllowed !== 'undefined' ? axApplyDownloadSubmitAllowed : true; %>
|
|
<% if (typeof assignments === 'undefined') { assignments = []; } %>
|
|
<div class="app-shell">
|
|
<%- include('partials/nav', { activeMenu: 'ax-apply' }) %>
|
|
<div class="content-area">
|
|
<header class="topbar">
|
|
<h1>AX 과제 신청</h1>
|
|
</header>
|
|
<main class="container">
|
|
<% if (!axDlSubmitOk) { %>
|
|
<p class="chat-api-warning" style="margin-bottom: 16px">
|
|
로그인 후 이용 가능합니다.
|
|
</p>
|
|
<% } %>
|
|
<section class="panel">
|
|
<h2>신청된 과제 목록</h2>
|
|
<p class="list-hint">소속 부서, 이름, 이메일을 입력하면 조회됩니다.</p>
|
|
<div id="axAssignmentsListWrap">
|
|
<% if (!assignments.length) { %>
|
|
<p class="empty">신청된 과제가 없습니다.</p>
|
|
<% } else { %>
|
|
<div class="table-wrap">
|
|
<table class="data-table">
|
|
<thead>
|
|
<tr>
|
|
<th>순번</th>
|
|
<th>신청일</th>
|
|
<th>소속 부서</th>
|
|
<th>이름</th>
|
|
<th>사번</th>
|
|
<th>직급</th>
|
|
<th>이메일</th>
|
|
<th>AI에게 원하는 것</th>
|
|
<th>신청서</th>
|
|
<th>상태</th>
|
|
<th>수정<% if (typeof adminMode !== 'undefined' && adminMode) { %> / 삭제<% } %></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<% assignments.forEach((a, idx) => { %>
|
|
<tr>
|
|
<td><%= assignments.length - idx %></td>
|
|
<td><%= new Date(a.createdAt).toLocaleDateString('ko-KR') %></td>
|
|
<td><%= a.department || '-' %></td>
|
|
<td><%= a.name || '-' %></td>
|
|
<td><%= a.employeeId || '-' %></td>
|
|
<td><%= a.position || '-' %></td>
|
|
<td><%= a.email || '-' %></td>
|
|
<td class="cell-truncate" title="<%= (a.aiExpectation || '').replace(/"/g, '"') %>"><%= (a.aiExpectation || '-').length > 30 ? (a.aiExpectation || '').slice(0, 30) + '…' : (a.aiExpectation || '-') %></td>
|
|
<td><% if (a.applicationFile) { %><a href="<%= a.applicationFile %>" target="_blank" download>보기</a><% } else { %>-<% } %></td>
|
|
<td><%= a.status || '신청' %></td>
|
|
<td>
|
|
<a href="#" class="ax-edit-link" data-id="<%= a.id %>">수정</a><% if (typeof adminMode !== 'undefined' && adminMode) { %> | <a href="#" class="ax-delete-link" data-id="<%= a.id %>" data-created-at="<%= (a.createdAt || '').toString().replace(/"/g, '"') %>" data-department="<%= (a.department || '').toString().replace(/"/g, '"') %>" data-name="<%= (a.name || '').toString().replace(/"/g, '"') %>" data-employee-id="<%= (a.employeeId || '').toString().replace(/"/g, '"') %>" data-position="<%= (a.position || '').toString().replace(/"/g, '"') %>" data-email="<%= (a.email || '').toString().replace(/"/g, '"') %>">삭제</a><% } %>
|
|
</td>
|
|
</tr>
|
|
<% }) %>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<% } %>
|
|
</div>
|
|
<% if (typeof adminMode !== 'undefined' && !adminMode) { %>
|
|
<div class="list-query-actions">
|
|
<button type="button" id="axApplyListQueryBtn" class="btn-ghost">조회</button>
|
|
</div>
|
|
<% } %>
|
|
</section>
|
|
|
|
<section class="panel" id="ax-apply-form">
|
|
<h2>
|
|
AX 과제 신청서
|
|
<% if (axDlSubmitOk) { %>
|
|
<a href="/resources/ax-apply/AX_과제_신청서.docx" download="AX_과제_신청서.docx" class="link-download">(신청서 다운로드)</a>
|
|
<% } else { %>
|
|
<span class="link-muted" tabindex="-1" aria-disabled="true">(신청서 다운로드)</span>
|
|
<% } %>
|
|
</h2>
|
|
<p class="subtitle">※ 모든 항목을 성실하게 작성해 주세요.</p>
|
|
<form id="axApplyForm" class="form-grid" enctype="multipart/form-data">
|
|
<input type="hidden" name="editId" id="axEditId" value="" />
|
|
<h3>1. 기본 정보</h3>
|
|
<label><span class="label-text">소속 부서<span class="required">*</span></span> <input type="text" name="department" required placeholder="부서명 입력" /></label>
|
|
<label><span class="label-text">이름<span class="required">*</span></span> <input type="text" name="name" required placeholder="이름 입력" /></label>
|
|
<label>사번 <input type="text" name="employeeId" placeholder="사번 입력" /></label>
|
|
<label>직급/직책 <input type="text" name="position" placeholder="직급 입력" /></label>
|
|
<label>연락처 <input type="text" name="phone" placeholder="연락처 입력" /></label>
|
|
<label><span class="label-text">이메일<span class="required">*</span></span> <input type="email" name="email" required placeholder="이메일 입력" /></label>
|
|
|
|
<h3 class="full">2. 현재 업무 현황 (As-Is)</h3>
|
|
<label class="full"><span class="label-text">업무 프로세스 설명<span class="required">*</span></span> <textarea name="workProcessDescription" rows="4" required placeholder="현재 업무의 전체 흐름을 단계별로 설명해 주세요."></textarea></label>
|
|
<label class="full"><span class="label-text">Pain Point<span class="required">*</span></span> <textarea name="painPoint" rows="3" required placeholder="현재 업무에서 가장 불편하거나 비효율적인 점을 구체적으로 기재해 주세요."></textarea></label>
|
|
<label><span class="label-text">현재 소요 시간<span class="required">*</span></span> <input type="text" name="currentTimeSpent" required placeholder="예: 1건 처리에 30분 소요" /></label>
|
|
<label><span class="label-text">AX 전환 전 오류율<span class="required">*</span></span> <input type="text" name="errorRateBefore" required placeholder="예: 약 5%" /></label>
|
|
<label class="full">협업 필요 부서 <input type="text" name="collaborationDepts" placeholder="AI혁신팀 외 협업이 필요한 부서가 있다면 기재해 주세요." /></label>
|
|
<label class="full"><span class="label-text">지금 해결해야 하는 이유<span class="required">*</span></span> <textarea name="reasonToSolve" rows="2" required placeholder="왜 지금 이 문제를 해결해야 하는지 배경을 설명해 주세요."></textarea></label>
|
|
|
|
<h3 class="full">3. 희망하는 결과 (To-Be)</h3>
|
|
<label class="full"><span class="label-text">AI에게 원하는 것<span class="required">*</span></span> <textarea name="aiExpectation" rows="3" required placeholder="예: 폴더에 파일만 넣으면 자동으로 합쳐진 엑셀 파일이 1개 생성되었으면 함"></textarea></label>
|
|
<label class="full"><span class="label-text">산출물 형태<span class="required">*</span></span> <textarea name="outputType" rows="2" required placeholder="원하는 결과물의 형태를 설명해 주세요."></textarea></label>
|
|
<label class="full">기대 자동화 수준
|
|
<select name="automationLevel">
|
|
<option value="">선택</option>
|
|
<option value="단순 자동화">단순 자동화 (사람이 결과를 검토·확정)</option>
|
|
<option value="AI 기반 의사결정">AI 기반 의사결정 (AI가 판단하고 사람이 승인)</option>
|
|
<option value="완전 무인화">완전 무인화 (AI가 처음부터 끝까지 수행)</option>
|
|
</select>
|
|
</label>
|
|
|
|
<h3 class="full">4. 데이터 준비 상태</h3>
|
|
<label>데이터 준비 여부
|
|
<select name="dataReadiness">
|
|
<option value="">선택</option>
|
|
<option value="준비완료">준비완료</option>
|
|
<option value="준비중">준비중</option>
|
|
<option value="미준비">미준비</option>
|
|
</select>
|
|
</label>
|
|
<label>데이터 위치 <input type="text" name="dataLocation" placeholder="예: 사내 DB / 업무 PC / 외부 API" /></label>
|
|
<label>개인정보 포함
|
|
<select name="personalInfo">
|
|
<option value="">선택</option>
|
|
<option value="포함">포함</option>
|
|
<option value="미포함">미포함</option>
|
|
<option value="확인 필요">확인 필요</option>
|
|
</select>
|
|
</label>
|
|
<label>데이터 정합성
|
|
<select name="dataQuality">
|
|
<option value="">선택</option>
|
|
<option value="양호">양호</option>
|
|
<option value="보통">보통</option>
|
|
<option value="정제 필요">정제 필요</option>
|
|
</select>
|
|
</label>
|
|
<label>데이터 건수 <input type="text" name="dataCount" placeholder="예: 약 10,000건" /></label>
|
|
|
|
<h3 class="full">5. 목표 및 기대 효과</h3>
|
|
<label>업무 시간 단축 <input type="text" name="timeReduction" placeholder="예: 30% 단축" /></label>
|
|
<label>오류율 감소 <input type="text" name="errorReduction" placeholder="예: 10% → 3%" /></label>
|
|
<label>월 처리량 증가 <input type="text" name="volumeIncrease" placeholder="예: 2배 증가" /></label>
|
|
<label>비용 절감 <input type="text" name="costReduction" placeholder="예: 월 200만원" /></label>
|
|
<label>응답/처리 시간 <input type="text" name="responseTime" placeholder="예: 2분 → 30초" /></label>
|
|
<label>기타 지표 <input type="text" name="otherMetrics" placeholder="직접 기재" /></label>
|
|
<label>연간 절감 비용 <input type="text" name="annualSavings" placeholder="예: 약 2,400만원/년" /></label>
|
|
<label>인력 대체 시간 <input type="text" name="laborReplacement" placeholder="예: 월 80시간" /></label>
|
|
<label>매출 증가 예상 <input type="text" name="revenueIncrease" placeholder="예: 해당 없음" /></label>
|
|
<label class="full">기타 <input type="text" name="otherEffects" placeholder="직접 기재" /></label>
|
|
|
|
<h3 class="full">6. 예상 AI 툴 및 인프라</h3>
|
|
<label class="full">필요 기술 스택 (쉼표 구분) <input type="text" name="techStackStr" placeholder="예: 노코드 워크플로우, LLM, OCR" /></label>
|
|
|
|
<h3 class="full">7. 리스크 및 제약사항</h3>
|
|
<label class="full">해당되는 리스크 (쉼표 구분) <input type="text" name="risksStr" placeholder="예: 개인정보 규제, 법적 이슈" /></label>
|
|
<label class="full">상세 설명 <textarea name="riskDetail" rows="2" placeholder="리스크 및 제약사항에 대한 추가 설명"></textarea></label>
|
|
|
|
<h3 class="full">8. 작성 완료 신청서 업로드</h3>
|
|
<label class="full">
|
|
<span class="label-text">AX_과제_신청서.docx<span class="required">*</span></span>
|
|
<input type="file" name="applicationFile" id="axApplicationFile" accept=".docx,.doc" />
|
|
<span class="form-hint" id="axFileHint">다운로드한 신청서를 작성 후 업로드해 주세요.</span>
|
|
<span class="form-hint" id="axFileEditHint" style="display:none">수정 시 기존 파일이 있습니다. 변경 시에만 새 파일을 선택하세요.</span>
|
|
</label>
|
|
|
|
<h3 class="full">9. 현업 참여 확약</h3>
|
|
<label class="full">
|
|
<span class="label-text">현업 참여 확약<span class="required">*</span></span>
|
|
<input type="checkbox" name="participationPledge" value="1" required />
|
|
프로젝트 수행 기간(약 1주일) 동안 매일 6시간 이상 AI담당팀과 협업, 실제 업무 데이터 제공, 결과물 테스트·피드백, 유지보수 1차 책임 인지에 동의합니다.
|
|
</label>
|
|
|
|
<div class="form-actions full">
|
|
<button type="button" class="btn-ghost" onclick="document.getElementById('axApplyForm').reset()">초기화</button>
|
|
<button
|
|
type="submit"
|
|
class="top-action"
|
|
id="axSubmitBtn"
|
|
<% if (!axDlSubmitOk) { %>disabled aria-disabled="true" title="로그인 후 이용 가능합니다."<% } %>
|
|
>
|
|
신청하기
|
|
</button>
|
|
<button type="button" class="btn-ghost" id="axCancelEditBtn" style="display:none">취소하기</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
<% if (typeof adminMode !== 'undefined' && adminMode) { %>
|
|
<div id="axDeleteModal" style="display:none;position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1000;align-items:center;justify-content:center" class="flex-center">
|
|
<div style="background:#fff;padding:1.5rem;border-radius:8px;max-width:400px;width:90%;box-shadow:0 4px 20px rgba(0,0,0,.2)">
|
|
<h3 style="margin:0 0 1rem">삭제 확인</h3>
|
|
<div id="axDeleteModalBody" style="font-size:0.9rem;line-height:1.6;margin-bottom:1rem"></div>
|
|
<p style="margin:0 0 1rem"><strong>이 신청을 삭제할까요?</strong></p>
|
|
<div style="display:flex;gap:0.5rem;justify-content:flex-end">
|
|
<button type="button" id="axDeleteModalNo" class="btn-ghost">아니오</button>
|
|
<button type="button" id="axDeleteModalYes" class="top-action" style="background:#c00">네</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<% } %>
|
|
<script>
|
|
(function() {
|
|
var form = document.getElementById('axApplyForm');
|
|
if (!form) return;
|
|
var axDlSubmitOk = (document.body.getAttribute('data-ax-apply-download-submit-allowed') || '0') === '1';
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
if (!axDlSubmitOk) return;
|
|
var editId = (form.querySelector('#axEditId') || {}).value || '';
|
|
var fileInput = form.querySelector('input[name="applicationFile"]');
|
|
var isEdit = !!editId.trim();
|
|
var isAdmin = (document.body.getAttribute('data-ax-admin-mode') || '0') === '1';
|
|
var dept = (form.querySelector('input[name="department"]') || {}).value || '';
|
|
var nameVal = (form.querySelector('input[name="name"]') || {}).value || '';
|
|
var isSample = ((dept || '').trim() === '샘플' && (nameVal || '').trim() === '데이터');
|
|
if (isEdit && isSample && !isAdmin) {
|
|
alert('샘플 데이터는 참고용으로 수정할 수 없습니다.');
|
|
return;
|
|
}
|
|
if (!isEdit && (!fileInput || !fileInput.files || !fileInput.files.length)) {
|
|
alert('작성 완료 신청서(.docx) 파일을 업로드해 주세요.');
|
|
return;
|
|
}
|
|
var fd = new FormData(form);
|
|
var btn = form.querySelector('button[type="submit"]');
|
|
btn.disabled = true;
|
|
var url = isEdit ? '/api/ax-apply/' + editId : '/api/ax-apply';
|
|
var method = isEdit ? 'PUT' : 'POST';
|
|
fetch(url, {
|
|
method: method,
|
|
body: fd
|
|
})
|
|
.then(function(r) {
|
|
return r.json().then(function(res) {
|
|
if (r.ok && res.ok) { alert(isEdit ? '수정되었습니다.' : '신청이 완료되었습니다.'); window.location.reload(); }
|
|
else { alert(res.error || res.message || '저장 실패'); }
|
|
}).catch(function() {
|
|
if (r.status === 403) alert('접근이 거부되었습니다. 서버 설정을 확인해주세요.');
|
|
else alert('저장 중 오류가 발생했습니다.');
|
|
});
|
|
})
|
|
.catch(function() { alert('저장 중 오류가 발생했습니다.'); })
|
|
.finally(function() { btn.disabled = false; });
|
|
});
|
|
})();
|
|
(function() {
|
|
var btn = document.getElementById('axApplyListQueryBtn');
|
|
var form = document.getElementById('axApplyForm');
|
|
var wrap = document.getElementById('axAssignmentsListWrap');
|
|
if (!btn || !form || !wrap) return;
|
|
btn.addEventListener('click', function() {
|
|
var dept = (form.querySelector('input[name="department"]') || {}).value || '';
|
|
var name = (form.querySelector('input[name="name"]') || {}).value || '';
|
|
var email = (form.querySelector('input[name="email"]') || {}).value || '';
|
|
if (!dept.trim() || !name.trim() || !email.trim()) {
|
|
alert('소속 부서, 이름, 이메일을 모두 입력해 주세요.');
|
|
return;
|
|
}
|
|
btn.disabled = true;
|
|
fetch('/api/ax-apply-list?department=' + encodeURIComponent(dept) + '&name=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email))
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(list) {
|
|
if (!Array.isArray(list)) list = [];
|
|
if (list.length === 0) {
|
|
wrap.innerHTML = '<p class="empty">신청된 과제가 없습니다.</p>';
|
|
return;
|
|
}
|
|
var html = '<div class="table-wrap"><table class="data-table"><thead><tr><th>순번</th><th>신청일</th><th>소속 부서</th><th>이름</th><th>사번</th><th>직급</th><th>이메일</th><th>AI에게 원하는 것</th><th>신청서</th><th>상태</th><th>수정</th></tr></thead><tbody>';
|
|
list.forEach(function(a, idx) {
|
|
var aiExp = (a.aiExpectation || '-');
|
|
var aiExpTitle = (a.aiExpectation || '').replace(/"/g, '"');
|
|
var aiExpShort = aiExp.length > 30 ? (a.aiExpectation || '').slice(0, 30) + '…' : aiExp;
|
|
var fileLink = a.applicationFile ? '<a href="' + a.applicationFile + '" target="_blank" download>보기</a>' : '-';
|
|
html += '<tr><td>' + (list.length - idx) + '</td><td>' + new Date(a.createdAt).toLocaleDateString('ko-KR') + '</td><td>' + (a.department || '-') + '</td><td>' + (a.name || '-') + '</td><td>' + (a.employeeId || '-') + '</td><td>' + (a.position || '-') + '</td><td>' + (a.email || '-') + '</td><td class="cell-truncate" title="' + aiExpTitle + '">' + aiExpShort + '</td><td>' + fileLink + '</td><td>' + (a.status || '신청') + '</td><td><a href="#" class="ax-edit-link" data-id="' + (a.id || '') + '">수정</a></td></tr>';
|
|
});
|
|
html += '</tbody></table></div>';
|
|
wrap.innerHTML = html;
|
|
})
|
|
.catch(function() { wrap.innerHTML = '<p class="empty">조회 중 오류가 발생했습니다.</p>'; })
|
|
.finally(function() { btn.disabled = false; });
|
|
});
|
|
})();
|
|
(function() {
|
|
var wrap = document.getElementById('axAssignmentsListWrap');
|
|
var form = document.getElementById('axApplyForm');
|
|
var editIdEl = document.getElementById('axEditId');
|
|
var submitBtn = document.getElementById('axSubmitBtn');
|
|
var cancelBtn = document.getElementById('axCancelEditBtn');
|
|
var initBtn = form ? form.querySelector('button[onclick*="reset"]') : null;
|
|
var fileHint = document.getElementById('axFileHint');
|
|
var fileEditHint = document.getElementById('axFileEditHint');
|
|
var axDlSubmitOk = (document.body.getAttribute('data-ax-apply-download-submit-allowed') || '0') === '1';
|
|
function applyAxDlSubmitGate() {
|
|
if (!submitBtn || axDlSubmitOk) return;
|
|
submitBtn.disabled = true;
|
|
submitBtn.setAttribute('disabled', 'disabled');
|
|
submitBtn.setAttribute('aria-disabled', 'true');
|
|
submitBtn.title = '로그인 후 이용 가능합니다.';
|
|
submitBtn.style.pointerEvents = '';
|
|
submitBtn.classList.remove('ax-sample-readonly');
|
|
}
|
|
function setEditMode(on) {
|
|
if (!editIdEl || !submitBtn || !cancelBtn) return;
|
|
if (on) {
|
|
editIdEl.value = editIdEl.value || '';
|
|
submitBtn.textContent = '수정하기';
|
|
submitBtn.style.display = '';
|
|
cancelBtn.style.display = '';
|
|
if (initBtn) initBtn.style.display = 'none';
|
|
if (fileHint) fileHint.style.display = 'none';
|
|
if (fileEditHint) fileEditHint.style.display = '';
|
|
applyAxDlSubmitGate();
|
|
} else {
|
|
editIdEl.value = '';
|
|
submitBtn.textContent = '신청하기';
|
|
submitBtn.style.display = '';
|
|
cancelBtn.style.display = 'none';
|
|
if (initBtn) initBtn.style.display = '';
|
|
if (fileHint) fileHint.style.display = '';
|
|
if (fileEditHint) fileEditHint.style.display = 'none';
|
|
if (axDlSubmitOk) {
|
|
submitBtn.disabled = false;
|
|
submitBtn.removeAttribute('disabled');
|
|
submitBtn.removeAttribute('aria-disabled');
|
|
submitBtn.classList.remove('ax-sample-readonly');
|
|
submitBtn.title = '';
|
|
submitBtn.style.pointerEvents = '';
|
|
} else {
|
|
applyAxDlSubmitGate();
|
|
}
|
|
}
|
|
}
|
|
function populateForm(a) {
|
|
if (!form || !a) return;
|
|
var set = function(name, val) { var el = form.querySelector('[name="' + name + '"]'); if (el) el.value = val || ''; };
|
|
var setCheck = function(name, val) { var el = form.querySelector('[name="' + name + '"]'); if (el) el.checked = !!val; };
|
|
set('department', a.department);
|
|
set('name', a.name);
|
|
set('employeeId', a.employeeId);
|
|
set('position', a.position);
|
|
set('phone', a.phone);
|
|
set('email', a.email);
|
|
set('workProcessDescription', a.workProcessDescription);
|
|
set('painPoint', a.painPoint);
|
|
set('currentTimeSpent', a.currentTimeSpent);
|
|
set('errorRateBefore', a.errorRateBefore);
|
|
set('collaborationDepts', a.collaborationDepts);
|
|
set('reasonToSolve', a.reasonToSolve);
|
|
set('aiExpectation', a.aiExpectation);
|
|
set('outputType', a.outputType);
|
|
set('automationLevel', a.automationLevel);
|
|
set('dataReadiness', a.dataReadiness);
|
|
set('dataLocation', a.dataLocation);
|
|
set('personalInfo', a.personalInfo);
|
|
set('dataQuality', a.dataQuality);
|
|
set('dataCount', a.dataCount);
|
|
set('timeReduction', a.timeReduction);
|
|
set('errorReduction', a.errorReduction);
|
|
set('volumeIncrease', a.volumeIncrease);
|
|
set('costReduction', a.costReduction);
|
|
set('responseTime', a.responseTime);
|
|
set('otherMetrics', a.otherMetrics);
|
|
set('annualSavings', a.annualSavings);
|
|
set('laborReplacement', a.laborReplacement);
|
|
set('revenueIncrease', a.revenueIncrease);
|
|
set('otherEffects', a.otherEffects);
|
|
set('techStackStr', Array.isArray(a.techStack) ? a.techStack.join(', ') : (a.techStack || ''));
|
|
set('risksStr', Array.isArray(a.risks) ? a.risks.join(', ') : (a.risks || ''));
|
|
set('riskDetail', a.riskDetail);
|
|
setCheck('participationPledge', a.participationPledge);
|
|
if (editIdEl) editIdEl.value = a.id || '';
|
|
setEditMode(true);
|
|
var isAdmin = (document.body.getAttribute('data-ax-admin-mode') || '0') === '1';
|
|
var deptVal = (a.department || a.department_name || '').toString().trim();
|
|
var nameVal = (a.name || a.name_ko || '').toString().trim();
|
|
var isSample = (deptVal === '샘플' && nameVal === '데이터');
|
|
if (submitBtn) {
|
|
if (isSample && !isAdmin) {
|
|
submitBtn.disabled = true;
|
|
submitBtn.setAttribute('disabled', 'disabled');
|
|
submitBtn.setAttribute('aria-disabled', 'true');
|
|
submitBtn.classList.add('ax-sample-readonly');
|
|
submitBtn.title = '샘플 데이터는 참고용으로 수정할 수 없습니다.';
|
|
submitBtn.style.pointerEvents = 'none';
|
|
} else if (axDlSubmitOk) {
|
|
submitBtn.disabled = false;
|
|
submitBtn.removeAttribute('disabled');
|
|
submitBtn.removeAttribute('aria-disabled');
|
|
submitBtn.classList.remove('ax-sample-readonly');
|
|
submitBtn.title = '';
|
|
submitBtn.style.pointerEvents = '';
|
|
} else {
|
|
applyAxDlSubmitGate();
|
|
}
|
|
}
|
|
}
|
|
if (wrap) {
|
|
wrap.addEventListener('click', function(e) {
|
|
var editLink = e.target && e.target.closest && e.target.closest('.ax-edit-link');
|
|
var deleteLink = e.target && e.target.closest && e.target.closest('.ax-delete-link');
|
|
if (editLink && form) {
|
|
e.preventDefault();
|
|
var id = (editLink.getAttribute('data-id') || '').trim();
|
|
if (!id) return;
|
|
var dept = (form.querySelector('input[name="department"]') || {}).value || '';
|
|
var name = (form.querySelector('input[name="name"]') || {}).value || '';
|
|
var email = (form.querySelector('input[name="email"]') || {}).value || '';
|
|
var q = '?department=' + encodeURIComponent(dept) + '&name=' + encodeURIComponent(name) + '&email=' + encodeURIComponent(email);
|
|
fetch('/api/ax-apply/' + id + q)
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(a) { if (a && a.id) populateForm(a); else alert(a && a.error ? a.error : '조회 실패'); })
|
|
.catch(function() { alert('조회 중 오류가 발생했습니다.'); });
|
|
return;
|
|
}
|
|
if (deleteLink) {
|
|
e.preventDefault();
|
|
var modal = document.getElementById('axDeleteModal');
|
|
var modalBody = document.getElementById('axDeleteModalBody');
|
|
if (!modal || !modalBody) return;
|
|
var id = (deleteLink.getAttribute('data-id') || '').trim();
|
|
var createdAt = deleteLink.getAttribute('data-created-at') || '-';
|
|
var dept = deleteLink.getAttribute('data-department') || '-';
|
|
var name = deleteLink.getAttribute('data-name') || '-';
|
|
var empId = deleteLink.getAttribute('data-employee-id') || '-';
|
|
var pos = deleteLink.getAttribute('data-position') || '-';
|
|
var email = deleteLink.getAttribute('data-email') || '-';
|
|
if (createdAt !== '-' && createdAt) {
|
|
try { createdAt = new Date(createdAt).toLocaleDateString('ko-KR'); } catch(err) {}
|
|
}
|
|
modalBody.innerHTML = '신청일: ' + createdAt + '<br>소속 부서: ' + dept + '<br>이름: ' + name + '<br>사번: ' + empId + '<br>직급: ' + pos + '<br>이메일: ' + email;
|
|
modal.dataset.deleteId = id;
|
|
modal.style.display = 'flex';
|
|
}
|
|
});
|
|
}
|
|
(function() {
|
|
var modal = document.getElementById('axDeleteModal');
|
|
var btnYes = document.getElementById('axDeleteModalYes');
|
|
var btnNo = document.getElementById('axDeleteModalNo');
|
|
if (!modal || !btnYes || !btnNo) return;
|
|
btnNo.addEventListener('click', function() { modal.style.display = 'none'; modal.dataset.deleteId = ''; });
|
|
modal.addEventListener('click', function(e) { if (e.target === modal) { modal.style.display = 'none'; modal.dataset.deleteId = ''; } });
|
|
btnYes.addEventListener('click', function() {
|
|
var id = (modal.dataset.deleteId || '').trim();
|
|
if (!id) { modal.style.display = 'none'; return; }
|
|
btnYes.disabled = true;
|
|
fetch('/api/ax-apply/' + id, { method: 'DELETE' })
|
|
.then(function(r) { return r.json(); })
|
|
.then(function(res) {
|
|
if (res.ok) { modal.style.display = 'none'; modal.dataset.deleteId = ''; window.location.reload(); }
|
|
else { alert(res.error || '삭제 실패'); }
|
|
})
|
|
.catch(function() { alert('삭제 중 오류가 발생했습니다.'); })
|
|
.finally(function() { btnYes.disabled = false; });
|
|
});
|
|
})();
|
|
if (cancelBtn) {
|
|
cancelBtn.addEventListener('click', function() {
|
|
if (editIdEl) editIdEl.value = '';
|
|
setEditMode(false);
|
|
if (form) form.reset();
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|