
--- client/resources/css/admin.css
+++ client/resources/css/admin.css
... | ... | @@ -433,7 +433,7 @@ |
433 | 433 |
.tab-content { |
434 | 434 |
width: 100%; |
435 | 435 |
height: 100%; |
436 |
- padding: 15px; |
|
436 |
+ padding: 15px 0; |
|
437 | 437 |
} |
438 | 438 |
|
439 | 439 |
.modal-content-monthly>div { |
... | ... | @@ -612,4 +612,12 @@ |
612 | 612 |
|
613 | 613 |
.insert-select{ |
614 | 614 |
margin-left: 0; |
615 |
+} |
|
616 |
+ |
|
617 |
+.middle-zone{ |
|
618 |
+ padding: 10px 0; |
|
619 |
+} |
|
620 |
+ |
|
621 |
+.middle-zone select{ |
|
622 |
+ margin-left: 0; |
|
615 | 623 |
}(No newline at end of file) |
--- client/views/component/chart/LineChart.vue
+++ client/views/component/chart/LineChart.vue
... | ... | @@ -1,6 +1,6 @@ |
1 | 1 |
<template> |
2 | 2 |
<div class="chart-wrap"> |
3 |
- <div class="chart" id="chartdiv" ref="chartdiv" style="width: 100%; height: 700px;"></div> |
|
3 |
+ <div class="chart" id="chartdiv" ref="chartdiv" style="width: 100%; height: 350px;"></div> |
|
4 | 4 |
</div> |
5 | 5 |
</template> |
6 | 6 |
|
... | ... | @@ -17,12 +17,21 @@ |
17 | 17 |
default: [], |
18 | 18 |
// required: true, |
19 | 19 |
}, |
20 |
+ keyMapping: { |
|
21 |
+ type: Object, |
|
22 |
+ }, |
|
23 |
+ columnX:{ |
|
24 |
+ type: String |
|
25 |
+ }, |
|
26 |
+ columnY:{ |
|
27 |
+ type: String |
|
28 |
+ } |
|
20 | 29 |
|
21 | 30 |
}, |
22 | 31 |
data() { |
23 | 32 |
return { |
24 | 33 |
// y축 컬럼 목록 |
25 |
- valueDataList: ["cpn_vst_cnt", "cmmn_vst_cnt", "non_vst_cnt", "total_cnt"], |
|
34 |
+ valueDataList: ["기업회원 방문자수", "일반회원 방문자수", "비회원 방문자수", "총 방문자수"], |
|
26 | 35 |
|
27 | 36 |
// 차트 옵션 변수 목록 |
28 | 37 |
chartOptions: { |
... | ... | @@ -68,7 +77,7 @@ |
68 | 77 |
/*************** 마우스 (끝) ***************/ |
69 | 78 |
|
70 | 79 |
|
71 |
- scrollbarX: true, // x축 스크롤바 표시 여부 |
|
80 |
+ scrollbarX: false, // x축 스크롤바 표시 여부 |
|
72 | 81 |
scrollbarY: false, // y축 스크롤바 표시 여부 |
73 | 82 |
|
74 | 83 |
categoryAxisTooltip: true, // 카테고리축 툴팁 숨김 여부 (숨김: true, 표시: false) |
... | ... | @@ -77,7 +86,7 @@ |
77 | 86 |
|
78 | 87 |
|
79 | 88 |
/*************** 셀 (시작) ***************/ |
80 |
- seriesColorList: ["#f9b5a0", "#f0acb2", "#e19dcf", "#d28eed"], // 차트 셀 색상 목록 (기본: []) |
|
89 |
+ seriesColorList: ["#4e79a6", "#f28e2c", "#e15659", "#76b7b1"], // 차트 셀 색상 목록 (기본: []) |
|
81 | 90 |
bullet: "Circle", // 글머리기호 (사용안함: "", 원형: "Circle", 텍스트: "Label") |
82 | 91 |
|
83 | 92 |
// 막대 차트 전용 |
... | ... | @@ -104,8 +113,28 @@ |
104 | 113 |
methods: { |
105 | 114 |
|
106 | 115 |
// 라인 차트 생성 함수 |
107 |
- createLineChart: function (theme, data, columnX, columnY, valueDataList, chartOptions) { |
|
108 |
- let chartData = JSON.parse(JSON.stringify(data)); // 차트 params 데이터 복사 |
|
116 |
+ createLineChart: function (theme, data, columnX, columnY, valueDataList, chartOptions, keyMapping) { |
|
117 |
+ let mappedData = []; |
|
118 |
+ let keys = Object.keys(data[0]); |
|
119 |
+ |
|
120 |
+ for (let dataIndex = 0; dataIndex < data.length; dataIndex++) { |
|
121 |
+ let currentItem = data[dataIndex]; |
|
122 |
+ let mappedItem = {}; |
|
123 |
+ |
|
124 |
+ for (let i = 0; i < keys.length; i++) { |
|
125 |
+ let key = keys[i]; |
|
126 |
+ let koreanKey = keyMapping[key]; |
|
127 |
+ |
|
128 |
+ if (koreanKey) { |
|
129 |
+ mappedItem[koreanKey] = currentItem[key]; |
|
130 |
+ } |
|
131 |
+ } |
|
132 |
+ |
|
133 |
+ mappedData.push(mappedItem); |
|
134 |
+ } |
|
135 |
+ |
|
136 |
+ console.log(mappedData) |
|
137 |
+ let chartData = JSON.parse(JSON.stringify(mappedData)); // 차트 params 데이터 복사 |
|
109 | 138 |
let options = JSON.parse(JSON.stringify(chartOptions)); // 차트 params 데이터 복사 |
110 | 139 |
|
111 | 140 |
/*************** 차트 생성 (시작) ***************/ |
... | ... | @@ -313,7 +342,7 @@ |
313 | 342 |
strokeWidth: 2, // 테두리 두께 |
314 | 343 |
stroke: root.interfaceColors.get("background"), // 테두리 색상 |
315 | 344 |
radius: 5, // 원형 크기 |
316 |
- fill: series.get("fill") // 원형 색상 |
|
345 |
+ fill: am5.color(seriesColor)// 원형 색상 |
|
317 | 346 |
} |
318 | 347 |
} else if (options['bullet'] == "Label") { // 텍스트 글머리기호 |
319 | 348 |
lineBulletSprite = { |
... | ... | @@ -449,7 +478,7 @@ |
449 | 478 |
root._logo.dispose(); //amChart 로고 삭제 |
450 | 479 |
|
451 | 480 |
// 히트맵일 시 일반범례 사용 안 하고 return |
452 |
- if(theme == "HeatMap") { |
|
481 |
+ if (theme == "HeatMap") { |
|
453 | 482 |
return { "root": root, "chart": chart } |
454 | 483 |
}; |
455 | 484 |
|
... | ... | @@ -459,9 +488,9 @@ |
459 | 488 |
/*************** 범례 (시작) ***************/ |
460 | 489 |
let nameField = null; |
461 | 490 |
|
462 |
- if(theme == "XY") { |
|
491 |
+ if (theme == "XY") { |
|
463 | 492 |
nameField = "categoryX" |
464 |
- } else if(theme == "YX") { |
|
493 |
+ } else if (theme == "YX") { |
|
465 | 494 |
nameField = "categoryY" |
466 | 495 |
} |
467 | 496 |
|
... | ... | @@ -525,7 +554,7 @@ |
525 | 554 |
'chartData': function (newData, oldData) { |
526 | 555 |
console.log("new:", newData, oldData); |
527 | 556 |
// this.createChart(newData); |
528 |
- this.createLineChart("ClusterLine", newData, "stats_date", "cpn_vst_cnt", this.valueDataList, this.chartOptions); |
|
557 |
+ this.createLineChart("ClusterLine", newData, this.columnX, this.columnY, this.valueDataList, this.chartOptions, this.keyMapping); |
|
529 | 558 |
}, |
530 | 559 |
}, |
531 | 560 |
computed: { |
--- client/views/layout/AdminMenu.vue
+++ client/views/layout/AdminMenu.vue
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 |
<p><span v-html="menu.icon"></span><span class="menu-text">{{ menu.pathName }}</span></p> |
10 | 10 |
<p v-html="menu.icon2"></p> |
11 | 11 |
</router-link> |
12 |
- <ul v-if="menu.subMenu" class="aSub-menu" :style="{ 'max-height': menu.isOpen ? '324px' : '0' }"> |
|
12 |
+ <ul v-if="menu.subMenu" class="aSub-menu" :style="{ 'max-height': menu.isOpen ? '360px' : '0' }"> |
|
13 | 13 |
<li v-for="(subMenu, subIndex) in menu.subMenu" :key="subIndex" @click="stopToggleSubMenuClick"> |
14 | 14 |
<router-link :to="subMenu.path">{{ subMenu.pathName }}</router-link> |
15 | 15 |
</li> |
... | ... | @@ -39,6 +39,7 @@ |
39 | 39 |
{ path: "/adm/noticeStatistics.page", pathName: "공지사항" }, |
40 | 40 |
{ path: "/adm/NewsAndPr.page", pathName: "홍보&뉴스" }, |
41 | 41 |
{ path: "/adm/wgCommunity.page", pathName: "전문가 협의체" }, |
42 |
+ { path: "/adm/matchingStatistics.page", pathName: "매칭현황" }, |
|
42 | 43 |
], |
43 | 44 |
icon: '<i class="fa-regular fa-folder-open"></i>', icon2: "<i class='fa-solid fa-angle-right'></i>", isOpen: false, isActive: false |
44 | 45 |
}, |
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -67,6 +67,7 @@ |
67 | 67 |
import AdminNotice from "../pages/admin/statistics/Notice.vue"; |
68 | 68 |
import AdminTech from "../pages/admin/statistics/Tech.vue"; |
69 | 69 |
import AdminWgCommunity from "../pages/admin/statistics/WgCommunity.vue"; |
70 |
+import AdminMatching from "../pages/admin/statistics/matchingStatistics.vue"; |
|
70 | 71 |
|
71 | 72 |
const routes = [ |
72 | 73 |
/* 메인화면 */ |
... | ... | @@ -135,6 +136,7 @@ |
135 | 136 |
{ path: "/adm/noticeStatistics.page", name: "AdminNotice", component: AdminNotice }, |
136 | 137 |
{ path: "/adm/techStatistics.page", name: "AdminTech", component: AdminTech }, |
137 | 138 |
{ path: "/adm/wgCommunity.page", name: "AdminWgCommunity", component: AdminWgCommunity }, |
139 |
+ { path: "/adm/matchingStatistics.page", name: "AdminMatching", component: AdminMatching }, |
|
138 | 140 |
]; |
139 | 141 |
|
140 | 142 |
const AppRouter = createRouter({ |
--- client/views/pages/admin/main/Amain.vue
+++ client/views/pages/admin/main/Amain.vue
... | ... | @@ -41,38 +41,15 @@ |
41 | 41 |
<p :class= item.nameClass> {{ item.menu }}</p> |
42 | 42 |
<p :class= item.cntClass>{{ item.value }}<span> 건</span></p> |
43 | 43 |
</div> |
44 |
- <!-- <div :class="blue"> |
|
45 |
- <p class="blue-sub-title main-sub-title">기술문서</p> |
|
46 |
- <p class="number blue-sub-title ">{{ }}<span> 건</span></p> |
|
47 |
- </div> |
|
48 |
- <div :class="blue"> |
|
49 |
- <p class="green-sub-title main-sub-title">자료집</p> |
|
50 |
- <p class="number green-sub-title">{{ }}<span> 건</span></p> |
|
51 |
- </div> |
|
52 |
- <div :class="yellow"> |
|
53 |
- <p class="yellow-sub-title main-sub-title">기업홍보관</p> |
|
54 |
- <p class="number yellow-sub-title">{{ }}<span> 건</span></p> |
|
55 |
- </div> |
|
56 |
- <div :class="green"> |
|
57 |
- <p class="orange-sub-title main-sub-title">공지사항</p> |
|
58 |
- <p class="number orange-sub-title">{{ }}<span> 건</span></p> |
|
59 |
- </div> |
|
60 |
- <div :class="pink"> |
|
61 |
- <p class="pink-sub-title main-sub-title">홍보&뉴스</p> |
|
62 |
- <p class="number pink-sub-title">{{ }}<span> 건</span></p> |
|
63 |
- </div> |
|
64 |
- <div :class="pink"> |
|
65 |
- <p class="pink-sub-title main-sub-title">전문가협의체</p> |
|
66 |
- <p class="number pink-sub-title">{{ }}<span> 건</span></p> |
|
67 |
- </div> --> |
|
68 | 44 |
</li> |
69 |
- |
|
70 | 45 |
</ul> |
71 | 46 |
</div> |
72 | 47 |
</div> |
73 | 48 |
<div class="content combine"> |
74 | 49 |
<div class="main-content-title">방문자수</div> |
75 |
- <div class="content-zone"></div> |
|
50 |
+ <div class="content-zone"> |
|
51 |
+ <LineChart :chartData="visitList" :keyMapping="keyMap" columnX="날짜" columnY="기업회원 방문자수"/> |
|
52 |
+ </div> |
|
76 | 53 |
</div> |
77 | 54 |
<div class="content"> |
78 | 55 |
<div class="main-content-title">페이지별 접속 통계</div> |
... | ... | @@ -138,6 +115,8 @@ |
138 | 115 |
import axios from 'axios'; |
139 | 116 |
import { useStore } from "vuex"; |
140 | 117 |
import SingleBarChart from "../../../component/chart/SingleBarChart.vue"; |
118 |
+import LineChart from '../../../component/chart/LineChart.vue'; |
|
119 |
+import COMMON_UTIL from '../../../../resources/js/commonUtil.js'; |
|
141 | 120 |
|
142 | 121 |
export default { |
143 | 122 |
|
... | ... | @@ -166,7 +145,22 @@ |
166 | 145 |
todayPageAccess: [], |
167 | 146 |
accumulatePageAccess: [], |
168 | 147 |
selectTop5: [], |
169 |
- |
|
148 |
+ visitListSearch: { |
|
149 |
+ currentPage: 1, |
|
150 |
+ perPage: 7, |
|
151 |
+ startDate: null, |
|
152 |
+ endDate: null, |
|
153 |
+ type: 'day' |
|
154 |
+ }, |
|
155 |
+ oneMonthLater: COMMON_UTIL.yesterday(), |
|
156 |
+ visitList: [], |
|
157 |
+ keyMap : { |
|
158 |
+ cmmn_vst_cnt: '일반회원 방문자수', |
|
159 |
+ cpn_vst_cnt: '기업회원 방문자수', |
|
160 |
+ non_vst_cnt: '비회원 방문자수', |
|
161 |
+ stats_date: '날짜', |
|
162 |
+ total_cnt: '총 방문자수', |
|
163 |
+ } |
|
170 | 164 |
}; |
171 | 165 |
}, |
172 | 166 |
methods: { |
... | ... | @@ -229,18 +223,49 @@ |
229 | 223 |
|
230 | 224 |
changeTop5: function() { |
231 | 225 |
this.top5(); |
232 |
- } |
|
226 |
+ }, |
|
227 |
+ /** 방문자 수 날짜 별 통계 */ |
|
228 |
+ visitSelectList: function () { |
|
229 |
+ const vm = this; |
|
230 |
+ axios({ |
|
231 |
+ url: '/statistics/visitSelectList.json', |
|
232 |
+ method: 'post', |
|
233 |
+ hearder: { |
|
234 |
+ 'Content-Type': "application/json; charset=UTF-8", |
|
235 |
+ }, |
|
236 |
+ data: vm.visitListSearch |
|
237 |
+ }).then(function (response) { |
|
238 |
+ vm.visitList = response.data |
|
239 |
+ }).catch(function (error) { |
|
240 |
+ console.log("error - ", error) |
|
241 |
+ alert("방문자 수 조회 오류, 관리자에게 문의하세요."); |
|
242 |
+ }) |
|
243 |
+ }, |
|
233 | 244 |
|
234 | 245 |
}, |
235 | 246 |
watch: { |
247 |
+ 'visitListSearch.startDate': function(newValue) { |
|
248 |
+ let date = COMMON_UTIL.oneMonthLater(newValue); |
|
249 |
+ if(date > COMMON_UTIL.today()) { |
|
250 |
+ this.oneMonthLater = COMMON_UTIL.yesterday(); |
|
251 |
+ } else { |
|
252 |
+ this.oneMonthLater = date; |
|
253 |
+ } |
|
254 |
+ } |
|
236 | 255 |
}, |
237 | 256 |
computed: {}, |
238 | 257 |
components: { |
258 |
+ 'LineChart': LineChart, |
|
239 | 259 |
'SingleBarChart': SingleBarChart |
260 |
+ }, |
|
261 |
+ created() { |
|
262 |
+ this.visitListSearch.endDate = COMMON_UTIL.yesterday(); |
|
263 |
+ this.visitListSearch.startDate = COMMON_UTIL.oneMonthAgo(COMMON_UTIL.yesterday()); |
|
240 | 264 |
}, |
241 | 265 |
mounted() { |
242 | 266 |
this.dashboard(); |
243 | 267 |
this.top5(); |
268 |
+ this.visitSelectList(); |
|
244 | 269 |
} |
245 | 270 |
}; |
246 | 271 |
</script> |
+++ client/views/pages/admin/statistics/MatchingStatistics.vue
... | ... | @@ -0,0 +1,189 @@ |
1 | +<template> | |
2 | + <div class="chart-page"> | |
3 | + <div class="content-wrap"> | |
4 | + <ul class="tab-menu"> | |
5 | + <li v-for="(tab, index) in tabMenu" :key="index"> | |
6 | + <a @click="currentTab = index" :class="{ active: currentTab === index }">{{ tab }}</a> | |
7 | + </li> | |
8 | + </ul> | |
9 | + <div class="tab-content"> | |
10 | + <div v-show="currentTab == 0"> | |
11 | + <div class="chart"> | |
12 | + <div class="chart-top"> | |
13 | + <div class="flex"> | |
14 | + <div class="date-zone flex-start"> | |
15 | + <input type="date" name="" id=""> | |
16 | + <span>~</span> | |
17 | + <input type="date" name="" id=""> | |
18 | + <button class="blue-btn">조회</button> | |
19 | + </div> | |
20 | + <div class="date-check flex-end"> | |
21 | + <div> | |
22 | + <input type="radio" name="pickMatching1" id="pick1" style="display:none" | |
23 | + v-model="selectedOption2" @click="handleRadioClick('pick')" | |
24 | + :checked="selectedOption2 === 'pick'"> | |
25 | + <label for="pick1">Pick</label> | |
26 | + </div> | |
27 | + <div> | |
28 | + <input type="radio" name="pickMatching1" id="matching1" style="display:none" | |
29 | + v-model="selectedOption2" @click="handleRadioClick('matching')" | |
30 | + :checked="selectedOption2 === 'matching'"> | |
31 | + <label for="matching1">Matching</label> | |
32 | + </div> | |
33 | + </div> | |
34 | + </div> | |
35 | + </div> | |
36 | + </div> | |
37 | + <BarChart :data="menuVisitData" :mapping="keyMapping" /> | |
38 | + <div class="table-zone"> | |
39 | + <div class="btn-wrap"> | |
40 | + <button class="blue-border-bnt">Excel 다운로드</button> | |
41 | + </div> | |
42 | + <table class="statistics-table"> | |
43 | + <colgroup> | |
44 | + <col style="width: 20%;" /> | |
45 | + <col style="width: 16%;" /> | |
46 | + <col style="width: 16%;" /> | |
47 | + <col style="width: 16%;" /> | |
48 | + <col style="width: 16%;" /> | |
49 | + <col style="width: 16%;" /> | |
50 | + </colgroup> | |
51 | + <thead> | |
52 | + <tr> | |
53 | + <th rowspan="2">기업별</th> | |
54 | + <th colspan="5" v-if="selectedOption1 === 'pick'">Pick</th> | |
55 | + <th colspan="5" v-else-if="selectedOption1 === 'matching'">Matching</th> | |
56 | + </tr> | |
57 | + <tr> | |
58 | + <th>성공건수</th> | |
59 | + <th>실패건수</th> | |
60 | + <th>진행중인건수</th> | |
61 | + <th>요청받은건수</th> | |
62 | + <th>요청한 건수</th> | |
63 | + <th>전체 요청수</th> | |
64 | + </tr> | |
65 | + </thead> | |
66 | + <tbody> | |
67 | + <tr v-for="(item, index) in menuVisitData" :key="index"> | |
68 | + <td>{{ item.date }}</td> | |
69 | + <td>{{ item.total }}</td> | |
70 | + <td>{{ item.company }}</td> | |
71 | + <td>{{ item.common }}</td> | |
72 | + </tr> | |
73 | + </tbody> | |
74 | + </table> | |
75 | + </div> | |
76 | + </div> | |
77 | + </div> | |
78 | + <div v-show="currentTab == 1"> | |
79 | + <div class="chart"> | |
80 | + <div class="chart-top"> | |
81 | + <div class="flex"> | |
82 | + <div class="date-zone flex-start"> | |
83 | + <input type="date" name="" id=""> | |
84 | + <span>~</span> | |
85 | + <input type="date" name="" id=""> | |
86 | + <button class="blue-btn">조회</button> | |
87 | + </div> | |
88 | + <div class="date-check flex-end"> | |
89 | + <div> | |
90 | + <input type="radio" name="pickMatching2" id="pick2" style="display:none" | |
91 | + v-model="selectedOption2" @click="handleRadioClick('pick')" | |
92 | + :checked="selectedOption2 === 'pick'"> | |
93 | + <label for="pick2">Pick</label> | |
94 | + </div> | |
95 | + <div> | |
96 | + <input type="radio" name="pickMatching2" id="matching2" style="display:none" | |
97 | + v-model="selectedOption2" @click="handleRadioClick('matching')" | |
98 | + :checked="selectedOption2 === 'matching'"> | |
99 | + <label for="matching2">Matching</label> | |
100 | + </div> | |
101 | + </div> | |
102 | + </div> | |
103 | + </div> | |
104 | + <BarChart :data="menuVisitData" :mapping="keyMapping" /> | |
105 | + <div class="table-zone"> | |
106 | + <div class="flex middle-zone"> | |
107 | + <select name="" id=""> | |
108 | + <option value="">A사</option> | |
109 | + <option value="">B사</option> | |
110 | + <option value="">C사</option> | |
111 | + <option value="">D사</option> | |
112 | + <option value="">E사</option> | |
113 | + <option value="">F사</option> | |
114 | + </select> | |
115 | + <button class="blue-border-bnt">Excel 다운로드</button> | |
116 | + </div> | |
117 | + <table class="statistics-table"> | |
118 | + <colgroup> | |
119 | + <col style="width: 20%;" /> | |
120 | + <col style="width: 16%;" /> | |
121 | + <col style="width: 16%;" /> | |
122 | + <col style="width: 16%;" /> | |
123 | + </colgroup> | |
124 | + <thead> | |
125 | + <tr> | |
126 | + <th rowspan="2">기업별</th> | |
127 | + <th colspan="3" v-if="selectedOption2 === 'pick'">Pick</th> | |
128 | + <th colspan="3" v-else-if="selectedOption2 === 'matching'">Matching</th> | |
129 | + </tr> | |
130 | + <tr> | |
131 | + <th>상대기업명</th> | |
132 | + <th colspan="2">현황</th> | |
133 | + </tr> | |
134 | + </thead> | |
135 | + <tbody> | |
136 | + <tr v-for="(item, index) in menuVisitData" :key="index"> | |
137 | + <td>{{ item.date }}</td> | |
138 | + <td>{{ item.total }}</td> | |
139 | + <td>{{ item.company }}</td> | |
140 | + <td>{{ item.common }}</td> | |
141 | + </tr> | |
142 | + </tbody> | |
143 | + </table> | |
144 | + </div> | |
145 | + </div> | |
146 | + | |
147 | + </div> | |
148 | + </div> | |
149 | + </div> | |
150 | +</template> | |
151 | +<script> | |
152 | +import { useStore } from "vuex"; | |
153 | +import axios from "axios"; | |
154 | + | |
155 | + | |
156 | + | |
157 | +export default { | |
158 | + | |
159 | + data() { | |
160 | + return { | |
161 | + currentTab: 0, | |
162 | + tabMenu: ['매칭관리', '매칭관리 세부통계'], | |
163 | + selectedOption2: "pick", | |
164 | + selectedOption1: "pick" | |
165 | + }; | |
166 | + }, | |
167 | + methods: { | |
168 | + handleRadioClick(option) { | |
169 | + this.selectedOption1 = option; | |
170 | + this.selectedOption2 = option; | |
171 | + } | |
172 | + }, | |
173 | + watch: { | |
174 | + "selectedOption1": function (newValue) { | |
175 | + console.log(newValue) | |
176 | + }, | |
177 | + "selectedOption2": function (newValue) { | |
178 | + console.log(newValue) | |
179 | + } | |
180 | + }, | |
181 | + computed: {}, | |
182 | + components: { | |
183 | + | |
184 | + }, | |
185 | + mounted() { | |
186 | + console.log(this.selectedOption1) | |
187 | + }, | |
188 | +}; | |
189 | +</script> |
--- client/views/pages/admin/statistics/Visit.vue
+++ client/views/pages/admin/statistics/Visit.vue
... | ... | @@ -3,28 +3,32 @@ |
3 | 3 |
<div class="chart-top"> |
4 | 4 |
<div class="flex"> |
5 | 5 |
<div class="date-zone flex-start"> |
6 |
- <input type="date" name="" id="" :max="visitListSearch.endDate" v-model="visitListSearch.startDate"/> |
|
6 |
+ <input type="date" name="" id="" :max="visitListSearch.endDate" v-model="visitListSearch.startDate" /> |
|
7 | 7 |
<span>~</span> |
8 |
- <input type="date" name="" id="" :min="visitListSearch.startDate" :max="oneMonthLater" v-model="visitListSearch.endDate"/> |
|
8 |
+ <input type="date" name="" id="" :min="visitListSearch.startDate" :max="oneMonthLater" |
|
9 |
+ v-model="visitListSearch.endDate" /> |
|
9 | 10 |
<button class="blue-btn">조회</button> |
10 | 11 |
</div> |
11 | 12 |
<div class="date-check flex-end"> |
12 | 13 |
<div> |
13 |
- <input type="radio" name="dayCategory" id="day" style="display:none" value="day" v-model="visitListSearch.type"> |
|
14 |
+ <input type="radio" name="dayCategory" id="day" style="display:none" value="day" |
|
15 |
+ v-model="visitListSearch.type"> |
|
14 | 16 |
<label for="day">일별</label> |
15 | 17 |
</div> |
16 | 18 |
<div> |
17 |
- <input type="radio" name="dayCategory" id="month" style="display:none" value="month" v-model="visitListSearch.type"> |
|
19 |
+ <input type="radio" name="dayCategory" id="month" style="display:none" value="month" |
|
20 |
+ v-model="visitListSearch.type"> |
|
18 | 21 |
<label for="month">월별</label> |
19 | 22 |
</div> |
20 | 23 |
<div> |
21 |
- <input type="radio" name="dayCategory" id="year" style="display:none" value="year" v-model="visitListSearch.type"> |
|
24 |
+ <input type="radio" name="dayCategory" id="year" style="display:none" value="year" |
|
25 |
+ v-model="visitListSearch.type"> |
|
22 | 26 |
<label for="year">년도별</label> |
23 | 27 |
</div> |
24 | 28 |
</div> |
25 | 29 |
</div> |
26 | 30 |
</div> |
27 |
- <LineChart :chartData="visitList"/> |
|
31 |
+ <LineChart :chartData="visitList" :keyMapping="keyMap" columnX="날짜" columnY="기업회원 방문자수" /> |
|
28 | 32 |
<div class="table-zone"> |
29 | 33 |
<div class="btn-wrap"> |
30 | 34 |
<button class="blue-border-bnt">Excel 다운로드</button> |
... | ... | @@ -45,7 +49,7 @@ |
45 | 49 |
<tbody> |
46 | 50 |
<tr v-for="(item, index) in visitList" :key="index"> |
47 | 51 |
<td>{{ item.stats_date }}</td> |
48 |
- <td>{{ item.total_cnt}}</td> |
|
52 |
+ <td>{{ item.total_cnt }}</td> |
|
49 | 53 |
<td>{{ item.cpn_vst_cnt }}</td> |
50 | 54 |
<td>{{ item.cmmn_vst_cnt }}</td> |
51 | 55 |
<td>{{ item.non_vst_cnt }}</td> |
... | ... | @@ -76,6 +80,13 @@ |
76 | 80 |
}, |
77 | 81 |
oneMonthLater: COMMON_UTIL.yesterday(), |
78 | 82 |
visitList: [], |
83 |
+ keyMap : { |
|
84 |
+ cmmn_vst_cnt: '일반회원 방문자수', |
|
85 |
+ cpn_vst_cnt: '기업회원 방문자수', |
|
86 |
+ non_vst_cnt: '비회원 방문자수', |
|
87 |
+ stats_date: '날짜', |
|
88 |
+ total_cnt: '총 방문자수', |
|
89 |
+ } |
|
79 | 90 |
}; |
80 | 91 |
}, |
81 | 92 |
methods: { |
... | ... | @@ -90,7 +101,7 @@ |
90 | 101 |
}, |
91 | 102 |
data: vm.visitListSearch |
92 | 103 |
}).then(function (response) { |
93 |
- vm.visitList = response.data |
|
104 |
+ vm.visitList = response.data |
|
94 | 105 |
}).catch(function (error) { |
95 | 106 |
console.log("error - ", error) |
96 | 107 |
alert("방문자 수 조회 오류, 관리자에게 문의하세요."); |
... | ... | @@ -98,9 +109,9 @@ |
98 | 109 |
}, |
99 | 110 |
}, |
100 | 111 |
watch: { |
101 |
- 'visitListSearch.startDate': function(newValue) { |
|
112 |
+ 'visitListSearch.startDate': function (newValue) { |
|
102 | 113 |
let date = COMMON_UTIL.oneMonthLater(newValue); |
103 |
- if(date > COMMON_UTIL.today()) { |
|
114 |
+ if (date > COMMON_UTIL.today()) { |
|
104 | 115 |
this.oneMonthLater = COMMON_UTIL.yesterday(); |
105 | 116 |
} else { |
106 | 117 |
this.oneMonthLater = date; |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?