TIL

[2021_06_23]fullCalendar && GanttChart API

뱅타 2021. 6. 23. 23:42

preview


Calendar.xml 수정
  • script에서는 String, java 에서는 ? , xml에서는 String
  • invalid character, invalid column index 오류

 

 

why?
  • 본인은 mac을 사용.
  • slack에서 보내준 코드를 그대로 복사해서 붙여넣었음.
  • ‘ 와 ' 게 다르게 생긴듯이 서로 다른 문자임.
  • mybatis에서 제대로 인식을 못함.
  • 지우고 직접 작성하니 잘 됨.
  • json 관련 사이트

https://www.json.org/json-en.html

 

 

jsGantt 사용하기


기본 sample 출력하기
<link rel="stylesheet" type="text/css" href="jsgantt.css" />
<script language="javascript" src="jsgantt.js"></script>
<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
<script>

var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'day');

if( g.getDivId() != null ) {
g.setCaptionType('Complete');
g.setQuarterColWidth(36);
g.setDateTaskDisplayFormat('day dd month yyyy');
g.setDayMajorDateDisplayFormat('mon yyyy - Week ww');
g.setWeekMinorDateDisplayFormat('dd mon');
g.setShowTaskInfoLink(1);
g.setShowEndWeekDate(0);
g.setUseSingleCell(10000);
g.setFormatArr('Day', 'Week', 'Month', 'Quarter');

g.AddTaskItem(new JSGantt.TaskItem(1,   'Define Chart API',     '',           '',          'ggroupblack',  '',       0, 'Brian',    0,   1, 0,  1, '',      '',      'Some Notes text', g ));
g.AddTaskItem(new JSGantt.TaskItem(11,  'Chart Object',         '2016-02-20','2016-02-20', 'gmilestone',   '',       1, 'Shlomy',   100, 0, 1,  1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(12,  'Task Objects',         '',           '',          'ggroupblack',  '',       0, 'Shlomy',   40,  1, 1,  1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(121, 'Constructor Proc',     '2016-02-21','2016-03-09', 'gtaskblue',    '',       0, 'Brian T.', 60,  0, 12, 1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(122, 'Task Variables',       '2016-03-06','2016-03-11', 'gtaskred',     '',       0, 'Brian',    60,  0, 12, 1, 121,     '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(123, 'Task by Minute/Hour',  '2016-03-09','2016-03-14 12:00', 'gtaskyellow', '',  0, 'Ilan',     60,  0, 12, 1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(124, 'Task Functions',       '2016-03-09','2016-03-29', 'gtaskred',     '',       0, 'Anyone',   60,  0, 12, 1, '123SS', 'This is a caption', null, g));
g.AddTaskItem(new JSGantt.TaskItem(2,   'Create HTML Shell',    '2016-03-24','2016-03-24', 'gtaskyellow',  '',       0, 'Brian',    20,  0, 0,  1, 122,     '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(3,   'Code Javascript',      '',           '',          'ggroupblack',  '',       0, 'Brian',    0,   1, 0,  1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(31,  'Define Variables',     '2016-02-25','2016-03-17', 'gtaskpurple',  '',       0, 'Brian',    30,  0, 3,  1, '',      'Caption 1','',   g));
g.AddTaskItem(new JSGantt.TaskItem(32,  'Calculate Chart Size', '2016-03-15','2016-03-24', 'gtaskgreen',   '',       0, 'Shlomy',   40,  0, 3,  1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(33,  'Draw Task Items',      '',           '',          'ggroupblack',  '',       0, 'Someone',  40,  2, 3,  1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(332, 'Task Label Table',     '2016-03-06','2016-03-09', 'gtaskblue',    '',       0, 'Brian',    60,  0, 33, 1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(333, 'Task Scrolling Grid',  '2016-03-11','2016-03-20', 'gtaskblue',    '',       0, 'Brian',    0,   0, 33, 1, '332',   '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(34,  'Draw Task Bars',       '',           '',          'ggroupblack',  '',       0, 'Anybody',  60,  1, 3,  0, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(341, 'Loop each Task',       '2016-03-26','2016-04-11', 'gtaskred',     '',       0, 'Brian',    60,  0, 34, 1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(342, 'Calculate Start/Stop', '2016-04-12','2016-05-18', 'gtaskpink',    '',       0, 'Brian',    60,  0, 34, 1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(343, 'Draw Task Div',        '2016-05-13','2016-05-17', 'gtaskred',     '',       0, 'Brian',    60,  0, 34, 1, '',      '',      '',      g));
g.AddTaskItem(new JSGantt.TaskItem(344, 'Draw Completion Div',  '2016-05-17','2016-06-04', 'gtaskred',     '',       0, 'Brian',    60,  0, 34, 1, "342,343",'',     '',      g));
g.AddTaskItem(new JSGantt.TaskItem(35,  'Make Updates',         '2016-07-17','2017-09-04', 'gtaskpurple',  '',       0, 'Brian',    30,  0, 3,  1, '333',   '',      '',      g));

g.Draw();
}
else
{
alert("Error, unable to create Gantt Chart");
}

</script>
  • 코드를 입맛에 맞게 수정해서 사용.
  • g.AddTaskItem(new JSGantt.TaskItem(35, 'Make Updates', '2016-07-17','2017-09-04', 'gtaskpurple', '', 0, 'Brian', 30, 0, 3, 1, '333', '', '', g));
  • 하단의 순서대로 내용물들이 들어감.
<pID>25</pID>
<pName>WCF Changes</pName>
<pStart></pStart>
<pEnd></pEnd>
<pClass>gtaskred</pClass>
<pLink></pLink>
<pMile>0</pMile>
<pRes></pRes>
<pComp>0</pComp>
<pGroup>1</pGroup>
<pParent>2</pParent>
<pOpen>1</pOpen>
<pDepend>2,24</pDepend>
<pCaption>A caption</pCaption>
<pNotes>Text - can include limited HTML</pNotes>

 

 

GanttChart view 출력하기


GanttChart 필요한 데이터 query 짜기
  • 해당 프로젝트의 모든 milestone과 issue가 필요.
  • milestone은 issue가 존재할 수도 없을 수도 있다.
  • issue는 milestone이 존재할 수도 있고 없을 수도 있다.
  1. full outer join 사용하기.
WITH ISSUEINFO AS (
SELECT A.ISSUE_SID, A.MILEST_SID, B.MEM_NO, A.PROJ_NO
FROM ISSUE A
    LEFT OUTER JOIN ISSUE_ASSIGNEE B ON (A.ISSUE_SID = B.ISSUE_SID)
    LEFT OUTER JOIN LABEL C ON (A.LABEL_NO = C.LABEL_NO)
)
SELECT D.MILEST_SID, F.ISSUE_SID, F.MEM_NO
FROM MILESTONE D
    FULL OUTER JOIN ISSUEINFO F ON (D.MILEST_SID = F.MILEST_SID)
WHERE D.PROJ_NO = 103 OR F.PROJ_NO=103;

2. union으로 중복 제거해서 결과값 출력하기

WITH ISSUEINFO AS (
SELECT A.ISSUE_SID, A.MILEST_SID, B.MEM_NO, A.PROJ_NO
FROM ISSUE A
    LEFT OUTER JOIN ISSUE_ASSIGNEE B ON (A.ISSUE_SID = B.ISSUE_SID)
    LEFT OUTER JOIN LABEL C ON (A.LABEL_NO = C.LABEL_NO)
)
SELECT D.MILEST_SID, F.ISSUE_SID, F.MEM_NO
FROM MILESTONE D
    LEFT OUTER JOIN ISSUEINFO F ON (D.MILEST_SID = F.MILEST_SID)
WHERE D.PROJ_NO = 103 

UNION

SELECT D.MILEST_SID, F.ISSUE_SID, F.MEM_NO
FROM MILESTONE D
    RIGHT OUTER JOIN ISSUEINFO F ON (D.MILEST_SID = F.MILEST_SID)
WHERE F.PROJ_NO = 103; 
  • 쿼리를 짜는데 실컷 조인은 잘 해놓고 where절에 proj_no를 milestone것만 줌.
  • issueinfo에 proj_no가 존재하지 않으니 마지막 결과에서 짤려서 left outer join만 된 것처럼 보였던 것.
  • 둘 중 어느것을 써도 무방함.

최종 쿼리문.

<collection property="issueList" ofType="best.gaia.vo.IssueVO" javaType="java.util.List" autoMapping="false">
				<id column="ISSUE_ID" property="issue_sid"/>
					<result column="ISSUE_NO" property="issue_no"></result>
					<result column="ISSUE_TITLE" property="issue_title"></result>
					<result column="MILEST_ID" property="milest_sid"></result>
					<result column="ISSUE_START_DATE" property="issue_start_date"></result>
					<result column="ISSUE_END_DATE" property="issue_end_date"></result>
					<result column="ISSUE_STATUS" property="issue_status"></result>
	<!-- 				<result column="ISSUE_WRI_MEM_PIC" property="mem_pic_file_name"></result> -->
				<association property="label" javaType="best.gaia.vo.LabelVO" autoMapping="false">
					<result column="LABEL_NO" property="label_no"></result>
					<result column="LABEL_NM" property="label_nm"></result>
				</association>
				<collection property="assigneeList" ofType="best.gaia.vo.MemberVO" javaType="java.util.Set" autoMapping="false">
						<id column="ISSUE_ASSIN_MEM_NO" property="mem_no" />	
						<result column="MEM_ID" property="mem_id"></result>
						<result column="ISSUE_ASSIGN_MEM_PIC" property="mem_pic_file_name"></result>
		<!-- 				<result column="ISSUE_ASIGN_MEM" property="proj_user_nick"></result> -->
				</collection>
				<collection property="historyList" ofType="best.gaia.vo.IssueHistoryVO" javaType="java.util.List" autoMapping="false">
						<id column="ISSUE_HIS_NO" property="issue_his_no" />	
						<result column="ISSUE_HIS_CONT" property="issue_his_cont"></result>
		<!-- 				<result column="ISSUE_ASIGN_MEM" property="proj_user_nick"></result> -->
				</collection>
			</collection>

<select id="selectMilestoneIssueList" resultMap="milestoneMap" parameterType="int" >
		WITH ISSUEINFO AS (
		    SELECT A.ISSUE_SID, B.MEM_NO, M.MEM_ID, A.ISSUE_TITLE,  A.PROJ_NO 
		        , A.MILEST_SID, A.ISSUE_START_DATE, A.ISSUE_END_DATE
		        , A.ISSUE_STATUS
		    FROM ISSUE A
		        LEFT OUTER JOIN ISSUE_ASSIGNEE B ON (A.ISSUE_SID = B.ISSUE_SID)
		        LEFT OUTER JOIN MEMBER M ON (B.MEM_NO = M.MEM_NO)
		        LEFT OUTER JOIN LABEL C ON (A.LABEL_NO = C.LABEL_NO)
		)
		SELECT D.MILEST_SID, D.MILEST_TITLE, D.MILEST_START_DATE, D.MILEST_END_DATE 
		    , D.MILEST_NO, D.MILEST_CONT, D.MILEST_STATUS, D.PROJ_NO
		    , F.ISSUE_SID AS ISSUE_ID, F.MEM_NO AS ISSUE_ASSIN_MEM_NO, F.MEM_ID, F.ISSUE_TITLE
		    , F.MILEST_SID AS MILEST_ID, F.ISSUE_START_DATE, F.ISSUE_END_DATE
		    , F.ISSUE_STATUS 
		FROM MILESTONE D
		FULL OUTER JOIN ISSUEINFO F ON (D.MILEST_SID = F.MILEST_SID)
		WHERE D.PROJ_NO = ${proj_no} OR F.PROJ_NO=${proj_no}
	</select>

 

 

마일스톤 공정률 구하기.

https://stackoverflow.com/questions/9129928/how-to-calculate-number-of-days-between-two-dates

  • 현재 moment.js를 쓰는 중이니 위의 링크에서 나오는 방법을 사용.
var a = moment([2007, 0, 29]); // end_date
var b = moment([2007, 0, 28]); // start_date
a.diff(b, 'days')   // =1
  • 실제 구현한 코드
const calComp = function(start_date, end_date, title){
	let currentTime = new Date();
	let today = moment(YYYYMMDD(currentTime));
	let process
	let total
	let result;
	if(CheckNullUndefined(start_date)){
		start_date = today
	}
	if(CheckNullUndefined(end_date)){
		return "0";	
	}else{
		end_date = moment(end_date);
		start_date = moment(start_date);
		total = end_date.diff(start_date, 'days');
		process = today < start_date ?  0 : today.diff(start_date, 'days');
		result = process<=total ? Math.round((process / total) * 100) : "100"
	}
	return result;
}
  • 시간이 급박해서 조금 대충 짠 느낌이 있음.
  • 추후에 refactoring 할 예정

 

 

.ajax로 받은 데이터를 형식에 맞게 출력해주기
  • milestoneList 의 milestone 내부에 issueList가 존재하는 형태.
$.each(list, function(i, milestone){
	g.AddTaskItem(new JSGantt.TaskItem(
			milestone.milest_sid 
			, CheckNullUndefined(milestone.milest_title) ? "독립적인 이슈 목록" : milestone.milest_title 
			, milestone.milest_start_date
			, milestone.milest_end_date
			, "ggroupblack"
			, ''
			, 0
			, ""
			, Number(milestone.milest_status) ? "100" : calComp(milestone.milest_start_date,milestone.milest_end_date)
			, 1
				, 0
			, Number(milestone.milest_status) ? "0" : "1"
			, ''
			, ''
			, milestone.milest_cont
			, g 
	));
	$.each(milestone.issueList, function(l, issue){
		console.log(cnt)
		if(CheckNullUndefined(issue)){
			return true;
		}
		g.AddTaskItem(new JSGantt.TaskItem(
			cnt++
			, issue.issue_title
			, issue.issue_start_date
			, issue.issue_end_date
			, Number(issue.issue_status) ? "gtaskred" : "gtaskblue"
			, ''
			, 0
			, CheckNullUndefined(issue.assigneeList) ? "" : calIssueAssignees(issue.assigneeList)
			, Number(issue.issue_status) ? "100" : calComp(issue.issue_start_date,issue.issue_end_date, issue.issue_title)
			, 0
				, milestone.milest_sid
			, 2
			, milestone.milest_sid
			, ''
			, Number(issue.issue_status) ? "Closed" : "Open"
			, g 
		));
	})
});
  • 실제 구현한 화면

 

 

jsGantt.css
  • 폰트가 너무 작게 설정 되어 있어서 변경. 9px → 14px
  • 각 셀의 height 역시 너무 좁게 잡혀있어서 수정.

 

 

의문점


 

  • 이렇게 쓸모없는 null milestone List가 많이 생겨남.
  • 최초의 의도는 null milestone 하나에 list들을 담는것(milestone에 속하지 않은 issue들을 하나의 null milestone에 모두 집어넣을 계획)
  • 실제로 최초의 시도때는 하나의 null milestone 안에 issue list 들이 담겨잇었음.
  • 추후 시간 날 때 query 혹은 mybatis 부분을 살펴 보아야 겠음.(혹은 질문도 괜찮을 듯함.)
  • 조금 쉬운 api를 겉핥기나마 건들이는 것은 이제 크게 두렵지 않음.
  • 조금 발전한 기분이 든다.

 

 

SUMMARY


  1. union과 full outer join은 같다.
  1. query를 짤 때 조건절에 대해 조금 더 고민하고 짜야한다.
  1. jsGantt Improved는 가벼운 툴이지만 사용하려면 손을 좀 많이 봐야한다.
  1. 개인적으로 관련 정보들이 많이 없어서 (심지어 document도 세세하게 설명되어있지 않음. js파일 들어가서 살펴봄) 입맛에 맞게 바꾸기 까다로웠음.

 

 

 

TOMORROW


  1. CHATTING CSS 수정
  1. overview isseu list 수정
  1. 전체적인 css 부분 수정하고 스토리 및 흐름도 수정하기.

 

728x90
반응형