Index: arms/js/analysis/cost/circularPackingChart.js =================================================================== diff -u -r18cf1a277a4afc58ceaec8b571756495367df6f1 -ra862639f509e04a8bcf265e9829c3117b4840134 --- arms/js/analysis/cost/circularPackingChart.js (.../circularPackingChart.js) (revision 18cf1a277a4afc58ceaec8b571756495367df6f1) +++ arms/js/analysis/cost/circularPackingChart.js (.../circularPackingChart.js) (revision a862639f509e04a8bcf265e9829c3117b4840134) @@ -152,7 +152,7 @@ d3 .pack() .size([api.getWidth() - 2, api.getHeight() - 2]) - .padding(3)(displayRoot); + .padding(6)(displayRoot); context.nodes = {}; displayRoot.descendants().forEach(function (node, index) { context.nodes[node.id] = node; @@ -272,11 +272,11 @@ let id = params.data.id; let parts = id.split('.'); if(params.data.depth === 0){ - return "제품(서비스) 정보
● 제품(서비스) :"+ parts[0] +"
● 비용 :"+params.data.value ; + return "제품(서비스) 정보
● 제품(서비스) :"+ parts[0] +"
● 비용 :"+params.data.value.toLocaleString() ; }else if(params.data.depth === 1){ - return "버전 정보
● 버전 :"+ params.data.version_name +"
● 비용 :"+params.data.value ; + return "버전 정보
● 버전 :"+ params.data.version_name +"
● 비용 :"+params.data.value.toLocaleString() ; }else if(params.data.depth === 2){ - return "요구사항 정보
● 버전 :"+ params.data.version_name +"
● 요구사항 :"+ params.data.req_name +"
● 비용 :"+params.data.value ; + return "요구사항 정보
● 버전 :"+ params.data.version_name +"
● 요구사항 :"+ params.data.req_name +"
● 비용 :"+params.data.value.toLocaleString() ; }else if(params.data.depth === 3){ return "요구사항 키 정보
● 버전 :"+ params.data.version_name +"
● 요구사항 :"+ params.data.req_name +"
● 요구사항 키 :"+ parts[3] ; } @@ -320,15 +320,52 @@ option && myChart.setOption(option, true); myChart.on('click', { seriesIndex: 0 }, function (params) { - if(params.data.depth != 3){ + if(params.data.depth == 1){ drillDown(params.data.id); } - if(params.data.depth === 2){ - incomeStatusChart(params.data); + else if(params.data.depth == 2){ + drillDown(params.data.id); + var childData = findChildItems(seriesData,params.data.id); + reqCostStatusChart(childData); + }else{ + var index =params.data.id.lastIndexOf(".") + var parentId = params.data.id.substring(0, index); + var childData = findChildItems(seriesData,parentId); + reqCostStatusChart(childData); + drillDown(parentId); } - }); + function findChildItems(data, parentId) { + const parentItem = data.find(item => item.id === parentId); + if (!parentItem) { + return []; + } + let reqCost = parentItem.value; + // 요구사항 하위 키 데이터 목록 + let childItems = data.filter(item => item.id.startsWith(parentId) && item.depth > parentItem.depth); + + let issueDatas = childItems.reduce((acc, item) => { + let parts = item.id.split('.'); + let issueKey = parts[parts.length - 1]; + let reqId = parts[parts.length - 2]; + + let existingItem = acc.find(a => a.reqId === reqId); + if (existingItem) { + existingItem.issueKey.push(issueKey); + } else { + acc.push({ + reqId: reqId, + issueKey:[issueKey], + reqCost:reqCost + }); + } + return acc; + }, []); + + return issueDatas.length > 0 ? issueDatas[0] : null; + } + function drillDown(targetNodeId) { displayRoot = stratify(); if (targetNodeId != null) { Index: arms/js/analysisCost.js =================================================================== diff -u -re19329f311f1f621a6cccd23c6201a84a72d1ee7 -ra862639f509e04a8bcf265e9829c3117b4840134 --- arms/js/analysisCost.js (.../analysisCost.js) (revision e19329f311f1f621a6cccd23c6201a84a72d1ee7) +++ arms/js/analysisCost.js (.../analysisCost.js) (revision a862639f509e04a8bcf265e9829c3117b4840134) @@ -730,7 +730,7 @@ // 요구사항별 수익현황 차트 $("#income_status_chart").height("620px"); - incomeStatusChart(); + reqCostStatusChart(); }); } @@ -1224,123 +1224,201 @@ ///////////////////////////////////////////////////////// // 요구사항 상세 차트 ///////////////////////////////////////////////////////// -function incomeStatusChart(){ +function 요구사항_계획일_목록(startDate, endDate) { + let dateList = []; + let currentDate = new Date(startDate); + + while (currentDate <= endDate) { + dateList.push(currentDate.toISOString().substring(0, 10)); + currentDate.setDate(currentDate.getDate() + 1); + } + + return dateList; +} +function reqCostStatusChart(data){ var chartDom = document.getElementById('income_status_chart'); - var myChart = echarts.init(chartDom, null, { - renderer: "canvas", - useDirtyRect: false - }); - var option; + let dateList; + let 요구사항_정보; + if(data != null){ + 요구사항_정보 = 요구사항전체목록[data.reqId]; + // 요구사항 일자 ( 시작일 계획일 없을 때 처리 전 ) + let 요구사항_시작일 = new Date(요구사항_정보.c_req_create_date); // c_req_start_date + let 요구사항_계획일 = 요구사항_정보.c_req_plan_time; + let 임시데이터 = new Date(요구사항_시작일.getTime()); + 임시데이터.setDate(임시데이터.getDate() + 요구사항_계획일); + let 요구사항_목표_종료일 = 임시데이터; - option = { - xAxis: { - type: 'category', - data: [ - '2024-01-01', - '2024-01-11', - '2024-01-12', - '2024-01-17', - '2024-01-23', - '2024-02-12', - '2024-02-11' - ], - axisLabel: { - color: '#FFFFFF' + dateList = 요구사항_계획일_목록(요구사항_시작일, 요구사항_목표_종료일); + +// const url = new UrlBuilder() +// .setBaseUrl('/auth-user/api/arms/analysis/cost/req-updated-status') +// .addQueryParam('reqIssueId', data.reqId) +// .addQueryParam('reqIssueKeys', data.issueKey) +// .build(); +// +// $.ajax({ +// url: url, +// type: "GET", +// contentType: "application/json;charset=UTF-8", +// dataType: "json", +// progress: true, +// statusCode: { +// 200: function (apiResponse) { +// console.log(" [ analysisCost :: 요구사항별_소모비용_차트 :: data -> "); +// console.log(apiResponse); +// } +// } +// }); + + var myChart = echarts.init(chartDom, null, { + renderer: "canvas", + useDirtyRect: false + }); + var option; + + option = { + title: { + text: 요구사항_정보.c_title, + left: 'center', + textStyle: { + fontSize: 12, + color: '#FFFFFF' // 타이틀의 색상을 파란색으로 설정 + } }, - scale: true - }, - yAxis: { - type: 'value', - axisLabel: { - color: '#FFFFFF' + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true }, - scale: true, - }, - legend: { - data: ['예상', '소모 비용', '투자비용'] , - textStyle: { - color: '#FFFFFF' // 범례 텍스트 색상 변경 - } - }, - series: [ - { - data: [0, 50, 100, 150, 200, 250, 300], - type: 'line', - name: '예상', // 첫 번째 선에 대한 라벨 - lineStyle: { - type: 'dashed' // 선의 스타일을 점선으로 변경 + xAxis: { + type: 'category', + data: dateList, + axisLabel: { + color: '#FFFFFF' }, - markLine: { - lineStyle: { - color: 'red', // line color - type: 'dashed', // line style - width: 3 // line width - }, - label: { - position: 'middle', // label이 markLine의 중간에 위치하도록 설정 - formatter: '투자 비용', // label의 텍스트 설정 - fontSize: 15, // label의 폰트 크기 설정 - color: '#FFFFFF' - }, - data: [ - { - yAxis: 300, - name: '투자비용' // line label - } - ] - } + scale: true }, - { - data: [0, 100, 120, 120, 280, 320, 320], - type: 'line', - name: '소모 비용', - markLine: { - lineStyle: { - color: 'red', // line color - type: 'dashed', // line style - width: 3 // line width - }, + yAxis: { + type: 'value', + axisLabel: { + color: '#FFFFFF' + }, + scale: true, + }, + series: [ + { + type: 'line', label: { - position: 'middle', // label이 markLine의 중간에 위치하도록 설정 - formatter: '요구사항 기한', // label의 텍스트 설정 - fontSize: 15, // label의 폰트 크기 설정 - color: '#FFFFFF' + show: true, + position: 'top' + }, + markLine: { + lineStyle: { + color: '#5470c6', // line color + type: 'dashed', // line style + width: 2 // line width + }, + label: { + position: 'middle', // label이 markLine의 중간에 위치하도록 설정 + formatter: '투자 비용', // label의 텍스트 설정 + fontSize: 15, // label의 폰트 크기 설정 + color: '#FFFFFF', + formatter: function(){ + return '투자 비용: '+data.reqCost.toLocaleString(); + } + }, + data: [ + { + yAxis: data.reqCost, + name: '투자비용' // line label + } + ] + } + }, + { + type: 'line', + label: { + show: true, + position: 'top' + }, + markLine: { + lineStyle: { + color: '#5470c6', // line color + type: 'dashed', // line style + width: 2 // line width + }, + label: { + position: 'middle', // label이 markLine의 중간에 위치하도록 설정 + formatter: '요구사항 기한', // label의 텍스트 설정 + fontSize: 15, // label의 폰트 크기 설정 + color: '#FFFFFF', + formatter: function(){ + return '요구사항 기한: '+ dateList[dateList.length -1]; + } + }, + data: [ + { + xAxis: dateList.length -1 + } + ] + } + }, + { + name: '누적 소모 비용', + type: 'bar', + stack: 'Total', + silent: true, + itemStyle: { + borderColor: 'transparent', + color: 'transparent' }, - data: [ - { - xAxis: 6, - name: '투자비용' // line label + emphasis: { + itemStyle: { + borderColor: 'transparent', + color: 'transparent' } - ] + }, + data: [0, 2000000, 5000000, 9000000, 14000000, 20000000, 21000000, 22000000] + }, + { + name: '소모 비용', + type: 'bar', + stack: 'Total', + label: { + show: true, + color: '#FFFFFF', + position: 'top' + }, + itemStyle: { + color: '#eb5454' // 바의 색상을 빨간색으로 변경 + }, + data: [2000000, 3000000, 4000000, 5000000, 6000000, 1000000, 1000000] + } + ], + tooltip: { + trigger: "axis", + position: "top", + borderWidth: 1, + axisPointer: { + type: "shadow" } }, - { - type: "candlestick", - data: [ - [120, 134, 110, 138], - [138, 144, 150, 178], - [120, 134, 110, 138], - [120, 134, 110, 138], - [120, 134, 110, 138], - [120, 134, 110, 138] - ], - } - ], - tooltip: { - trigger: "axis", - position: "top", - borderWidth: 1, - axisPointer: { - type: "shadow" - } - }, - }; + }; if (option && typeof option === "object") { myChart.setOption(option, true); } - window.addEventListener("resize", myChart.resize); + window.addEventListener("resize", myChart.resize); + }else{ + chartDom.style.display = 'flex'; + chartDom.style.justifyContent = 'center'; + chartDom.style.alignItems = 'center'; + chartDom.innerHTML = '

좌측 요구사항을 선택해주세요.

'; + } + + } /////////////////////////////////////////////////////////