최초 커밋
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
<?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);
|
||||
|
||||
// 사번 매핑
|
||||
$tagMap = [
|
||||
"j01201" => "권",
|
||||
"223070" => "염",
|
||||
"m21430" => "김",
|
||||
"b21367" => "윤",
|
||||
];
|
||||
|
||||
$eventsData = [];
|
||||
|
||||
foreach ($rows as $r) {
|
||||
$date = $r["schedule_date"];
|
||||
$empNo = strtolower($r["emp_no"]);
|
||||
|
||||
if (!isset($eventsData[$date])) {
|
||||
$eventsData[$date] = [];
|
||||
}
|
||||
|
||||
$time = trim($r["time_period"]); // 공백 제거
|
||||
$time = str_replace(["\r", "\n", "\t"], "", $time); // 숨은 문자 제거
|
||||
|
||||
$eventsData[$date][] = [
|
||||
"time" => $time, // ⭐ 핵심
|
||||
"title" => $r["content"],
|
||||
"tags" => [ $tagMap[$empNo] ?? "" ]
|
||||
];
|
||||
}
|
||||
// JS로 전달
|
||||
echo "<script>var eventsData = " . json_encode($eventsData, JSON_UNESCAPED_UNICODE) . ";</script>";
|
||||
?>
|
||||
|
||||
<div class="main-weekly weekly" id="weekly">
|
||||
<div class="weekly-grid">
|
||||
<div class="weekly-header">
|
||||
<div class="weekly-title">
|
||||
<p>주간 영업 계획</p>
|
||||
<div class="week-navigation">
|
||||
<button class="week-nav-btn" id="prevWeek" title="이전 주">
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#424242"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M15 18l-6-6 6-6" />
|
||||
</svg>
|
||||
</button>
|
||||
<h3 id="weekTitle">11월 5주차</h3>
|
||||
<button class="week-nav-btn" id="nextWeek" title="다음 주">
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#424242"
|
||||
stroke-width="2"
|
||||
>
|
||||
<path d="M9 18l6-6-6-6" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="person-list">
|
||||
<li>
|
||||
<span class="badge-green">권</span><span class="name">권혁진 <small>수석</small></span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge-purple">염</span><span class="name">염승호 <small>수석</small></span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge-teal">김</span><span class="name">김지영 <small>선임</small></span>
|
||||
</li>
|
||||
<li>
|
||||
<span class="badge-black">윤</span><span class="name">윤준수 <small>선임</small></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="schedule" id="scheduleContainer"></div>
|
||||
</div>
|
||||
<div class="main-issue">
|
||||
<div class="issue-header">
|
||||
<h3>주요 이슈 사항</h3>
|
||||
</div>
|
||||
<div class="issue">
|
||||
<ul class="issue-list">
|
||||
<li>주요 이슈 A</li>
|
||||
<li>주요 이슈 B</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./assets/js/schedule-manager.min.js"></script>
|
||||
<!-- <script src="./assets/js/events-data.min.js"></script> -->
|
||||
<script>
|
||||
const personOrder = {
|
||||
"권": 1,
|
||||
"염": 2,
|
||||
"김": 3,
|
||||
"윤": 4,
|
||||
};
|
||||
|
||||
function isMorning(event) {
|
||||
return event.time === "오전";
|
||||
}
|
||||
|
||||
function isAfternoon(event) {
|
||||
return event.time === "오후";
|
||||
}
|
||||
|
||||
// 태그 매핑
|
||||
const tagMapping = {
|
||||
권: "green",
|
||||
염: "purple",
|
||||
김: "teal",
|
||||
윤: "black",
|
||||
};
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// ⭐ scheduleManager를 상단에 선언 (초기화는 나중에)
|
||||
let scheduleManager;
|
||||
async function loadIssueText() {
|
||||
|
||||
// ⭐ 현재 주간 달 기준으로 변경
|
||||
const year = currentWeekStart.getFullYear();
|
||||
const month = String(currentWeekStart.getMonth() + 1).padStart(2, "0");
|
||||
const ym = `${year}-${month}`;
|
||||
|
||||
let res = await fetch(`/egbim/bbs/sales_issue.php?action=get&issue_month=${ym}`);
|
||||
let json = await res.json();
|
||||
|
||||
const issue = json.issue_text ?? "";
|
||||
|
||||
const ul = document.querySelector(".issue-list");
|
||||
ul.innerHTML = "";
|
||||
|
||||
if (issue.trim() === "") {
|
||||
ul.innerHTML = "<li>이번 달 주요 이슈가 없습니다.</li>";
|
||||
return;
|
||||
}
|
||||
|
||||
issue.split("\n").forEach(line => {
|
||||
if (line.trim() !== "") {
|
||||
ul.innerHTML += `<li>${line}</li>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 현재 날짜에서 이번 주 월요일 구하기
|
||||
function getThisMonday() {
|
||||
const today = new Date();
|
||||
const day = today.getDay(); // 0(일) ~ 6(토)
|
||||
const diff = day === 0 ? -6 : 1 - day; // 일요일이면 -6, 아니면 1-day
|
||||
|
||||
const monday = new Date(today);
|
||||
monday.setDate(today.getDate() + diff);
|
||||
monday.setHours(0, 0, 0, 0); // 시간 초기화
|
||||
|
||||
return monday;
|
||||
}
|
||||
|
||||
// 현재 주차 상태
|
||||
let currentWeekStart = getThisMonday();
|
||||
|
||||
// 주차 타이틀 업데이트
|
||||
function updateWeekTitle() {
|
||||
const weekStart = new Date(currentWeekStart);
|
||||
const month = weekStart.getMonth() + 1;
|
||||
const startDate = weekStart.getDate();
|
||||
|
||||
// 해당 월의 몇 번째 주인지 계산
|
||||
const firstDayOfMonth = new Date(
|
||||
weekStart.getFullYear(),
|
||||
weekStart.getMonth(),
|
||||
1,
|
||||
);
|
||||
|
||||
const firstDayOfWeek = firstDayOfMonth.getDay() < 2 ? 7 : firstDayOfMonth.getDay();
|
||||
const offset = firstDayOfWeek - 1;
|
||||
|
||||
//const weekOfMonth = Math.ceil((startDate + firstDayOfMonth.getDay()) / 7);
|
||||
const weekOfMonth = Math.floor((startDate + offset) / 7);
|
||||
|
||||
document.getElementById("weekTitle").textContent =
|
||||
`${month}월 ${weekOfMonth}주차`;
|
||||
}
|
||||
|
||||
// 요일 이름 가져오기
|
||||
function getDayName(dayIndex) {
|
||||
const days = ["일", "월", "화", "수", "목", "금", "토"];
|
||||
return days[dayIndex];
|
||||
}
|
||||
|
||||
|
||||
// 주간 일정 렌더링
|
||||
function renderWeeklySchedule() {
|
||||
const container = document.getElementById("scheduleContainer");
|
||||
container.innerHTML = "";
|
||||
|
||||
// 월요일부터 금요일까지 (5일)
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const currentDate = new Date(currentWeekStart);
|
||||
currentDate.setDate(currentWeekStart.getDate() + i);
|
||||
|
||||
const year = currentDate.getFullYear();
|
||||
const month = String(currentDate.getMonth() + 1).padStart(2, "0");
|
||||
const day = String(currentDate.getDate()).padStart(2, "0");
|
||||
const dateKey = `${year}-${month}-${day}`;
|
||||
|
||||
const dayOfWeek = getDayName(currentDate.getDay());
|
||||
const dayEvents = eventsData[dateKey] || [];
|
||||
|
||||
dayEvents.sort((a, b) => {
|
||||
const aTag = a.tags[0] ?? "";
|
||||
const bTag = b.tags[0] ?? "";
|
||||
|
||||
return (personOrder[aTag] || 99) - (personOrder[bTag] || 99);
|
||||
});
|
||||
|
||||
// 카드 생성
|
||||
const dayCard = document.createElement("div");
|
||||
dayCard.className = "day-card";
|
||||
dayCard.dataset.date = dateKey;
|
||||
|
||||
let morningHTML = "";
|
||||
let afternoonHTML = "";
|
||||
|
||||
dayEvents.forEach((event) => {
|
||||
console.log(
|
||||
dateKey,
|
||||
event.time,
|
||||
JSON.stringify(event.time),
|
||||
isMorning(event),
|
||||
isAfternoon(event)
|
||||
);
|
||||
});
|
||||
|
||||
dayEvents.forEach((event) => {
|
||||
const tagsHTML = event.tags
|
||||
.map(tag => `<span class="badge-${tagMapping[tag]}">${tag}</span>`)
|
||||
.join("");
|
||||
|
||||
const itemHTML = `
|
||||
<li>
|
||||
<a href="#" class="schedule-item">
|
||||
${tagsHTML}
|
||||
${event.title}
|
||||
</a>
|
||||
</li>
|
||||
`;
|
||||
|
||||
if (isMorning(event)) {
|
||||
morningHTML += itemHTML;
|
||||
}
|
||||
|
||||
if (isAfternoon(event)) {
|
||||
afternoonHTML += itemHTML;
|
||||
}
|
||||
});
|
||||
|
||||
let dayHTML = `
|
||||
<div class="day-title">${day}일 <span>(${dayOfWeek})</span></div>
|
||||
|
||||
<div class="day">
|
||||
<dl>
|
||||
<dt>오전</dt>
|
||||
<dd class="day-content">
|
||||
${morningHTML}
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt>오후</dt>
|
||||
<dd class="day-content">
|
||||
${afternoonHTML}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
`;
|
||||
|
||||
dayCard.innerHTML = dayHTML;
|
||||
container.appendChild(dayCard);
|
||||
}
|
||||
|
||||
updateWeekTitle();
|
||||
if (scheduleManager && typeof scheduleManager.initialize === "function") {
|
||||
scheduleManager.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 이벤트 리스너 등록 함수
|
||||
function setupEventListeners() {
|
||||
const prevWeekBtn = document.getElementById("prevWeek");
|
||||
const nextWeekBtn = document.getElementById("nextWeek");
|
||||
|
||||
// 이전 주로 이동
|
||||
if (prevWeekBtn) {
|
||||
prevWeekBtn.addEventListener("click", () => {
|
||||
currentWeekStart.setDate(currentWeekStart.getDate() - 7);
|
||||
renderWeeklySchedule();
|
||||
loadIssueText();
|
||||
});
|
||||
}
|
||||
|
||||
// 다음 주로 이동
|
||||
if (nextWeekBtn) {
|
||||
nextWeekBtn.addEventListener("click", () => {
|
||||
currentWeekStart.setDate(currentWeekStart.getDate() + 7);
|
||||
renderWeeklySchedule();
|
||||
loadIssueText();
|
||||
});
|
||||
}
|
||||
}
|
||||
// ⭐ 초기화 함수
|
||||
function init() {
|
||||
// ScheduleManager가 존재하는지 확인
|
||||
if (typeof ScheduleManager !== 'undefined') {
|
||||
scheduleManager = new ScheduleManager();
|
||||
scheduleManager.initialize();
|
||||
}
|
||||
|
||||
// 이벤트 리스너 등록
|
||||
setupEventListeners();
|
||||
|
||||
// 초기 렌더링
|
||||
renderWeeklySchedule();
|
||||
loadIssueText();
|
||||
}
|
||||
|
||||
// ⭐ DOM 로드 완료 후 실행
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
let isCalendarLoaded = false;
|
||||
// 모달 열기
|
||||
function openModal() {
|
||||
const existingModal = document.getElementById("scheduleModal");
|
||||
|
||||
// 기존 모달이 있으면 제거
|
||||
if (existingModal) {
|
||||
existingModal.remove();
|
||||
}
|
||||
|
||||
// 항상 새로 로드 (데이터 최신화)
|
||||
fetchScheduleDetail();
|
||||
}
|
||||
|
||||
// 모달 닫기
|
||||
function closeModal() {
|
||||
const modal = document.getElementById("scheduleModal");
|
||||
modal.classList.add("closing");
|
||||
isCalendarLoaded = false;
|
||||
setTimeout(() => {
|
||||
modal.remove();
|
||||
}, 400);
|
||||
}
|
||||
|
||||
// AJAX로 calendar.html 페이지 가져오기
|
||||
let calendarScriptsLoaded = false;
|
||||
|
||||
function fetchScheduleDetail() {
|
||||
const weekly = document.getElementById("weekly");
|
||||
|
||||
fetch(`./html/main_sub/calendar.php`)
|
||||
.then((response) => response.text())
|
||||
.then((html) => {
|
||||
// 기존 모달 제거
|
||||
const existingModal = document.getElementById("scheduleModal");
|
||||
if (existingModal) existingModal.remove();
|
||||
|
||||
// 새로운 모달 삽입
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, "text/html");
|
||||
|
||||
// ⭐ body의 자식 노드들을 추가
|
||||
doc.body.childNodes.forEach(node => {
|
||||
if (node.nodeType === Node.ELEMENT_NODE || node.nodeType === Node.TEXT_NODE) {
|
||||
weekly.appendChild(node.cloneNode(true));
|
||||
}
|
||||
});
|
||||
|
||||
// ⭐ 스크립트 처리 개선
|
||||
const scripts = doc.querySelectorAll("script");
|
||||
|
||||
if (!calendarScriptsLoaded) {
|
||||
// 첫 번째 로딩: 모든 스크립트 실행
|
||||
scripts.forEach(script => {
|
||||
const newScript = document.createElement("script");
|
||||
if (script.src) {
|
||||
newScript.src = script.src;
|
||||
} else {
|
||||
newScript.textContent = script.textContent;
|
||||
}
|
||||
document.body.appendChild(newScript);
|
||||
});
|
||||
calendarScriptsLoaded = true;
|
||||
} else {
|
||||
// ⭐ 두 번째 이후: 인라인 스크립트만 재실행
|
||||
scripts.forEach(script => {
|
||||
if (!script.src) {
|
||||
// src가 없는 인라인 스크립트만 실행
|
||||
try {
|
||||
eval(script.textContent);
|
||||
} catch (error) {
|
||||
console.error('Script execution error:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ⭐ 모달이 추가된 후 초기화 함수 명시적 호출
|
||||
setTimeout(() => {
|
||||
if (typeof initializeCalendar === "function") {
|
||||
initializeCalendar();
|
||||
}
|
||||
if (typeof renderCalendar === "function") {
|
||||
renderCalendar();
|
||||
}
|
||||
if (typeof checkOverflow === "function") {
|
||||
checkOverflow();
|
||||
}
|
||||
if (typeof bindToggleEvents === "function") {
|
||||
bindToggleEvents();
|
||||
}
|
||||
}, 100);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Calendar loading error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// 일정 항목 클릭 이벤트
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.closest('.schedule-item')) {
|
||||
e.preventDefault();
|
||||
const scheduleItem = e.target.closest('.schedule-item');
|
||||
const scheduleId = scheduleItem.getAttribute("data-id");
|
||||
openModal(scheduleId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
Reference in New Issue
Block a user