Files
PM_test/views/main/jsm/overview/overviewPageRenderer.js
2026-06-12 17:14:03 +09:00

1130 lines
49 KiB
JavaScript

import { vars } from '../archive/variable.js';
import { checkProjectInactive } from '../main.js';
import { getPresignedURL, generateDeleteImgUrl, uploadImgData, sliceDate, applyUtcOffsetTime, splitStr, formatHour, calculateRemPosition, setDefaultScheduleTime, changeColor, fillPartialBlock } from './overviewCommon.js';
import { overviewVars } from './overviewVariable.js';
//🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽 Section-Left, Middle 페이지 랜더링 시작 🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽
export async function drawList(data) {
if (checkProjectInactive()) return;
overviewVars.originalFilesArr = [];
overviewVars.originalFilesNameArr = [];
overviewVars.originalFilesSizeArr = [];
overviewVars.filesNameArr = [];
/* Section-Left 페이지 랜더링 */
// 사업목적
const businessPurposeBox = document.querySelector('.business-purpose');
businessPurposeBox.textContent = data[0]?.business_purpose;
businessPurposeBox.title = data[0]?.business_purpose;
// 위치도
const locationImgKey = JSON.parse(data[0]?.location_img || '[]');
const swiperUl = document.querySelector('.overview .swiper-wrapper');
if(locationImgKey.length > 0){
// 페이지 재랜더링용 초기화
overviewVars.filesNameArr.push(...locationImgKey);
vbSwiper.removeAllSlides();
swiperUl.innerHTML = '';
// swiper 동적 생성
for(let i = 0; overviewVars.filesNameArr.length > i; i++){
const li = document.createElement('li');
li.classList.add('swiper-slide');
li.dataset.save = true;
li.dataset.filepath = overviewVars.filesNameArr[i];
const img = document.createElement('img');
const { url } = await getPresignedURL(overviewVars.filesNameArr[i]);
img.src = url;
li.appendChild(img);
vbSwiper.appendSlide(li);
}
} else { // 기본 설정
swiperUl.innerHTML = '';
const li = document.createElement('li');
li.classList.add('swiper-slide');
const img = document.createElement('img');
img.src = '/main/img/overview/non-photo-overview.svg';
li.appendChild(img);
vbSwiper.appendSlide(li);
}
vbSwiper.update();
// 사진이 2장 이상일때 스와이퍼 루프옵션 활성화
if(locationImgKey.length > 1){
vbSwiper.params.loop = true;
vbSwiper.loopCreate();
vbSwiper.update();
} else { // 사진이 1장 이하일때는 스와이퍼 루프옵션 비활성화
vbSwiper.params.loop = false;
vbSwiper.loopDestroy();
vbSwiper.update();
}
// 대륙
const continentBox = document.querySelector('.continent');
continentBox.textContent = data[0]?.continent;
// 국가
const nationNmBox = document.querySelector('.nation-nm');
nationNmBox.textContent = data[0]?.nation_nm;
nationNmBox.dataset.iso = data[0]?.nation_code;
nationNmBox.dataset.utcOffset = data[0]?.nation_offset;
// 수행지역
const performanceAreaBox = document.querySelector('.performance-area');
performanceAreaBox.textContent = data[0]?.performance_area;
// 참고지역
const referenceAreaBox = document.querySelector('.reference-area');
referenceAreaBox.textContent = data[0]?.reference_area;
// 누적 중복을 위한 초기화
overviewVars.filesSizeArr = [];
// 파일 사이즈 DB default값 0일때 배열로 초기화
if(data[0]?.data_size === '0')data[0].data_size = '[0]';
const filesSize = JSON.parse(data[0]?.data_size || '[0]');
overviewVars.filesSizeArr.push(...filesSize);
/* 시설규모 */
// 개요
const facilityOverviewBox = document.querySelector('.facility-overview');
facilityOverviewBox.textContent = data[0]?.facility_size_overview;
facilityOverviewBox.title = data[0]?.facility_size_overview;
// 페이지 랜더링 이후에 원본배열을 복사
overviewVars.originalFilesNameArr = [...overviewVars.filesNameArr];
overviewVars.originalFilesSizeArr = [...overviewVars.filesSizeArr];
await makeFacilitySizeTable();
// 시설규모 횡스크롤
document.querySelector('.overview .scroll-box').addEventListener('wheel', (event) => {
event.preventDefault();
document.querySelector('.overview .scroll-box').scrollLeft += event.deltaY;
});
/* Section-Middle 페이지 랜더링 */
// 약칭
const abbreviatedNameBox = document.querySelector('.abbreviated-name');
abbreviatedNameBox.textContent = data[0]?.abbreviated_name;
// Project Code 프로젝트 코드
const projectNoBox = document.querySelector('.project-no');
projectNoBox.textContent = data[0]?.project_no;
// 과업명(국)
const taskNmKrBox = document.querySelector('.task-nm-kr');
taskNmKrBox.textContent = data[0]?.task_nm_kr;
// 과업명(영)
const taskNmEnBox = document.querySelector('.task-nm-en');
taskNmEnBox.textContent = data[0]?.task_nm_en;
// 과업목적
const taskPurposeBox = document.querySelector('.task-purpose');
taskPurposeBox.textContent = data[0]?.task_purpose;
// 과업종류
const taskTypeBox = document.querySelector('.task-type');
taskTypeBox.textContent = data[0]?.task_type;
// 외화구분코드
const currencyCode = document.querySelector('.currency-code');
currencyCode.textContent = data[0]?.currency_code ?? 'USD';
// 발주규모(USD)
const orderSizeUsdBox = document.querySelector('.order-size-usd');
orderSizeUsdBox.textContent = data[0]?.order_size_usd;
// 발주규모(USD)
const orderSizeKrwBox = document.querySelector('.order-size-krw');
orderSizeKrwBox.textContent = data[0]?.order_size_krw;
// 예정착공일과 착수일은 동일한 컬럼(tb_overview.commencement_date) 값을 사용
const scheuledCommencementDateBox = document.querySelector('.scheuled-commencement-date');
// 계약기간
const contractPeriodBox = document.querySelector('.contract-period');
// 발주처
const clientBox = document.querySelector('.client');
clientBox.textContent = data[0]?.client;
// 원발주처
const clientOriginBox = document.querySelector('.client-origin');
clientOriginBox.textContent = data[0]?.client_origin;
// 재원
const financialBox = document.querySelector('.financial');
financialBox.textContent = data[0]?.financial;
// 입찰방식
const bidBox = document.querySelector('.bid');
bidBox.textContent = data[0]?.bid;
// 재원국가
const financialCountryBox = document.querySelector('.financial-country');
financialCountryBox.textContent = data[0]?.financial_country;
// 선정방식
const selectionMethodBox = document.querySelector('.selection-method');
selectionMethodBox.textContent = data[0]?.selection_method;
/* 공동도급 */
await makeJointTable(data);
/* 과업기간 */
// 계약일
const contractDateBox = document.querySelector('.contract-date');
// 착수일
const commencementDateBox = document.querySelector('.commencement-date');
// 종료예정일
const changedCompletionDateBox = document.querySelector('.scheduled-completion-date');
// overseas용 분기
if(!overviewVars.overseas){
scheuledCommencementDateBox.textContent = data[0]?.scheuled_commencement_date;
contractPeriodBox.textContent = data[0]?.contract_period != null ? data[0]?.contract_period : '';
changedCompletionDateBox.textContent = data[0]?.original_completion_date;
commencementDateBox.textContent = data[0]?.commencement_date;
contractDateBox.textContent = data[0]?.contract_date;
} else{
scheuledCommencementDateBox.textContent = sliceDate(data[0]?.commencement_date);
changedCompletionDateBox.textContent = sliceDate(data[0]?.original_completion_date);
contractPeriodBox.textContent = data[0]?.contract_period != null ? data[0]?.contract_period + '개월' : '';
commencementDateBox.textContent = sliceDate(data[0]?.commencement_date);
contractDateBox.textContent = sliceDate(data[0]?.contract_date);
}
// 종료일
const completionDateBox = document.querySelector('.completion-date');
completionDateBox.textContent = data[0]?.completion_date;
/* 사내담당 */
// 담당부서
const departmentBox = document.querySelector('.department');
departmentBox.textContent = data[0]?.department;
// 책임자
const projectmanagerNmBox = document.querySelector('.projectmanager-nm');
projectmanagerNmBox.textContent = data[0]?.projectmanager_nm;
// 담당자
const managerNmBox = document.querySelector('.manager-nm');
managerNmBox.textContent = data[0]?.manager_nm;
// 지원부서
const supportDepartmentBox = document.querySelector('.support-department');
supportDepartmentBox.textContent = data[0]?.support_department;
// 담당자
const supportManagerNmBox = document.querySelector('.support-manager-nm');
supportManagerNmBox.textContent = data[0]?.support_manager_nm;
// 주요 현안 및 이슈
const Issue = document.querySelector('.overview .issue-content');
Issue.value = data[0]?.issue ?? '';
overviewVars.issueData = data[0]?.issue ?? '';
// overview-main 표시
document.querySelector('.overview-main').style.display = 'flex';
}
// 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼 Section-Left, Middle 페이지 랜더링 끝 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼
//🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽 Section-Left 페이지 랜더링 시작 🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽
// 위치도 개요도 스와이퍼
export const vbSwiper = new Swiper('.vb-swiper .swiper', {
slidesPerView: 1,
spaceBetween: 0,
centeredSlides: true,
speed: 400,
loop: false,
navigation: {
nextEl: '.vb-swiper .swiper-button-next',
prevEl: '.vb-swiper .swiper-button-prev',
},
pagination: {
el: ".vb-swiper .swiper-pagination",
clickable: true,
},
});
// 시설규모 일부 리스트 (4개)
async function makeFacilitySizeTable() {
try {
const res = await axios.get(`/${vars.project_id}/overview/getFacilitySizeData`, { params: { projectId: vars.project_id } });
if (res.data.message === '200') {
const scrollBox = document.querySelector('.overview .scroll-box.facility-size');
scrollBox.innerHTML = '';
const dataArr = res.data.data;
// 기존에 갖고있던 sectionTabData를 초기화
if(overviewVars.originalSectionTabData)overviewVars.originalSectionTabData = {};
// section-left 모달 열었을때 탭과 셀 그리기 위한 전역변수에 저장
dataArr.forEach(item => {
if (!overviewVars.originalSectionTabData[item.title]) {
overviewVars.originalSectionTabData[item.title] = [];
}
overviewVars.originalSectionTabData[item.title].push({
key: item.key,
value: item.value,
id: item.facility_id,
projectId: vars.project_id
});
});
overviewVars.sectionTabData = JSON.parse(JSON.stringify(overviewVars.originalSectionTabData));
let currentTitle = '';
let currentBoxBody = null;
let typeWrapCount = 0;
for (let i = 0; i < dataArr.length; i++) {
if (dataArr[i].title !== currentTitle) {
currentTitle = dataArr[i].title;
typeWrapCount = 0;
const sectionBox = document.createElement('div');
sectionBox.className = 'section-box';
const header = document.createElement('div');
header.className = 'section-box--header';
const h3 = document.createElement('h3');
h3.textContent = dataArr[i].title;
header.appendChild(h3);
currentBoxBody = document.createElement('div');
currentBoxBody.className = 'box-body';
sectionBox.appendChild(header);
sectionBox.appendChild(currentBoxBody);
scrollBox.appendChild(sectionBox);
}
if (typeWrapCount < 4) {
const typeWrap = document.createElement('div');
typeWrap.className = 'type--wrap';
const left = document.createElement('div');
left.className = 'type--wrap-left';
const p = document.createElement('p');
p.textContent = dataArr[i].key;
left.appendChild(p);
const right = document.createElement('div');
right.className = 'type--wrap-right';
const h4 = document.createElement('h4');
h4.textContent = dataArr[i].value;
right.appendChild(h4);
typeWrap.appendChild(left);
typeWrap.appendChild(right);
currentBoxBody.appendChild(typeWrap);
typeWrapCount++;
}
}
}
} catch (err) {
console.log(err);
}
}
// 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼 section-Left 페이지 랜더링 끝 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼
//🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽 Section-Middle 페이지 랜더링 시작 🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽
// 공동도급 표 만들기
function makeJointTable(data) {
// 회사명
const companyNames = splitStr(data[0]?.joint_contract_nm);
const companyLength = (companyNames?.length - 1) || 0;
// 지분율
const shares = splitStr(data[0]?.joint_contract_shareratio);
// 계약금(원)
const contract1 = splitStr(data[0]?.contract_amount);
// 계약금(달러)
const contract2 = splitStr(data[0]?.foreign_currency_amount);
for (let i = 0; i < companyLength; i++) {
overviewVars.companyArr.push({
companyNames: companyNames[i],
shares: shares[i],
contract1: contract1[i],
contract2: contract2[i]
});
}
overviewVars.companyArr.sort((a, b) => {
// 합계에 들어갈 공백이 최우선
if (a.companyNames === "" && b.companyNames !== "") return -1;
if (a.companyNames !== "" && b.companyNames === "") return 1;
// 대표사와 동일한게 제일 먼저 앞으로
if (a.companyNames === data[0]?.representative_company && b.companyNames !== data[0]?.representative_company) return -1;
if (a.companyNames !== data[0]?.representative_company && b.companyNames === data[0]?.representative_company) return 1;
// 대표사 다음으로 삼안이 오도록
if (a.companyNames === '삼안' && b.companyNames !== '삼안') return -1;
if (a.companyNames !== '삼안' && b.companyNames === '삼안') return 1;
// 그 다음에 자연수 정렬
let aNum = parseFloat(a.shares);
let bNum = parseFloat(b.shares);
return bNum - aNum;
});
let tableHTML = document.createElement('table');
// 테이블 헤드
let tableHead = document.createElement('thead');
const tableTr = document.createElement('tr');
const stickyTh = document.createElement('th');
stickyTh.classList.add('sticky');
const totalTh = document.createElement('th');
totalTh.innerText = '총계'
tableTr.appendChild(stickyTh);
tableTr.appendChild(totalTh);
if (companyLength > 0) {
const subjectMatterTh = document.createElement('th');
subjectMatterTh.innerText = '주관사';
tableTr.appendChild(subjectMatterTh);
}
for (let i = 1; companyLength > i; i++) {
const tableTh = document.createElement('th');
tableTh.innerText = `공동도급${i}`;
tableTr.appendChild(tableTh);
}
tableHead.appendChild(tableTr);
tableHTML.appendChild(tableHead);
// 회사명
let companyRow = document.createElement('tr');
companyRow.innerHTML = `<td class="sticky">회사명</td><td class="total-joint-contract-company-name">${companyLength}</td>`;
overviewVars.companyArr.forEach((company) => {
if (company.companyNames) {
let td = document.createElement('td');
td.textContent = company.companyNames;
if (company.companyNames === '삼안') {
td.style.color = '#111';
td.style.fontWeight = '700';
};
td.classList.add('joint-contract-company-name');
companyRow.appendChild(td);
}
});
tableHTML.appendChild(companyRow);
// 지분율
let shareRow = document.createElement('tr');
shareRow.innerHTML += `<td class="sticky">지분율(%)</td><td class="total-joint-contract-company-shares"></td>`;
let totalShares = 0;
overviewVars.companyArr.forEach((share) => {
if (share.shares) {
let td = document.createElement('td');
td.textContent = share.shares;
if (share.companyNames === '삼안') {
td.style.color = '#111';
td.style.fontWeight = '700';
};
if (!isNaN(share.shares)) totalShares += parseFloat(share.shares);
td.classList.add('joint-contract-company-shares');
shareRow.appendChild(td);
}
});
shareRow.children[1].innerText = totalShares;
tableHTML.appendChild(shareRow);
// 계약금(원)
let contractRow1 = document.createElement('tr');
contractRow1.innerHTML += `<td class="sticky">계약금(KRW)</td><td class="total-joint-contract-krw"></td>`;
let totalContract1 = 0;
overviewVars.companyArr.forEach((amount) => {
// 회사가 삼안일 때 강조처리
if (amount.contract1) {
let td = document.createElement('td');
if (amount.companyNames === '삼안') {
td.style.color = '#111';
td.style.fontWeight = '700';
};
td.textContent = parseFloat(amount.contract1).toLocaleString();
if (!isNaN(amount.contract1)) totalContract1 += parseFloat(amount.contract1);
td.classList.add('joint-contract-krw');
contractRow1.appendChild(td);
}
});
contractRow1.children[1].innerText = totalContract1.toLocaleString();
tableHTML.appendChild(contractRow1);
// 계약금(외화)
let contractRow2 = document.createElement('tr');
contractRow2.innerHTML += `<td class="sticky">계약금(${data[0]?.currency_code ?? 'USD'})</td><td class="total-joint-contract-usd"></td>`;
let totalContract2 = 0;
overviewVars.companyArr.forEach((amount) => {
if (amount.contract2) {
let td = document.createElement('td');
if (amount.companyNames === '삼안') {
td.style.color = '#111';
td.style.fontWeight = '700';
};
td.textContent = parseFloat(amount.contract2).toLocaleString();
if (!isNaN(amount.contract2)) totalContract2 += parseFloat(amount.contract2);
td.classList.add('joint-contract-usd');
contractRow2.appendChild(td);
}
});
contractRow2.children[1].innerText = totalContract2.toLocaleString();
tableHTML.appendChild(contractRow2);
const container = document.querySelector('#overview-table-container');
container.innerHTML = '';
container.appendChild(tableHTML);
container.addEventListener('wheel', (event) => {
event.preventDefault();
container.scrollLeft += event.deltaY;
});
// 공동도급 중복생성 방지를 위한 초기화
overviewVars.companyArr = [];
}
// 과업중지 이력 리스트 생성
export async function makeTaskHistory() {
const res = await axios.get(`/${vars.project_id}/overview/getTaskPeriodData`, { params: { projectId: vars.project_id } })
try {
if (res.data.message === '200') {
document.querySelector('.overview-modal.task-period .overview-modal-body ul').innerHTML = '';
const ul = document.querySelector('.overview-modal.task-period .overview-modal-body ul');
res.data.data.forEach(item => {
const li = document.createElement('li');
// 차수
const numberDiv = document.createElement('div');
numberDiv.className = 'work-list-number';
const orderH4 = document.createElement('h4');
orderH4.className = 'order';
orderH4.textContent = item.task_order;
numberDiv.appendChild(orderH4);
// 중지일자
const dateDiv = document.createElement('div');
dateDiv.className = 'work-list-date';
const dateH4 = document.createElement('h4');
dateH4.className = 'suspension-date';
dateH4.textContent = item.suspension_date;
dateDiv.appendChild(dateH4);
// 중지사유
const reasonDiv = document.createElement('div');
reasonDiv.className = 'work-list-script';
const reasonH4 = document.createElement('h4');
reasonH4.className = 'suspension-reason';
reasonH4.textContent = item.suspension_reason;
reasonH4.title = item.suspension_reason;
reasonDiv.appendChild(reasonH4);
// 재개일자
const redateDiv = document.createElement('div');
redateDiv.className = 'work-list-redate';
const redateH4 = document.createElement('h4');
redateH4.className = 'resumption-date';
redateH4.textContent = item.resumption_date;
redateDiv.appendChild(redateH4);
// 협의내용
const detailDiv = document.createElement('div');
detailDiv.className = 'work-list-detail';
const consultH4 = document.createElement('h4');
consultH4.className = 'consuletation-content';
consultH4.textContent = item.consultation_content;
consultH4.title = item.consultation_content;
detailDiv.appendChild(consultH4);
// 변경 일자
const changeDiv = document.createElement('div');
changeDiv.className = 'work-list-changedate';
const changeH4 = document.createElement('h4');
changeH4.className = 'change-date';
changeH4.textContent = item.change_date;
changeDiv.appendChild(changeH4);
// 과업 중지이력 리스트 개별 삭제버튼
const btn = document.createElement('button');
btn.className = 'xs-btn-type';
btn.setAttribute('data-id', item.task_history_id);
const img = document.createElement('img');
img.className = 'icon';
img.src = '/main/img/overview/icon-close-111.svg';
img.alt = 'icon-close-111';
btn.appendChild(img);
btn.addEventListener('click', async (e) => {
overviewVars.deleteTaskHistory.push(e.target.getAttribute('data-id'))
li.remove();
});
li.append(numberDiv, dateDiv, reasonDiv, redateDiv, detailDiv, changeDiv, btn);
if(!vars.permission.checkPermission('overview-task-history-delete')) btn.remove();
ul.appendChild(li);
});
}
} catch (err) {
console.log(err);
}
}
// 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼 Section-Middle 페이지 랜더링 끝 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼
//🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽 Section-Right 페이지 랜더링 시작 🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽
// 달력 생성 함수
export async function generateCalendar(year, month) {
const calendarContainer = document.getElementById('calendar');
const monthNames = ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'];
//html에서 생성
const nextMonthBtn = document.querySelector('.overview .calendar-btn.next-month');
const prevMonthBtn = document.querySelector('.overview .calendar-btn.prev-month');
const addScheduleBtn = document.querySelector('.overview .calendar .add-schedule-btn');
// 이벤트 바인딩을 한번만 하기위해 dataset을 사용
if(nextMonthBtn && !nextMonthBtn.dataset.event){
nextMonthBtn.addEventListener('click', () => {
overviewVars.currentMonth++;
if (overviewVars.currentMonth > 11) {
overviewVars.currentMonth = 0;
overviewVars.currentYear++;
}
generateCalendar(overviewVars.currentYear, overviewVars.currentMonth);
});
nextMonthBtn.dataset.event = 'true';
}
if(prevMonthBtn && !prevMonthBtn.dataset.event){
prevMonthBtn.addEventListener('click', () => {
overviewVars.currentMonth--;
if (overviewVars.currentMonth < 0) {
overviewVars.currentMonth = 11;
overviewVars.currentYear--;
}
generateCalendar(overviewVars.currentYear, overviewVars.currentMonth);
});
prevMonthBtn.dataset.event = 'true';
}
if(addScheduleBtn && !addScheduleBtn.dataset.event){
addScheduleBtn.addEventListener('click', () => {
const modal = document.querySelector('.overview-modal.schedule');
const modalWrapper = document.querySelector('.overview-modal-wrapper');
// 주요일정 모달 초기화
modal.querySelector('.schedule-title').value = '';
modal.querySelector('.schedule-content').value = '';
modal.querySelectorAll('input[type=radio][name=country]').forEach(country => {
if(country.value === '대한민국'){
country.checked = true;
} else {
country.checked = false;
}
});
modal.querySelector('.custom-checkbox.all-day input').checked = false;
modal.querySelector('.schedule-delete.btn-delete').style.display = 'none';
modal.querySelectorAll('.color .label-color').forEach(label => {
label.classList.remove('on');
});
modal.querySelector('.color .label-color').classList.add('on');
if (modal.style.display === 'block') {
modal.style.display = 'none';
return;
}
if (modal.dataset.scheduleId) {
delete modal.dataset.scheduleId;
}
setDefaultScheduleTime();
modal.style.display = 'block';
modalWrapper.style.display = 'block';
});
addScheduleBtn.dataset.event = 'true';
}
const monthHeader = document.querySelector('.overview .month-header');
if (monthHeader) monthHeader.innerText = `${year}${monthNames[month]}`;
// 요일 생성
const existDaysOfWeek = document.querySelector('.overview .days-of-week');
if (!existDaysOfWeek) {
const daysOfWeek = document.createElement('div');
daysOfWeek.classList.add('days-of-week');
const weekdays = ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'];
weekdays.forEach((day, index) => {
const dayElement = document.createElement('div');
dayElement.classList.add('days-of-week-day');
dayElement.innerText = day;
if (index === 0) dayElement.classList.add('sunday');
daysOfWeek.appendChild(dayElement);
});
calendarContainer.appendChild(daysOfWeek);
}
const existDays = document.querySelector('.overview .days');
// days가 이미 있다면 삭제하고 재생성
if (existDays) existDays.remove();
const daysContainer = document.createElement('div');
daysContainer.classList.add('days');
const daysInMonth = new Date(year, month + 1, 0).getDate();
const firstDay = new Date(year, month).getDay();
for (let i = 0; i < firstDay; i++) {
const emptyDay = document.createElement('div');
emptyDay.classList.add('day', 'empty');
daysContainer.appendChild(emptyDay);
}
for (let i = 1; i <= daysInMonth; i++) {
const day = document.createElement('div');
day.classList.add('day');
const mm = (month + 1).toString().padStart(2, '0');
const dd = i.toString().padStart(2, '0');
day.dataset.date = `${year}-${mm}-${dd}`;
const dayOfWeek = new Date(year, month, i).getDay();
if (dayOfWeek === 0) day.classList.add('sunday');
if (dayOfWeek === 6) day.classList.add('saturday');
// 당일 조건
if (year === new Date().getFullYear() && month === new Date().getMonth() && i === new Date().getDate())day.classList.add('today');
day.innerHTML = `<div class="day-today">${i}</div>`;
daysContainer.appendChild(day);
}
calendarContainer.appendChild(daysContainer);
// 공휴일, 일정로드
getCalendarEventData(overviewVars.currentYear, overviewVars.currentMonth);
}
// 쿼리문 한번으로 holiday와 일정을 가져와 일정표에 표시한다.
async function getCalendarEventData(currentYear, currentMonth) {
let nationName = document.querySelector('.overview .nation-nm').innerText;
let nationCode = document.querySelector('.overview .nation-nm').dataset.iso.toLowerCase();
try {
const res = await axios.get(`/${vars.project_id}/overview/getCalendarEventData`, { params: { nationName: nationName, projectId: vars.project_id, currentYear: overviewVars.currentYear, currentMonth: overviewVars.currentMonth + 1 } })
// 데이터를 가져온 이후 type에 따라서 분기를 나눈다 type : holiday / type : schedule
if (res.data.message === '200') {
const calendarEvent = res.data.data;
calendarEvent.sort((a, b) => {
// 휴일 일정을 앞으로
if (a.type === 'holiday' && b.type !== 'holiday') return -1;
if (a.type !== 'holiday' && b.type === 'holiday') return 1;
// 연속일정 판별
const aDate = a.start_date !== a.end_date;
const bDate = b.start_date !== b.end_date;
if (aDate && !bDate) return -1;
if (!aDate && bDate) return 1;
// 연속일정별로 기간의 길이 판별
const aPeriod = new Date(a.end_date) - new Date(a.start_date);
const bPeriod = new Date(b.end_date) - new Date(b.start_date);
if (aPeriod > bPeriod) return -1;
if (aPeriod < bPeriod) return 1;
return 0;
});
calendarEvent.forEach(event => {
if (event.type === 'holiday') {
const holidayDate = event.start_date;
const holidayTitle = event.title;
const country = event.nation_nm;
const dayEl = document.querySelector(`.day[data-date="${holidayDate}"]`);
if (dayEl) {
if (dayEl.dataset.date === holidayDate && country == '한국') {
if (dayEl.classList.contains('saturday')) dayEl.classList.remove('saturday');
dayEl.classList.add('sunday');
const holidayDiv = document.createElement('div');
holidayDiv.classList.add('holiday');
const holidayImg = document.createElement('img');
holidayImg.src = `https://flagcdn.com/kr.svg`;
holidayDiv.appendChild(holidayImg);
const holidayText = document.createElement('p');
holidayText.textContent = holidayTitle;
holidayText.title = holidayTitle;
holidayText.style.color = '#1F7C5D';
holidayDiv.appendChild(holidayText);
dayEl.appendChild(holidayDiv);
} else {
if (dayEl.classList.contains('saturday')) dayEl.classList.remove('saturday');
dayEl.classList.add('sunday');
const holidayDiv = document.createElement('div');
holidayDiv.classList.add('holiday');
const holidayImg = document.createElement('img');
holidayImg.src = `https://flagcdn.com/${nationCode}.svg`;
holidayDiv.appendChild(holidayImg);
const holidayText = document.createElement('p');
holidayText.textContent = holidayTitle;
holidayText.title = holidayTitle;
holidayText.style.color = '#FF3D00';
holidayDiv.appendChild(holidayText);
dayEl.appendChild(holidayDiv);
}
}
} else if (event.type === 'schedule') {
const startDateStr = event.start_date.split('T')[0];
const endDateStr = event.end_date.split('T')[0];
const startDate = new Date(startDateStr);
const endDate = new Date(endDateStr);
let currentDate = new Date(startDate);
while (currentDate <= endDate) {
const dateStr = currentDate.toISOString().split('T')[0];
const dayEl = document.querySelector(`.day[data-date="${dateStr}"]`);
const holidayEl = document.querySelector(`.day[data-date="${dateStr}"] .holiday`);
if (dayEl) {
// 기존 배열 초기화 및 누적
if (!dayEl.dataset.schedules) dayEl.dataset.schedules = JSON.stringify([]);
const schedules = JSON.parse(dayEl.dataset.schedules);
schedules.push(event);
dayEl.dataset.schedules = JSON.stringify(schedules);
const scheduleDiv = document.createElement('div');
scheduleDiv.classList.add('schedule');
const scheduleTimeDiv = document.createElement('div');
scheduleTimeDiv.classList.add('time');
const scheduleTitleDiv = document.createElement('div');
scheduleTitleDiv.classList.add('title');
scheduleTitleDiv.style.color = '#000';
// 단일 일정
if (dateStr === startDateStr) {
scheduleTitleDiv.innerText = event.title;
// 연속 일정
if (startDateStr !== endDateStr) {
const dataColor = changeColor(event.color)
scheduleDiv.style.backgroundColor = dataColor;
scheduleDiv.classList.add('start_date', 'continuous');
}
// 일정 마지막
} else if (dateStr === endDateStr) {
const dataColor = changeColor(event.color)
scheduleDiv.style.backgroundColor = dataColor;
scheduleDiv.classList.add('end_date', 'continuous');
// 일정 중간
} else {
const dataColor = changeColor(event.color)
scheduleDiv.style.backgroundColor = dataColor;
scheduleDiv.classList.add('continuous');
}
if (dateStr === startDateStr) {
scheduleTitleDiv.innerText = event.title;
}
const scheduleColorDiv = document.createElement('div');
scheduleColorDiv.classList.add('color');
if (dateStr === startDateStr) {
if (startDateStr === endDateStr) {
scheduleColorDiv.innerText = '⦁';
} else {
scheduleColorDiv.innerHTML = '&nbsp;';
}
scheduleColorDiv.style.color = event.color;
} else {
scheduleColorDiv.innerHTML = '&nbsp;';
}
scheduleDiv.append(scheduleColorDiv, scheduleTitleDiv, scheduleTimeDiv);
const existinSchedules = dayEl.querySelectorAll('.schedule').length;
// 일정 최대 두개까지만 생성
if (existinSchedules < 2) {
// 공휴일 일정과 연속일정일때 공휴일 일정 앞으로 연속일정 생성
if (holidayEl && scheduleDiv.classList.contains('continuous')) {
dayEl.insertBefore(scheduleDiv, holidayEl);
} else {
dayEl.appendChild(scheduleDiv);
}
}
}
currentDate.setDate(currentDate.getDate() + 1);
}
// 일정 3개 이후로는 개수 표시
document.querySelectorAll('.day[data-schedules]').forEach(dayEl => {
const schedules = JSON.parse(dayEl.dataset.schedules);
// 이미 추가된 경우 삭제
if (dayEl.querySelector('.remain-schedules')) dayEl.querySelector('.remain-schedules').remove();
if (schedules.length > 2) {
const remainDiv = document.createElement('p');
remainDiv.innerText = `${schedules.length - 2}개...`;
remainDiv.classList.add('remain-schedules');
dayEl.appendChild(remainDiv);
}
});
}
});
// 일정 리스트 모달
document.querySelectorAll('.overview .days .day[data-schedules]').forEach(schedule => {
const schedules = JSON.parse(schedule.dataset.schedules);
schedule.addEventListener('click', () => {
const modal = document.querySelector('.overview-modal');
const modalWrapper = document.querySelector('.overview-modal-wrapper');
if (modal.style.display === 'block') {
modal.style.display = 'none';
return;
}
const modalBody = modal.querySelector('.overview-modal-body');
modalBody.innerHTML = '';
schedules.forEach(schedule => {
const scheduleStartDate = schedule.start_date.split('T')[0];
const scheduleStartTime = schedule.start_date.split('T')[1];
const scheduleEndDate = schedule.end_date.split('T')[0];
const scheduleEndTime = schedule.end_date.split('T')[1];
const scheduleDiv = document.createElement('div');
scheduleDiv.classList.add('calendar-list');
const scheduleWrap = document.createElement('div');
const subDiv = document.createElement('div');
subDiv.className = 'schedule-title';
scheduleWrap.appendChild(subDiv);
const scheduleColor = document.createElement('div');
scheduleColor.innerText = '⦁'
scheduleColor.style.color = schedule.color;
subDiv.appendChild(scheduleColor);
const scheduleTitle = document.createElement('h3');
scheduleTitle.textContent = schedule.title;
subDiv.appendChild(scheduleTitle);
const scheduleContent = document.createElement('h6');
scheduleContent.textContent = schedule.content;
scheduleWrap.appendChild(scheduleContent);
const scheduleTime = document.createElement('p');
if (scheduleStartTime != '' && scheduleEndTime != '') {
scheduleTime.textContent = `${scheduleStartDate} ${scheduleStartTime} ~ ${scheduleEndDate} ${scheduleEndTime}`
} else {
scheduleTime.textContent = '하루종일'
scheduleTime.style.color = '#FF3D00';
}
scheduleWrap.appendChild(scheduleTime);
const editbtn = document.createElement('button');
editbtn.className = 'xs-btn-type-icon';
editbtn.innerHTML = '<h6>편집</h6>';
scheduleDiv.appendChild(scheduleWrap);
scheduleDiv.appendChild(editbtn)
modalBody.appendChild(scheduleDiv);
// 이벤트 편집 페이지
editbtn.addEventListener('click', () => {
document.querySelector('.overview-modal.schedule-list').style.display = 'none';
const modal = document.querySelector('.overview-modal.schedule');
const modalWrapper = document.querySelector('.overview-modal-wrapper');
if (modal.style.display === 'block') {
modal.style.display = 'none';
return;
}
if(scheduleStartTime === '' && scheduleEndTime === ''){
modal.querySelector('.all-day input').checked = true;
modal.querySelector('.startTime').disabled = true;
modal.querySelector('.endTime').disabled = true;
}
modal.querySelector('.schedule-title').value = schedule.title;
modal.querySelector('.schedule-content').value = schedule.content;
modal.querySelectorAll('.color .label-color').forEach(btn => {
btn.classList.remove('on');
});
if (modal.querySelector(`.color .label-color[data-color="${schedule.color}"]`)) {
modal.querySelector(`.color .label-color[data-color="${schedule.color}"]`).classList.add('on');
}
modal.querySelector('.startDate').value = scheduleStartDate;
modal.querySelector('.startTime').value = scheduleStartTime;
modal.querySelector('.endDate').value = scheduleEndDate;
modal.querySelector('.endTime').value = scheduleEndTime;
modal.dataset.scheduleId = schedule.calendar_event_id;
if (modal.querySelector(`input[type="radio"][name="country"][value="${schedule.nation_nm}"]`)) {
modal.querySelector(`input[type="radio"][name="country"][value="${schedule.nation_nm}"]`).checked = true;
};
modal.querySelector('.schedule-delete').style.display = 'flex';
modal.style.display = 'block';
modalWrapper.style.display = 'block';
});
// 권한 이하일땐 편집버튼 삭제
if(!vars.permission.checkPermission('overview-schedule-edit')) editbtn.remove();
});
modal.style.display = 'block';
modalWrapper.style.display = 'block';
});
})
}
} catch {
}
}
export function startTimer(nation) {
// nation의 값이 없거나 대한민국 일때 교류시간 활성화 x
if (nation === '대한민국' || nation === '' || nation === 'ㅡ') {
document.querySelector('.overview .overview-box-3 .box.exchange-time').style.display = 'none';
return;
} else {
// 초기 로드 이후 남은 시간 계산해서 setTimeOut 이후에 setInterval로 1분에 한번씩 동작
updateTimeBar();
const currentTime = new Date();
const remainingSecond = 60 - currentTime.getSeconds();
setTimeout(() => {
updateTimeBar();
setInterval(updateTimeBar, 60 * 1000);
}, remainingSecond * 1000);
}
}
// 교류시간 기능 개발
export async function updateTimeBar() {
// overseas에서만 사용
if(!overviewVars.overseas) return;
const otherCountry = document.querySelector('.overview .nation-nm').innerText.trim();
const otherCountryIso = document.querySelector('.overview .nation-nm').dataset.iso.toUpperCase();
const otherUtcOffset = document.querySelector('.overview .nation-nm').dataset.utcOffset;
const krUtcOffset = 32400;
const offsetHours = otherUtcOffset / 3600;
// 프로젝트 국가가 대한민국이라면 생성X
if (otherCountry && otherCountry !== '대한민국' && otherCountry !== '한국') {
document.querySelector('.overview .overview-box-3 .box.exchange-time').style.display = 'block';
// 시차계산하여 현재 시간 출력 timebar에 사용
const kstTime = applyUtcOffsetTime(krUtcOffset);
const otherCountryTime = applyUtcOffsetTime(otherUtcOffset);
// 교류시간 3시간 동적 생성
for (let i = 0; i <= 8; i++) {
const hour = (i * 3) + (offsetHours - 9);
document.querySelector(`.overview .bottom-section-4 .other-country-time${i + 1}`).textContent = formatHour(hour)
}
// 교류시간 일과 시간 생성
const workTime = document.querySelectorAll('.overview .bottom-section-3 .timetable-block');
// 한국 기준 + 대상 국가 offset 시차 보정
let startTime = 9 + (9 - offsetHours);
let endTime = 9 + (17 - offsetHours);
// 0~24 범위로 보정
startTime = (startTime + 24) % 24;
endTime = (endTime + 24) % 24;
const startHour = Math.floor(startTime);
const endHour = Math.floor(endTime);
const startFraction = startTime - startHour;
const endFraction = endTime - endHour;
// 외국 근무시간 9~18 동적 생성
for (let i = 0; workTime.length > i; i++) {
if (startTime <= endTime) {
// 같은 날
if (i >= startTime && i <= endTime) {
workTime[i].classList.add('work-hour');
}
} else {
// 자정 넘는 경우
if (i >= startTime || i <= endTime) {
workTime[i].classList.add('work-hour');
}
}
}
// 15분 30분 45분 시차 부분색칠
if(startFraction && endFraction){
fillPartialBlock(workTime[startHour], startFraction, true);
fillPartialBlock(workTime[endHour+1], endFraction, false);
}
// 교류시간 시간과 나라
document.querySelector('.overview .time-bar .kst-time').innerText = 'KR : ' + kstTime;
document.querySelector('.overview .other-country').innerText = otherCountry;
document.querySelector('.overview .time-bar .other-country-time').innerText = ` ${otherCountryIso} : ` + otherCountryTime;
// 대한민국 시간 기준 left 계산
const moveRem = calculateRemPosition(kstTime); // 9시부터 시작
document.querySelector('.overview .time-bar').style.left = `${moveRem}rem`;
} else {
document.querySelector('.overview .overview-box-3 .box.exchange-time').style.display = 'none';
}
}
// 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼 Section-Right 페이지 랜더링 끝 🔼🔼🔼🔼🔼🔼🔼🔼🔼🔼