first commit 2

This commit is contained in:
hmw1001
2026-06-11 18:47:38 +09:00
parent c768729ce6
commit 6f534e33a6
11095 changed files with 1595758 additions and 0 deletions
+394
View File
@@ -0,0 +1,394 @@
/**
* 설문 작성/수정 폼 JavaScript
*/
let questionCount = 0;
const questionTypes = {
'text': '단답형',
'textarea': '장문형',
'radio': '단일선택',
'checkbox': '다중선택',
'select': '드롭다운',
'rating': '평점',
'date': '날짜'
};
// 페이지 로드 시 초기화
document.addEventListener('DOMContentLoaded', function() {
initSurveyForm();
});
function initSurveyForm() {
// 탭 전환 이벤트
initTabs();
// 템플릿 선택 이벤트
initTemplateSelection();
// 폼 검증 이벤트
initFormValidation();
// 기존 질문들의 타입에 따라 옵션 표시
document.querySelectorAll('.question-type-select').forEach(select => {
updateQuestionType(select);
});
// URL에서 template_id가 있으면 해당 템플릿 자동 선택
const templateId = document.getElementById('templateId')?.value;
if (templateId > 0) {
const templateCard = document.querySelector(`[data-template="${templateId}"]`);
if (templateCard) {
templateCard.click();
}
}
// 질문 개수 초기화
questionCount = document.querySelectorAll('.question-item').length;
}
// 탭 전환 기능
function initTabs() {
document.querySelectorAll('.form-tab').forEach(tab => {
tab.addEventListener('click', function() {
const targetTab = this.dataset.tab;
// 탭 활성화
document.querySelectorAll('.form-tab').forEach(t => t.classList.remove('active'));
this.classList.add('active');
// 콘텐츠 표시
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(targetTab).classList.add('active');
});
});
}
// 템플릿 선택 기능
function initTemplateSelection() {
document.querySelectorAll('.template-card').forEach(card => {
card.addEventListener('click', function() {
document.querySelectorAll('.template-card').forEach(c => c.classList.remove('selected'));
this.classList.add('selected');
const templateId = this.dataset.template;
document.getElementById('templateId').value = templateId;
// 템플릿 질문 로드
if (templateId > 0) {
loadTemplateQuestions(templateId);
} else {
// 직접 작성 선택 시 기존 질문들 초기화
document.getElementById('questionsList').innerHTML = '';
questionCount = 0;
}
});
});
}
// 템플릿 질문 로드
function loadTemplateQuestions(templateId) {
fetch(`ajax_get_template.php?st_id=${templateId}`)
.then(response => response.json())
.then(data => {
if (data.success) {
// 기존 질문들 초기화
document.getElementById('questionsList').innerHTML = '';
questionCount = 0;
// 템플릿 질문들 추가
data.questions.forEach((question, index) => {
addTemplateQuestion(question, index + 1);
});
// 기본 정보도 템플릿에서 가져오기
if (data.template.st_name) {
document.querySelector('input[name="sv_title"]').value = data.template.st_name;
}
if (data.template.st_description) {
document.querySelector('textarea[name="sv_description"]').value = data.template.st_description;
}
alert('템플릿이 적용되었습니다. 질문 설정 탭에서 확인해보세요.');
} else {
alert('템플릿 로드 실패: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('템플릿 로드 중 오류가 발생했습니다.');
});
}
// 템플릿 질문 추가
function addTemplateQuestion(questionData, questionNumber) {
questionCount = questionNumber;
const optionsHtml = ['radio', 'checkbox', 'select'].includes(questionData.stq_type) && questionData.stq_options.length > 0
? `<div class="options-container" style="display: block;">
<label class="form-label">선택지</label>
<div class="options-list">
${questionData.stq_options.map((option, index) => `
<div class="option-item">
<input type="text" name="questions[${questionNumber}][options][]" class="option-input" value="${option}" placeholder="선택지 ${index + 1}">
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">삭제</button>
</div>
`).join('')}
</div>
<button type="button" class="add-option-btn" onclick="addOption(this)">선택지 추가</button>
</div>`
: `<div class="options-container" style="display: none;">
<label class="form-label">선택지</label>
<div class="options-list">
<div class="option-item">
<input type="text" name="questions[${questionNumber}][options][]" class="option-input" placeholder="선택지 1">
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">삭제</button>
</div>
<div class="option-item">
<input type="text" name="questions[${questionNumber}][options][]" class="option-input" placeholder="선택지 2">
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">삭제</button>
</div>
</div>
<button type="button" class="add-option-btn" onclick="addOption(this)">선택지 추가</button>
</div>`;
const questionHtml = `
<div class="question-item" data-question-index="${questionNumber}">
<div class="question-header">
<div style="display: flex; align-items: center;">
<div class="question-number">${questionNumber}</div>
<div style="flex: 1;">
<select name="questions[${questionNumber}][type]" class="question-type-select form-select" onchange="updateQuestionType(this)">
<option value="text" ${questionData.stq_type === 'text' ? 'selected' : ''}>단답형</option>
<option value="textarea" ${questionData.stq_type === 'textarea' ? 'selected' : ''}>장문형</option>
<option value="radio" ${questionData.stq_type === 'radio' ? 'selected' : ''}>단일선택</option>
<option value="checkbox" ${questionData.stq_type === 'checkbox' ? 'selected' : ''}>다중선택</option>
<option value="select" ${questionData.stq_type === 'select' ? 'selected' : ''}>드롭다운</option>
<option value="rating" ${questionData.stq_type === 'rating' ? 'selected' : ''}>평점</option>
<option value="date" ${questionData.stq_type === 'date' ? 'selected' : ''}>날짜</option>
</select>
</div>
</div>
<div class="question-controls">
<button type="button" class="btn-sm btn-secondary" onclick="moveQuestion(this, 'up')">↑</button>
<button type="button" class="btn-sm btn-secondary" onclick="moveQuestion(this, 'down')">↓</button>
<button type="button" class="btn-sm btn-danger" onclick="removeQuestion(this)">삭제</button>
</div>
</div>
<div class="form-group">
<label class="form-label">질문 제목</label>
<input type="text" name="questions[${questionNumber}][title]" class="form-input"
value="${questionData.stq_title}" placeholder="질문을 입력하세요" required>
</div>
<div class="form-group">
<label class="form-label">질문 설명 (선택사항)</label>
<textarea name="questions[${questionNumber}][description]" class="form-textarea"
placeholder="질문에 대한 추가 설명">${questionData.stq_description || ''}</textarea>
</div>
<div class="form-group">
<div class="checkbox-item">
<input type="checkbox" name="questions[${questionNumber}][required]" value="1" ${questionData.stq_required ? 'checked' : ''}>
<label>필수 질문</label>
</div>
</div>
${optionsHtml}
</div>
`;
document.getElementById('questionsList').insertAdjacentHTML('beforeend', questionHtml);
}
// 질문 추가
function addQuestion() {
questionCount++;
const questionHtml = `
<div class="question-item" data-question-index="${questionCount}">
<div class="question-header">
<div style="display: flex; align-items: center;">
<div class="question-number">${questionCount}</div>
<div style="flex: 1;">
<select name="questions[${questionCount}][type]" class="question-type-select form-select" onchange="updateQuestionType(this)">
<option value="text">단답형</option>
<option value="textarea">장문형</option>
<option value="radio">단일선택</option>
<option value="checkbox">다중선택</option>
<option value="select">드롭다운</option>
<option value="rating">평점</option>
<option value="date">날짜</option>
</select>
</div>
</div>
<div class="question-controls">
<button type="button" class="btn-sm btn-secondary" onclick="moveQuestion(this, 'up')">↑</button>
<button type="button" class="btn-sm btn-secondary" onclick="moveQuestion(this, 'down')">↓</button>
<button type="button" class="btn-sm btn-danger" onclick="removeQuestion(this)">삭제</button>
</div>
</div>
<div class="form-group">
<label class="form-label">질문 제목</label>
<input type="text" name="questions[${questionCount}][title]" class="form-input" placeholder="질문을 입력하세요" required>
</div>
<div class="form-group">
<label class="form-label">질문 설명 (선택사항)</label>
<textarea name="questions[${questionCount}][description]" class="form-textarea" placeholder="질문에 대한 추가 설명"></textarea>
</div>
<div class="form-group">
<div class="checkbox-item">
<input type="checkbox" name="questions[${questionCount}][required]" value="1">
<label>필수 질문</label>
</div>
</div>
<div class="options-container" style="display: none;">
<label class="form-label">선택지</label>
<div class="options-list">
<div class="option-item">
<input type="text" name="questions[${questionCount}][options][]" class="option-input" placeholder="선택지 1">
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">삭제</button>
</div>
<div class="option-item">
<input type="text" name="questions[${questionCount}][options][]" class="option-input" placeholder="선택지 2">
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">삭제</button>
</div>
</div>
<button type="button" class="add-option-btn" onclick="addOption(this)">선택지 추가</button>
</div>
</div>
`;
document.getElementById('questionsList').insertAdjacentHTML('beforeend', questionHtml);
updateQuestionNumbers();
}
// 질문 타입 변경
function updateQuestionType(select) {
const questionItem = select.closest('.question-item');
const optionsContainer = questionItem.querySelector('.options-container');
const questionType = select.value;
if (['radio', 'checkbox', 'select'].includes(questionType)) {
optionsContainer.style.display = 'block';
} else {
optionsContainer.style.display = 'none';
}
}
// 질문 삭제
function removeQuestion(button) {
if (confirm('이 질문을 삭제하시겠습니까?')) {
button.closest('.question-item').remove();
updateQuestionNumbers();
}
}
// 질문 순서 변경
function moveQuestion(button, direction) {
const questionItem = button.closest('.question-item');
const sibling = direction === 'up' ? questionItem.previousElementSibling : questionItem.nextElementSibling;
if (sibling) {
if (direction === 'up') {
questionItem.parentNode.insertBefore(questionItem, sibling);
} else {
questionItem.parentNode.insertBefore(sibling, questionItem);
}
updateQuestionNumbers();
}
}
// 선택지 추가
function addOption(button) {
const optionsList = button.previousElementSibling;
const questionIndex = button.closest('.question-item').dataset.questionIndex;
const optionCount = optionsList.children.length + 1;
const optionHtml = `
<div class="option-item">
<input type="text" name="questions[${questionIndex}][options][]" class="option-input" placeholder="선택지 ${optionCount}">
<button type="button" class="btn-sm btn-danger" onclick="removeOption(this)">삭제</button>
</div>
`;
optionsList.insertAdjacentHTML('beforeend', optionHtml);
}
// 선택지 삭제
function removeOption(button) {
const optionsList = button.closest('.options-list');
if (optionsList.children.length > 2) {
button.closest('.option-item').remove();
} else {
alert('최소 2개의 선택지가 필요합니다.');
}
}
// 질문 번호 업데이트
function updateQuestionNumbers() {
const questions = document.querySelectorAll('.question-item');
questions.forEach((question, index) => {
const number = index + 1;
question.querySelector('.question-number').textContent = number;
question.dataset.questionIndex = number;
// input name 속성 업데이트
const inputs = question.querySelectorAll('input, textarea, select');
inputs.forEach(input => {
if (input.name && input.name.includes('questions[')) {
input.name = input.name.replace(/questions\[\d+\]/, `questions[${number}]`);
}
});
});
questionCount = questions.length;
}
// 폼 검증
function initFormValidation() {
document.getElementById('surveyForm').addEventListener('submit', function(e) {
const title = document.querySelector('input[name="sv_title"]').value.trim();
const startDate = new Date(document.querySelector('input[name="sv_start_date"]').value);
const endDate = new Date(document.querySelector('input[name="sv_end_date"]').value);
if (!title) {
alert('설문 제목을 입력해주세요.');
e.preventDefault();
return;
}
if (startDate >= endDate) {
alert('종료일시는 시작일시보다 늦어야 합니다.');
e.preventDefault();
return;
}
const questions = document.querySelectorAll('.question-item');
if (questions.length === 0) {
alert('최소 1개의 질문을 추가해주세요.');
e.preventDefault();
return;
}
// 질문 제목 검증
let hasEmptyQuestion = false;
questions.forEach(question => {
const titleInput = question.querySelector('input[name*="[title]"]');
if (!titleInput.value.trim()) {
hasEmptyQuestion = true;
}
});
if (hasEmptyQuestion) {
alert('모든 질문의 제목을 입력해주세요.');
e.preventDefault();
return;
}
});
}