<?php // config + ์ผ์ ์ ์ฅ ์ฒ๋ฆฌ $pdo = new PDO("mysql:host=localhost;dbname=calendar_db;charset=utf8mb4", "root", "wjs3603825!", [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); // ์ผ์ ์ ์ฅ ์ฒ๋ฆฌ if ($_SERVER['REQUEST_METHOD'] === 'POST') { header('Content-Type: application/json'); $data = json_decode(file_get_contents('php://input'), true); if (!$data || empty($data['event-title']) || empty($data['event-date'])) { echo json_encode(['success' => false, 'error' => '์ ๋ชฉ ๋๋ ๋ ์ง ๋๋ฝ']); exit; } // ๊ธ์ก ์ฒ๋ฆฌ: ์ซ์๊ฐ ์๋๋ฉด 0 $amount = isset($data['event-amount']) && is_numeric($data['event-amount']) ? (int)$data['event-amount'] : 0; // ๊ธ์ก๊น์ง ํฌํจํด์ INSERT $stmt = $pdo->prepare("INSERT INTO events (title, event_date, org, description, amount) VALUES (?, ?, ?, ?, ?)"); $success = $stmt->execute([ $data['event-title'], $data['event-date'], $data['event-org'], $data['event-desc'], $amount ]); echo json_encode(['success' => $success]); exit; } // ์ค๋ ์ผ์ ๋ถ๋ฌ์ค๊ธฐ $today = date('Y-m-d'); $stmt = $pdo->prepare("SELECT title, org, description, amount FROM events WHERE event_date = ?"); $stmt->execute([$today]); $today_events = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($today_events as &$event) { $event['icon'] = match ($event['org']) { 'uniedu' => '๐', 'mod' => '๐ก๏ธ', 'peacemaker' => '๐๏ธ', 'hyundai' => '๐ญ', 'bus' => '๐', 'camp' => '๐๏ธ', default => '' }; } ?> <!-- HTML ์์ --> <!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>์ด๋ค์ ์บ๋ฆฐ๋</title> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"> <style> :root { --uniedu: #2b7de9; --mod: #e63946; --peacemaker: #2a9d8f; --hyundai: #f77f00; --bus: #00b4d8; --camp: #7209b7; --shadow: 0 10px 30px rgba(0,0,0,0.1); --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); --radius: 12px; --sunday: #ff5a5f; --monday: #4a6bdf; --tuesday: #2a9d8f; --wednesday: #f77f00; --thursday: #7209b7; --friday: #2b7de9; --saturday: #9c4dcc; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif; } body { background-color: #f8fafc; color: #1e293b; line-height: 1.6; padding: 0.5rem; font-size: 14px; } .calendar-container { max-width: 1400px; margin: 2rem auto; padding: 2.5rem; background: white; border-radius: var(--radius); box-shadow: var(--shadow); transition: var(--transition); backdrop-filter: blur(10px); background: rgba(255, 255, 255, 0.9); } .calendar-container:hover { box-shadow: 0 15px 35px rgba(0,0,0,0.15); transform: translateY(-2px); } .calendar-header { display: flex; flex-direction: column; gap: 1.5rem; margin-bottom: 2rem; padding-bottom: 1.5rem; border-bottom: 1px solid #f1f5f9; } @media (min-width: 768px) { .calendar-header { flex-direction: row; justify-content: space-between; align-items: center; } } .calendar-title { font-size: 2.2rem; font-weight: 900; background: linear-gradient(90deg, #2b7de9, #00b4d8); -webkit-background-clip: text; background-clip: text; color: transparent; display: inline-block; letter-spacing: -0.5px; text-shadow: 0 2px 4px rgba(0,0,0,0.05); } .calendar-nav { display: flex; gap: 1.2rem; align-items: center; } .nav-button { padding: 0.8rem 1.6rem; background: white; border: none; border-radius: 12px; cursor: pointer; transition: var(--transition); font-weight: 600; color: white; box-shadow: 0 4px 6px rgba(0,0,0,0.1); background: linear-gradient(135deg, #2b7de9, #00b4d8); } .nav-button:hover { transform: translateY(-2px); box-shadow: 0 6px 12px rgba(0,0,0,0.15); opacity: 0.9; } .current-month { font-size: 1.6rem; font-weight: 700; color: #334155; min-width: 160px; text-align: center; text-shadow: 0 2px 4px rgba(0,0,0,0.05); } .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 12px; } .day-header { text-align: center; padding: 0.8rem 0.5rem; font-weight: 700; color: #64748b; background: white; border-radius: var(--radius); text-transform: uppercase; font-size: 0.85rem; letter-spacing: 0.3px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); position: relative; overflow: hidden; border-bottom: 2px solid #f1f5f9; } .day-header:nth-child(1) { /* ์ผ */ color: var(--sunday); border-bottom: 3px solid var(--sunday); } .day-header:nth-child(2) { /* ์ */ color: var(--monday); border-bottom: 3px solid var(--monday); } .day-header:nth-child(3) { /* ํ */ color: var(--tuesday); border-bottom: 3px solid var(--tuesday); } .day-header:nth-child(4) { /* ์ */ color: var(--wednesday); border-bottom: 3px solid var(--wednesday); } .day-header:nth-child(5) { /* ๋ชฉ */ color: var(--thursday); border-bottom: 3px solid var(--thursday); } .day-header:nth-child(6) { /* ๊ธ */ color: var(--friday); border-bottom: 3px solid var(--friday); } .day-header:nth-child(7) { /* ํ */ color: var(--saturday); border-bottom: 3px solid var(--saturday); } .day-cell { min-height: 100px; padding: 0.5rem; background: white; border-radius: var(--radius); transition: var(--transition); box-shadow: 0 2px 4px rgba(0,0,0,0.05); position: relative; overflow: hidden; } .day-cell.sunday { background-color: rgba(255, 90, 95, 0.1); } .day-cell.saturday { background-color: rgba(74, 107, 223, 0.1); } .day-cell:hover { box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); transform: translateY(-2px); } .day-number { font-weight: 700; margin-bottom: 0.5rem; color: #334155; font-size: 1.1rem; display: inline-block; padding: 2px 6px; border-radius: 6px; background: rgba(0,0,0,0.02); } .day-today .day-number { background: linear-gradient(135deg, #2b7de9, #00b4d8); color: white; font-weight: 800; padding: 4px 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .event-card { padding: 0.4rem; margin-bottom: 0.4rem; font-size: 0.8rem; border-radius: 6px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; transition: var(--transition); display: flex; align-items: center; gap: 4px; box-shadow: 0 1px 2px rgba(0,0,0,0.05); } .event-card:hover { transform: translateY(-3px); box-shadow: 0 2px 8px rgba(0,0,0,0.1); } .event-uniedu { border-left: 3px solid var(--uniedu); background-color: rgba(43, 125, 233, 0.08); } .event-mod { border-left: 3px solid var(--mod); background-color: rgba(230, 57, 70, 0.08); } .event-peacemaker { border-left: 3px solid var(--peacemaker); background-color: rgba(42, 157, 143, 0.08); } .event-hyundai { border-left: 3px solid var(--hyundai); background-color: rgba(247, 127, 0, 0.08); } .event-bus { border-left: 3px solid var(--bus); background-color: rgba(0, 180, 216, 0.08); } .event-camp { border-left: 3px solid var(--camp); background-color: rgba(114, 9, 183, 0.08); } .calendar-actions { display: flex; justify-content: flex-end; gap: 1rem; margin-top: 1.5rem; } .action-button { padding: 0.7rem 1.5rem; border: none; border-radius: 6px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .print-button { background: #2b7de9; color: white; } .print-button:hover { background: #1a5fb4; } .add-button { background: #2a9d8f; color: white; } .add-button:hover { background: #21867a; } /* ๋ชจ๋ฌ ์คํ์ผ */ .modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 1000; justify-content: center; align-items: center; } .modal-content { background: white; padding: 1.5rem; border-radius: 8px; width: 95%; max-width: 100%; margin: 0 10px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); } @media (max-width: 768px) { .calendar-container { padding: 1rem; margin: 1rem auto; } .calendar-grid { gap: 6px; } .day-cell { min-height: 70px; padding: 0.3rem; } .event-card { font-size: 0.7rem; padding: 0.3rem; } .calendar-title { font-size: 1.3rem; } .current-month { font-size: 1.1rem; } .nav-button { padding: 0.4rem 0.8rem; font-size: 0.8rem; } .calendar-actions { margin-top: 1rem; } .action-button { padding: 0.5rem 1rem; font-size: 0.8rem; } } /* ์ค๋ ์ผ์ ์น์
์คํ์ผ */ .today-events-container { max-width: 1400px; margin: 0 auto 2rem; padding: 1.5rem; background: white; border-radius: var(--radius); box-shadow: var(--shadow); } .today-events-title { font-size: 1.5rem; font-weight: 700; margin-bottom: 1rem; color: #334155; padding-bottom: 0.5rem; border-bottom: 1px solid #f1f5f9; } .today-events-list { display: grid; gap: 0.8rem; } .today-event { padding: 1rem; border-radius: 8px; display: flex; align-items: center; gap: 1rem; transition: var(--transition); } .today-event:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(0,0,0,0.1); } .today-event-icon { font-size: 1.5rem; flex-shrink: 0; } .today-event-content { flex-grow: 1; } .today-event-title { font-weight: 600; margin-bottom: 0.3rem; } .today-event-org { font-size: 0.8rem; color: #64748b; } .today-event-desc { font-size: 0.9rem; margin-top: 0.5rem; color: #475569; } .no-events { text-align: center; color: #94a3b8; padding: 1rem; } @media (max-width: 768px) { .today-events-container { padding: 1rem; } .today-events-title { font-size: 1.2rem; } .today-event { padding: 0.8rem; } } @media print { body * { visibility: hidden; } .print-area, .print-area * { visibility: visible; } .print-area { position: absolute; left: 0; top: 0; width: 100%; } } </style> </head> <body> <div class="calendar-container"> <div class="calendar-header"> <div class="calendar-title"> ์ผ์ ์บ๋ฆฐ๋</div> <div class="calendar-nav"> <button class="nav-button" id="prev-month">์ด์ ๋ฌ</button> <div class="current-month" id="current-month">2025๋
6์</div> <button class="nav-button" id="next-month">๋ค์ ๋ฌ</button> </div> </div> <div class="calendar-grid" id="calendar-grid"> <!-- ์ผ์์ผ๋ถํฐ ํ ์์ผ๊น์ง ์์ผ ํค๋ --> <div class="day-header">์ผ</div> <div class="day-header">์</div> <div class="day-header">ํ</div> <div class="day-header">์</div> <div class="day-header">๋ชฉ</div> <div class="day-header">๊ธ</div> <div class="day-header">ํ </div> <!-- ๋ฌ๋ ฅ ์ผ์๋ JavaScript๋ก ๋์ ์์ฑ --> </div> <div class="calendar-actions"> <button class="action-button add-button" id="add-event">์ผ์ ์ถ๊ฐ</button> <button class="action-button print-button" id="print-calendar">์ธ์ํ๊ธฐ</button> </div> </div> <div class="today-events-container"> <h3 class="today-events-title">์ค๋์ ์ผ์ </h3> <div class="today-events-list" id="today-events"> <!-- ์ค๋ ์ผ์ ์ JavaScript๋ก ๋์ ์์ฑ --> <div class="no-events">์ค๋ ์์ ๋ ์ผ์ ์ด ์์ต๋๋ค</div> </div> </div> <!-- ์ด๋ฒคํธ ์ถ๊ฐ/์์ ๋ชจ๋ฌ --> <div class="modal" id="event-modal"> <div class="modal-content"> <h3>์ผ์ ์ถ๊ฐ</h3> <form id="event-form"> <div style="margin-bottom: 1rem;"> <label for="event-title">์ ๋ชฉ</label> <input type="text" id="event-title" required style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"> </div> <div style="margin-bottom: 1rem;"> <label for="event-date">๋ ์ง</label> <input type="date" id="event-date" required style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"> </div> <div style="margin-bottom: 1rem;"> <label for="event-org">๊ธฐ๊ด</label> <select id="event-org" style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"> <option value="uniedu">๐ ํต์ผ๊ต์ก์</option> <option value="mod">๐ก๏ธ ๊ตญ๋ฐฉ๋ถ</option> <option value="peacemaker">๐๏ธ ํผ์ค๋ฉ์ดํฌ</option> <option value="hyundai">๐๏ธ ํ์บ </option> <!-- ๋ณ๊ฒฝ๋ ๋ถ๋ถ --> <option value="bus">๐ ๋ฒ์ค๊ฐ์</option> <option value="camp">๐ ๊ธฐํ</option> <!-- ๋ณ๊ฒฝ๋ ๋ถ๋ถ --> </select> </div> <div style="margin-bottom: 1.5rem;"> <label for="event-desc">์ค๋ช
</label> <textarea id="event-desc" rows="3" style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"></textarea> </div> <div style="margin-bottom: 1rem;"> <label for="event-amount">๊ธ์ก (์)</label> <input type="number" id="event-amount" style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;" min="0" /> </div> <div style="display: flex; justify-content: flex-end; gap: 0.5rem;"> <button type="button" id="cancel-event" style="padding: 0.5rem 1rem; background: #f8f9fa; border: 1px solid #ddd; border-radius: 4px;">์ทจ์</button> <button type="submit" style="padding: 0.5rem 1rem; background: #2b7de9; color: white; border: none; border-radius: 4px;">์ ์ฅ</button> </div> </form> </div> </div> <script> const todayEventData = <?php echo json_encode($today_events); ?>; </script> <script> // ํ์ฌ ๋ ์ง ๊ธฐ์ค์ผ๋ก ๋ฌ๋ ฅ ์์ฑ document.addEventListener('DOMContentLoaded', function() { const currentDate = new Date(); renderCalendar(currentDate); showDayEvents(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()); // ๋ชจ๋ฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ const modal = document.getElementById('event-modal'); document.getElementById('add-event').addEventListener('click', () => { modal.style.display = 'flex'; }); document.getElementById('cancel-event').addEventListener('click', () => { modal.style.display = 'none'; document.getElementById('event-form').reset(); }); // Handle form submission document.getElementById('event-form').addEventListener('submit', function(e) { e.preventDefault(); const formData = { 'event-title': document.getElementById('event-title').value, 'event-date': document.getElementById('event-date').value, 'event-org': document.getElementById('event-org').value, 'event-desc': document.getElementById('event-desc').value }; fetch('<?php echo $_SERVER['PHP_SELF']; ?>', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(formData) }) .then(response => response.json()) .then(data => { if (data.success) { modal.style.display = 'none'; this.reset(); renderCalendar(currentDate); renderTodayEvents(currentDate); } }); }); // ๊ธ์ก ์
๋ ฅ ๋ถ๋ถ const formData = { 'event-title': document.getElementById('event-title').value.trim(), 'event-date': document.getElementById('event-date').value, 'event-org': document.getElementById('event-org').value, 'event-desc': document.getElementById('event-desc').value.trim(), 'event-amount': parseInt(document.getElementById('event-amount').value || '0', 10) }; // ์ธ์ ๋ฒํผ document.getElementById('print-calendar').addEventListener('click', () => { window.print(); }); // ์ ์ด๋ ๋ฒํผ document.getElementById('prev-month').addEventListener('click', () => { currentDate.setMonth(currentDate.getMonth() - 1); renderCalendar(currentDate); }); document.getElementById('next-month').addEventListener('click', () => { currentDate.setMonth(currentDate.getMonth() + 1); renderCalendar(currentDate); renderTodayEvents(currentDate); }); }); function showDayEvents(year, month, day) { const formattedDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; fetch(`get_events.php?date=${formattedDate}`) .then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.json(); }) .then(events => { const todayEvents = document.getElementById('today-events'); todayEvents.innerHTML = ''; // Update title to show selected date document.querySelector('.today-events-title').textContent = `${year}๋
${month + 1}์ ${day}์ผ ์ผ์ `; if (events.length === 0) { todayEvents.innerHTML = '<div class="no-events">์์ ๋ ์ผ์ ์ด ์์ต๋๋ค</div>'; return; } events.forEach(event => { const eventEl = document.createElement('div'); eventEl.className = `today-event event-${event.org}`; eventEl.innerHTML = ` <div class="today-event-icon">${getOrgIcon(event.org)}</div> <div class="today-event-content"> <div class="today-event-title">${event.title}</div> <div class="today-event-org">${getOrgName(event.org)}</div> <div class="today-event-desc"> ${event.description} ${event.amount && parseInt(event.amount) > 0 ? `<br><strong>๊ธ์ก:</strong> ${parseInt(event.amount).toLocaleString()}์` : ''} </div> </div> `; todayEvents.appendChild(eventEl); }); }) .catch(error => { console.error('Error fetching events:', error); }); } function renderTodayEvents(date) { const todayEvents = document.getElementById('today-events'); todayEvents.innerHTML = ''; // PHP์์ ๊ฐ์ ธ์จ ์ค๋์ ์ด๋ฒคํธ ๋ฐ์ดํฐ const events = <?php echo json_encode($today_events); ?>; if (events.length === 0) { todayEvents.innerHTML = '<div class="no-events">์ค๋ ์์ ๋ ์ผ์ ์ด ์์ต๋๋ค</div>'; return; } events.forEach(event => { const eventEl = document.createElement('div'); eventEl.className = `today-event event-${event.org}`; eventEl.innerHTML = ` <div class="today-event-icon">${event.icon}</div> <div class="today-event-content"> <div class="today-event-title">${event.title}</div> <div class="today-event-org">${getOrgName(event.org)}</div> <div class="today-event-desc">${event.desc}</div> </div> `; todayEvents.appendChild(eventEl); }); } function getOrgIcon(org) { const orgIcons = { 'uniedu': '๐', 'mod': '๐ก๏ธ', 'peacemaker': '๐๏ธ', 'hyundai': '๐๏ธ', // ํ๋์์ฐ โ ํ์บ (์์ด์ฝ ๋ณ๊ฒฝ) 'bus': '๐', 'camp': '๐' // ํ์บ โ ๊ธฐํ }; return orgIcons[org] || ''; } function getOrgName(org) { const orgNames = { 'uniedu': 'ํต์ผ๊ต์ก์', 'mod': '๊ตญ๋ฐฉ๋ถ', 'peacemaker': 'ํผ์ค๋ฉ์ดํฌ', 'hyundai': 'ํ์บ ', // ํ๋์์ฐ โ ํ์บ 'bus': '๋ฒ์ค๊ฐ์', 'camp': '๊ธฐํ' // ํ์บ โ ๊ธฐํ }; return orgNames[org] || ''; } function renderCalendar(date) { const year = date.getFullYear(); const month = date.getMonth(); // ํ์ฌ ์ ํ์ ์
๋ฐ์ดํธ document.getElementById('current-month').textContent = `${year}๋
${month + 1}์`; // ๋ฌ๋ ฅ ๊ทธ๋ฆฌ๋ ์ด๊ธฐํ const calendarGrid = document.getElementById('calendar-grid'); // ์์ผ ํค๋๋ฅผ ์ ์ธํ๊ณ ๋ชจ๋ ์์ ์ ๊ฑฐ while (calendarGrid.children.length > 7) { calendarGrid.removeChild(calendarGrid.lastChild); } // ํ์ฌ ์์ ์ฒซ์งธ ๋ ๊ณผ ๋ง์ง๋ง ๋ const firstDay = new Date(year, month, 1); const lastDay = new Date(year, month + 1, 0); // ์ฒซ์งธ ๋ ์ ์์ผ (0: ์ผ์์ผ) const firstDayOfWeek = firstDay.getDay(); // ๋ฌ๋ ฅ ์์ ์ ๋น ์นธ ์ถ๊ฐ for (let i = 0; i < firstDayOfWeek; i++) { const emptyCell = document.createElement('div'); emptyCell.className = 'day-cell'; calendarGrid.appendChild(emptyCell); } // ๋ ์ง ์นธ ์ถ๊ฐ for (let day = 1; day <= lastDay.getDate(); day++) { const dayCell = document.createElement('div'); dayCell.className = 'day-cell'; // Add Sunday/Saturday classes const dayOfWeek = new Date(year, month, day).getDay(); if (dayOfWeek === 0) { dayCell.classList.add('sunday'); } else if (dayOfWeek === 6) { dayCell.classList.add('saturday'); } const dayNumber = document.createElement('div'); dayNumber.className = 'day-number'; dayNumber.textContent = day; // ์ค๋ ๋ ์ง ์ฒดํฌ const today = new Date(); if (today.getFullYear() === year && today.getMonth() === month && today.getDate() === day) { dayCell.classList.add('day-today'); } dayCell.appendChild(dayNumber); dayCell.addEventListener('click', () => { showDayEvents(year, month, day); }); // ๋ ์ง ํ์ ๋ง์ถ๊ธฐ (YYYY-MM-DD) const formattedDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; // ํด๋น ๋ ์ง์ ์ด๋ฒคํธ ๊ฐ์ ธ์ค๊ธฐ fetch(`get_events.php?date=${formattedDate}`) .then(response => { if (!response.ok) throw new Error('Network response was not ok'); return response.json(); }) .then(events => { if (events && events.length > 0) { events.forEach(event => { const eventEl = document.createElement('div'); eventEl.className = `event-card event-${event.org}`; eventEl.textContent = `${getOrgIcon(event.org)} ${event.title}`; dayCell.appendChild(eventEl); }); } }) .catch(error => { console.error('Error fetching events:', error); }); calendarGrid.appendChild(dayCell); } } </script> </body> </html> - Follow Up Deployment
55ea541 verified | <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>๊ฐ์๋ฃ ์ ๊ธ ํ์ธ ์์คํ </title> | |
| <style> | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Noto Sans KR', sans-serif; | |
| } | |
| body { | |
| background-color: #f8fafc; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| background: white; | |
| padding: 30px; | |
| border-radius: 12px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| } | |
| h1 { | |
| color: #2b7de9; | |
| margin-bottom: 20px; | |
| font-size: 2rem; | |
| } | |
| .summary-cards { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 20px; | |
| margin-bottom: 30px; | |
| } | |
| .summary-card { | |
| padding: 20px; | |
| border-radius: 8px; | |
| text-align: center; | |
| color: white; | |
| box-shadow: 0 4px 6px rgba(0,0,0,0.1); | |
| } | |
| .summary-card.total { | |
| background: linear-gradient(135deg, #2b7de9, #00b4d8); | |
| } | |
| .summary-card.paid { | |
| background: linear-gradient(135deg, #2a9d8f, #21867a); | |
| } | |
| .summary-card.unpaid { | |
| background: linear-gradient(135deg, #e63946, #d90429); | |
| } | |
| .summary-card h3 { | |
| font-size: 1.2rem; | |
| margin-bottom: 10px; | |
| } | |
| .summary-card p { | |
| font-size: 1.8rem; | |
| font-weight: 700; | |
| } | |
| .search-box { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 30px; | |
| } | |
| .search-box input { | |
| flex: 1; | |
| padding: 12px; | |
| border: 1px solid #ddd; | |
| border-radius: 6px; | |
| font-size: 16px; | |
| } | |
| .search-box button { | |
| padding: 12px 20px; | |
| background: #2b7de9; | |
| color: white; | |
| border: none; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| } | |
| .payment-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .payment-table th, .payment-table td { | |
| padding: 15px; | |
| text-align: left; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .payment-table th { | |
| background: #f5f9ff; | |
| font-weight: 600; | |
| color: #2b7de9; | |
| } | |
| .payment-status { | |
| padding: 6px 12px; | |
| border-radius: 20px; | |
| font-size: 14px; | |
| font-weight: 500; | |
| } | |
| .status-paid { | |
| background: #e6f7f0; | |
| color: #2a9d8f; | |
| } | |
| .status-unpaid { | |
| background: #ffebee; | |
| color: #e63946; | |
| } | |
| .action-btn { | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| border: none; | |
| cursor: pointer; | |
| font-weight: 500; | |
| } | |
| .confirm-btn { | |
| background: #2b7de9; | |
| color: white; | |
| } | |
| .receipt-btn { | |
| background: #2a9d8f; | |
| color: white; | |
| } | |
| .pagination { | |
| display: flex; | |
| justify-content: center; | |
| margin-top: 30px; | |
| gap: 10px; | |
| } | |
| .pagination button { | |
| padding: 10px 15px; | |
| border: 1px solid #ddd; | |
| background: white; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| } | |
| .pagination button.active { | |
| background: #2b7de9; | |
| color: white; | |
| border-color: #2b7de9; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>๊ฐ์๋ฃ ์ ๊ธ ํ์ธ ์์คํ </h1> | |
| <div class="summary-cards"> | |
| <div class="summary-card total"> | |
| <h3>์ด ๊ฐ์๋ฃ</h3> | |
| <p><?= number_format($totalAmount) ?>์</p> | |
| </div> | |
| <div class="summary-card paid"> | |
| <h3>์ ๊ธ ์๋ฃ</h3> | |
| <p><?= number_format($paidAmount) ?>์</p> | |
| </div> | |
| <div class="summary-card unpaid"> | |
| <h3>๋ฏธ์ ๊ธ</h3> | |
| <p><?= number_format($unpaidAmount) ?>์</p> | |
| </div> | |
| </div> | |
| <div class="search-box"> | |
| <input type="text" id="search-input" placeholder="๊ฐ์ฌ๋ช ๋๋ ๊ฐ์๋ช ์ผ๋ก ๊ฒ์"> | |
| <button id="search-btn">๊ฒ์</button> | |
| </div> | |
| <table class="payment-table"> | |
| <thead> | |
| <tr> | |
| <th>๊ฐ์์ผ์</th> | |
| <th>๊ฐ์ฌ๋ช </th> | |
| <th>๊ฐ์๋ช </th> | |
| <th>๊ธฐ๊ด</th> | |
| <th>๊ฐ์๋ฃ</th> | |
| <th>์ ๊ธ์ํ</th> | |
| <th>๊ด๋ฆฌ</th> | |
| </tr> | |
| </thead> | |
| <tbody id="payment-list"> | |
| <tr> | |
| <td><?= $event['event_date'] ?></td> | |
| <td><?= $event['lecturer'] ?? 'N/A' ?></td> | |
| <td><?= $event['title'] ?></td> | |
| <td><?= $event['org'] ?></td> | |
| <td><?= number_format($event['amount']) ?>์</td> | |
| <td> | |
| <span class="payment-status <?= $event['paid'] ? 'status-paid' : 'status-unpaid' ?>"> | |
| <?= $event['paid'] ? '์ ๊ธ์๋ฃ' : '๋ฏธ์ ๊ธ' ?> | |
| </span> | |
| </td> | |
| <td> | |
| <button class="action-btn confirm-btn" onclick="confirmPayment(<?= $event['id'] ?>)">์ ๊ธํ์ธ</button> | |
| <button class="action-btn receipt-btn" onclick="viewReceipt(<?= $event['id'] ?>)">์์์ฆ</button> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <script> | |
| function confirmPayment(eventId) { | |
| if (confirm('์ ๋ง๋ก ์ ๊ธ ํ์ธ ์ฒ๋ฆฌ๋ฅผ ํ์๊ฒ ์ต๋๊น?')) { | |
| fetch('confirm_payment.php', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ eventId: eventId }) | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| alert('์ ๊ธ ํ์ธ์ด ์๋ฃ๋์์ต๋๋ค.'); | |
| location.reload(); | |
| } else { | |
| alert('์ ๊ธ ํ์ธ ์ฒ๋ฆฌ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.'); | |
| } | |
| }); | |
| } | |
| } | |
| function viewReceipt(eventId) { | |
| // ์์์ฆ ๋ณด๊ธฐ ๊ธฐ๋ฅ ๊ตฌํ | |
| alert('์์์ฆ ๋ณด๊ธฐ ๊ธฐ๋ฅ: ' + eventId); | |
| } | |
| // ๊ฒ์ ๊ธฐ๋ฅ | |
| document.getElementById('search-btn').addEventListener('click', function() { | |
| const searchTerm = document.getElementById('search-input').value.toLowerCase(); | |
| const rows = document.querySelectorAll('#payment-list tr'); | |
| rows.forEach(row => { | |
| const text = row.textContent.toLowerCase(); | |
| if (text.includes(searchTerm)) { | |
| row.style.display = ''; | |
| } else { | |
| row.style.display = 'none'; | |
| } | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - ๐งฌ <a href="https://enzostvs-deepsite.hf.space?remix=nkjoy/joy01" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> | |
| <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>๊ฐ์๋ฃ ์ ๊ธ ํ์ธ ์์คํ </title> | |
| <style> | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Noto Sans KR', sans-serif; | |
| } | |
| body { | |
| background-color: #f8fafc; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| background: white; | |
| padding: 30px; | |
| border-radius: 12px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| } | |
| h1 { | |
| color: #2b7de9; | |
| margin-bottom: 20px; | |
| font-size: 2rem; | |
| } | |
| .search-box { | |
| display: flex; | |
| gap: 10px; | |
| margin-bottom: 30px; | |
| } | |
| .search-box input { | |
| flex: 1; | |
| padding: 12px; | |
| border: 1px solid #ddd; | |
| border-radius: 6px; | |
| font-size: 16px; | |
| } | |
| .search-box button { | |
| padding: 12px 20px; | |
| background: #2b7de9; | |
| color: white; | |
| border: none; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| font-weight: 600; | |
| } | |
| .payment-table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .payment-table th, .payment-table td { | |
| padding: 15px; | |
| text-align: left; | |
| border-bottom: 1px solid #eee; | |
| } | |
| .payment-table th { | |
| background: #f5f9ff; | |
| font-weight: 600; | |
| color: #2b7de9; | |
| } | |
| .payment-status { | |
| padding: 6px 12px; | |
| border-radius: 20px; | |
| font-size: 14px; | |
| font-weight: 500; | |
| } | |
| .status-paid { | |
| background: #e6f7f0; | |
| color: #2a9d8f; | |
| } | |
| .status-unpaid { | |
| background: #ffebee; | |
| color: #e63946; | |
| } | |
| .action-btn { | |
| padding: 8px 12px; | |
| border-radius: 6px; | |
| border: none; | |
| cursor: pointer; | |
| font-weight: 500; | |
| } | |
| .confirm-btn { | |
| background: #2b7de9; | |
| color: white; | |
| } | |
| .receipt-btn { | |
| background: #2a9d8f; | |
| color: white; | |
| } | |
| .pagination { | |
| display: flex; | |
| justify-content: center; | |
| margin-top: 30px; | |
| gap: 10px; | |
| } | |
| .pagination button { | |
| padding: 10px 15px; | |
| border: 1px solid #ddd; | |
| background: white; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| } | |
| .pagination button.active { | |
| background: #2b7de9; | |
| color: white; | |
| border-color: #2b7de9; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>๊ฐ์๋ฃ ์ ๊ธ ํ์ธ ์์คํ </h1> | |
| <div class="search-box"> | |
| <input type="text" id="search-input" placeholder="๊ฐ์ฌ๋ช ๋๋ ๊ฐ์๋ช ์ผ๋ก ๊ฒ์"> | |
| <button id="search-btn">๊ฒ์</button> | |
| </div> | |
| <table class="payment-table"> | |
| <thead> | |
| <tr> | |
| <th>๊ฐ์์ผ์</th> | |
| <th>๊ฐ์ฌ๋ช </th> | |
| <th>๊ฐ์๋ช </th> | |
| <th>๊ธฐ๊ด</th> | |
| <th>๊ฐ์๋ฃ</th> | |
| <th>์ ๊ธ์ํ</th> | |
| <th>๊ด๋ฆฌ</th> | |
| </tr> | |
| </thead> | |
| <tbody id="payment-list"> | |
| <!-- ๋ฐ์ดํฐ๊ฐ ์ฌ๊ธฐ์ ๋์ ์ผ๋ก ๋ก๋๋ฉ๋๋ค --> | |
| <tr> | |
| <td colspan="7" style="text-align: center;">๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <div class="pagination"> | |
| <button><</button> | |
| <button class="active">1</button> | |
| <button>2</button> | |
| <button>3</button> | |
| <button>></button> | |
| </div> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // ์ฌ๊ธฐ์ ์ค์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค | |
| // ์์ ๋ฐ์ดํฐ | |
| const sampleData = [ | |
| { | |
| date: '2023-11-15', | |
| lecturer: '๊น๊ฐ์ฌ', | |
| title: 'ํต์ผ๊ต์ก ๊ธฐ๋ณธ๊ณผ์ ', | |
| org: 'ํต์ผ๊ต์ก์', | |
| amount: '300,000์', | |
| status: 'paid' | |
| }, | |
| { | |
| date: '2023-11-20', | |
| lecturer: '์ด๊ฐ์ฌ', | |
| title: 'ํํํต์ผ ๊ฐ์', | |
| org: 'ํผ์ค๋ฉ์ดํฌ', | |
| amount: '250,000์', | |
| status: 'unpaid' | |
| }, | |
| { | |
| date: '2023-11-25', | |
| lecturer: '๋ฐ๊ฐ์ฌ', | |
| title: '์๋ณด๊ต์ก', | |
| org: '๊ตญ๋ฐฉ๋ถ', | |
| amount: '350,000์', | |
| status: 'paid' | |
| } | |
| ]; | |
| renderPayments(sampleData); | |
| // ๊ฒ์ ๊ธฐ๋ฅ | |
| document.getElementById('search-btn').addEventListener('click', function() { | |
| const searchTerm = document.getElementById('search-input').value.toLowerCase(); | |
| const filteredData = sampleData.filter(item => | |
| item.lecturer.toLowerCase().includes(searchTerm) || | |
| item.title.toLowerCase().includes(searchTerm) | |
| ); | |
| renderPayments(filteredData); | |
| }); | |
| }); | |
| function renderPayments(data) { | |
| const paymentList = document.getElementById('payment-list'); | |
| if (data.length === 0) { | |
| paymentList.innerHTML = '<tr><td colspan="7" style="text-align: center;">๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค</td></tr>'; | |
| return; | |
| } | |
| paymentList.innerHTML = ''; | |
| data.forEach(item => { | |
| const row = document.createElement('tr'); | |
| row.innerHTML = ` | |
| <td>${item.date}</td> | |
| <td>${item.lecturer}</td> | |
| <td>${item.title}</td> | |
| <td>${item.org}</td> | |
| <td>${item.amount}</td> | |
| <td><span class="payment-status status-${item.status}">${ | |
| item.status === 'paid' ? '์ ๊ธ์๋ฃ' : '๋ฏธ์ ๊ธ' | |
| }</span></td> | |
| <td> | |
| ${item.status === 'unpaid' ? | |
| '<button class="action-btn confirm-btn">์ ๊ธํ์ธ</button>' : | |
| '<button class="action-btn receipt-btn">์์์ฆ</button>'} | |
| </td> | |
| `; | |
| paymentList.appendChild(row); | |
| }); | |
| } | |
| </script> | |
| </body> | |
| </html> | |
| <!-- HTML ์์ --> | |
| <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>๊ธฐ๊ด๋ณ ์ผ์ ์บ๋ฆฐ๋</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --uniedu: #2b7de9; | |
| --mod: #e63946; | |
| --peacemaker: #2a9d8f; | |
| --hyundai: #f77f00; | |
| --bus: #00b4d8; | |
| --camp: #7209b7; | |
| --shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| --transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); | |
| --radius: 12px; | |
| --sunday: #ff5a5f; | |
| --monday: #4a6bdf; | |
| --tuesday: #2a9d8f; | |
| --wednesday: #f77f00; | |
| --thursday: #7209b7; | |
| --friday: #2b7de9; | |
| --saturday: #9c4dcc; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, sans-serif; | |
| } | |
| body { | |
| background-color: #f8fafc; | |
| color: #1e293b; | |
| line-height: 1.6; | |
| padding: 0.5rem; | |
| font-size: 14px; | |
| } | |
| .calendar-container { | |
| max-width: 1400px; | |
| margin: 2rem auto; | |
| padding: 2.5rem; | |
| background: white; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| transition: var(--transition); | |
| backdrop-filter: blur(10px); | |
| background: rgba(255, 255, 255, 0.9); | |
| } | |
| .calendar-container:hover { | |
| box-shadow: 0 15px 35px rgba(0,0,0,0.15); | |
| transform: translateY(-2px); | |
| } | |
| .calendar-header { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| margin-bottom: 2rem; | |
| padding-bottom: 1.5rem; | |
| border-bottom: 1px solid #f1f5f9; | |
| } | |
| @media (min-width: 768px) { | |
| .calendar-header { | |
| flex-direction: row; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| } | |
| .calendar-title { | |
| font-size: 2.2rem; | |
| font-weight: 900; | |
| background: linear-gradient(90deg, #2b7de9, #00b4d8); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| display: inline-block; | |
| letter-spacing: -0.5px; | |
| text-shadow: 0 2px 4px rgba(0,0,0,0.05); | |
| } | |
| .calendar-nav { | |
| display: flex; | |
| gap: 1.2rem; | |
| align-items: center; | |
| } | |
| .nav-button { | |
| padding: 0.8rem 1.6rem; | |
| background: white; | |
| border: none; | |
| border-radius: 12px; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| font-weight: 600; | |
| color: white; | |
| box-shadow: 0 4px 6px rgba(0,0,0,0.1); | |
| background: linear-gradient(135deg, #2b7de9, #00b4d8); | |
| } | |
| .nav-button:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 6px 12px rgba(0,0,0,0.15); | |
| opacity: 0.9; | |
| } | |
| .current-month { | |
| font-size: 1.6rem; | |
| font-weight: 700; | |
| color: #334155; | |
| min-width: 160px; | |
| text-align: center; | |
| text-shadow: 0 2px 4px rgba(0,0,0,0.05); | |
| } | |
| .calendar-grid { | |
| display: grid; | |
| grid-template-columns: repeat(7, 1fr); | |
| gap: 12px; | |
| } | |
| .day-header { | |
| text-align: center; | |
| padding: 0.8rem 0.5rem; | |
| font-weight: 700; | |
| color: #64748b; | |
| background: white; | |
| border-radius: var(--radius); | |
| text-transform: uppercase; | |
| font-size: 0.85rem; | |
| letter-spacing: 0.3px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.05); | |
| position: relative; | |
| overflow: hidden; | |
| border-bottom: 2px solid #f1f5f9; | |
| } | |
| .day-header:nth-child(1) { /* ์ผ */ | |
| color: var(--sunday); | |
| border-bottom: 3px solid var(--sunday); | |
| } | |
| .day-header:nth-child(2) { /* ์ */ | |
| color: var(--monday); | |
| border-bottom: 3px solid var(--monday); | |
| } | |
| .day-header:nth-child(3) { /* ํ */ | |
| color: var(--tuesday); | |
| border-bottom: 3px solid var(--tuesday); | |
| } | |
| .day-header:nth-child(4) { /* ์ */ | |
| color: var(--wednesday); | |
| border-bottom: 3px solid var(--wednesday); | |
| } | |
| .day-header:nth-child(5) { /* ๋ชฉ */ | |
| color: var(--thursday); | |
| border-bottom: 3px solid var(--thursday); | |
| } | |
| .day-header:nth-child(6) { /* ๊ธ */ | |
| color: var(--friday); | |
| border-bottom: 3px solid var(--friday); | |
| } | |
| .day-header:nth-child(7) { /* ํ */ | |
| color: var(--saturday); | |
| border-bottom: 3px solid var(--saturday); | |
| } | |
| .day-cell { | |
| min-height: 100px; | |
| padding: 0.5rem; | |
| background: white; | |
| border-radius: var(--radius); | |
| transition: var(--transition); | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.05); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .day-cell.sunday { | |
| background-color: rgba(255, 90, 95, 0.1); | |
| } | |
| .day-cell.saturday { | |
| background-color: rgba(74, 107, 223, 0.1); | |
| } | |
| .day-cell:hover { | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); | |
| transform: translateY(-2px); | |
| } | |
| .day-number { | |
| font-weight: 700; | |
| margin-bottom: 0.5rem; | |
| color: #334155; | |
| font-size: 1.1rem; | |
| display: inline-block; | |
| padding: 2px 6px; | |
| border-radius: 6px; | |
| background: rgba(0,0,0,0.02); | |
| } | |
| .day-today .day-number { | |
| background: linear-gradient(135deg, #2b7de9, #00b4d8); | |
| color: white; | |
| font-weight: 800; | |
| padding: 4px 8px; | |
| box-shadow: 0 2px 4px rgba(0,0,0,0.1); | |
| } | |
| .event-card { | |
| padding: 0.4rem; | |
| margin-bottom: 0.4rem; | |
| font-size: 0.8rem; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| white-space: nowrap; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 4px; | |
| box-shadow: 0 1px 2px rgba(0,0,0,0.05); | |
| } | |
| .event-card:hover { | |
| transform: translateY(-3px); | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.1); | |
| } | |
| .event-uniedu { border-left: 3px solid var(--uniedu); background-color: rgba(43, 125, 233, 0.08); } | |
| .event-mod { border-left: 3px solid var(--mod); background-color: rgba(230, 57, 70, 0.08); } | |
| .event-peacemaker { border-left: 3px solid var(--peacemaker); background-color: rgba(42, 157, 143, 0.08); } | |
| .event-hyundai { border-left: 3px solid var(--hyundai); background-color: rgba(247, 127, 0, 0.08); } | |
| .event-bus { border-left: 3px solid var(--bus); background-color: rgba(0, 180, 216, 0.08); } | |
| .event-camp { border-left: 3px solid var(--camp); background-color: rgba(114, 9, 183, 0.08); } | |
| .calendar-actions { | |
| display: flex; | |
| justify-content: flex-end; | |
| gap: 1rem; | |
| margin-top: 1.5rem; | |
| } | |
| .action-button { | |
| padding: 0.7rem 1.5rem; | |
| border: none; | |
| border-radius: 6px; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| } | |
| .print-button { | |
| background: #2b7de9; | |
| color: white; | |
| } | |
| .print-button:hover { | |
| background: #1a5fb4; | |
| } | |
| .add-button { | |
| background: #2a9d8f; | |
| color: white; | |
| } | |
| .add-button:hover { | |
| background: #21867a; | |
| } | |
| /* ๋ชจ๋ฌ ์คํ์ผ */ | |
| .modal { | |
| display: none; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background: rgba(0, 0, 0, 0.5); | |
| z-index: 1000; | |
| justify-content: center; | |
| align-items: center; | |
| } | |
| .modal-content { | |
| background: white; | |
| padding: 1.5rem; | |
| border-radius: 8px; | |
| width: 95%; | |
| max-width: 100%; | |
| margin: 0 10px; | |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); | |
| } | |
| @media (max-width: 768px) { | |
| .calendar-container { | |
| padding: 1rem; | |
| margin: 1rem auto; | |
| } | |
| .calendar-grid { | |
| gap: 6px; | |
| } | |
| .day-cell { | |
| min-height: 70px; | |
| padding: 0.3rem; | |
| } | |
| .event-card { | |
| font-size: 0.7rem; | |
| padding: 0.3rem; | |
| } | |
| .calendar-title { | |
| font-size: 1.3rem; | |
| } | |
| .current-month { | |
| font-size: 1.1rem; | |
| } | |
| .nav-button { | |
| padding: 0.4rem 0.8rem; | |
| font-size: 0.8rem; | |
| } | |
| .calendar-actions { | |
| margin-top: 1rem; | |
| } | |
| .action-button { | |
| padding: 0.5rem 1rem; | |
| font-size: 0.8rem; | |
| } | |
| } | |
| /* ์ค๋ ์ผ์ ์น์ ์คํ์ผ */ | |
| .today-events-container { | |
| max-width: 1400px; | |
| margin: 0 auto 2rem; | |
| padding: 1.5rem; | |
| background: white; | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow); | |
| } | |
| .today-events-title { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| margin-bottom: 1rem; | |
| color: #334155; | |
| padding-bottom: 0.5rem; | |
| border-bottom: 1px solid #f1f5f9; | |
| } | |
| .today-events-list { | |
| display: grid; | |
| gap: 0.8rem; | |
| } | |
| .today-event { | |
| padding: 1rem; | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| transition: var(--transition); | |
| } | |
| .today-event:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.1); | |
| } | |
| .today-event-icon { | |
| font-size: 1.5rem; | |
| flex-shrink: 0; | |
| } | |
| .today-event-content { | |
| flex-grow: 1; | |
| } | |
| .today-event-title { | |
| font-weight: 600; | |
| margin-bottom: 0.3rem; | |
| } | |
| .today-event-org { | |
| font-size: 0.8rem; | |
| color: #64748b; | |
| } | |
| .today-event-desc { | |
| font-size: 0.9rem; | |
| margin-top: 0.5rem; | |
| color: #475569; | |
| } | |
| .no-events { | |
| text-align: center; | |
| color: #94a3b8; | |
| padding: 1rem; | |
| } | |
| @media (max-width: 768px) { | |
| .today-events-container { | |
| padding: 1rem; | |
| } | |
| .today-events-title { | |
| font-size: 1.2rem; | |
| } | |
| .today-event { | |
| padding: 0.8rem; | |
| } | |
| } | |
| @media print { | |
| body * { | |
| visibility: hidden; | |
| } | |
| .print-area, .print-area * { | |
| visibility: visible; | |
| } | |
| .print-area { | |
| position: absolute; | |
| left: 0; | |
| top: 0; | |
| width: 100%; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="calendar-container"> | |
| <div class="calendar-header"> | |
| <div class="calendar-title">๊ธฐ๊ด๋ณ ์ผ์ ์บ๋ฆฐ๋</div> | |
| <div class="calendar-nav"> | |
| <button class="nav-button" id="prev-month">์ด์ ๋ฌ</button> | |
| <div class="current-month" id="current-month">2025๋ 6์</div> | |
| <button class="nav-button" id="next-month">๋ค์ ๋ฌ</button> | |
| </div> | |
| </div> | |
| <div class="calendar-grid" id="calendar-grid"> | |
| <!-- ์ผ์์ผ๋ถํฐ ํ ์์ผ๊น์ง ์์ผ ํค๋ --> | |
| <div class="day-header">์ผ</div> | |
| <div class="day-header">์</div> | |
| <div class="day-header">ํ</div> | |
| <div class="day-header">์</div> | |
| <div class="day-header">๋ชฉ</div> | |
| <div class="day-header">๊ธ</div> | |
| <div class="day-header">ํ </div> | |
| <!-- ๋ฌ๋ ฅ ์ผ์๋ JavaScript๋ก ๋์ ์์ฑ --> | |
| </div> | |
| <div class="calendar-actions"> | |
| <button class="action-button add-button" id="add-event">์ผ์ ์ถ๊ฐ</button> | |
| <button class="action-button print-button" id="print-calendar">์ธ์ํ๊ธฐ</button> | |
| <a href="payment_confirmation.php" class="action-button" style="background:#7209b7; color:white; text-decoration:none;">๊ฐ์๋ฃ ํ์ธ</a> | |
| </div> | |
| </div> | |
| <div class="today-events-container"> | |
| <h3 class="today-events-title">์ค๋์ ์ผ์ </h3> | |
| <div class="today-events-list" id="today-events"> | |
| <!-- ์ค๋ ์ผ์ ์ JavaScript๋ก ๋์ ์์ฑ --> | |
| <div class="no-events">์ค๋ ์์ ๋ ์ผ์ ์ด ์์ต๋๋ค</div> | |
| </div> | |
| </div> | |
| <!-- ์ด๋ฒคํธ ์ถ๊ฐ/์์ ๋ชจ๋ฌ --> | |
| <div class="modal" id="event-modal"> | |
| <div class="modal-content"> | |
| <h3>์ผ์ ์ถ๊ฐ</h3> | |
| <form id="event-form"> | |
| <div style="margin-bottom: 1rem;"> | |
| <label for="event-title">์ ๋ชฉ</label> | |
| <input type="text" id="event-title" required style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"> | |
| </div> | |
| <div style="margin-bottom: 1rem;"> | |
| <label for="event-date">๋ ์ง</label> | |
| <input type="date" id="event-date" required style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"> | |
| </div> | |
| <div style="margin-bottom: 1rem;"> | |
| <label for="event-org">๊ธฐ๊ด</label> | |
| <select id="event-org" style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"> | |
| <option value="uniedu">๐ ํต์ผ๊ต์ก์</option> | |
| <option value="mod">๐ก๏ธ ๊ตญ๋ฐฉ๋ถ</option> | |
| <option value="peacemaker">๐๏ธ ํผ์ค๋ฉ์ดํฌ</option> | |
| <option value="hyundai">๐ญ ํ๋์์ฐ</option> | |
| <option value="bus">๐ ๋ฒ์ค๊ฐ์</option> | |
| <option value="camp">๐๏ธ ํ์บ </option> | |
| </select> | |
| </div> | |
| <div style="margin-bottom: 1.5rem;"> | |
| <label for="event-desc">์ค๋ช </label> | |
| <textarea id="event-desc" rows="3" style="width: 100%; padding: 0.5rem; margin-top: 0.3rem;"></textarea> | |
| </div> | |
| <div style="display: flex; justify-content: flex-end; gap: 0.5rem;"> | |
| <button type="button" id="cancel-event" style="padding: 0.5rem 1rem; background: #f8f9fa; border: 1px solid #ddd; border-radius: 4px;">์ทจ์</button> | |
| <button type="submit" style="padding: 0.5rem 1rem; background: #2b7de9; color: white; border: none; border-radius: 4px;">์ ์ฅ</button> | |
| </div> | |
| </form> | |
| </div> | |
| </div> | |
| <script> | |
| const todayEventData = <?php echo json_encode($today_events); ?>; | |
| </script> | |
| <script> | |
| // ํ์ฌ ๋ ์ง ๊ธฐ์ค์ผ๋ก ๋ฌ๋ ฅ ์์ฑ | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const currentDate = new Date(); | |
| renderCalendar(currentDate); | |
| showDayEvents(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()); | |
| // ๋ชจ๋ฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ | |
| const modal = document.getElementById('event-modal'); | |
| document.getElementById('add-event').addEventListener('click', () => { | |
| modal.style.display = 'flex'; | |
| }); | |
| document.getElementById('cancel-event').addEventListener('click', () => { | |
| modal.style.display = 'none'; | |
| document.getElementById('event-form').reset(); | |
| }); | |
| // Handle form submission | |
| document.getElementById('event-form').addEventListener('submit', function(e) { | |
| e.preventDefault(); | |
| const formData = { | |
| 'event-title': document.getElementById('event-title').value, | |
| 'event-date': document.getElementById('event-date').value, | |
| 'event-org': document.getElementById('event-org').value, | |
| 'event-desc': document.getElementById('event-desc').value | |
| }; | |
| fetch('<?php echo $_SERVER['PHP_SELF']; ?>', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify(formData) | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.success) { | |
| modal.style.display = 'none'; | |
| this.reset(); | |
| renderCalendar(currentDate); | |
| renderTodayEvents(currentDate); | |
| } | |
| }); | |
| }); | |
| // ์ธ์ ๋ฒํผ | |
| document.getElementById('print-calendar').addEventListener('click', () => { | |
| window.print(); | |
| }); | |
| // ์ ์ด๋ ๋ฒํผ | |
| document.getElementById('prev-month').addEventListener('click', () => { | |
| currentDate.setMonth(currentDate.getMonth() - 1); | |
| renderCalendar(currentDate); | |
| }); | |
| document.getElementById('next-month').addEventListener('click', () => { | |
| currentDate.setMonth(currentDate.getMonth() + 1); | |
| renderCalendar(currentDate); | |
| renderTodayEvents(currentDate); | |
| }); | |
| }); | |
| function showDayEvents(year, month, day) { | |
| const formattedDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; | |
| fetch(`get_events.php?date=${formattedDate}`) | |
| .then(response => { | |
| if (!response.ok) throw new Error('Network response was not ok'); | |
| return response.json(); | |
| }) | |
| .then(events => { | |
| const todayEvents = document.getElementById('today-events'); | |
| todayEvents.innerHTML = ''; | |
| // Update title to show selected date | |
| document.querySelector('.today-events-title').textContent = | |
| `${year}๋ ${month + 1}์ ${day}์ผ ์ผ์ `; | |
| if (events.length === 0) { | |
| todayEvents.innerHTML = '<div class="no-events">์์ ๋ ์ผ์ ์ด ์์ต๋๋ค</div>'; | |
| return; | |
| } | |
| events.forEach(event => { | |
| const eventEl = document.createElement('div'); | |
| eventEl.className = `today-event event-${event.org}`; | |
| eventEl.innerHTML = ` | |
| <div class="today-event-icon">${getOrgIcon(event.org)}</div> | |
| <div class="today-event-content"> | |
| <div class="today-event-title">${event.title}</div> | |
| <div class="today-event-org">${getOrgName(event.org)}</div> | |
| <div class="today-event-desc">${event.description}</div> | |
| </div> | |
| `; | |
| todayEvents.appendChild(eventEl); | |
| }); | |
| }) | |
| .catch(error => { | |
| console.error('Error fetching events:', error); | |
| }); | |
| } | |
| function renderTodayEvents(date) { | |
| const todayEvents = document.getElementById('today-events'); | |
| todayEvents.innerHTML = ''; | |
| // PHP์์ ๊ฐ์ ธ์จ ์ค๋์ ์ด๋ฒคํธ ๋ฐ์ดํฐ | |
| const events = <?php echo json_encode($today_events); ?>; | |
| if (events.length === 0) { | |
| todayEvents.innerHTML = '<div class="no-events">์ค๋ ์์ ๋ ์ผ์ ์ด ์์ต๋๋ค</div>'; | |
| return; | |
| } | |
| events.forEach(event => { | |
| const eventEl = document.createElement('div'); | |
| eventEl.className = `today-event event-${event.org}`; | |
| eventEl.innerHTML = ` | |
| <div class="today-event-icon">${event.icon}</div> | |
| <div class="today-event-content"> | |
| <div class="today-event-title">${event.title}</div> | |
| <div class="today-event-org">${getOrgName(event.org)}</div> | |
| <div class="today-event-desc">${event.desc}</div> | |
| </div> | |
| `; | |
| todayEvents.appendChild(eventEl); | |
| }); | |
| } | |
| function getOrgIcon(org) { | |
| const orgIcons = { | |
| 'uniedu': '๐', | |
| 'mod': '๐ก๏ธ', | |
| 'peacemaker': '๐๏ธ', | |
| 'hyundai': '๐ญ', | |
| 'bus': '๐', | |
| 'camp': '๐๏ธ' | |
| }; | |
| return orgIcons[org] || ''; | |
| } | |
| function getOrgName(org) { | |
| const orgNames = { | |
| 'uniedu': 'ํต์ผ๊ต์ก์', | |
| 'mod': '๊ตญ๋ฐฉ๋ถ', | |
| 'peacemaker': 'ํผ์ค๋ฉ์ดํฌ', | |
| 'hyundai': 'ํ๋์์ฐ', | |
| 'bus': '๋ฒ์ค๊ฐ์', | |
| 'camp': 'ํ์บ ' | |
| }; | |
| return orgNames[org] || ''; | |
| } | |
| function renderCalendar(date) { | |
| const year = date.getFullYear(); | |
| const month = date.getMonth(); | |
| // ํ์ฌ ์ ํ์ ์ ๋ฐ์ดํธ | |
| document.getElementById('current-month').textContent = `${year}๋ ${month + 1}์`; | |
| // ๋ฌ๋ ฅ ๊ทธ๋ฆฌ๋ ์ด๊ธฐํ | |
| const calendarGrid = document.getElementById('calendar-grid'); | |
| // ์์ผ ํค๋๋ฅผ ์ ์ธํ๊ณ ๋ชจ๋ ์์ ์ ๊ฑฐ | |
| while (calendarGrid.children.length > 7) { | |
| calendarGrid.removeChild(calendarGrid.lastChild); | |
| } | |
| // ํ์ฌ ์์ ์ฒซ์งธ ๋ ๊ณผ ๋ง์ง๋ง ๋ | |
| const firstDay = new Date(year, month, 1); | |
| const lastDay = new Date(year, month + 1, 0); | |
| // ์ฒซ์งธ ๋ ์ ์์ผ (0: ์ผ์์ผ) | |
| const firstDayOfWeek = firstDay.getDay(); | |
| // ๋ฌ๋ ฅ ์์ ์ ๋น ์นธ ์ถ๊ฐ | |
| for (let i = 0; i < firstDayOfWeek; i++) { | |
| const emptyCell = document.createElement('div'); | |
| emptyCell.className = 'day-cell'; | |
| calendarGrid.appendChild(emptyCell); | |
| } | |
| // ๋ ์ง ์นธ ์ถ๊ฐ | |
| for (let day = 1; day <= lastDay.getDate(); day++) { | |
| const dayCell = document.createElement('div'); | |
| dayCell.className = 'day-cell'; | |
| // Add Sunday/Saturday classes | |
| const dayOfWeek = new Date(year, month, day).getDay(); | |
| if (dayOfWeek === 0) { | |
| dayCell.classList.add('sunday'); | |
| } else if (dayOfWeek === 6) { | |
| dayCell.classList.add('saturday'); | |
| } | |
| const dayNumber = document.createElement('div'); | |
| dayNumber.className = 'day-number'; | |
| dayNumber.textContent = day; | |
| // ์ค๋ ๋ ์ง ์ฒดํฌ | |
| const today = new Date(); | |
| if (today.getFullYear() === year && today.getMonth() === month && today.getDate() === day) { | |
| dayCell.classList.add('day-today'); | |
| } | |
| dayCell.appendChild(dayNumber); | |
| dayCell.addEventListener('click', () => { | |
| showDayEvents(year, month, day); | |
| }); | |
| // ๋ ์ง ํ์ ๋ง์ถ๊ธฐ (YYYY-MM-DD) | |
| const formattedDate = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`; | |
| // ํด๋น ๋ ์ง์ ์ด๋ฒคํธ ๊ฐ์ ธ์ค๊ธฐ | |
| fetch(`get_events.php?date=${formattedDate}`) | |
| .then(response => { | |
| if (!response.ok) throw new Error('Network response was not ok'); | |
| return response.json(); | |
| }) | |
| .then(events => { | |
| if (events && events.length > 0) { | |
| events.forEach(event => { | |
| const eventEl = document.createElement('div'); | |
| eventEl.className = `event-card event-${event.org}`; | |
| eventEl.textContent = `${getOrgIcon(event.org)} ${event.title}`; | |
| dayCell.appendChild(eventEl); | |
| }); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error fetching events:', error); | |
| }); | |
| calendarGrid.appendChild(dayCell); | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> | |