본문 바로가기
AyoProject/Ayotera-Trade

[AT] 33. 우량주 매매시점 알림 Dashboard 제작 (1)

by 청양호박이 2021. 4. 1.

이제 본격적으로 우량주 매매시점 알림 대시보드(Dashboard)의 각 영역별로 구현하는 방법에 대해서 알아보겠습니다. 우선 첫 시간으로 첫째줄의 첫번째 영역에 대해서 보시죠~!!

 

아참!! 그리고 Dashboard의 전체적인 구성에 대해서는 제가 기존에 작성했던 vue.js쪽 내용을 참조해주시면 되겠습니다.

2021.03.04 - [Vue.js] - [Vue.js] 13. use Grid System

 

[Vue.js] 13. use Grid System

이번에는 Dashboard 등 화면 Layout구성의 근간이 되는 Grid System에 대해서 알아보고자 합니다. Vuetify에서는 Layout 구성을 위한 방법을 제공하는데... 그것이 Grid System 입니다. 1. Grid System이란? Vueti..

ayoteralab.tistory.com

 

 

1. 분기별 우량주 정보 표시 영역 분석


지금부터 이 화면을 구현해 보도록 하겠습니다. 해당 화면은 다음의 3가지로 구성이 되어 있습니다. 

 

  • 왼쪽 - doughnut chart 영역 (우량주와 우량주 중 저평가 종목의 비율을 표시)
  • 오른쪽 상단 - 해당 영역의 제목과 저평가 판단 설정항목을 표시
  • 오른쪽 하단 - 우량주 중 저평가 종목의 리스트를 표시

 

이렇게 총 3가지의 구현이 필요합니다. 가장 처음으로 영역자체를 chart / 정보표시 영역으로 소분류하는 방법을 살펴보면, 영역자체는 <v-card/>로 높이 330px고정으로 생성을 해 줍니다. 그리고 그 안에 <v-col/>로 크기를 4:8의 비율로 나누어 줍니다. 

<v-card class="mx-auto" elevation="2" style="height: 330px;">
  <v-card-text>
    <v-row align="center">
      <!-- Left Chart Area -->
      <v-col cols="4" align="center" style="height: 330px;">

      </v-col>
      <!-- Left Chart Area -->
      <!-- Right Data List Area -->
      <v-col cols="8">

      </v-col>
      <!-- Right Data List Area -->
    </v-row>
  </v-card-text>
</v-card>

이제 doughnut chart는 <v-col cols="4">에 넣어주면 되고, 실질적인 데이터는 <v-col cols="8">에 넣어주면 됩니다.

 

 

2. doughnut chart 영역


의외로 doughnut chart를 구현하는 방법은 간단합니다. 이미 vue.js쪽에서 vue-chartjs를 다루는 글이 있었기 때문에 그와 유사하게 진행하면 됩니다. 우선 단도직입적으로 doughnut chart를 위한 component를 작성해 보겠습니다. 

(참고 : 2021.03.08 - [Vue.js] - [Vue.js] 14. use Vue chart plugin )

 

[DoughnutChart.vue]

<script>
import { Doughnut, mixins } from 'vue-chartjs';

export default{
  extends: Doughnut,
  mixins: [mixins.reactiveProp],
  props: ['options'],
  mounted() {
    this.renderChart(this.chartData, this.options);
  },
};
</script>

<style>

</style>

기존 글에서 단순히 import와 extends부분이 Doughnut으로 변경된 부분을 제외하고는 차이가 없습니다. 그럼 실행해보면 어떻게 나올까요??

어라... 뭔가 상당히 휑하네요... 최종 구현된 장면에서는 display doughnut chart datalabel, place label text in the center of doughnut chart 가 되어있습니다. chart.js의 document와 여러가지 방법으로 찾아보았지만 자체적으로 구현하기에는 어려움이 있었습니다. 

 

그래서 찾게된 것이 아래의 방법입니다. 기타 doughnut chart의 주요한 options, datalabel의 표시... 중앙에 label의 표시등 세부적인 내용은 아래를 이전에 올린 글을 참조해주시면 됩니다. 

2021.03.30 - [Vue.js] - [Vue.js] 16. use doughnut chart with label plugin

 

