Files
2026-06-11 18:47:38 +09:00

427 lines
16 KiB
PHP

<?php
/**
* 알림 템플릿 관리
*/
$sub_menu = '850620';
include_once('./_common.php');
// 관리자 권한 확인
if (!$is_admin) {
alert('관리자만 접근할 수 있습니다.');
}
// 설치 확인
if (!is_consultant_installed()) {
alert('상담 예약 시스템이 설치되지 않았습니다.', 'install.php');
}
$g5['title'] = '알림 템플릿 관리';
// 템플릿 저장 처리
if ($_POST['action'] == 'save_template') {
$template_key = $_POST['template_key'];
$template_subject = $_POST['template_subject'];
$template_type = $_POST['template_type'] ?? 'email'; // 💡 [추가] 템플릿 타입
$template_content = $_POST['template_content'];
$template_name = $_POST['template_name']; // 💡 [추가] 템플릿 이름을 폼에서 받아옵니다.
if ($template_key && $template_subject && $template_content) {
// 템플릿 저장/업데이트
// 💡 [수정] 타입에 따라 테이블 분기
$table_name = ($template_type === 'sms') ? 'consultant_sms_templates' : 'consultant_mail_templates';
$sql = "INSERT INTO {$table_name}
(template_key, template_type, template_name, template_subject, template_content, updated_at)
VALUES (
'" . sql_real_escape_string($template_key) . "',
'" . sql_real_escape_string($template_type) . "',
'" . sql_real_escape_string($template_name) . "',
'" . sql_real_escape_string($template_subject) . "',
'" . sql_real_escape_string($template_content) . "',
NOW()
)
ON DUPLICATE KEY UPDATE
template_subject = '" . sql_real_escape_string($template_subject) . "',
template_type = '" . sql_real_escape_string($template_type) . "',
template_content = '" . sql_real_escape_string($template_content) . "',
updated_at = NOW()";
if (sql_query($sql)) {
alert('템플릿이 저장되었습니다.', $_SERVER['PHP_SELF'] . '?type=' . $template_type . '&template=' . $template_key);
} else {
alert('템플릿 저장에 실패했습니다.');
}
}
}
// 💡 [추가] 현재 탭 확인
$current_type = $_GET['type'] ?? 'email';
// 기본 템플릿 정의
$default_templates = [
'consultant_reservation_customer' => [
'name' => '고객 예약 신청 확인',
'subject' => '[상담예약] 예약 신청이 접수되었습니다',
'content' => "안녕하세요 {customer_name}님,\n\n상담 예약 신청이 정상적으로 접수되었습니다.\n\n예약 정보:\n- 날짜: {reservation_date}\n- 시간: {reservation_time}\n- 상담비: {payment_amount}원\n\n입금 계좌: {account_info}\n\n입금 확인 후 예약이 확정됩니다.\n\n감사합니다."
],
'consultant_confirmed_customer' => [
'name' => '고객 예약 확정 알림',
'subject' => '[상담예약] 예약이 확정되었습니다',
'content' => "안녕하세요 {customer_name}님,\n\n입금이 확인되어 예약이 확정되었습니다.\n\n예약 정보:\n- 날짜: {reservation_date}\n- 시간: {reservation_time}\n\n상담 당일 시간에 맞춰 방문해주시기 바랍니다.\n\n감사합니다."
],
'consultant_cancelled_customer' => [
'name' => '고객 예약 취소 알림',
'subject' => '[상담예약] 예약이 취소되었습니다',
'content' => "안녕하세요 {customer_name}님,\n\n예약이 취소되었습니다.\n\n취소된 예약 정보:\n- 날짜: {reservation_date}\n- 시간: {reservation_time}\n\n취소 사유: {cancel_reason}\n\n문의사항이 있으시면 연락주시기 바랍니다.\n\n감사합니다."
]
];
// 현재 템플릿 조회
$templates = [];
// 💡 [수정] 현재 탭의 타입에 맞는 템플릿만 조회합니다.
if (is_consultant_installed()) {
// 💡 [수정] 타입에 따라 테이블 분기
$table_name = ($current_type === 'sms') ? 'consultant_sms_templates' : 'consultant_mail_templates';
// 테이블 존재 여부 확인 (설치 초기 단계 고려)
$table_check = sql_query("SHOW TABLES LIKE '{$table_name}'", false);
if (sql_num_rows($table_check) > 0) {
$sql = "SELECT * FROM {$table_name} WHERE template_type = '".sql_real_escape_string($current_type)."' ORDER BY template_key";
$result = sql_query($sql, false);
if ($result) {
while ($row = sql_fetch_array($result)) {
$templates[$row['template_key']] = $row;
}
}
}
}
// 기본 템플릿과 병합
foreach ($default_templates as $key => $default) {
if (!isset($templates[$key])) {
$templates[$key] = [
'template_key' => $key,
'template_name' => $default['name'],
'template_subject' => $default['subject'],
'template_content' => $default['content']
];
}
}
$current_template_key = $_GET['template'] ?? array_key_first($templates);
include_once(G5_ADMIN_PATH . '/admin.head.php');
?>
<style>
.templates-container {
max-width: 1000px;
margin: 0 auto;
padding: 20px;
}
.template-nav {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.template-tabs {
display: flex; border-bottom: 2px solid #ddd; margin-bottom: 30px;
}
.template-tab {
padding: 16px 28px;
border: none;
background: none;
cursor: pointer;
font-size: 16px;
font-weight: 600;
color: #666;
text-decoration: none;
border-bottom: 3px solid transparent;
transition: all 0.2s;
}
.template-tab.active {
background: #007bff;
color: white;
border-color: #007bff;
}
.template-form {
background: white;
border: 1px solid #ddd;
border-radius: 8px;
padding: 30px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: #333;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
box-sizing: border-box;
font-family: inherit;
}
.form-group textarea {
height: 200px;
resize: vertical;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: 600;
text-decoration: none;
display: inline-block;
}
.btn-primary {
background: #007bff;
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.variables-info {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 15px;
margin-bottom: 20px;
}
.variables-title {
font-weight: bold;
margin-bottom: 10px;
color: #333;
}
.variables-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
}
.variable-item {
background: white;
padding: 8px;
border-radius: 4px;
font-family: monospace;
font-size: 12px;
border: 1px solid #ddd;
}
.alert {
padding: 15px;
margin-bottom: 20px;
border: 1px solid transparent;
border-radius: 4px;
}
.alert-info {
color: #0c5460;
background-color: #d1ecf1;
border-color: #bee5eb;
}
@media (max-width: 768px) {
.template-tabs {
flex-direction: column;
}
.variables-list {
grid-template-columns: 1fr;
}
}
</style>
<div class="templates-container">
<h2><?php echo $g5['title']; ?></h2>
<div class="alert alert-info">
<strong>안내:</strong> 예약 관련 자동 발송 <?php echo ($current_type == 'sms') ? '문자' : '이메일'; ?>의 템플릿을 관리합니다.
중괄호 {} 안의 변수들은 실제 데이터로 자동 치환됩니다.
</div>
<!-- 템플릿 탭 -->
<div class="template-nav">
<div class="template-tabs">
<a href="?type=email" class="template-tab <?php echo $current_type == 'email' ? 'active' : ''; ?>">📧 메일 템플릿</a>
<a href="?type=sms" class="template-tab <?php echo $current_type == 'sms' ? 'active' : ''; ?>">📱 문자 템플릿</a>
</div>
<?php if(!empty($templates)): ?>
<div class="template-tabs" style="border-bottom:none; margin-bottom: 10px;">
<?php foreach ($templates as $key => $template): ?>
<a href="?type=<?php echo $current_type; ?>&template=<?php echo $key; ?>"
class="template-tab <?php echo $current_template_key == $key ? 'active' : ''; ?>" style="font-size:14px; padding: 8px 16px;">
<?php echo htmlspecialchars($template['template_name']); ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<!-- 사용 가능한 변수 안내 -->
<div class="variables-info">
<div class="variables-title">📝 사용 가능한 변수</div>
<div class="variables-list">
<div class="variable-item">{customer_name} - 고객명</div>
<div class="variable-item">{customer_phone} - 고객 연락처</div>
<div class="variable-item">{customer_email} - 고객 이메일</div>
<div class="variable-item">{reservation_date} - 예약 날짜</div>
<div class="variable-item">{reservation_time} - 예약 시간</div>
<div class="variable-item">{payment_amount} - 상담 비용</div>
<div class="variable-item">{account_info} - 입금 계좌</div>
<div class="variable-item">{cancel_reason} - 취소 사유</div>
</div>
</div>
<!-- 템플릿 편집 폼 -->
<?php if (isset($templates[$current_template_key])): ?>
<?php $template = $templates[$current_template_key]; ?>
<form method="post" class="template-form">
<input type="hidden" name="action" value="save_template">
<input type="hidden" name="template_key" value="<?php echo $current_template_key; ?>">
<input type="hidden" name="template_name" value="<?php echo htmlspecialchars($template['template_name']); ?>">
<input type="hidden" name="template_type" value="<?php echo $current_type; ?>">
<div class="form-group">
<label for="template_subject"><?php echo ($current_type == 'sms') ? '문자 제목 (LMS용)' : '이메일 제목'; ?></label>
<input type="text" id="template_subject" name="template_subject"
value="<?php echo htmlspecialchars($template['template_subject']); ?>"
required>
</div>
<div class="form-group">
<label for="template_content"><?php echo ($current_type == 'sms') ? '문자 내용' : '이메일 내용'; ?></label>
<textarea id="template_content" name="template_content" required><?php echo htmlspecialchars($template['template_content']); ?></textarea>
</div>
<div style="text-align: center; margin-top: 30px;">
<!-- 💡 [개선] 미리보기 버튼을 JS로 생성하는 대신 HTML에 직접 추가하여 안정성을 높이고, 저장 버튼과 나란히 배치합니다. -->
<button type="button" onclick="previewTemplate()" class="btn btn-secondary" style="margin-right: 10px;">미리보기</button>
<button type="submit" class="btn btn-primary">템플릿 저장</button>
<a href="dashboard.php" class="btn btn-secondary">대시보드로</a>
</div>
</form>
<?php endif; ?>
</div>
<script>
// 변수 삽입 도우미
document.addEventListener('DOMContentLoaded', function() {
const textarea = document.getElementById('template_content');
const variableItems = document.querySelectorAll('.variable-item');
variableItems.forEach(item => {
item.style.cursor = 'pointer';
item.title = '클릭하여 템플릿에 삽입';
item.addEventListener('click', function() {
const variable = this.textContent.split(' - ')[0];
const cursorPos = textarea.selectionStart;
const textBefore = textarea.value.substring(0, cursorPos);
const textAfter = textarea.value.substring(cursorPos);
textarea.value = textBefore + variable + textAfter;
textarea.focus();
textarea.setSelectionRange(cursorPos + variable.length, cursorPos + variable.length);
});
});
});
// 템플릿 미리보기
function previewTemplate() {
const subject = document.getElementById('template_subject').value;
const content = document.getElementById('template_content').value;
// 샘플 데이터로 치환
const sampleData = {
'{customer_name}': '홍길동',
'{customer_phone}': '010-1234-5678',
'{customer_email}': 'hong@example.com',
'{reservation_date}': '2024-12-15',
'{reservation_time}': '14:00',
'{payment_amount}': '50,000',
'{account_info}': '국민은행 123-456-789 (주)상담센터',
'{cancel_reason}': '개인 사정'
};
let previewSubject = subject;
let previewContent = content;
for (const [variable, value] of Object.entries(sampleData)) {
previewSubject = previewSubject.replace(new RegExp(variable.replace(/[{}]/g, '\\\\$&'), 'g'), value);
previewContent = previewContent.replace(new RegExp(variable.replace(/[{}]/g, '\\\\$&'), 'g'), value);
}
// 💡 [개선] 실제 이메일처럼 보이도록 nl2br 처리 및 UI 개선
const previewHtmlContent = previewContent.replace(/\n/g, '<br>');
// 💡 [개선] document.write() 대신 DOM 조작을 사용하여 안정성을 높입니다.
const previewWindow = window.open('', '_blank', 'width=800,height=600');
const previewDoc = previewWindow.document;
previewDoc.open();
previewDoc.write(`
<!DOCTYPE html>
<html>
<head>
<title>미리보기</title>
<style>
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; padding: 0; background-color: #f6f8fa; }
.preview-container { max-width: 800px; margin: 20px auto; background-color: #fff; border: 1px solid #ddd; border-radius: 8px; box-shadow: 0 1px 5px rgba(0,0,0,0.1); }
.preview-header { padding: 20px; border-bottom: 1px solid #eee; }
.preview-header h2 { margin: 0; font-size: 20px; color: #333; }
.preview-meta { padding: 15px 20px; background-color: #fdfdfd; border-bottom: 1px solid #eee; font-size: 14px; }
.meta-item { display: flex; margin-bottom: 8px; }
.meta-label { font-weight: bold; color: #555; width: 80px; }
.meta-value { color: #333; }
.preview-body { padding: 30px 20px; line-height: 1.7; color: #333; font-size: 15px; }
</style>
</head>
<bo`+`dy>
<div class='preview-container'>
<div class="preview-header"><h2>미리보기</h2></div>
<div class="preview-meta">
<div class="meta-item"><span class="meta-label">보내는사람:</span><span class="meta-value">관리자 &lt;admin@example.com&gt;</span></div>
<div class="meta-item"><span class="meta-label">받는사람:</span><span class="meta-value">홍길동 &lt;hong@example.com&gt;</span></div>
<div class="meta-item"><span class="meta-label">제 목:</span><span class="meta-value">${previewSubject}</span></div>
</div>
<div class="preview-body">${previewHtmlContent}</div>
</div>
</bo`+`dy>
</html>
`);
previewWindow.document.close();
}
</script>
<?php
include_once(G5_ADMIN_PATH . '/admin.tail.php');
?>