Files
ai_platform/views/ax-apply.ejs
dsyoon 9f647cd783 feat(ui): 파비콘을 xavis-logo.png로 통일
- partials/favicon.ejs로 icon·apple-touch-icon 링크
- 전 페이지 head에 include, /favicon.ico는 동일 PNG 제공
- 인라인 403 HTML에도 favicon 링크

Made-with: Cursor
2026-04-05 22:33:36 +09:00

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, '&quot;') %>"><%= (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, '&quot;') %>" data-department="<%= (a.department || '').toString().replace(/"/g, '&quot;') %>" data-name="<%= (a.name || '').toString().replace(/"/g, '&quot;') %>" data-employee-id="<%= (a.employeeId || '').toString().replace(/"/g, '&quot;') %>" data-position="<%= (a.position || '').toString().replace(/"/g, '&quot;') %>" data-email="<%= (a.email || '').toString().replace(/"/g, '&quot;') %>">삭제</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, '&quot;');
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>