[Vue.js] 16. use doughnut chart with label plugin

vue-chartjs를 사용하다 보면, 여러가지 custom하고 싶은 욕구가 생기기 마련입니다. 물론 다른 여러가지 chart를 그려주는 library를 사용할때도 마찬가지 입니다. 오늘은 vue-chartjs 중 doughnut chart를 구현

ayoteralab.tistory.com

구현된 doughnut chart를 표시하기 위한 options는 아래와 같이, 세팅합니다. 대신, 해당 options는 axios.get을 통해서 우량주 종목을 가져올 때 dataCollection을 설정하면서 함께 설정해 줍니다.

 

[doughnutOptions]

this.doughnutOptions = {
  responsive: true,
  maintainAspectRatio: false,
  cutoutPercentage: 60,
  legend: { display: false, },
  animation: { duration: 1000, },
  layout: { padding: 7, },
  plugins: {
    datalabels: {
      backgroundColor: function(context) {
        return context.dataset.backgroundColor;
      },
      borderColor: 'white',
      borderRadius: 25,
      borderWidth: 2,
      color: 'white',
      display: true,
      font: {
        weight: 'bold'
      },
      padding: 6,
      formatter: Math.round
    },
    doughnutlabel: {
      labels: [	
        {
          text: Math.round(this.qssListPerUserItem.length*100/(this.qssListPerUserItem.length+this.stockListAllCount))+"%",
          font: {
            size: '20',
            weight: 'bold',
          }
        },
      ],
    }
  },            
};

이 모든것을 적용한 결과가 바로 아래의 화면입니다.

이제 정상적으로 보여지기 때문에, 위의 분리된 영역에 component를 호출하도록 하겠습니다. 

 

[Dashboard.vue]

<v-card class="mx-auto" elevation="2" style="height: 330px;">
  <v-card-text>
    <v-row align="center">
      <!-- Left Chart Area -->
      <v-col cols="4" align="center" style="height: 330px;">
        <doughnut-chart :chart-data="doughnutCollection" :options="doughnutOptions" style="height: 330px;"></doughnut-chart>
      </v-col>
      <!-- Left Chart Area -->
      <!-- Right Data List Area -->
      <v-col cols="8">

      </v-col>
      <!-- Right Data List Area -->
    </v-row>
  </v-card-text>
</v-card>




<script>
import doughnutChart from '@/components/chart/DoughnutChart';

