v6:HWPX 템플릿 분석·저장·관리_20260128
This commit is contained in:
@@ -19,6 +19,334 @@
|
||||
--ui-error: #f85149;
|
||||
--ui-info: #58a6ff;
|
||||
}
|
||||
|
||||
/* ===== 사용자 템플릿 영역 ===== */
|
||||
.user-templates-section {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
margin: 10px 0;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.user-templates-section::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.user-templates-section::-webkit-scrollbar-thumb {
|
||||
background: var(--ui-border);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.user-templates-section::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--ui-dim);
|
||||
}
|
||||
|
||||
.template-divider {
|
||||
height: 1px;
|
||||
background: var(--ui-border);
|
||||
margin: 10px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.template-divider::after {
|
||||
content: '사용자 템플릿';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: var(--ui-nav);
|
||||
padding: 0 8px;
|
||||
font-size: 9px;
|
||||
color: var(--ui-dim);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
/* 사용자 템플릿 아이템 */
|
||||
.user-template-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
background: var(--ui-panel);
|
||||
border: 1px solid var(--ui-border);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
position: relative;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.user-template-item:hover {
|
||||
background: var(--ui-hover);
|
||||
border-color: var(--ui-dim);
|
||||
}
|
||||
|
||||
.user-template-item.selected {
|
||||
border-color: var(--ui-accent);
|
||||
background: rgba(0, 200, 83, 0.1);
|
||||
}
|
||||
|
||||
.user-template-item .label {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.user-template-item .delete-btn {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--ui-dim);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.user-template-item:hover .delete-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.user-template-item .delete-btn:hover {
|
||||
background: var(--ui-error);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 템플릿 추가 모달 */
|
||||
.template-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.75);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.template-modal.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.template-modal-content {
|
||||
background: var(--ui-panel);
|
||||
border: 1px solid var(--ui-border);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
width: 420px;
|
||||
box-shadow: 0 15px 50px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.template-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.template-modal-title {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--ui-accent);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.template-modal-close {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--ui-dim);
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.template-modal-close:hover {
|
||||
background: var(--ui-hover);
|
||||
color: var(--ui-text);
|
||||
}
|
||||
|
||||
.template-input-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.template-input-label {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--ui-dim);
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.template-name-input {
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid var(--ui-border);
|
||||
border-radius: 6px;
|
||||
background: var(--ui-bg);
|
||||
color: var(--ui-text);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.template-name-input:focus {
|
||||
outline: none;
|
||||
border-color: var(--ui-accent);
|
||||
}
|
||||
|
||||
.template-dropzone {
|
||||
border: 2px dashed var(--ui-border);
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.template-dropzone:hover,
|
||||
.template-dropzone.dragover {
|
||||
border-color: var(--ui-accent);
|
||||
background: rgba(0, 200, 83, 0.05);
|
||||
}
|
||||
|
||||
.template-dropzone-icon {
|
||||
font-size: 36px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.template-dropzone-text {
|
||||
font-size: 13px;
|
||||
color: var(--ui-text);
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.template-dropzone-hint {
|
||||
font-size: 11px;
|
||||
color: var(--ui-dim);
|
||||
}
|
||||
|
||||
.template-dropzone-file {
|
||||
display: none;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px;
|
||||
background: var(--ui-bg);
|
||||
border-radius: 6px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.template-dropzone-file.show {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.template-dropzone-file .filename {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
color: var(--ui-accent);
|
||||
}
|
||||
|
||||
.template-dropzone-file .remove {
|
||||
color: var(--ui-dim);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.template-dropzone-file .remove:hover {
|
||||
color: var(--ui-error);
|
||||
}
|
||||
|
||||
.template-submit-btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: linear-gradient(135deg, var(--ui-accent), #00a844);
|
||||
color: #003300;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-top: 20px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.template-submit-btn:hover:not(:disabled) {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 15px rgba(0, 200, 83, 0.3);
|
||||
}
|
||||
|
||||
.template-submit-btn:disabled {
|
||||
background: var(--ui-border);
|
||||
color: var(--ui-dim);
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.template-submit-btn .spinner {
|
||||
display: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid transparent;
|
||||
border-top-color: currentColor;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
/* 사용자 템플릿 프리뷰 */
|
||||
.user-template-preview {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 280px;
|
||||
background: var(--ui-panel);
|
||||
border: 1px solid var(--ui-border);
|
||||
border-radius: 12px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.5);
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.user-template-preview::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -8px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border: 8px solid transparent;
|
||||
border-left-color: var(--ui-panel);
|
||||
}
|
||||
|
||||
.user-template-preview.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.preview-analyzed-features {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.preview-analyzed-feature {
|
||||
font-size: 11px;
|
||||
color: var(--ui-accent);
|
||||
padding: 3px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.preview-analyzed-feature::before {
|
||||
content: '✓';
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
@@ -1354,9 +1682,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="userTemplatesArea" style="display: none;">
|
||||
<div class="template-divider"></div>
|
||||
<div class="user-templates-section" id="userTemplatesList">
|
||||
<!-- 동적으로 추가됨 -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 템플릿 추가 버튼 -->
|
||||
<button class="add-template-btn" onclick="addTemplate()">+ 템플릿 추가</button>
|
||||
<button class="add-template-btn" onclick="openTemplateModal()">+ 템플릿 추가</button>
|
||||
</div>
|
||||
|
||||
<!-- 기획서 옵션 -->
|
||||
@@ -1411,7 +1746,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 템플릿 옵션 (요청사항만) -->
|
||||
<div id="templateOptions" style="display:none;">
|
||||
<div class="option-section">
|
||||
<div class="option-title">요청사항</div>
|
||||
<textarea class="request-textarea" id="templateInstructionInput" placeholder="예: 요약을 상세하게 작성해줘 예: 특정 섹션 강조"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 요청사항 -->
|
||||
<div class="option-section">
|
||||
<div class="option-title">요청사항</div>
|
||||
@@ -1502,6 +1845,232 @@
|
||||
let selectedText = '';
|
||||
let selectedRange = null;
|
||||
|
||||
|
||||
// ===== 템플릿 관련 변수 =====
|
||||
let userTemplates = []; // [{id, name, features, created_at}, ...]
|
||||
let selectedTemplateFile = null;
|
||||
|
||||
// ===== 템플릿 모달 =====
|
||||
function openTemplateModal() {
|
||||
document.getElementById('templateModal').classList.add('active');
|
||||
document.getElementById('templateNameInput').value = '';
|
||||
removeTemplateFile();
|
||||
|
||||
// 이벤트 리스너 재연결
|
||||
document.getElementById('templateNameInput').oninput = updateTemplateSubmitBtn;
|
||||
}
|
||||
|
||||
function closeTemplateModal() {
|
||||
document.getElementById('templateModal').classList.remove('active');
|
||||
}
|
||||
|
||||
function handleTemplateFile(input) {
|
||||
if (input.files.length > 0) {
|
||||
handleTemplateFileSelect(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function handleTemplateFileSelect(file) {
|
||||
const validExtensions = ['.hwpx', '.hwp', '.pdf'];
|
||||
const ext = '.' + file.name.split('.').pop().toLowerCase();
|
||||
|
||||
if (!validExtensions.includes(ext)) {
|
||||
alert('지원하지 않는 파일 형식입니다.\n(HWPX, HWP, PDF만 지원)');
|
||||
return;
|
||||
}
|
||||
|
||||
selectedTemplateFile = file;
|
||||
document.getElementById('templateFileName').textContent = file.name;
|
||||
document.getElementById('templateFileInfo').classList.add('show');
|
||||
document.getElementById('templateDropzone').style.display = 'none';
|
||||
|
||||
// 파일명에서 템플릿 이름 자동 추출
|
||||
const nameInput = document.getElementById('templateNameInput');
|
||||
if (!nameInput.value.trim()) {
|
||||
const baseName = file.name.replace(/\.[^/.]+$/, '');
|
||||
nameInput.value = baseName;
|
||||
}
|
||||
|
||||
updateTemplateSubmitBtn();
|
||||
}
|
||||
|
||||
function removeTemplateFile() {
|
||||
selectedTemplateFile = null;
|
||||
document.getElementById('templateFileInput').value = '';
|
||||
document.getElementById('templateFileInfo').classList.remove('show');
|
||||
document.getElementById('templateDropzone').style.display = 'block';
|
||||
updateTemplateSubmitBtn();
|
||||
}
|
||||
|
||||
function updateTemplateSubmitBtn() {
|
||||
const nameInput = document.getElementById('templateNameInput');
|
||||
const btn = document.getElementById('templateSubmitBtn');
|
||||
btn.disabled = !selectedTemplateFile || !nameInput.value.trim();
|
||||
}
|
||||
|
||||
document.getElementById('templateNameInput')?.addEventListener('input', updateTemplateSubmitBtn);
|
||||
|
||||
// ===== 템플릿 제출 =====
|
||||
async function submitTemplate() {
|
||||
const name = document.getElementById('templateNameInput').value.trim();
|
||||
if (!name || !selectedTemplateFile) return;
|
||||
|
||||
const btn = document.getElementById('templateSubmitBtn');
|
||||
const spinner = document.getElementById('templateSpinner');
|
||||
const text = document.getElementById('templateSubmitText');
|
||||
|
||||
btn.disabled = true;
|
||||
spinner.style.display = 'inline-block';
|
||||
text.textContent = '분석 중...';
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('name', name);
|
||||
formData.append('file', selectedTemplateFile);
|
||||
|
||||
const response = await fetch('/analyze-template', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error) {
|
||||
throw new Error(data.error);
|
||||
}
|
||||
|
||||
// 템플릿 목록에 추가
|
||||
userTemplates.push(data.template);
|
||||
renderUserTemplates();
|
||||
closeTemplateModal();
|
||||
|
||||
setStatus(`템플릿 "${name}" 추가 완료`, true);
|
||||
|
||||
} catch (error) {
|
||||
alert('템플릿 분석 오류: ' + error.message);
|
||||
} finally {
|
||||
btn.disabled = false;
|
||||
spinner.style.display = 'none';
|
||||
text.textContent = '✨ 분석 및 추가';
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 템플릿 목록 렌더링 =====
|
||||
function renderUserTemplates() {
|
||||
const container = document.getElementById('userTemplatesList');
|
||||
const area = document.getElementById('userTemplatesArea');
|
||||
|
||||
if (userTemplates.length === 0) {
|
||||
area.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
area.style.display = 'block';
|
||||
container.innerHTML = userTemplates.map((tpl, idx) => `
|
||||
<div class="user-template-item" data-id="${tpl.id}" onclick="selectDocType('template_${tpl.id}')">
|
||||
<input type="radio" name="docType">
|
||||
<span class="label">📑 ${tpl.name}</span>
|
||||
<button class="delete-btn" onclick="event.stopPropagation(); deleteTemplate('${tpl.id}')" title="삭제">✕</button>
|
||||
|
||||
<div class="user-template-preview doc-type-preview">
|
||||
<div class="preview-thumbnail report">
|
||||
<div class="line h1"></div>
|
||||
<div class="line body"></div>
|
||||
<div class="line body" style="width:90%"></div>
|
||||
<div class="line h2"></div>
|
||||
<div class="line body" style="width:85%"></div>
|
||||
</div>
|
||||
<div class="preview-title">${tpl.name}</div>
|
||||
<div class="preview-desc">사용자 정의 템플릿</div>
|
||||
<div class="preview-analyzed-features">
|
||||
${(tpl.features || []).map(f => `<div class="preview-analyzed-feature">${f}</div>`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
// 호버 이벤트 연결
|
||||
container.querySelectorAll('.user-template-item').forEach(item => {
|
||||
const preview = item.querySelector('.user-template-preview');
|
||||
if (!preview) return;
|
||||
|
||||
item.addEventListener('mouseenter', (e) => {
|
||||
const rect = item.getBoundingClientRect();
|
||||
preview.style.top = (rect.top + rect.height / 2 - 150) + 'px';
|
||||
preview.style.left = (rect.left - 295) + 'px';
|
||||
preview.classList.add('show');
|
||||
});
|
||||
|
||||
item.addEventListener('mouseleave', () => {
|
||||
preview.classList.remove('show');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ===== 템플릿 목록 로드 =====
|
||||
async function loadUserTemplates() {
|
||||
try {
|
||||
const response = await fetch('/templates');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.templates) {
|
||||
userTemplates = data.templates;
|
||||
renderUserTemplates();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('템플릿 목록 로드 실패:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 문서 유형 선택 =====
|
||||
function selectDocType(type) {
|
||||
// PPT는 비활성화
|
||||
if (type === 'presentation') {
|
||||
return;
|
||||
}
|
||||
|
||||
currentDocType = type;
|
||||
|
||||
// 모든 doc-type-item 선택 해제
|
||||
document.querySelectorAll('.doc-type-item').forEach(item => {
|
||||
item.classList.remove('selected');
|
||||
const radio = item.querySelector('input[type="radio"]');
|
||||
if (radio) radio.checked = false;
|
||||
});
|
||||
|
||||
// 모든 user-template-item 선택 해제
|
||||
document.querySelectorAll('.user-template-item').forEach(item => {
|
||||
item.classList.remove('selected');
|
||||
const radio = item.querySelector('input[type="radio"]');
|
||||
if (radio) radio.checked = false;
|
||||
});
|
||||
|
||||
// 선택한 아이템 활성화
|
||||
let selectedItem;
|
||||
if (type.startsWith('template_')) {
|
||||
const templateId = type.replace('template_', '');
|
||||
selectedItem = document.querySelector(`.user-template-item[data-id="${templateId}"]`);
|
||||
} else {
|
||||
selectedItem = document.querySelector(`.doc-type-item[data-type="${type}"]`);
|
||||
}
|
||||
|
||||
if (selectedItem && !selectedItem.classList.contains('disabled')) {
|
||||
selectedItem.classList.add('selected');
|
||||
const radio = selectedItem.querySelector('input[type="radio"]');
|
||||
if (radio) radio.checked = true;
|
||||
}
|
||||
|
||||
// ⭐ 옵션 패널 전환 (3가지로 분기)
|
||||
const isBriefing = (type === 'briefing');
|
||||
const isReport = (type === 'report');
|
||||
const isTemplate = type.startsWith('template_');
|
||||
|
||||
document.getElementById('briefingOptions').style.display = isBriefing ? 'block' : 'none';
|
||||
document.getElementById('reportOptions').style.display = isReport ? 'block' : 'none';
|
||||
document.getElementById('templateOptions').style.display = isTemplate ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// ===== HWP 추출 =====
|
||||
async function exportHwp() {
|
||||
if (!generatedHTML) {
|
||||
@@ -1920,32 +2489,7 @@
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
// ===== 문서 유형 선택 =====
|
||||
function selectDocType(type) {
|
||||
if (type === 'presentation') {
|
||||
return; // PPT만 disabled
|
||||
}
|
||||
|
||||
currentDocType = type;
|
||||
document.querySelectorAll('.doc-type-item').forEach(item => {
|
||||
item.classList.remove('selected');
|
||||
if (item.dataset.type === type) {
|
||||
item.classList.add('selected');
|
||||
item.querySelector('input[type="radio"]').checked = true;
|
||||
}
|
||||
});
|
||||
|
||||
// 옵션 패널 표시/숨김
|
||||
document.getElementById('briefingOptions').style.display = (type === 'briefing') ? 'block' : 'none';
|
||||
document.getElementById('reportOptions').style.display = (type === 'report') ? 'block' : 'none';
|
||||
}
|
||||
|
||||
// ===== 템플릿 추가 =====
|
||||
function addTemplate() {
|
||||
alert('템플릿 추가 기능은 준비중입니다.\n\n향후 사용자 정의 양식을 추가할 수 있습니다.');
|
||||
}
|
||||
|
||||
// ===== 페이지 옵션 선택 =====
|
||||
// ===== 페이지 옵션 선택 =====
|
||||
function selectPageOption(option) {
|
||||
currentPageOption = option;
|
||||
document.querySelectorAll('.option-item').forEach(item => {
|
||||
@@ -1961,9 +2505,13 @@
|
||||
await generateBriefing();
|
||||
} else if (currentDocType === 'report') {
|
||||
await generateReport();
|
||||
} else if (currentDocType.startsWith('template_')) {
|
||||
// ⭐ 사용자 템플릿: 보고서와 동일하게 처리
|
||||
await generateReport();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===== 기획서 생성 (기존 로직) =====
|
||||
async function generateBriefing() {
|
||||
if (!inputContent && !folderPath && referenceLinks.length === 0) {
|
||||
@@ -2083,19 +2631,27 @@
|
||||
updateStep(i, 'done');
|
||||
}
|
||||
|
||||
let instruction = '';
|
||||
if (currentDocType === 'report') {
|
||||
instruction = document.getElementById('reportInstructionInput').value;
|
||||
} else if (currentDocType.startsWith('template_')) {
|
||||
instruction = document.getElementById('templateInstructionInput').value;
|
||||
}
|
||||
|
||||
const response = await fetch('/generate-report', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
content: inputContent, // HTML 내용 추가
|
||||
content: inputContent,
|
||||
folder_path: folderPath,
|
||||
cover: document.getElementById('reportCover').checked,
|
||||
toc: document.getElementById('reportToc').checked,
|
||||
divider: document.getElementById('reportDivider').checked,
|
||||
instruction: document.getElementById('reportInstructionInput').value
|
||||
template_id: currentDocType.startsWith('template_') ? currentDocType.replace('template_', '') : null,
|
||||
cover: currentDocType === 'report' ? document.getElementById('reportCover').checked : false,
|
||||
toc: currentDocType === 'report' ? document.getElementById('reportToc').checked : false,
|
||||
divider: currentDocType === 'report' ? document.getElementById('reportDivider').checked : false,
|
||||
instruction: instruction
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.error) {
|
||||
@@ -2333,6 +2889,33 @@
|
||||
preview.classList.remove('show');
|
||||
});
|
||||
});
|
||||
|
||||
// 드롭존 이벤트 연결
|
||||
const dropzone = document.getElementById('templateDropzone');
|
||||
if (dropzone) {
|
||||
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||
dropzone.addEventListener(eventName, (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
['dragenter', 'dragover'].forEach(eventName => {
|
||||
dropzone.addEventListener(eventName, () => dropzone.classList.add('dragover'));
|
||||
});
|
||||
['dragleave', 'drop'].forEach(eventName => {
|
||||
dropzone.addEventListener(eventName, () => dropzone.classList.remove('dragover'));
|
||||
});
|
||||
dropzone.addEventListener('drop', (e) => {
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
handleTemplateFileSelect(files[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 템플릿 목록 로드
|
||||
loadUserTemplates();
|
||||
|
||||
});
|
||||
|
||||
// Enter 키로 피드백 제출
|
||||
@@ -2352,5 +2935,41 @@
|
||||
<button class="ai-edit-btn" onclick="submitAiEdit()">✨ 수정하기</button>
|
||||
</div>
|
||||
<script src="/static/js/editor.js"></script>
|
||||
|
||||
<!-- 템플릿 추가 모달 -->
|
||||
<div class="template-modal" id="templateModal">
|
||||
<div class="template-modal-content">
|
||||
<div class="template-modal-header">
|
||||
<div class="template-modal-title">📁 템플릿 추가</div>
|
||||
<button class="template-modal-close" onclick="closeTemplateModal()">✕</button>
|
||||
</div>
|
||||
|
||||
<div class="template-input-group">
|
||||
<label class="template-input-label">템플릿 이름</label>
|
||||
<input type="text" class="template-name-input" id="templateNameInput"
|
||||
placeholder="예: 걸포4지구 교통영향평가">
|
||||
</div>
|
||||
|
||||
<div class="template-input-group">
|
||||
<label class="template-input-label">템플릿 파일</label>
|
||||
<div class="template-dropzone" id="templateDropzone" onclick="document.getElementById('templateFileInput').click()">
|
||||
<div class="template-dropzone-icon">📄</div>
|
||||
<div class="template-dropzone-text">파일을 드래그하거나 클릭하여 선택</div>
|
||||
<div class="template-dropzone-hint">HWPX, HWP, PDF 지원</div>
|
||||
</div>
|
||||
<input type="file" id="templateFileInput" accept=".hwpx,.hwp,.pdf" style="display:none" onchange="handleTemplateFile(this)">
|
||||
<div class="template-dropzone-file" id="templateFileInfo">
|
||||
<span class="filename" id="templateFileName"></span>
|
||||
<span class="remove" onclick="removeTemplateFile()">✕</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="template-submit-btn" id="templateSubmitBtn" onclick="submitTemplate()" disabled>
|
||||
<span class="spinner" id="templateSpinner"></span>
|
||||
<span id="templateSubmitText">✨ 분석 및 추가</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user