결과 화면


개발환경 : 스프링부트 2.7.9 + mybatis +mysql + jsp
fullcalendar 소스는 다음 링크 주소에 있으며 현재 시점 6.15 이다.
https://github.com/fullcalendar/fullcalendar
여기 프로젝에서 적용한 fullcalendar 버전은 5.9.0 이다.
https://github.com/braverokmc79/fullcalendar-5.9.0
MYSQL
CREATE TABLE `tbl_schedulemanage` ( `scheduleId` int(11) NOT NULL AUTO_INCREMENT COMMENT 'schedule번호(PK)', `scheduleName` varchar(255) DEFAULT NULL COMMENT '스케줄제목', `url` varchar(100) DEFAULT NULL COMMENT '링크주소', `textColor` varchar(15) DEFAULT NULL COMMENT '글자색', `color` varchar(15) DEFAULT NULL COMMENT '테두리색', `backgroundColor` varchar(15) DEFAULT NULL COMMENT '배경색', `startDate` varchar(25) DEFAULT NULL COMMENT '시작일', `endDate` varchar(25) DEFAULT NULL COMMENT '끝일', PRIMARY KEY (`scheduleId`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Mybatis
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="패키지명.model.dao.mapper.ScheduleManageMapper">
<!-- 관리자 화면일경우 url 생략 -->
<select id="selectAdminEventList" resultType="패키지명.model.vo.ScheduleManageVO">
SELECT
scheduleid AS "id" , schedulename as "title" ,
if(textColor is null, '#ffffff', textColor ) as textColor,
if(color is null, '#3788d8', color ) as color,
if(backgroundColor is null, '#3788d8', backgroundColor ) as backgroundColor
, startdate as "start" , enddate AS "end"
FROM tbl_schedulemanage
</select>
<!-- 5년전 데이터까지만 가져오기 -->
<select id="selectEventList" resultType="lineage.choco.model.vo.ScheduleManageVO">
SELECT
scheduleid AS "id" , schedulename as "title" ,
if(url is null, '#', url ) as url,
if(textColor is null, '#ffffff', textColor ) as textColor,
if(color is null, '#3788d8', color ) as color,
if(backgroundColor is null, '#3788d8', backgroundColor ) as backgroundColor
, startdate as "start" , enddate AS "end"
FROM tbl_schedulemanage
WHERE startdate >= date_add(now(), interval -5 year)
</select>
<insert id="addSchedule" parameterType="패키지명.model.vo.ScheduleManageVO">
INSERT INTO tbl_schedulemanage (schedulename, url , textColor, color , backgroundColor , startdate, enddate)
VALUES( #{scheduleName}, #{url} , #{textColor} , #{color} , #{backgroundColor} , #{startDate}, #{endDate})
</insert>
<select id="getEvent" resultType="패키지명.model.vo.ScheduleManageVO">
SELECT
scheduleid AS "id" , schedulename as "title" ,
if(url is null, '#', url ) as url,
if(textColor is null, '#ffffff', textColor ) as textColor,
if(color is null, '#3788d8', color ) as color,
if(backgroundColor is null, '#3788d8', backgroundColor ) as backgroundColor
, startdate as "start" , enddate AS "end"
FROM tbl_schedulemanage WHERE scheduleid =#{id}
</select>
<delete id="deleteSch">
DELETE FROM tbl_schedulemanage WHERE SCHEDULEID =#{id}
</delete>
<update id="updateSch">
UPDATE tbl_schedulemanage SET
<if test="scheduleName!=null and !scheduleName.equals('') ">
scheduleName= #{scheduleName},
</if>
<if test="url!=null and !url.equals('') ">
url=#{url},
</if>
<if test="textColor!=null and !textColor.equals('') ">
textColor=#{textColor},
</if>
<if test="color!=null and !color.equals('') ">
color=#{color},
</if>
<if test="backgroundColor!=null and !backgroundColor.equals('') ">
backgroundColor=#{backgroundColor},
</if>
startdate=#{startDate},
enddate=#{endDate}
WHERE scheduleid=#{scheduleId}
</update>
</mapper>
ScheduleManageVO
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class ScheduleManageVO {
private int scheduleId;
private String scheduleName;
private String startDate;
private String endDate;
private String id;
private String title; //스케줄제목
private String url;// 링크주소
private String textColor; //글자색
private String color; //테두리색
private String backgroundColor;//배경색
private String start; //시작일
private String end; //종료일
}
ScheduleManageService
import java.util.List;
import java.util.Map;
import 패키지.model.vo.ScheduleManageVO;
public interface ScheduleManageService {
public List<ScheduleManageVO> showSchedule() throws Exception;
public int addSchedule(ScheduleManageVO calendarVO) throws Exception;
public List<ScheduleManageVO> selectEventList(Map<String, Object> map) throws Exception;
public ScheduleManageVO getEvent(Map<String, Object> map) throws Exception;
public int deleteSch(ScheduleManageVO calendarVO) throws Exception;
public int updateSch(ScheduleManageVO calendarVO) throws Exception;
}
ScheduleManageServiceImpl
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Service;
import 패키지.model.dao.mapper.ScheduleManageMapper;
import 패키지.model.vo.ScheduleManageVO;
import 패키지.service.ScheduleManageService;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ScheduleManageServiceImpl implements ScheduleManageService {
private final ScheduleManageMapper scheduleManageMapper;
public List<ScheduleManageVO> showSchedule() throws Exception {
return scheduleManageMapper.showSchedule();
}
public int addSchedule(ScheduleManageVO calendarVO) throws Exception {
return scheduleManageMapper.addSchedule(calendarVO);
}
public List<ScheduleManageVO> selectEventList(Map<String, Object> map) throws Exception {
return scheduleManageMapper.selectEventList(map);
}
public ScheduleManageVO getEvent(Map<String, Object> map) throws Exception {
return scheduleManageMapper.getEvent(map);
}
public int deleteSch(ScheduleManageVO calendarVO) throws Exception {
return scheduleManageMapper.deleteSch(calendarVO);
}
public int updateSch(ScheduleManageVO calendarVO) throws Exception {
return scheduleManageMapper.updateSch(calendarVO);
}
}
ScheduleManageMapper
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;
import 패키지.model.vo.ScheduleManageVO;
@Repository
public interface ScheduleManageMapper {
public List<ScheduleManageVO> showSchedule() throws Exception;
public int addSchedule(ScheduleManageVO calendarVO) throws Exception;
public List<ScheduleManageVO> selectEventList(Map<String, Object> map) throws Exception;
public ScheduleManageVO getEvent(Map<String, Object> map) throws Exception;
public int deleteSch(ScheduleManageVO calendarVO) throws Exception;
public int updateSch(ScheduleManageVO calendarVO) throws Exception;
}
1) 관리자 화면
컨트롤
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import 패키지.config.auth.PrincipalDetails;
import 패키지.model.vo.BoardVO;
import 패키지.model.vo.ScheduleManageVO;
import 패키지.service.BoardService;
import 패키지.service.ScheduleManageService;
import lombok.RequiredArgsConstructor;
@Controller
@RequiredArgsConstructor
@RequestMapping("/admin/scheduleManage/")
public class AdminScheduleManageController {
private final ScheduleManageService calendarService;
private final BoardService boardService;
/** 스캐쥴 화면 */
@GetMapping("list")
public String scheduleManageList(@AuthenticationPrincipal PrincipalDetails priDetails, Model model) throws Exception {
model.addAttribute("menuName", "일정관리");
return "admin/scheduleManage/scheduleManage_list";
}
@ResponseBody
@PostMapping("addSchedule")
public int addSchedule(ScheduleManageVO scheduleManageVO) throws Exception {
return calendarService.addSchedule(scheduleManageVO);
}
/** 스캐쥴 목록 가져오기 */
@ResponseBody
@PostMapping("selectEventList")
public List<ScheduleManageVO> selectEventList(@RequestParam Map<String, Object> map) throws Exception {
return calendarService.selectEventList(map);
}
@ResponseBody
@PostMapping("getEvent")
public ScheduleManageVO getEvent(@RequestParam Map<String, Object> map) throws Exception {
return calendarService.getEvent(map);
}
@ResponseBody
@PostMapping("deleteSch")
public int deleteSch(ScheduleManageVO scheduleManageVO) throws Exception {
return calendarService.deleteSch(scheduleManageVO);
}
@ResponseBody
@PostMapping("updateSch")
public int updateSch(ScheduleManageVO scheduleManageVO) throws Exception {
return calendarService.updateSch(scheduleManageVO);
}
/** 게시판 링크 URL 가져오기 */
@ResponseBody
@PostMapping("findBoardTypeByTitleList")
public List<BoardVO> findBoardTypeByTitleList(@RequestParam Map<String, Object> map) throws Exception {
return boardService.findBoardTypeByTitleList(map);
}
}
scheduleManage_list.jsp
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<!-- 부트스트랩 라이브러리 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<!-- fullcalendar 라이브러리 -->
<link href='https://cdn.jsdelivr.net/gh/braverokmc79/fullcalendar-5.9.0@v5.9.0/lib/main.css' rel='stylesheet' />
<!-- daterangepicker 라이브러리 -->
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" />
<!-- 커스텀 .css -->
<link href="/resources/lib/fullcalendar/css/scheduleManage_list.css" rel="stylesheet">
</head>
<body>
<div id='calendar-container'>
<div id='calendar'></div>
</div>
<%@ include file="schedule_manage_modal.jsp" %>
<!-- jquery 라이브러리 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 부트스트랩 라이브러리 -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
<!-- 날짜 라이브러리 -->
<script type="text/javascript" src="//cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<!-- fullcalendar 라이브러리 -->
<script src='https://cdn.jsdelivr.net/gh/braverokmc79/fullcalendar-5.9.0@v5.9.0/lib/main.js'></script>
<script src='https://cdn.jsdelivr.net/gh/braverokmc79/fullcalendar-5.9.0@v5.9.0/lib/locales-all.min.js'></script>
<!-- daterangepicker 라이브러리 -->
<script type="text/javascript" src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
<!-- 커스텀 js -->
<script src="/resources/lib/fullcalendar/js/scheduleManage_list.js"></script>
</body>
</html>
scheduleManage_list.css
@charset "utf-8";
#calendar{
width:80%;
margin:20px auto;
margin-bottom:200px;
}
a {
color: #000000;
text-decoration: none;
}
/* 드래그 박스의 스타일 */
#external-events {
position: fixed;
left: 20px;
top: 20px;
width: 100px;
padding: 0 10px;
border: 1px solid #ccc;
background: #eee;
text-align: left;
}
#external-events h4 {
font-size: 16px;
margin-top: 0;
padding-top: 1em;
}
#external-events .fc-event {
margin: 3px 0;
cursor: move;
}
#external-events p {
margin: 1.5em 0;
font-size: 11px;
color: #666;
}
#external-events p input {
margin: 0;
vertical-align: middle;
}
#calendar-wrap {
margin-left: 0px;
}
#calendar1 {
max-width: 1100px;
margin: 0 auto;
}
.fc-myCustomButton-button {
/* background: #b31515 !important; */
}
.form-group{
margin-bottom: 30px;
}
.fc-event-time, .fc-event-title{
font-size: 15px;
}
.empl_nm{
display: none;
}
.daterangepicker .table-condensed tbody tr td.available:first-child { color: #0d6efd;}
.daterangepicker .table-condensed tbody tr td.available:last-child { color: #f95f53 !important;}
.daterangepicker td.active, .daterangepicker td.active:hover {background-color: #c5daed; border-color: transparent; color: #fff !important;}
.daterangepicker .table-condensed tbody tr td.off { color: #999 !important; opacity:0.5;}
.modal .modal-dialog .modal-content .modal-footer { padding: 15px 31px;display: flex;justify-content: space-around;}
.fc-daygrid-day.fc-day.fc-day-sat.fc-day-past .fc-daygrid-day-top a ,
.fc-daygrid-day.fc-day.fc-day-sat.fc-day-future .fc-daygrid-day-top a
{ color:#2575fc; } /* 토요일 */
.fc-daygrid-day.fc-day.fc-day-sun.fc-day-past .fc-daygrid-day-top a,
.fc-daygrid-day.fc-day.fc-day-sun.fc-day-future .fc-daygrid-day-top a
{color:#dd3e0e; }/* 일요일 */
scheduleManage_list.js
다음 사이틀 참조해서 googleCalendarApiKey 구글 api 키값 적용
Spring에서 FullCalendar(풀 캘린더)로 Google(구글) 캘린더 DB 연동하기
let $g_arg; //모달창에서 호출하는 함수에서 참조하기 위함)
let $calendar;
let $daterangeStartDate = "";
let $daterangeEndDate = "";
document.addEventListener('DOMContentLoaded', function() {
//FullCalendar 초기 셋팅 및 데이터 불러오기
getFullCalendarEvent();
$('body').on('click', 'button.fc-prev-button', function(e) {
console.log("prev1");
});
$('body').on('click', 'button.fc-next-button', function(e) {
console.log("next");
});
});
//FullCalendar 초기 셋팅
function getFullCalendarEvent(currentDatePage) {
const calendarEl = document.getElementById('calendar');
$calendar = new FullCalendar.Calendar(calendarEl, {
googleCalendarApiKey: '구글 APIKEY',
//className은 되도록 캘린더랑 맞추길
eventSources: [
{
googleCalendarId: 'ko.south_korea#holiday@group.v.calendar.google.com',
className: '대한민국의 휴일',
color: '#be5683', //rgb,#ffffff 등의 형식으로 할 수 있다
//textColor: 'black'
},
],
customButtons: {
myCustomButton: {
text: '일정입력',
click: function(event) {
onSelectEvent(event);
}
}
},
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek,myCustomButton'
},
initialDate: currentDatePage, // 초기 날짜 설정 (설정하지 않으면 오늘 날짜가 보인다.)
locale: 'ko', // 한국어 설정
editable: true, // 수정 가능
droppable: true, // 드래그 가능
drop: function(arg) { // 드래그 엔 드롭 성공시
},
defaultView: 'timeGridWeek',
navLinks: false, // can click day/week names to navigate views
allDaySlot: false,
eventLimit: true, // allow "more" link when too many events
//minTime: '10:00:00',
//maxTime: '24:00:00',
//contentHeight: 'auto',
dateClick: function(arg) {
//해당월 페이지 이동을 위한 날짜가져오기
var getData = this.getCurrentData();
var currentDatePage = moment(getData.currentDate).format('YYYY-MM-DD');
$("#currentDatePage").val(currentDatePage);
insertModalOpen(arg);
},
eventClick: function(info) {
//여기서 info 가 아니라 event 로 처리해야 함
event.preventDefault();
//만약 구글 캘린던라면 링크 이동 중단 처리
if (info.event.url.includes('https://www.google.com/calendar/')) {
return;
}
//해당월 페이지 이동을 위한 날짜가져오기
var getData = this.getCurrentData();
var currentDatePage = moment(getData.currentDate).format('YYYY-MM-DD');
$("#currentDatePage").val(currentDatePage);
var url = info.event.url;
//모달창 호출
updateModalOpen(info.event.id, url);
},
eventAdd: function(obj) { // 이벤트가 추가되면 발생하는 이벤트
//console.log(" 이벤트가 추가되면 발생하는 이벤트" ,obj);
},
eventChange: function(obj) { // 이벤트가 수정되면 발생하는 이벤트
console.log("1.벤트가 수정되면 발생하는 이벤트 ", obj);
const scheduleId = obj.event._def.publicId;
const startDate = moment(obj.event._instance.range.start).format();
const endDate = moment(obj.event._instance.range.end).format();
const param = {
scheduleId,
startDate,
endDate
}
console.log("2.벤트가 수정되면 발생하는 이벤트 ", obj.event._def.url);
//만약 구글 캘린던라면 링크 중단 처리
if (obj.event._def.url.includes('https://www.google.com/calendar/')) {
alert("지정된 공휴일은 업데이트 처리 될수 없습니다.");
getFullCalendarEvent();
return;
}
$.ajax({
url: "/admin/scheduleManage/updateSch",
type: "POST",
data: param,
dataType: "text",
success: function(result) {
console.log(" 업데이트 : ", result);
},
error: function(result) {
console.log("error:");
console.log(result);
}
});
},
select: function(arg) { // 캘린더에서 드래그로 이벤트를 생성할 수 있다.
/* console.log(" 드래그 ", arg)
var title = prompt('Event Title:');
if (title) {
calendar.addEvent({
title: title,
start: arg.start,
end: arg.end,
allDay: arg.allDay
})
}
calendar.unselect() */
}
}); //End ------------ var calendar = new FullCalendar.Calendar(calendarEl,
//DB에서 데이터 가져오기
const arr = getCalendarDataInDB();
$.each(arr, function(index, item) {
$calendar.addEvent(item);
});
$calendar.render();
$calendar.on('dateClick', function(info) {
// console.log('clicked on ' + info.dateStr);
});
return $calendar;
}
//일정 입력
function onSelectEvent() {
insertModalOpen("onSelectEvent");
}
//arr 는 테스트용으로 DB 에서 스케즐 데이터를 가져오지 못했을 경우 테스트용 데이터
function getCalendarDataInDB() {
//arr 임의 데이터
let arr = [{
title: 'evt111',
start: '2023-03-22T10:30:00',
end: '2023-03-23T10:30:00',
backgroundColor: "#52cdff",
color: "#000",
textColor: "#fff",
url: "https://daum.net"
}];
$.ajax({
contentType: 'application/json',
dataType: 'json',
url: '/admin/scheduleManage/selectEventList',
type: 'post',
async: false,
success: function(res) {
arr = res;
},
error: function(res) {
console.log(res);
}
});
return arr;
}
// 받은 날짜값을 date 형태로 형변환 해주어야 한다.
function convertDate(date) {
var date = new Date(date);
alert(date.yyyymmdd());
}
/*
******************************************************************************************************
여기서 부터 모달 JS
******************************************************************************************************
*
*/
function customDaterangePicker() {
$('input[name="daterange"]').daterangepicker({
"showDropdowns": true,
"showWeekNumbers": true,
"showISOWeekNumbers": true,
"timePicker": true,
"timePicker24Hour": true,
"timePickerSeconds": true,
"locale": {
"format": "YYYY-MM-DD Ah:mm",
"separator": " - ",
"applyLabel": "적용",
"cancelLabel": "취소",
"fromLabel": "From",
"toLabel": "To",
"customRangeLabel": "사용자 지정",
"weekLabel": "W",
"daysOfWeek": [
"일",
"월",
"화",
"수",
"목",
"금",
"토"
],
"monthNames": [
"1월",
"2월",
"3월",
"4월",
"5월",
"6월",
"7월",
"8월",
"9월",
"10월",
"11월",
"12월"
],
"firstDay": 1
},
"autoUpdateInput": false,
"alwaysShowCalendars": true,
"startDate": $daterangeStartDate,
"endDate": $daterangeEndDate,
"minDate": "2000-12-31",
"maxDate": "2050-12-31"
}, function(start, end, label) {
$("#startDate").val(moment(start).format());
$("#endDate").val(moment(end).format());
$("#daterange").val(start.format('YYYY-MM-DD Ah:mm') + " ~ " + end.format('YYYY-MM-DD Ah:mm'));
});
}
//이벤트 등록 모달
function insertModalOpen(arg) {
$(".scheDeleteBtn").css("display", "none");
$(".schInsertBtn").css("display", "block");
$(".schUpdateBtn").css("display", "none");
$(".modal-title").text("일정 등록");
$("#title").val("");
$("#url").val("");
$("#textColor").val("#ffffff");
$("#color").val("#1466b8");
$("#backgroundColor").val("#3788d8");
if (arg == "onSelectEvent") {
const date1 = new Date();
arg = {
dateStr: moment(date1).format('YYYY MM DD')
}
}
$g_arg = arg;
//초기 해당일 날짜 셋팅
$daterangeStartDate = arg.dateStr + " AM12:00";
$daterangeEndDate = arg.dateStr + " PM1:00";
$("#daterange").val($daterangeStartDate + " ~ " + $daterangeEndDate);
const sd1 = new Date(arg.dateStr + "T12:00:00");
const ed1 = new Date(arg.dateStr + "T13:00:00");
$("#startDate").val(moment(sd1).format());
$("#endDate").val(moment(ed1).format());
$(".daterangepicker_input input[name=daterangepicker_start]").val($daterangeStartDate);
$(".daterangepicker_input input[name=daterangepicker_end]").val($daterangeEndDate);
//end - 초기 해당일 날짜 셋팅
customDaterangePicker();
$('.insertModal').modal("show");
}
//스케쥴 등록
function insertSch(modal, arg) {
const scheduleName = $("#title").val();
const url = $("#url").val();
const textColor = $("#textColor").val();
const color = $("#color").val();
const backgroundColor = $("#backgroundColor").val();
const startDate = $("#startDate").val();
const endDate = $("#endDate").val();
if ($('.insertModal #end').val() <= $('.insertModal #start').val()) {
alert('종료시간을 시작시간보다 크게 선택해주세요');
$('.insertModal #end').focus();
return;
}
if ($('.' + modal + ' #title').val() == '') {
alert('제목을 입력해주세요');
$("#title").focus();
return;
}
if (startDate == "" || startDate == "Invalid date") {
alert("시작 날짜를 다시 선택해 주세요.");
return;
}
if (endDate == "" || endDate == "Invalid date") {
alert("종료 날짜를 다시 선택해 주세요.");
return;
}
const param = {
scheduleName: scheduleName,
url: url,
textColor: textColor,
color: color,
backgroundColor: backgroundColor,
startDate: startDate,
endDate: endDate
}
//스케줄 작성
$.ajax({
url: "/admin/scheduleManage/addSchedule",
type: "POST",
data: param,
dataType: "text",
success: function(result) {
//console.log(result);
loadEvents();
},
error: function(result) {
console.log("error:");
console.log(result);
}
});
}
//캘린더 Refresh
function loadEvents() {
$calendar.destroy();
const currentDatePage = $("#currentDatePage").val();
//캘린더 데이터 목록 다시 불러오기
getFullCalendarEvent(currentDatePage);
$('.insertModal').modal("hide");
}
//모달 닫기
function closeModal() {
$('.insertModal').modal("hide");
}
//이벤트 수정 및 삭제 모달
function updateModalOpen(id, url) {
const currentState = "admin";
$(".scheDeleteBtn").css("display", "block");
$(".schInsertBtn").css("display", "none");
$(".schUpdateBtn").css("display", "block");
$(".modal-title").text("일정 수정");
if (currentState == "admin") {
$.ajax({
url: "/admin/scheduleManage/getEvent",
type: "POST",
data: { id: id },
dataType: "json",
success: function(data) {
const { id, title, url, textColor, color, backgroundColor, start, end } = data;
$("#scheduleId").val(id);
$("#title").val(title);
$("#url").val(data.url);
$("#textColor").val(textColor);
$("#color").val(color);
$("#backgroundColor").val(backgroundColor);
//초기 해당일 날짜 셋팅
$("#startDate").val(start);
$("#endDate").val(end);
$daterangeStartDate = moment(start).format('YYYY-MM-DD Ah:mm');
$daterangeEndDate = moment(end).format('YYYY-MM-DD Ah:mm');
$("#daterange").val($daterangeStartDate + " ~ " + $daterangeEndDate);
$(".daterangepicker_input input[name=daterangepicker_start]").val($daterangeStartDate);
$(".daterangepicker_input input[name=daterangepicker_end]").val($daterangeEndDate);
//end - 해당일 날짜 셋팅
//date picker 호출
customDaterangePicker();
$('.insertModal').modal("show");
},
error: function(result) {
console.log("error:");
console.log(result);
}
});
} else {
//구글 이동
//window.open(url);
}
}
//삭제 처리
function deleteSch() {
const id = $("#scheduleId").val();
if (confirm("정말 삭제 하시겠습니까?")) {
$.ajax({
url: "/admin/scheduleManage/deleteSch",
type: "POST",
data: { id: id },
dataType: "json",
success: function(result) {
// console.log(result);
if (result == 1) {
loadEvents();
} else {
console.log("error");
}
},
error: function(result) {
console.log("error:");
console.log(result);
}
});
}
}
//스케쥴 수정
function updateSch(modal, arg) {
const scheduleId = $("#scheduleId").val();
const url = $("#url").val();
const textColor = $("#textColor").val();
const color = $("#color").val();
const backgroundColor = $("#backgroundColor").val();
const scheduleName = $("#title").val();
const startDate = $("#startDate").val();
const endDate = $("#endDate").val();
if ($('.insertModal #end').val() <= $('.insertModal #start').val()) {
alert('종료시간을 시작시간보다 크게 선택해주세요');
$('.insertModal #end').focus();
return;
}
if ($('.' + modal + ' #title').val() == '') {
alert('제목을 입력해주세요');
$("#title").focus();
return;
}
if (startDate == "" || startDate == "Invalid date") {
alert("시작 날짜를 다시 선택해 주세요.");
return;
}
if (endDate == "" || endDate == "Invalid date") {
alert("종료 날짜를 다시 선택해 주세요.");
return;
}
const param = {
scheduleId: scheduleId,
scheduleName: scheduleName,
url: url,
textColor: textColor,
color: color,
backgroundColor: backgroundColor,
startDate: startDate,
endDate: endDate
}
$.ajax({
url: "/admin/scheduleManage/updateSch",
type: "POST",
data: param,
dataType: "text",
success: function(result) {
loadEvents();
},
error: function(result) {
console.log("error:");
console.log(result);
}
});
}
/*
******************************************************************************************************
여기서 부터는 fullcalendar 과 상관없는 게시판 목록 가져오기
******************************************************************************************************
*
*/
function findBoardTypeByTitleList(event) {
const boardType = event.value;
if (boardType) {
$.ajax({
type: "POST",
url: "/admin/scheduleManage/findBoardTypeByTitleList",
data: { boardType },
success: function(res) {
console.log(res);
const titleList = res.map(board => {
console.log(board.agoTime);
let agoTime = "";
if (parseInt(board.agoTime) >= 1) {
agoTime = "[" + board.agoTime + "일전]"
} else {
agoTime = "[오늘]";
}
let title = "";
if (board.title.length >= 20) {
title = board.title.substring(0, 20) + "...";
} else {
title = board.title;
}
title = title + " " + agoTime;
return ("<option value='/board/" + boardType + "/read/" + board.bno + "' >" + title + "</option>")
});
$("#boardTitleList").html(titleList);
setBoardLink();
},
error: function(err) {
console.error("에러 : ", err);
}
})
}
}
function setBoardLink() {
const url = $("#boardTitleList").val();
$('#url').val(url);
}
schedule_manage_modal.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div class="modal fade insertModal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h2 class="modal-title text-center" style="width: 100%; font-size: 1.7rem"></h2>
<button type="button" class="close" onclick="closeModal()">×</button>
</div>
<!-- Modal body -->
<div class="modal-body">
<div class="form-group empl_nm">
<label for="empl_nm">scheduleId:</label>
<input type="text" class="form-control" id="scheduleId" name="scheduleId" readonly="readonly">
</div>
<br>
<div class="form-group">
<label for="empl_nm">날짜:</label>
<input type="text" name="daterange" id="daterange" class="form-control" />
</div>
<div class="form-group empl_nm">
<label for="date">시작일:</label>
<input type="text" class="form-control" id="startDate" name="startDate">
</div>
<div class="form-group empl_nm">
<label for="date">종료일:</label>
<input type="text" class="form-control" id="endDate" name="endDate">
</div>
<div class="form-group">
<label for="title">제목:</label>
<input type="text" class="form-control" placeholder="" id="title" maxlength="30">
</div>
<div class="form-group">
<label for="title">게시판 URL 선택:</label>
<select onchange="findBoardTypeByTitleList(this)" class="form-control">
<option value="">게시판을 선택해 주세요.</option>
<option value="lineage_news">소식</option>
<option value="lineage_stats">서버통계</option>
<option value="free">자유게시판</option>
<option value="broadcast">방송정보</option>
<option value="screen_capture">스크린샷</option>
<option value="events">스크린샷</option>
</select>
<select id="boardTitleList" class="form-control" onchange="setBoardLink()">
</select>
</div>
<div class="form-group">
<label for="url">url : </label>
<input type="url" class="form-control" placeholder="링크주소" name="url" id="url" >
</div>
<div class="form-group">
<label for="textColor">글자색 : </label>
<input type="color" class="form-control" name="textColor" id="textColor" value="#ffffff" >
</div>
<div class="form-group">
<label for="color">테두리색 : </label>
<input type="color" class="form-control" name="color" id="color" value="#1466b8">
</div>
<div class="form-group">
<label for="backgroundColor">배경색 : </label>
<input type="color" class="form-control" name="backgroundColor" id="backgroundColor" value="#3788d8">
</div>
<!-- Modal footer -->
<div class="modal-footer text-center">
<button type="button" class="btn btn-danger scheDeleteBtn" onclick="deleteSch()" >삭제</button>
<button type="button" class="btn btn-warning schInsertBtn" onclick="insertSch('insertModal', $g_arg)">등록</button>
<button type="button" class="btn btn-warning schUpdateBtn" onclick="updateSch('insertModal', $g_arg)" >수정</button>
</div>
</div>
</div>
</div>
</div>
2) 유저화면
컨트롤
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import 패키지.model.vo.ScheduleManageVO;
import 패키지.service.ScheduleManageService;
import lombok.RequiredArgsConstructor;
@Controller
@RequestMapping("/schedule/")
@RequiredArgsConstructor
public class ScheduleController {
private final ScheduleManageService calendarService;
/** 목록 */
@GetMapping("list")
public String scheduleList( Model model) throws Exception {
return "web/schedule/schedule_list";
}
@ResponseBody
@GetMapping("selectEventList")
public List<ScheduleManageVO> selectEventList(@RequestParam Map<String, Object> map) throws Exception {
return calendarService.selectEventList(map);
}
}
schedule_list.jsp
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<!-- 부트스트랩 라이브러리 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<!-- fullcalendar 라이브러리 -->
<link href='https://cdn.jsdelivr.net/gh/braverokmc79/fullcalendar-5.9.0@v5.9.0/lib/main.css' rel='stylesheet' />
<!-- daterangepicker 라이브러리 -->
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.css" />
<!-- 커스텀 .css -->
<link href="/resources/lib/fullcalendar/css/scheduleManage_list.css" rel="stylesheet">
</head>
<body>
<div id='calendar-container'>
<div id='calendar'></div>
</div>
<%@ include file="schedule_manage_modal.jsp" %>
<!-- jquery 라이브러리 -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- 부트스트랩 라이브러리 -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
<!-- 날짜 라이브러리 -->
<script type="text/javascript" src="//cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<!-- fullcalendar 라이브러리 -->
<script src='https://cdn.jsdelivr.net/gh/braverokmc79/fullcalendar-5.9.0@v5.9.0/lib/main.js'></script>
<script src='https://cdn.jsdelivr.net/gh/braverokmc79/fullcalendar-5.9.0@v5.9.0/lib/locales-all.min.js'></script>
<!-- daterangepicker 라이브러리 -->
<script type="text/javascript" src="//cdn.jsdelivr.net/bootstrap.daterangepicker/2/daterangepicker.js"></script>
<!-- 커스텀 js -->
<script src="/resources/lib/fullcalendar/js/schedule_list.js"></script>
</body>
</html>
schedule_list.js
let $calendar;
document.addEventListener('DOMContentLoaded', function() {
//FullCalendar 초기 셋팅 및 데이터 불러오기
getFullCalendarEvent();
});
//FullCalendar 초기 셋팅
function getFullCalendarEvent() {
const calendarEl = document.getElementById('calendar');
$calendar = new FullCalendar.Calendar(calendarEl, {
googleCalendarApiKey: '구글 APIKEY',
//className은 되도록 캘린더랑 맞추길
eventSources: [
{
googleCalendarId: 'ko.south_korea#holiday@group.v.calendar.google.com',
className: '대한민국의 휴일',
color: '#be5683', //rgb,#ffffff 등의 형식으로 할 수 있다
//textColor: 'black'
},
],
headerToolbar: {
left: 'prev,next today',
center: 'title',
right: 'dayGridMonth,timeGridWeek,timeGridDay,listWeek,myCustomButton'
},
//initialDate: currentDatePage, // 초기 날짜 설정 (설정하지 않으면 오늘 날짜가 보인다.)
locale: 'ko', // 한국어 설정
editable: false, // 수정 가능
droppable: false, // 드래그 가능
drop: function(arg) { // 드래그 엔 드롭 성공시
},
defaultView: 'timeGridWeek',
navLinks: false, // can click day/week names to navigate views
allDaySlot: false,
eventLimit: true, // allow "more" link when too many events
dateClick: function(arg) {
},
eventClick: function(info) {
//여기서 info 가 아니라 event 로 처리해야 함
event.preventDefault();
//만약 구글 캘린던라면 링크 이동 중단 처리
if (info.event.url.includes('https://www.google.com/calendar/')) {
return;
}
const url = info.event.url;
if(url!="" || url!="#"){
location.href=url;
}
},
});
//DB에서 데이터 가져오기
const arr = getCalendarDataInDB();
$.each(arr, function(index, item) {
$calendar.addEvent(item);
});
$calendar.render();
return $calendar;
}
//arr 는 테스트용으로 DB 에서 스케즐 데이터를 가져오지 못했을 경우 테스트용 데이터
function getCalendarDataInDB() {
//arr 임의 데이터
let arr = [{
title: 'evt111',
start: '2023-03-22T10:30:00',
end: '2023-03-23T10:30:00',
backgroundColor: "#52cdff",
color: "#000",
textColor: "#fff",
url: "https://daum.net"
}];
$.ajax({
contentType: 'application/json',
dataType: 'json',
url: '/schedule/selectEventList',
type: 'GET',
async: false,
success: function(res) {
arr = res;
},
error: function(res) {
console.log(res);
}
});
return arr;
}

















댓글 ( 5)
댓글 남기기