export default {
  components: {
    doughnutChart,
  },

당연히 해당 vue파일을 import해주고 components에도 추가해 줍니다. 이렇게 doughnut chart영역은 마무리가 되었습니다.

 



 

3. 정보표시 영역


정보 표시 영역은 아무래도 axios.get을 통해서 가져온 데이터를 화면에 뿌려주기 때문에 어렵지 않습니다. list로 뿌려주기 위해서는 여러가지 방법을 사용하는데, 기존에 vue.js 글 중에서 v-data-table을 활용해서 dataset으로 가져온 항목을 table형태로 구현하는 방법에 대해서 알아보았습니다.

 

이번에는 v-data-table이 아닌 v-for를 통해서 반복수행하는 방법으로 구현하였습니다. 

 

[핵심코드]

<!-- Right Data List Area -->
<v-col cols="8">
  <!-- 상단 제목 -->
  <v-list-item two-line>
    <v-list-item-content>
      <v-list-item-title class="headline">
      	{{searchCondition.bsnsYear}}년 {{searchCondition.bsnsQuarter}}분기 우량주
      </v-list-item-title>
      <v-list-item-subtitle>
      	ROE 3.0이상 + 시가총액 5,000억 이상
      </v-list-item-subtitle>
    </v-list-item-content>
  </v-list-item>
  <!-- 상단 제목 -->
  <v-divider></v-divider>
  <!-- 하단 리스트 -->
  <v-list one-line>
    <v-list-item-group v-model="selected1" active-class="pink--text">
      <template v-for="(item, index) in qssListPerUserItem">
        <v-list-item :key="item.stocksId"  @click="stockDetailInfo(item)">
          <template v-slot:default="{active}">
            <v-list-item-content>
              <v-list-item-title v-text="item.stocksName + ' ('  + item.stocksId + ')'"></v-list-item-title>
              <v-list-item-subtitle v-text="'ROE '+item.stocksRoe+', PBR '+item.stocksPbr+' 시총 '+item.stocksMarketcap"></v-list-item-subtitle>
            </v-list-item-content>
            <v-list-item-action>
              <v-list-item-action-text v-text="'TOP '+(index+1)"></v-list-item-action-text>
              <v-icon v-if="!active" color="grey lighten-1">mdi-star</v-icon>
              <v-icon v-else color="yellow darken-3">mdi-star</v-icon>
            </v-list-item-action>
          </template>
        </v-list-item>
        <v-divider/>
      </template>            
    </v-list-item-group>
  </v-list>
  <!-- 하단 리스트 -->
</v-col>
<!-- Right Data List Area -->

이 부분은 디자인 적인 요소도 포함되어 있기때문에, 디자인 적인 내용은 줄이고 코드적인 부분만 살펴보도록 하겠습니다. 우선 상단의 제목은 <v-list-item>으로 구현을 하고, 구분선을 <v-divider/>로 주어 구분해 줍니다.

 

그 아래가 우량주 중 저평가 종목에 대한 리스트를 뿌려주는 부분입니다. 여기서 중요한 부분은 v-for로 axios.get을 통해서 받아온 우량주 종목을 반복문을 통해서 그려주고, 각 반복되는 item에 대해서 click event를 넣어서 특정 methods를 동작하게 합니다.

 [반복로직]
 <template v-for="(item, index) in qssListPerUserItem">
 
 [click event로직]
 <v-list-item :key="item.stocksId"  @click="stockDetailInfo(item)">

여기서 index는 python에 의하면 enumerate에 해당하는 dataset내 해당 data의 순번이고, item은 실제 해당 data를 의미합니다. 따라서 data에는 해당 종목에 대한 모든 정보가 들어가 있게 됩니다. 따라서, click event로 item을 넘겨주면, 해당 데이터를 가지고 여러가지 일을 할 수 있게 되는 것 입니다.

 

@click에 대해서는 추후에 관련 dashboard내 card로 별도 설명하겠습니다.

 

이번에는 axios.get으로 우량주 종목을 가져오는 로직을 살펴보겠습니다.

    getQSSListPerUser() {
      const url = '/qss/listPerUser';
      axios.get(url, {
        params: {
          bsnsYear: this.searchCondition.bsnsYear,
          bsnsQuarter: this.searchCondition.bsnsQuarter,
          userId: this.searchCondition.userId,
        },
      }).then((res) => {
        this.qssListPerUserItem = res.data;
        this.doughnutCollection1 = {
          labels: ["저평가 항목", "우량주 전체"],
          datasets: [
            {
              borderWidth: 5,
              backgroundColor: ["#F48FB1", "#AAAAAA"],
              hoverBackgroundColor: ["#F48FB1", "#AAAAAA"],
              hoverBorderColor: ["#F48FB1", "#FFFFFF"],
              data: [this.qssListPerUserItem.length, this.stockListAllCount],
              datalabels: { anchor: 'end' },
            }
          ],
        };
        this.doughnutOptions1 = { };
      }).catch((error) => {
        console.log(error);
      }).then(() => {
        console.log('getQSSListPerUser End!!');
      });
    },

AT-Back에서 작성한 QSSController에서 작성된 RequestMapping 주소 중에서 listPerUser를 사용합니다. 해당 API는 parameter를 추가하여 전송해야하기 때문에, params: { }를 추가해 줍니다. API로부터 응답이 오면 res.data를 두군데의 변수에 넣어줘야 합니다.

 

  • 첫째, v-for로 반복 list를 구현할 this.qssListPerUserItem 변수에 넣어주고,
  • 둘째, doughnut chart에 그려주기 위한 data영역에 넣어주기

 

doughnut chart에서는 어차피 API를 통해서 받아온 dataset의 개수만 활용하기 때문에 length로 값을 구해서 인자로 넣어주면 됩니다. 이렇게 대시보드의 첫번째 줄의 첫번째 카드가 완성되었습니다. 

 

다음에는 첫번째 줄의 두번째, 세번째 카드에 대한 구현에 대해서 알아보겠습니다.

 

- Ayotera Lab -

댓글