200 lines
9.7 KiB
HTML
200 lines
9.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Project Mail Manager</title>
|
|
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css" />
|
|
<link rel="stylesheet" href="/style/style.css">
|
|
</head>
|
|
<body>
|
|
<nav class="topbar">
|
|
<div class="topbar-header">
|
|
<a href="/"><h2>Project Master Test</h2></a>
|
|
</div>
|
|
<ul class="nav-list">
|
|
<li class="nav-item" onclick="location.href='/dashboard'">대시보드</li>
|
|
<li class="nav-item active" onclick="location.href='/mailTest'">메일관리</li>
|
|
<li class="nav-item">로그관리</li>
|
|
<li class="nav-item">파일관리</li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<div class="mail-wrapper">
|
|
<aside class="mail-sidebar">
|
|
<select class="project-select">
|
|
<option>라오스 ITTC 관개 교육센터</option>
|
|
<option>베트남 푸옥호아 발전소</option>
|
|
</select>
|
|
<ul class="folder-list">
|
|
<li class="folder-item active" style="list-style:none;"><span>📥 수신함</span><span>12</span></li>
|
|
<li class="folder-item" style="list-style:none;"><span>📤 발신함</span></li>
|
|
<li class="folder-item" style="list-style:none;"><span>📁 중요메일</span></li>
|
|
</ul>
|
|
</aside>
|
|
|
|
<section class="mail-list-area">
|
|
<div class="search-bar">
|
|
<input type="text" placeholder="제목, 내용, 기관 검색...">
|
|
<div style="display:flex; gap:4px;">
|
|
<select style="flex:1; padding:4px; font-size:11px;"><option>모든 상대기관</option></select>
|
|
<select style="flex:1; padding:4px; font-size:11px;"><option>전체 기간</option></select>
|
|
</div>
|
|
</div>
|
|
<div class="mail-items-container">
|
|
<div class="mail-item active">
|
|
<div style="display:flex; justify-content:space-between; margin-bottom:4px;">
|
|
<span style="font-weight:700; color:var(--primary-color);">라오스 농림부</span>
|
|
<span style="font-size:11px; color:var(--text-sub);">오후 2:30</span>
|
|
</div>
|
|
<div style="font-weight:600; font-size:12px; margin-bottom:4px;">ITTC 교육센터 착공식 일정 협의</div>
|
|
<div style="font-size:11px; color:var(--text-sub); display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;">안녕하세요. 착공식 관련하여 첨부 드리는 공문을...</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="mail-content-area">
|
|
<div class="mail-content-header">
|
|
<h2 style="font-size:18px; color:var(--primary-color); margin-bottom:8px;">ITTC 교육센터 착공식 일정 협의 요청</h2>
|
|
<div style="font-size:12px; color:var(--text-sub);"><strong>보낸사람</strong> pany.s@lao.gov.la (라오스 농림부)</div>
|
|
<div style="font-size:12px; color:var(--text-sub);"><strong>날짜</strong> 2026년 2월 26일 14:30</div>
|
|
</div>
|
|
<div class="mail-body">
|
|
안녕하세요. 이태훈 선임연구원님.<br><br>
|
|
라오스 ITTC 관개 교육센터 착공식과 관련하여 정부 측 인사의 일정을 반영한 최종 공문을 송부합니다.<br>
|
|
첨부파일의 세부 계획안을 검토하신 후, 프로젝트 대시보드의 '과업계획' 탭에 업로드 및 공유 부탁드립니다.
|
|
</div>
|
|
|
|
<div class="attachment-area">
|
|
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:12px;">
|
|
<div style="font-weight:700; font-size:13px;">첨부파일 리스트</div>
|
|
<div class="ai-toggle-wrap">
|
|
<span class="ai-label">AI 판단</span>
|
|
<label class="switch">
|
|
<input type="checkbox" id="aiToggle" checked onchange="renderFiles()">
|
|
<span class="slider"></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div id="attachmentList"></div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<script>
|
|
let currentFiles = [];
|
|
|
|
async function loadAttachments() {
|
|
try {
|
|
const res = await fetch('/attachments');
|
|
currentFiles = await res.json();
|
|
renderFiles();
|
|
} catch (e) {
|
|
console.error("Failed to load attachments:", e);
|
|
}
|
|
}
|
|
|
|
function renderFiles() {
|
|
const isAiActive = document.getElementById('aiToggle').checked;
|
|
const container = document.getElementById('attachmentList');
|
|
container.innerHTML = '';
|
|
|
|
currentFiles.forEach((file, index) => {
|
|
const item = document.createElement('div');
|
|
item.className = 'attachment-item-wrap';
|
|
item.style.marginBottom = "8px";
|
|
|
|
const btnAiClass = isAiActive ? 'btn-ai' : 'btn-normal';
|
|
|
|
item.innerHTML = `
|
|
<div class="attachment-item">
|
|
<div class="file-info">
|
|
<span style="font-size:20px;">📄</span>
|
|
<div>
|
|
<div style="font-size:12px; font-weight:700;">${file.name}</div>
|
|
<div style="font-size:10px; color:var(--text-sub);">${file.size}</div>
|
|
</div>
|
|
<span id="recommend-${index}" class="ai-recommend" style="display:none;">추천 위치 탐색 중...</span>
|
|
</div>
|
|
<div class="btn-group">
|
|
<button class="btn-upload ${btnAiClass}" onclick="startAnalysis(${index})">AI 분석</button>
|
|
<button class="btn-upload btn-normal" onclick="confirmUpload(${index})">파일 업로드</button>
|
|
</div>
|
|
</div>
|
|
<div id="log-area-${index}" class="file-log-area">
|
|
<div id="log-content-${index}"></div>
|
|
</div>
|
|
`;
|
|
container.appendChild(item);
|
|
});
|
|
}
|
|
|
|
async function startAnalysis(index) {
|
|
const file = currentFiles[index];
|
|
const logArea = document.getElementById(`log-area-${index}`);
|
|
const logContent = document.getElementById(`log-content-${index}`);
|
|
const recLabel = document.getElementById(`recommend-${index}`);
|
|
|
|
logArea.classList.add('active');
|
|
logContent.innerHTML = '<div class="log-line log-info">>>> 3중 레이어 AI 분석 엔진 가동...</div>';
|
|
recLabel.style.display = 'inline-block';
|
|
recLabel.innerText = '분석 중...';
|
|
|
|
try {
|
|
const res = await fetch(`/analyze-file?filename=${encodeURIComponent(file.name)}`);
|
|
const analysis = await res.json();
|
|
|
|
analysis.log_steps.forEach(step => {
|
|
const line = document.createElement('div');
|
|
line.className = 'log-line';
|
|
line.innerText = " " + step;
|
|
logContent.appendChild(line);
|
|
});
|
|
|
|
const resultLine = document.createElement('div');
|
|
resultLine.className = 'log-line log-success';
|
|
resultLine.style.marginTop = "8px";
|
|
resultLine.innerHTML = `[결과] ${analysis.suggested_path}<br>└ ${analysis.reason}`;
|
|
logContent.appendChild(resultLine);
|
|
|
|
// 원본 보기 추가
|
|
const details = document.createElement('details');
|
|
details.style.marginTop = "5px";
|
|
details.innerHTML = `
|
|
<summary style="color:#da8cf1; cursor:pointer; font-size:10px;">[추출 원본 데이터 확인]</summary>
|
|
<div style="color:#a0aec0; padding:8px; background:#2d3748; margin-top:5px; white-space:pre-wrap; max-height:150px; overflow-y:auto; border-radius:4px;">${analysis.raw_text}</div>
|
|
`;
|
|
logContent.appendChild(details);
|
|
|
|
recLabel.innerText = `추천: ${analysis.suggested_path}`;
|
|
if(analysis.suggested_path === "분석실패") {
|
|
recLabel.style.color = "#f21d0d";
|
|
recLabel.style.background = "#fee9e7";
|
|
}
|
|
|
|
currentFiles[index].analysis = analysis; // 결과 저장
|
|
|
|
} catch (e) {
|
|
logContent.innerHTML += '<div class="log-line" style="color:red;">ERR: 분석 오류</div>';
|
|
}
|
|
}
|
|
|
|
function confirmUpload(index) {
|
|
const file = currentFiles[index];
|
|
const path = file.analysis ? file.analysis.suggested_path : "선택한 탭";
|
|
|
|
let message = `[${file.name}] 파일을 업로드하시겠습니까?`;
|
|
if(file.analysis && file.analysis.suggested_path !== "분석실패") {
|
|
message = `AI가 추천한 위치로 업로드하시겠습니까?\n\n위치: ${path}`;
|
|
}
|
|
|
|
if (confirm(message)) {
|
|
alert("업로드가 완료되었습니다.");
|
|
}
|
|
}
|
|
|
|
loadAttachments();
|
|
</script>
|
|
</body>
|
|
</html>
|