yjryu / KERIS star
류윤주 류윤주 2023-11-27
231127 라인차트 수정
@02e1ce36a940a3fead52f3aa76a97cb09c7345d5
client/resources/css/admin.css
--- client/resources/css/admin.css
+++ client/resources/css/admin.css
@@ -433,7 +433,7 @@
 .tab-content {
   width: 100%;
   height: 100%;
-  padding: 15px;
+  padding: 15px 0;
 }
 
 .modal-content-monthly>div {
@@ -612,4 +612,12 @@
 
 .insert-select{
   margin-left: 0;
+}
+
+.middle-zone{
+  padding: 10px 0;
+}
+
+.middle-zone select{
+  margin-left: 0;
 }
(No newline at end of file)
client/views/component/chart/LineChart.vue
--- client/views/component/chart/LineChart.vue
+++ client/views/component/chart/LineChart.vue
@@ -1,6 +1,6 @@
 <template>
     <div class="chart-wrap">
-        <div class="chart" id="chartdiv" ref="chartdiv" style="width: 100%; height: 700px;"></div>
+        <div class="chart" id="chartdiv" ref="chartdiv" style="width: 100%; height: 350px;"></div>
     </div>
 </template>
  
@@ -17,12 +17,21 @@
             default: [],
             // required: true,
         },
