427 lines
16 KiB
PHP
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">관리자 <admin@example.com></span></div>
|
|
<div class="meta-item"><span class="meta-label">받는사람:</span><span class="meta-value">홍길동 <hong@example.com></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');
|
|
?>
|