Files
kngil_home/kngil/skin/qa_detail.skin.php
2026-02-04 12:40:02 +09:00

612 lines
27 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ko">
<head>
<?php include __DIR__ . "/_head.php"; ?>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Q&A 상세보기</title>
<link rel="stylesheet" href="/kngil/css/qa/font-awesome.min.css?ver=2303229">
<!-- 디자인팀 작성 -->
<script src="/kngil/js/lib/jquery-3.6.1.min.js" type="text/javascript"></script>
<script src="/kngil/js/qa/jquery.mousewheel.min.js" type="text/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollToPlugin.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/aos@2.3.1/dist/aos.css" type="text/css"/>
<link rel="stylesheet" href="https://unpkg.com/lenis@1.1.9/dist/lenis.css">
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
<script src="https://unpkg.com/lenis@1.1.9/dist/lenis.min.js"></script>
</head>
<body>
<div class="wrap">
<?php
include __DIR__ . "/_header.php";
if (!$isLogin) {
echo "<script>
alert('로그인 후 문의 등록이 가능합니다.');
location.href = '/kngil/skin/qa_list.skin.php';
</script>";
exit;
}
$isLoggedIn = !empty($_SESSION['login']);
?>
<?php
include __DIR__ . "/pop_join.php";
include __DIR__ . "/pop_agreement.php";
include __DIR__ . "/pop_mypage01.php";
include __DIR__ . "/pop_mypage02.php";
include __DIR__ . "/pop_mypage03.php";
include __DIR__ . "/pop_password.php";
include __DIR__ . "/pop_privacy.php";
include __DIR__ . "/pop_search.php";
?>
<div class="container faq">
<section class="sub-header">
<div class="page-title">
<h2 data-aos="fade-down" data-aos-duration="1000">Q&A</h2>
<p class="sub-txt">KNGIL 관련 문의하기</p>
</div>
<ul class="sub-tab">
<li><a href="/kngil/skin/faq_list.skin.php">자주하는 질문(FAQ)</a></li>
<li class="on"><a href="/kngil/bbs/qa_list.php">문의하기(Q&A)</a></li>
<li><a href="https://939.co.kr/saman/" target="_blank">원격지원</a></li>
</ul>
</section>
<section class="sub-content">
<h3 class="sub-tit">문의하기(Q&A)</h3>
<article class="qa-detail">
<div class="qa-view">
<div class="qa-view-header">
<div class="title-area">
<!-- 왼쪽: 카테고리 + 제목 -->
<div class="title-left">
<span class="cate"><?=htmlspecialchars($post['category_label'])?></span>
<span class="title"><?=htmlspecialchars($post['title'])?></span>
</div>
<!-- 오른쪽: 상태 -->
<div class="title-right">
<?php if ($isSuperAdmin): ?>
<form method="post" action="/kngil/bbs/qa_status.php">
<input type="hidden" name="post_id" value="<?= $post['post_id'] ?>">
<select name="status" onchange="this.form.submit()" class="status-select status-<?= htmlspecialchars($post['stat_bc']) ?>">
<option value="new" <?= $post['stat_bc']==='new'?'selected':'' ?>>문의접수</option>
<option value="review" <?= $post['stat_bc']==='review'?'selected':'' ?>>문의검토</option>
<option value="deep" <?= $post['stat_bc']==='deep'?'selected':'' ?>>정밀검토</option>
<option value="patch" <?= $post['stat_bc']==='patch'?'selected':'' ?>>패치예정</option>
<option value="done" <?= $post['stat_bc']==='done'?'selected':'' ?>>답변완료</option>
</select>
</form>
<?php else: ?>
<div class="status"><?= htmlspecialchars($post['status_label']) ?></div>
<?php endif; ?>
</div>
</div>
<div class="user-info">
<div class="user-item">
<span>
<i class="fa fa-clock-o" aria-hidden="true"></i>
<?=htmlspecialchars($post['cdt_dt'])?>
</span>
</div>
<div class="user-item">
<!-- 글번호 -->
<span class="post">
<i class="fa fa-hashtag" aria-hidden="true"></i>
<?= htmlspecialchars($post['post_id']) ?>
</span>
<?php if ($post['category'] === 'notice'): ?>
<!-- ✅ 공지사항이면 "관리자"만 표시 -->
<span>
<i class="fa fa-user" aria-hidden="true"></i>
관리자
</span>
<?php else: ?>
<!-- 작성자 이메일 -->
<span>
<i class="fa fa-envelope-o" aria-hidden="true"></i>
<?= htmlspecialchars($post['email']) ?>
</span>
<!-- 회사 -->
<span>
<i class="fa fa-building-o" aria-hidden="true"></i>
<?= htmlspecialchars($post['co_nm'] ?? '') ?>
</span>
<!-- 부서 -->
<?php if (!empty($post['dept_nm'])): ?>
<span>
<i class="fa fa-sitemap" aria-hidden="true"></i>
<?= htmlspecialchars($post['dept_nm']) ?>
</span>
<?php endif; ?>
<!-- 작성자 이름 -->
<!-- <span>
<i class="fa fa-user" aria-hidden="true"></i>
<?= htmlspecialchars($post['display_name']) ?>
</span> -->
<!-- 관리자 전용 -->
<?php if ($isSuperAdmin): ?>
<?php if (!empty($post['tel_no'])): ?>
<span>
<i class="fa fa-phone" aria-hidden="true"></i>
<?= htmlspecialchars($post['tel_no']) ?>
</span>
<?php endif; ?>
<span>
<i class="fa fa-key" aria-hidden="true"></i>
Q&A : <?= htmlspecialchars($post['post_id']) ?>
</span>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</div>
<div class="content">
<?= $post['content'] ?>
</div>
</div>
<!-- 첨부파일 -->
<?php if (!empty($attachments)): ?>
<div class="attachments" style="margin-top:20px;">
<h3>첨부파일</h3>
<ul>
<?php foreach ($attachments as $file): ?>
<li>
<?php if (!empty($_SESSION['user']['userId'])): ?>
<!-- ✅ 로그인한 경우: 다운로드 가능 -->
<a href="<?= htmlspecialchars($file['save_path']) ?>" download>
<?= htmlspecialchars($file['ori_name']) ?>
</a>
<?php else: ?>
<!-- 🚫 비회원: 이름만 표시 (다운로드 막음) -->
<?= htmlspecialchars($file['ori_name']) ?> <span style="color:#888;"></span>
<?php endif; ?>
<small>
(<?= round($file['file_size'] / 1024, 1) ?> KB,
<?= htmlspecialchars(substr($file['uploaded_at'],0,16)) ?>)
</small>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</article>
<div class="btn-wrap right">
<!-- 수정 버튼 (로그인 사용자 == 작성자 인 경우에만) -->
<?php if ($me === $_SESSION['login']['user_id'] ?? ''): ?>
<button class="btn-secondary" onclick="location.href='/kngil/bbs/qa_write.php?id=<?= $post['post_id'] ?>'">수정</button>
<button class="btn-secondary" id="btn-delete" data-status="<?= $post['stat_bc'] ?>" data-id="<?= $post['post_id'] ?>">삭제</button>
<?php endif; ?>
<!-- <button onclick="history.back()">닫기</button> -->
<button class="btn-primary" onclick="location.href='/kngil/bbs/qa_list.php'">
<i class="fa fa-list" aria-hidden="true"></i> 목록</button>
</div>
<article class="comment-section">
<h4 class="comment-title">댓글 (<span id="comment-count"><?= count($comments ?? []) ?></span>)</h4>
<div class="comment-wrap form-wrap">
<div id="comments" class="comment-list">
<?php foreach ($comments ?? [] as $c): ?>
<div class="comment" id="comment-<?= $c['comment_id'] ?>">
<div class="comment-body">
<!-- 댓글 내용 -->
<div class="comment-text">
<?= nl2br(htmlspecialchars($c['content'] ?? '')) ?>
</div>
<!-- (이미지 영역 구조 유지 아직 로직 안 붙여도 됨) -->
<?php if (!empty($c['images'])): ?>
<div class="comment-images" style="margin-top:6px; display:flex; gap:12px;">
<?php foreach ($c['images'] as $img): ?>
<div style="text-align:center;">
<img
src="<?= htmlspecialchars($img['thumb_path']) ?>"
onclick="window.open('<?= htmlspecialchars($img['file_path']) ?>', '_blank')"
style="width:140px; border-radius:6px; margin:4px; cursor:pointer;">
<div style="font-size:12px; color:#555; margin-top:4px; max-width:140px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
<?= htmlspecialchars($img['file_name']) ?>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- 작성자 + 날짜 -->
<div class="comment-meta">
<span class="comment-author">
<strong><?= htmlspecialchars($c['user_nm'] ?? '') ?></strong>
</span>
<span class="comment-date">
<small><?= $c['cdt_dt'] ?? '' ?></small>
</span>
</div>
</div>
<!-- 수정 / 삭제 버튼 -->
<div class="comment-actions" style="text-align:right;">
<?php if ($isLoggedIn): ?>
<?php if (($_SESSION['login']['user_id'] ?? '') === ($c['commenter'] ?? '')): ?>
<button class="btn-edit" data-id="<?= $c['comment_id'] ?>">수정</button>
<button class="btn-delete" data-id="<?= $c['comment_id'] ?>">삭제</button>
<?php elseif ($isSuperAdmin): ?>
<button class="btn-delete" data-id="<?= $c['comment_id'] ?>">삭제</button>
<?php endif; ?>
<?php endif; ?>
</div>
<!-- 수정 모드 textarea (구조 유지) -->
<div class="comment-edit-box" style="display:none; margin-top:5px;">
<textarea class="comment-edit-input" rows="3"><?= htmlspecialchars($c['content'] ?? '') ?></textarea>
<div class="comment-edit-actions" style="text-align:right; margin-top:3px;">
<button class="btn-save-edit" data-id="<?= $c['comment_id'] ?>">저장</button>
<button class="btn-cancel-edit">취소</button>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<!-- 신규 댓글 입력 -->
<?php if ($isLoggedIn): ?>
<form id="commentForm" enctype="multipart/form-data">
<div class="comment-row">
<textarea id="newComment"
name="comment"
class="input-text"
rows="3"
placeholder="댓글을 입력하세요"></textarea>
<button type="submit" class="btn-save">저장</button>
</div>
<!-- 업로드 영역 (구조 유지) -->
<div class="upload-wrap">
<label for="commentImages" class="img-upload-btn">📷 이미지 첨부</label>
<input type="file" id="commentImages" name="images[]" accept="image/*" multiple>
<span id="fileName" class="file-name">선택된 파일 없음</span>
<div id="previewArea"></div>
</div>
</form>
<?php else: ?>
<p style="color:#888;">댓글 작성은 로그인 후 이용 가능합니다.</p>
<?php endif; ?>
</div>
</article>
</section>
</div> <!-- container END -->
<?php include __DIR__ . "/_footer.php"; ?>
</div> <!-- wrapper END -->
<script>
$(document).on('click', '#btn-delete', function (e) {
e.preventDefault();
const status = $(this).data('status');
const postId = $(this).data('id');
if (status === 'review' || status === 'done') {
alert("검토중이거나 답변완료 된 상태에서는 글을 삭제할 수 없습니다.\n관리자에게 문의해 주세요");
return;
}
if (!confirm("정말 삭제하시겠습니까?\n댓글과 첨부파일도 함께 삭제됩니다.")) {
return;
}
const form = document.createElement('form');
form.method = 'post';
form.action = "/kngil/bbs/qa_detail.php"; // ✅ 중요
const actionInput = document.createElement('input');
actionInput.type = 'hidden';
actionInput.name = 'action';
actionInput.value = 'delete';
const idInput = document.createElement('input');
idInput.type = 'hidden';
idInput.name = 'post_id';
idInput.value = postId;
form.appendChild(actionInput);
form.appendChild(idInput);
document.body.appendChild(form);
form.submit();
});
</script>
<script src="/kngil/js/index.js"></script>
<script src="/kngil/js/mypage.js"></script>
<script src="/kngil/js/join.js"></script>
<script src="/kngil/js/login_sms.js"></script>
<script>
try{
AOS.init();
if (typeof Lenis !== 'undefined') {
const lenis = new Lenis();
lenis.on('scroll', ScrollTrigger.update);
gsap.ticker.add((time)=>{ lenis.raf(time * 1000) });
gsap.ticker.lagSmoothing(0);
window.lenis = lenis;
}
} catch(e){ console.error(e); }
</script>
<script>
//상태 색상 변경 동적 업데이트
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.status-select').forEach(sel => {
sel.addEventListener('change', function() {
this.className = 'status-select status-' + this.value;
});
});
});
// ✅ 댓글 저장 (이미지 포함)
document.getElementById('commentForm')?.addEventListener('submit', async (e) => {
e.preventDefault();
const text = document.getElementById('newComment').value.trim();
const files = document.getElementById('commentImages').files;
if (!text && files.length === 0) {
alert('댓글 또는 이미지를 입력하세요.');
return;
}
const formData = new FormData();
formData.append('postId', <?= json_encode($post['post_id']) ?>);
formData.append('comment', text);
for (let i = 0; i < files.length; i++) {
formData.append('images[]', files[i]);
}
const res = await fetch('/kngil/bbs/qa_comment.php', {
method: 'POST',
body: formData,
credentials: 'include'
});
const json = await res.json();
if (json.status !== 'ok') {
alert(json.message || '저장 실패');
return;
}
// ✅ DOM 추가 (서버에서 이미지 URL 배열 반환한다고 가정)
const div = document.createElement('div');
div.className = 'comment';
div.id = "comment-" + json.comment_id;
const safeText = (json.comment_text || '').replace(/\r?\n/g, '<br>');
let imageHTML = "";
if (json.images && json.images.length > 0) {
imageHTML = `
<div class="comment-images"
style="margin-top:6px; display:flex; gap:12px; flex-wrap:wrap;">
${json.images
.map(
(img) => `
<div style="text-align:center; width:140px;">
<img
src="${img.thumb}"
onclick="window.open('${img.full}', '_blank')"
style="width:140px; height:auto; border-radius:6px; cursor:pointer;"
>
<div style="
font-size:12px;
color:#555;
margin-top:4px;
white-space:nowrap;
overflow:hidden;
text-overflow:ellipsis;
">
${img.name}
</div>
</div>
`
)
.join("")}
</div>`;
}
div.innerHTML = `
<div class="comment-body">
<div class="comment-text">${safeText}</div>
${imageHTML}
<div class="comment-meta">
<span class="comment-author"><strong>${json.user_name || json.login_id}</strong></span>
<span class="comment-date"><small>${json.created_at}</small></span>
</div>
</div>
`;
document.getElementById('comments').append(div);
document.getElementById('newComment').value = '';
document.getElementById('commentImages').value = '';
document.getElementById('previewArea').innerHTML = '';
});
// 댓글 수정 버튼
$(document).on('click', '.btn-edit', function() {
const id = $(this).data('id');
const $comment = $(this).closest('.comment');
const $text = $comment.find('.comment-text');
const original = $text.text().trim();
// input으로 교체
$text.replaceWith(`<textarea class="edit-input" data-id="${id}" rows="3">${original}</textarea>`);
$(this).text("저장").removeClass("btn-edit").addClass("btn-save-edit").attr("data-id", id);;
});
// 댓글 수정 저장
$(document).on('click', '.btn-save-edit', function() {
const id = $(this).data('id');
const $input = $('.edit-input[data-id="'+id+'"]');
const newText = $input.val().trim();
if (!newText) return alert("내용을 입력하세요");
console.log("update click", id, newText);
$.post("/kngil/bbs/qa_comment_update.php",
{ commentId:id, comment:newText },
function(res) {
if (res.status === 'ok') {
alert(res.message || "댓글이 수정되었습니다.");
$input.replaceWith(`<div class="comment-text">${newText}</div>`);
$('.btn-save-edit[data-id="'+id+'"]').text("수정")
.removeClass("btn-save-edit").addClass("btn-edit");
} else {
alert(res.message || "수정 실패");
}
}, "json");
});
document.addEventListener('click', function(e) {
// 수정 버튼 클릭 → textarea 열기
if (e.target.classList.contains('btn-edit')) {
const comment = e.target.closest('.comment');
comment.querySelector('.comment-text').style.display = 'none';
comment.querySelector('.comment-actions').style.display = 'none';
comment.querySelector('.comment-edit-box').style.display = 'block';
}
// 취소 버튼 → 원래 상태로
if (e.target.classList.contains('btn-cancel-edit')) {
const comment = e.target.closest('.comment');
comment.querySelector('.comment-text').style.display = 'inline';
comment.querySelector('.comment-actions').style.display = 'block';
comment.querySelector('.comment-edit-box').style.display = 'none';
}
// 저장 버튼 → AJAX로 수정 요청 (예시)
if (e.target.classList.contains('btn-save-edit')) {
const comment = e.target.closest('.comment');
const id = e.target.dataset.id;
const newText = comment.querySelector('.comment-edit-input').value;
// TODO: AJAX 호출해서 서버 업데이트
console.log("수정 저장:", id, newText);
// UI 갱신
comment.querySelector('.comment-text').textContent = newText;
comment.querySelector('.comment-text').style.display = 'inline';
comment.querySelector('.comment-actions').style.display = 'block';
comment.querySelector('.comment-edit-box').style.display = 'none';
}
});
// 댓글 삭제 버튼
$(document).on("click", ".btn-delete", function () {
if (!confirm("정말 삭제하시겠습니까?")) return;
var commentId = $(this).data("id");
$.ajax({
url: "/kngil/bbs/qa_comment_delete.php",
type: "POST",
data: { commentId: commentId },
dataType: "json",
success: function (res) {
if (res.status === "ok") {
// DOM에서도 삭제
$("#comment-" + commentId).fadeOut(300, function () {
$(this).remove();
});
// ✅ 댓글 수 감소
var countEl = $("#comment-count");
var current = parseInt(countEl.text(), 10);
if (current > 0) {
countEl.text(current - 1);
}
alert("댓글이 삭제되었습니다.");
} else {
alert(res.message || "삭제 실패");
}
},
error: function (xhr) {
alert("삭제 요청 에러: " + xhr.responseText);
}
});
});
</script>
</body>
</html>
<script>
// ✅ 댓글 이미지 미리보기
document.addEventListener("change", function (e) {
if (e.target.id === "commentImages") {
const preview = document.getElementById("previewArea");
preview.innerHTML = ""; // 초기화
[...e.target.files].forEach((file) => {
// ▶ 개별 박스 생성
const box = document.createElement("div");
box.style.width = "80px";
box.style.marginRight = "10px";
box.style.textAlign = "center";
box.style.display = "inline-block";
// ▶ 썸네일 이미지
const img = document.createElement("img");
img.src = URL.createObjectURL(file);
img.style.width = "80px";
img.style.height = "80px";
img.style.objectFit = "cover";
img.style.borderRadius = "6px";
// ▶ 파일명 (길면 ... 처리)
const name = document.createElement("div");
name.textContent = file.name;
name.style.marginTop = "4px";
name.style.whiteSpace = "nowrap";
name.style.overflow = "hidden";
name.style.textOverflow = "ellipsis";
name.style.width = "80px";
// ▶ 박스에 넣기
box.appendChild(img);
box.appendChild(name);
// ▶ preview 영역에 넣기
preview.appendChild(box);
});
}
});
</script>