+        keyMapping: {
+            type: Object,
+        },
+        columnX:{
+            type: String
+        },
+        columnY:{
+            type: String
+        }
 
     },
     data() {
         return {
             // y축 컬럼 목록
-            valueDataList: ["cpn_vst_cnt", "cmmn_vst_cnt", "non_vst_cnt", "total_cnt"],
+            valueDataList: ["기업회원 방문자수", "일반회원 방문자수", "비회원 방문자수", "총 방문자수"],
 
             // 차트 옵션 변수 목록
             chartOptions: {
@@ -68,7 +77,7 @@
                 /*************** 마우스 (끝) ***************/
 
 
-                scrollbarX: true, // x축 스크롤바 표시 여부
+                scrollbarX: false, // x축 스크롤바 표시 여부
                 scrollbarY: false, // y축 스크롤바 표시 여부
 
                 categoryAxisTooltip: true, // 카테고리축 툴팁 숨김 여부 (숨김: true, 표시: false)
@@ -77,7 +86,7 @@
 
 
                 /*************** 셀 (시작) ***************/
-                seriesColorList: ["#f9b5a0", "#f0acb2", "#e19dcf", "#d28eed"], // 차트 셀 색상 목록 (기본: [])
+                seriesColorList: ["#4e79a6", "#f28e2c", "#e15659", "#76b7b1"], // 차트 셀 색상 목록 (기본: [])
                 bullet: "Circle", // 글머리기호 (사용안함: "", 원형: "Circle", 텍스트: "Label")
 
                 // 막대 차트 전용
@@ -104,8 +113,28 @@
     methods: {
 
         // 라인 차트 생성 함수
-        createLineChart: function (theme, data, columnX, columnY, valueDataList, chartOptions) {
-            let chartData = JSON.parse(JSON.stringify(data)); // 차트 params 데이터 복사
+        createLineChart: function (theme, data, columnX, columnY, valueDataList, chartOptions, keyMapping) {
+            let mappedData = [];
+            let keys = Object.keys(data[0]);
+
+            for (let dataIndex = 0; dataIndex < data.length; dataIndex++) {
+                let currentItem = data[dataIndex];
+                let mappedItem = {};
+
+                for (let i = 0; i < keys.length; i++) {
+                    let key = keys[i];
+                    let koreanKey = keyMapping[key];
+
+                    if (koreanKey) {
+                        mappedItem[koreanKey] = currentItem[key];
+                    }
+                }
+
+                mappedData.push(mappedItem);
+            }
+
+            console.log(mappedData)
+            let chartData = JSON.parse(JSON.stringify(mappedData)); // 차트 params 데이터 복사
             let options = JSON.parse(JSON.stringify(chartOptions)); // 차트 params 데이터 복사
 
             /*************** 차트 생성 (시작) ***************/
@@ -313,7 +342,7 @@
                             strokeWidth: 2, // 테두리 두께
                             stroke: root.interfaceColors.get("background"), // 테두리 색상
                             radius: 5, // 원형 크기
-                            fill: series.get("fill") // 원형 색상
+                            fill: am5.color(seriesColor)// 원형 색상
                         }
                     } else if (options['bullet'] == "Label") { // 텍스트 글머리기호
                         lineBulletSprite = {
@@ -449,7 +478,7 @@
             root._logo.dispose(); //amChart 로고 삭제
 
             // 히트맵일 시 일반범례 사용 안 하고 return
-            if(theme == "HeatMap") {
+            if (theme == "HeatMap") {
                 return { "root": root, "chart": chart }
             };
 
@@ -459,9 +488,9 @@
             /*************** 범례 (시작) ***************/
             let nameField = null;
 
-            if(theme == "XY") {
+            if (theme == "XY") {
                 nameField = "categoryX"
-            } else if(theme == "YX") {
+            } else if (theme == "YX") {
                 nameField = "categoryY"
             }
 
@@ -525,7 +554,7 @@
         'chartData': function (newData, oldData) {
             console.log("new:", newData, oldData);
             // this.createChart(newData);
-            this.createLineChart("ClusterLine", newData, "stats_date", "cpn_vst_cnt", this.valueDataList, this.chartOptions);
+            this.createLineChart("ClusterLine", newData, this.columnX, this.columnY, this.valueDataList, this.chartOptions, this.keyMapping);
         },
     },
     computed: {
client/views/layout/AdminMenu.vue
--- client/views/layout/AdminMenu.vue
+++ client/views/layout/AdminMenu.vue
@@ -9,7 +9,7 @@
           <p><span v-html="menu.icon"></span><span class="menu-text">{{ menu.pathName }}</span></p>
           <p v-html="menu.icon2"></p>
         </router-link>
-        <ul v-if="menu.subMenu" class="aSub-menu" :style="{ 'max-height': menu.isOpen ? '324px' : '0' }">
+        <ul v-if="menu.subMenu" class="aSub-menu" :style="{ 'max-height': menu.isOpen ? '360px' : '0' }">
           <li v-for="(subMenu, subIndex) in menu.subMenu" :key="subIndex" @click="stopToggleSubMenuClick">
             <router-link :to="subMenu.path">{{ subMenu.pathName }}</router-link>
           </li>
@@ -39,6 +39,7 @@
               { path: "/adm/noticeStatistics.page", pathName: "공지사항" },
               { path: "/adm/NewsAndPr.page", pathName: "홍보&뉴스" },
               { path: "/adm/wgCommunity.page", pathName: "전문가 협의체" },
+              { path: "/adm/matchingStatistics.page", pathName: "매칭현황" },
             ],
           icon: '<i class="fa-regular fa-folder-open"></i>', icon2: "<i class='fa-solid fa-angle-right'></i>", isOpen: false, isActive: false
         },
client/views/pages/AppRouter.js
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
@@ -67,6 +67,7 @@
 import AdminNotice from "../pages/admin/statistics/Notice.vue";
 import AdminTech from "../pages/admin/statistics/Tech.vue";
 import AdminWgCommunity from "../pages/admin/statistics/WgCommunity.vue";
+import AdminMatching from "../pages/admin/statistics/matchingStatistics.vue";
 
 const routes = [
   /* 메인화면 */
@@ -135,6 +136,7 @@
   { path: "/adm/noticeStatistics.page", name: "AdminNotice", component: AdminNotice },
   { path: "/adm/techStatistics.page", name: "AdminTech", component: AdminTech },
   { path: "/adm/wgCommunity.page", name: "AdminWgCommunity", component: AdminWgCommunity },
+  { path: "/adm/matchingStatistics.page", name: "AdminMatching", component: AdminMatching },
 ];
 
 const AppRouter = createRouter({
client/views/pages/admin/main/Amain.vue
--- client/views/pages/admin/main/Amain.vue
+++ client/views/pages/admin/main/Amain.vue
@@ -41,38 +41,15 @@
                                     <p :class= item.nameClass> {{ item.menu }}</p>
                                     <p :class= item.cntClass>{{ item.value }}<span> 건</span></p>
                                 </div>
-                                <!-- <div :class="blue">
-                                    <p class="blue-sub-title main-sub-title">기술문서</p>
-                                    <p class="number blue-sub-title ">{{  }}<span> 건</span></p>
-                                </div>
-                                <div :class="blue">
-                                    <p class="green-sub-title main-sub-title">자료집</p>
-                                    <p class="number green-sub-title">{{  }}<span> 건</span></p>
-                                </div>
-                                <div :class="yellow">
-                                    <p class="yellow-sub-title main-sub-title">기업홍보관</p>
-                                    <p class="number yellow-sub-title">{{  }}<span> 건</span></p>
-                                </div>
-                                <div :class="green">
-                                    <p class="orange-sub-title main-sub-title">공지사항</p>
-                                    <p class="number orange-sub-title">{{  }}<span> 건</span></p>
-                                </div>
-                                <div :class="pink">
-                                    <p class="pink-sub-title main-sub-title">홍보&뉴스</p>
-                                    <p class="number pink-sub-title">{{  }}<span> 건</span></p>
-                                </div>
-                                <div :class="pink">
-                                    <p class="pink-sub-title main-sub-title">전문가협의체</p>
-                                    <p class="number pink-sub-title">{{  }}<span> 건</span></p>
-                                </div> -->
                             </li>
- 
                         </ul>
                     </div>
                 </div>
                 <div class="content combine">
                     <div class="main-content-title">방문자수</div>
-                    <div class="content-zone"></div>
+                    <div class="content-zone">
+                        <LineChart :chartData="visitList" :keyMapping="keyMap" columnX="날짜" columnY="기업회원 방문자수"/>
+                    </div>
                 </div>
                 <div class="content">
                     <div class="main-content-title">페이지별 접속 통계</div>
@@ -138,6 +115,8 @@
 import axios from 'axios';
 import { useStore } from "vuex";
 import SingleBarChart from "../../../component/chart/SingleBarChart.vue";
+import LineChart from '../../../component/chart/LineChart.vue';
+import COMMON_UTIL from '../../../../resources/js/commonUtil.js';
 
 export default {
 
@@ -166,7 +145,22 @@
             todayPageAccess: [],
             accumulatePageAccess: [],
             selectTop5: [],
-
+            visitListSearch: {
+                currentPage: 1,
+                perPage: 7,
+                startDate: null,
+                endDate: null,
+                type: 'day'
+            },
+            oneMonthLater: COMMON_UTIL.yesterday(),
+            visitList: [],
+            keyMap : {
+                cmmn_vst_cnt: '일반회원 방문자수',
+                cpn_vst_cnt: '기업회원 방문자수',
+                non_vst_cnt: '비회원 방문자수',
+                stats_date: '날짜',
+                total_cnt: '총 방문자수',
+            }
         };
     },
     methods: {
@@ -229,18 +223,49 @@
 
         changeTop5: function() {
             this.top5();
-        }
+        },
+        /** 방문자 수 날짜 별 통계 */
+        visitSelectList: function () {
+            const vm = this;
+            axios({
+                url: '/statistics/visitSelectList.json',
+                method: 'post',
+                hearder: {
+                    'Content-Type': "application/json; charset=UTF-8",
+                },
+                data: vm.visitListSearch
+            }).then(function (response) {
+               vm.visitList = response.data
+            }).catch(function (error) {
+                console.log("error - ", error)
+                alert("방문자 수 조회 오류, 관리자에게 문의하세요.");
+            })
+        },
         
     },
     watch: {
+        'visitListSearch.startDate': function(newValue) {
+            let date = COMMON_UTIL.oneMonthLater(newValue);
+            if(date > COMMON_UTIL.today()) {
+                this.oneMonthLater = COMMON_UTIL.yesterday();
+            } else {
+                this.oneMonthLater = date;
+            }
+        }
     },
     computed: {},
     components: {
+        'LineChart': LineChart,
         'SingleBarChart': SingleBarChart
+    },
+    created() {
+        this.visitListSearch.endDate = COMMON_UTIL.yesterday();
+        this.visitListSearch.startDate = COMMON_UTIL.oneMonthAgo(COMMON_UTIL.yesterday());
     },
     mounted() {
         this.dashboard();
         this.top5();
+        this.visitSelectList();
     }
 };
 </script>
 
client/views/pages/admin/statistics/MatchingStatistics.vue (added)
+++ client/views/pages/admin/statistics/MatchingStatistics.vue
@@ -0,0 +1,189 @@
+<template>
+    <div class="chart-page">
+        <div class="content-wrap">
+            <ul class="tab-menu">
+                <li v-for="(tab, index) in tabMenu" :key="index">
+                    <a @click="currentTab = index" :class="{ active: currentTab === index }">{{ tab }}</a>
+                </li>
+            </ul>
+            <div class="tab-content">
+                <div v-show="currentTab == 0">
+                    <div class="chart">
+                        <div class="chart-top">
+                            <div class="flex">
+                                <div class="date-zone flex-start">
+                                    <input type="date" name="" id="">
+                                    <span>~</span>
+                                    <input type="date" name="" id="">
+                                    <button class="blue-btn">조회</button>
+                                </div>
+                                <div class="date-check flex-end">
+                                    <div>
+                                        <input type="radio" name="pickMatching1" id="pick1" style="display:none"
+                                            v-model="selectedOption2" @click="handleRadioClick('pick')"
+                                            :checked="selectedOption2 === 'pick'">
+                                        <label for="pick1">Pick</label>
+                                    </div>
+                                    <div>
+                                        <input type="radio" name="pickMatching1" id="matching1" style="display:none"
+                                            v-model="selectedOption2" @click="handleRadioClick('matching')"
+                                            :checked="selectedOption2 === 'matching'">
+                                        <label for="matching1">Matching</label>
+                                    </div>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <BarChart :data="menuVisitData" :mapping="keyMapping" />
+                    <div class="table-zone">
+                        <div class="btn-wrap">
+                            <button class="blue-border-bnt">Excel 다운로드</button>
+                        </div>
+                        <table class="statistics-table">
+                            <colgroup>
+                                <col style="width: 20%;" />
+                                <col style="width: 16%;" />
+                                <col style="width: 16%;" />
+                                <col style="width: 16%;" />
+                                <col style="width: 16%;" />
+                                <col style="width: 16%;" />
+                            </colgroup>
+                            <thead>
+                                <tr>
+                                    <th rowspan="2">기업별</th>
+                                    <th colspan="5" v-if="selectedOption1 === 'pick'">Pick</th>
+                                    <th colspan="5" v-else-if="selectedOption1 === 'matching'">Matching</th>
+                                </tr>
+                                <tr>
+                                    <th>성공건수</th>
+                                    <th>실패건수</th>
+                                    <th>진행중인건수</th>
+                                    <th>요청받은건수</th>
+                                    <th>요청한 건수</th>
+                                    <th>전체 요청수</th>
+                                </tr>
+                            </thead>
+                            <tbody>
+                                <tr v-for="(item, index) in menuVisitData" :key="index">
+                                    <td>{{ item.date }}</td>
+                                    <td>{{ item.total }}</td>
+                                    <td>{{ item.company }}</td>
+                                    <td>{{ item.common }}</td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+            </div>
+            <div v-show="currentTab == 1">
+                <div class="chart">
+                    <div class="chart-top">
+                        <div class="flex">
+                            <div class="date-zone flex-start">
+                                <input type="date" name="" id="">
+                                <span>~</span>
+                                <input type="date" name="" id="">
+                                <button class="blue-btn">조회</button>
+                            </div>
+                            <div class="date-check flex-end">
+                                <div>
+                                    <input type="radio" name="pickMatching2" id="pick2" style="display:none"
+                                        v-model="selectedOption2" @click="handleRadioClick('pick')"
+                                        :checked="selectedOption2 === 'pick'">
+                                    <label for="pick2">Pick</label>
+                                </div>
+                                <div>
+                                    <input type="radio" name="pickMatching2" id="matching2" style="display:none"
+                                        v-model="selectedOption2" @click="handleRadioClick('matching')"
+                                        :checked="selectedOption2 === 'matching'">
+                                    <label for="matching2">Matching</label>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                    <BarChart :data="menuVisitData" :mapping="keyMapping" />
+                    <div class="table-zone">
+                        <div class="flex middle-zone">
+                            <select name="" id="">
+                                <option value="">A사</option>
+                                <option value="">B사</option>
+                                <option value="">C사</option>
+                                <option value="">D사</option>
+                                <option value="">E사</option>
+                                <option value="">F사</option>
+                            </select>
+                            <button class="blue-border-bnt">Excel 다운로드</button>
+                        </div>
+                        <table class="statistics-table">
+                            <colgroup>
+                                <col style="width: 20%;" />
+                                <col style="width: 16%;" />
+                                <col style="width: 16%;" />
+                                <col style="width: 16%;" />
+                            </colgroup>
+                            <thead>
+                                <tr>
+                                    <th rowspan="2">기업별</th>
+                                    <th colspan="3" v-if="selectedOption2 === 'pick'">Pick</th>
+                                    <th colspan="3" v-else-if="selectedOption2 === 'matching'">Matching</th>
+                                </tr>
+                                <tr>
+                                    <th>상대기업명</th>
+                                    <th colspan="2">현황</th>
+                                </tr>
+                            </thead>
+                            <tbody>
+                                <tr v-for="(item, index) in menuVisitData" :key="index">
+                                    <td>{{ item.date }}</td>
+                                    <td>{{ item.total }}</td>
+                                    <td>{{ item.company }}</td>
+                                    <td>{{ item.common }}</td>
+                                </tr>
+                            </tbody>
+                        </table>
+                    </div>
+                </div>
+
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import { useStore } from "vuex";
+import axios from "axios";
+
+
+
+export default {
+
+    data() {
+        return {
+            currentTab: 0,
+            tabMenu: ['매칭관리', '매칭관리 세부통계'],
+            selectedOption2: "pick",
+            selectedOption1: "pick"
+        };
+    },
+    methods: {
+        handleRadioClick(option) {
+            this.selectedOption1 = option;
+            this.selectedOption2 = option;
+        }
+    },
+    watch: {
+        "selectedOption1": function (newValue) {
+            console.log(newValue)
+        },
+        "selectedOption2": function (newValue) {
+            console.log(newValue)
+        }
+    },
+    computed: {},
+    components: {
+
+    },
+    mounted() {
+        console.log(this.selectedOption1)
+    },
+};
+</script>
client/views/pages/admin/statistics/Visit.vue
--- client/views/pages/admin/statistics/Visit.vue
+++ client/views/pages/admin/statistics/Visit.vue
@@ -3,28 +3,32 @@
         <div class="chart-top">
             <div class="flex">
                 <div class="date-zone flex-start">
-                    <input type="date" name="" id="" :max="visitListSearch.endDate" v-model="visitListSearch.startDate"/>
+                    <input type="date" name="" id="" :max="visitListSearch.endDate" v-model="visitListSearch.startDate" />
                     <span>~</span>
-                    <input type="date" name="" id="" :min="visitListSearch.startDate" :max="oneMonthLater" v-model="visitListSearch.endDate"/>
+                    <input type="date" name="" id="" :min="visitListSearch.startDate" :max="oneMonthLater"
+                        v-model="visitListSearch.endDate" />
                     <button class="blue-btn">조회</button>
                 </div>
                 <div class="date-check flex-end">
                     <div>
-                        <input type="radio" name="dayCategory" id="day" style="display:none" value="day" v-model="visitListSearch.type">
+                        <input type="radio" name="dayCategory" id="day" style="display:none" value="day"
+                            v-model="visitListSearch.type">
                         <label for="day">일별</label>
                     </div>
                     <div>
-                        <input type="radio" name="dayCategory" id="month" style="display:none" value="month" v-model="visitListSearch.type">
+                        <input type="radio" name="dayCategory" id="month" style="display:none" value="month"
+                            v-model="visitListSearch.type">
                         <label for="month">월별</label>
                     </div>
                     <div>
-                        <input type="radio" name="dayCategory" id="year" style="display:none" value="year" v-model="visitListSearch.type">
+                        <input type="radio" name="dayCategory" id="year" style="display:none" value="year"
+                            v-model="visitListSearch.type">
                         <label for="year">년도별</label>
                     </div>
                 </div>
             </div>
         </div>
-        <LineChart :chartData="visitList"/>
+        <LineChart :chartData="visitList" :keyMapping="keyMap" columnX="날짜" columnY="기업회원 방문자수" />
         <div class="table-zone">
             <div class="btn-wrap">
                 <button class="blue-border-bnt">Excel 다운로드</button>
@@ -45,7 +49,7 @@
                 <tbody>
                     <tr v-for="(item, index) in visitList" :key="index">
                         <td>{{ item.stats_date }}</td>
-                        <td>{{ item.total_cnt}}</td>
+                        <td>{{ item.total_cnt }}</td>
                         <td>{{ item.cpn_vst_cnt }}</td>
                         <td>{{ item.cmmn_vst_cnt }}</td>
                         <td>{{ item.non_vst_cnt }}</td>
@@ -76,6 +80,13 @@
             },
             oneMonthLater: COMMON_UTIL.yesterday(),
             visitList: [],
+            keyMap : {
+                cmmn_vst_cnt: '일반회원 방문자수',
+                cpn_vst_cnt: '기업회원 방문자수',
+                non_vst_cnt: '비회원 방문자수',
+                stats_date: '날짜',
+                total_cnt: '총 방문자수',
+            }
         };
     },
     methods: {
@@ -90,7 +101,7 @@
                 },
                 data: vm.visitListSearch
             }).then(function (response) {
-               vm.visitList = response.data
+                vm.visitList = response.data
             }).catch(function (error) {
                 console.log("error - ", error)
                 alert("방문자 수 조회 오류, 관리자에게 문의하세요.");
@@ -98,9 +109,9 @@
         },
     },
     watch: {
-        'visitListSearch.startDate': function(newValue) {
+        'visitListSearch.startDate': function (newValue) {
             let date = COMMON_UTIL.oneMonthLater(newValue);
-            if(date > COMMON_UTIL.today()) {
+            if (date > COMMON_UTIL.today()) {
                 this.oneMonthLater = COMMON_UTIL.yesterday();
             } else {
                 this.oneMonthLater = date;
Add a comment
List