Files
egbim_homepage/egbim/skin/sales/html/main_sub/calendar.php
T
2026-07-23 16:15:57 +09:00

546 lines
20 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.
<?php
$pdo = new PDO("mysql:host=localhost;dbname=egbim;charset=utf8mb4","egbim","baron3840!!");
$rows = $pdo->query("
SELECT
s.schedule_date,
s.time_period,
s.content,
s.emp_no,
m.emp_name,
c.client_name
FROM sales_schedules s
LEFT JOIN sales_members m ON s.emp_no = m.emp_no
LEFT JOIN sales_clients c ON s.client_code = c.client_code
")->fetchAll(PDO::FETCH_ASSOC);
// 모든 emp_no는 소문자로 통일!
$tagMap = [
"j01201" => "권",
"223070" => "염",
"m21430" => "김",
"b21367" => "윤"
];
$eventsData = [];
foreach ($rows as $r) {
$date = $r["schedule_date"];
$empNo = strtolower($r["emp_no"]); // ★ emp_no를 소문자로 통일
// 날짜 키가 없으면 배열 초기화
if (!isset($eventsData[$date])) {
$eventsData[$date] = [];
}
// 여러 개가 정상적으로 PUSH됨
$eventsData[$date][] = [
"time" => $r["time_period"],
"title" => $r["content"],
"tags" => [ $tagMap[$empNo] ?? "" ]
];
}
echo "<script>var eventsData = " . json_encode($eventsData, JSON_UNESCAPED_UNICODE) . ";</script>";
?>
<div id="scheduleModal" class="modal calendar">
<div class="modal-content">
<div class="modal-header">
<div class="filter-options">
<div class="checkbox-group green">
<input type="checkbox" id="check1" value="green" checked />
<label for="check1">권혁진 수석</label>
</div>
<div class="checkbox-group purple">
<input type="checkbox" id="check2" value="purple" checked />
<label for="check2">염승호 수석</label>
</div>
<div class="checkbox-group teal">
<input type="checkbox" id="check3" value="teal" checked />
<label for="check3">김지영 선임</label>
</div>
<div class="checkbox-group black">
<input type="checkbox" id="check4" value="black" checked />
<label for="check4">윤준수 선임</label>
</div>
</div>
<div class="date-navigation">
<button class="prev-btn" id="prevMonth"></button>
<div class="current-date" id="currentDate">2025.11</div>
<button class="next-btn" id="nextMonth"></button>
</div>
<div class="flex">
<div class="toggle-area">
<input type="radio" id="option1" name="toggle" value="접기" checked />
<label for="option1">접기</label>
<input type="radio" id="option2" name="toggle" value="펼치기" />
<label for="option2">펼치기</label>
<div class="toggle-slider"></div>
</div>
<button class="modal-close" onclick="closeModal()">&times;</button>
</div>
</div>
<div class="modal-body" id="modalBody">
<div class="weekdays">
<div class="weekday">일</div>
<div class="weekday">월</div>
<div class="weekday">화</div>
<div class="weekday">수</div>
<div class="weekday">목</div>
<div class="weekday">금</div>
<div class="weekday">토</div>
</div>
<div class="calendar-days">
<div class="days collapsed" id="calendarDays"></div>
</div>
</div>
</div>
<script>
// 모달 배경 클릭시 닫기
const modal = document.getElementById("scheduleModal");
modal.addEventListener("click", function (e) {
if (e.target === modal) {
closeModal();
}
});
</script>
<script>
function initializeCalendar() {
const tagMapping = {
"권": "green",
"염": "purple",
"김": "teal",
"윤": "black"
};
// 사람 고정 순서 (우선순위 낮을수록 뒤로)
const PERSON_ORDER = {
"권": 1, // 권혁진
"염": 2, // 염승호
"김": 3, // 김지영
"윤": 4 // 윤준수
};
function sortEventsByPerson(events) {
return events.slice().sort((a, b) => {
const aTag = a.tags[0] || "";
const bTag = b.tags[0] || "";
return (PERSON_ORDER[aTag] || 99) - (PERSON_ORDER[bTag] || 99);
});
}
/* ===============================
오전 / 오후 판별 (핵심)
→ title 문자열 기준
=============================== */
function isMorning(event) {
return event.time === "오전";
}
function isAfternoon(event) {
return event.time === "오후";
}
const today = new Date();
let currentYear = today.getFullYear(); // 2025 대신
let currentMonth = today.getMonth(); // 11 대신
let selectedFilters = ["green", "purple", "teal", "black"];
function renderCalendar() {
const calendarDays = document.getElementById("calendarDays");
const currentDate = document.getElementById("currentDate");
currentDate.textContent = `${currentYear}.${String(currentMonth + 1).padStart(2, "0")}`;
const firstDay = new Date(currentYear, currentMonth, 1);
const lastDay = new Date(currentYear, currentMonth + 1, 0);
const prevLastDay = new Date(currentYear, currentMonth, 0);
const firstDayOfWeek = firstDay.getDay();
const lastDate = lastDay.getDate();
const prevLastDate = prevLastDay.getDate();
// 오늘 날짜의 주차 계산
const today = new Date();
let todayWeekStart = -1;
let todayWeekEnd = -1;
// 현재 달력에 오늘이 포함되어 있는지 확인
if (
currentMonth === today.getMonth() &&
currentYear === today.getFullYear()
) {
const todayDate = today.getDate();
const currentDate = new Date(currentYear, currentMonth, todayDate);
const dayOfWeek = currentDate.getDay();
// 이번 주의 시작(일요일)과 끝(토요일) 날짜 계산
todayWeekStart = todayDate - dayOfWeek;
todayWeekEnd = todayDate + (6 - dayOfWeek);
}
let weeks = "";
let currentWeekDays = "";
let dayCount = 0;
let weekNumber = 0;
// Previous month days
const prevMonth = currentMonth === 0 ? 11 : currentMonth - 1;
const prevYear = currentMonth === 0 ? currentYear - 1 : currentYear;
for (let i = firstDayOfWeek - 1; i >= 0; i--) {
const dayNum = prevLastDate - i;
const dateKey = `${prevYear}-${String(prevMonth + 1).padStart(2, "0")}-${String(dayNum).padStart(2, "0")}`;
const dayEvents = eventsData[dateKey] || [];
const filteredEvents = sortEventsByPerson(
dayEvents.filter((event) =>
event.tags.some((tag) => selectedFilters.includes(tagMapping[tag]))
)
);
let morningHtml = "";
let afternoonHtml = "";
filteredEvents.forEach((event) => {
const tagsHtml = event.tags
.filter((tag) => selectedFilters.includes(tagMapping[tag]))
.map(
(tag) =>
`<span class="event-tag badge-${tagMapping[tag]}">${tag}</span>`
)
.join("");
const html = `
<div class="event-item">
<span class="event-title">${tagsHtml}${event.title}</span>
</div>
`;
if (isMorning(event)) {
morningHtml += html;
}
if (isAfternoon(event)) {
afternoonHtml += html;
}
});
currentWeekDays += `<div class="day other-month">
<div class="day-number">${dayNum}</div>
<dl>
<dt>오전</dt>
<dd class="day-content">${morningHtml}</dd>
</dl>
<dl>
<dt>오후</dt>
<dd class="day-content">${afternoonHtml}</dd>
</dl>
</div>`;
dayCount++;
}
// Current month days
for (let i = 1; i <= lastDate; i++) {
const isToday =
i === today.getDate() &&
currentMonth === today.getMonth() &&
currentYear === today.getFullYear();
const isCurrentWeek =
todayWeekStart >= 0 && i >= todayWeekStart && i <= todayWeekEnd;
const dateKey = `${currentYear}-${String(currentMonth + 1).padStart(2, "0")}-${String(i).padStart(2, "0")}`;
const dayEvents = eventsData[dateKey] || [];
const filteredEvents = sortEventsByPerson(
dayEvents.filter((event) =>
event.tags.some((tag) => selectedFilters.includes(tagMapping[tag]))
)
);
filteredEvents.forEach((event) => {
console.log(event.title);
});
let morningHtml = "";
let afternoonHtml = "";
filteredEvents.forEach((event) => {
const tagsHtml = event.tags
.filter((tag) => selectedFilters.includes(tagMapping[tag]))
.map(
(tag) =>
`<span class="event-tag badge-${tagMapping[tag]}">${tag}</span>`
)
.join("");
const html = `
<div class="event-item">
<span class="event-title">${tagsHtml}${event.title}</span>
</div>
`;
if (isMorning(event)) {
morningHtml += html;
}
if (isAfternoon(event)) {
afternoonHtml += html;
}
});
currentWeekDays += `<div class="day ${isToday ? "today" : ""} ${isCurrentWeek ? "current-week" : ""}">
<div class="day-number">${i}</div>
<dl>
<dt>오전</dt>
<dd class="day-content">${morningHtml}</dd>
</dl>
<dl>
<dt>오후</dt>
<dd class="day-content">${afternoonHtml}</dd>
</dl>
</div>`;
dayCount++;
// 7일마다 한 주 완성
if (dayCount === 7) {
const hasCurrentWeek =
currentWeekDays.includes('class="day today"') ||
currentWeekDays.includes("current-week");
weeks += `<div class="week ${hasCurrentWeek ? "current-week-row" : ""}">${currentWeekDays}</div>`;
currentWeekDays = "";
dayCount = 0;
weekNumber++;
}
}
// Next month days
const nextMonth = currentMonth === 11 ? 0 : currentMonth + 1;
const nextYear = currentMonth === 11 ? currentYear + 1 : currentYear;
const remainingDays = 42 - (firstDayOfWeek + lastDate);
for (let i = 1; i <= remainingDays; i++) {
const dateKey = `${nextYear}-${String(nextMonth + 1).padStart(2, "0")}-${String(i).padStart(2, "0")}`;
const dayEvents = eventsData[dateKey] || [];
const filteredEvents = sortEventsByPerson(
dayEvents.filter((event) =>
event.tags.some((tag) => selectedFilters.includes(tagMapping[tag]))
)
);
let morningHtml = "";
let afternoonHtml = "";
filteredEvents.forEach((event) => {
const tagsHtml = event.tags
.filter((tag) => selectedFilters.includes(tagMapping[tag]))
.map(
(tag) =>
`<span class="event-tag badge-${tagMapping[tag]}">${tag}</span>`
)
.join("");
const html = `
<div class="event-item">
<span class="event-title">${tagsHtml}${event.title}</span>
</div>
`;
if (isMorning(event)) morningHtml += html;
if (isAfternoon(event)) afternoonHtml += html;
});
currentWeekDays += `<div class="day other-month">
<div class="day-number">${i}</div>
<dl>
<dt>오전</dt>
<dd class="day-content">${morningHtml}</dd>
</dl>
<dl>
<dt>오후</dt>
<dd class="day-content">${afternoonHtml}</dd>
</dl>
</div>`;
dayCount++;
// 7일마다 한 주 완성
if (dayCount === 7) {
weeks += `<div class="week">${currentWeekDays}</div>`;
currentWeekDays = "";
dayCount = 0;
}
}
calendarDays.innerHTML = weeks;
document.querySelectorAll(".day:not(.other-month)").forEach((day) => {
day.addEventListener("click", function () {
document
.querySelectorAll(".day")
.forEach((d) => d.classList.remove("selected"));
this.classList.add("selected");
});
});
}
function checkOverflow() {
const calendarDaysEl = document.getElementById("calendarDays");
if (!calendarDaysEl.classList.contains("collapsed")) return;
document.querySelectorAll(".day-content").forEach((content) => {
// 스크롤 높이가 실제 높이보다 크면 overflow 발생
if (content.scrollHeight > content.clientHeight) {
content.classList.add("has-overflow");
} else {
content.classList.remove("has-overflow");
}
});
}
// document.getElementById("prevMonth").addEventListener("click", () => {
// currentMonth--;
// if (currentMonth < 0) {
// currentMonth = 11;
// currentYear--;
// }
// renderCalendar();
// checkOverflow();
// });
// document.getElementById("nextMonth").addEventListener("click", () => {
// currentMonth++;
// if (currentMonth > 11) {
// currentMonth = 0;
// currentYear++;
// }
// renderCalendar();
// checkOverflow();
// });
// 필터 체크박스
const filterCheckboxes = document.querySelectorAll(
'.filter-options input[type="checkbox"]',
);
filterCheckboxes.forEach((checkbox) => {
checkbox.addEventListener("change", () => {
selectedFilters = Array.from(filterCheckboxes)
.filter((cb) => cb.checked)
.map((cb) => cb.value);
renderCalendar();
checkOverflow();
});
});
// 접기/펼치기 토글
const calendarDaysEl = document.getElementById("calendarDays");
const toggleRadios = document.querySelectorAll('input[name="toggle"]');
toggleRadios.forEach((radio) => {
radio.addEventListener("change", (e) => {
if (e.target.value === "접기") {
calendarDaysEl.classList.add("collapsed");
} else {
calendarDaysEl.classList.remove("collapsed");
}
});
});
calendarDaysEl.classList.add("collapsed");
renderCalendar();
checkOverflow();
bindCalendarEvents();
//바인드 함수 컨트롤
function bindCalendarEvents() {
// 이전 월
const prevBtn = document.getElementById("prevMonth");
if (prevBtn) {
prevBtn.onclick = () => {
currentMonth--;
if (currentMonth < 0) {
currentMonth = 11;
currentYear--;
}
renderCalendar();
checkOverflow();
};
}
// 다음 월
const nextBtn = document.getElementById("nextMonth");
if (nextBtn) {
nextBtn.onclick = () => {
currentMonth++;
if (currentMonth > 11) {
currentMonth = 0;
currentYear++;
}
renderCalendar();
checkOverflow();
};
}
// 필터 체크박스
const filterCheckboxes = document.querySelectorAll('.filter-options input[type="checkbox"]');
filterCheckboxes.forEach((checkbox) => {
checkbox.onclick = () => {
selectedFilters = Array.from(filterCheckboxes)
.filter((cb) => cb.checked)
.map((cb) => cb.value);
renderCalendar();
checkOverflow();
};
});
// 접기&펼치기 토글
const radios = document.querySelectorAll('input[name="toggle"]');
radios.forEach((radio) => {
radio.addEventListener("change", (e) => {
const calendarDaysEl = document.getElementById("calendarDays");
if (e.target.value === "접기") {
calendarDaysEl.classList.add("collapsed");
} else {
calendarDaysEl.classList.remove("collapsed");
// 스크롤을 맨 아래로 이동
setTimeout(() => {
const scheduleList = document.querySelector(".calendar-days");
const scheduleItem = document.querySelector(".current-week-row");
if (scheduleList && scheduleItem) {
// 현재 주가 보이도록 + 살짝 아래로 여유 있게
scheduleList.scrollTo({
top:
scheduleItem.offsetTop -
scheduleList.offsetHeight / 2 +
scheduleItem.offsetHeight / 2,
// 또는 그냥 맨 아래로 내리고 싶으면:
// top: scheduleList.scrollHeight,
behavior: "smooth",
});
}
}, 100);
}
});
});
}
}
// 모달이 로드되면 자동 실행
initializeCalendar();
</script>
</div>