프로그래밍/Vue.js

vuejs 공공데이터 공적 마스크 판매 정보 api 사용해보기 (1)

p-a-r-k 2020. 3. 11. 18:03
반응형

(참고. https://github.com/19park/mask-finder)

10일 19시부터 건강보험심사평가원에서 제공하는 마스크 정보(판매처별 입고량, 판매량 등)를

공공데이터활용지원센터에서 오픈API형태로 제공해주길래 테스트 해봄.

 

vue 프로젝트를 하나만들기

vue create mask-finder

 

모듈 설치해주기

npm i

 

통신위한 axios와 라우팅위한 vue-router, 전역상태관리위한 vuex 설치하기

npm i axios lodash vue-router material-design-icons-iconfont
npm i -D eslint-config-airbnb-base eslint-plugin-import eslint-plugin-vue
vue add vuetify
vue add vuex

 

eslint 는 ide 오류떠서 ^5.16.0 버전으로 재설치하면 사라짐

시작해보기

npm run serve

기본화면 확인..

기본적으로 사용하는 보일러플레이트가 있지만, jest나 여러설정들을 빼고 다시세팅..

아래는 기본세팅이 완료 된 package.json 임 ㅋ

{
  "name": "mask-finder",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "axios": "^0.19.2",
    "core-js": "^3.6.4",
    "lodash": "^4.17.15",
    "vue": "^2.6.11",
    "vue-router": "^3.1.6",
    "vuetify": "^2.2.11",
    "vuex": "^3.1.2"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.2.0",
    "@vue/cli-plugin-eslint": "~4.2.0",
    "@vue/cli-plugin-vuex": "~4.2.0",
    "@vue/cli-service": "~4.2.0",
    "babel-eslint": "^10.0.3",
    "eslint": "^5.16.0",
    "eslint-config-airbnb-base": "^14.0.0",
    "eslint-plugin-import": "^2.20.1",
    "eslint-plugin-vue": "^6.2.2",
    "sass": "^1.19.0",
    "sass-loader": "^8.0.0",
    "vue-cli-plugin-vuetify": "~2.0.5",
    "vue-template-compiler": "^2.6.11",
    "vuetify-loader": "^1.3.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true,
      "es6": true
    },
    "plugins": [
      "vue"
    ],
    "extends": [
      "airbnb-base",
      "plugin:vue/essential",
      "eslint:recommended"
    ],
    "rules": {
      "import/no-unresolved": "off",
      "import/order": "off",
      "no-console": "off",
      "indent": "off",
      "linebreak-style": 0,
      "semi": [
        2,
        "always"
      ]
    },
    "parserOptions": {
      "parser": "babel-eslint"
    }
  },
  "browserslist": [
    "> 1%",
    "last 2 versions"
  ]
}

 아래는 route, store 기본세팅하고 main페이지 정의해주고 api를 분리시킨 폴더구조임

ㅇㅇㅋ

실행하면 vuetify 기본템플릿으로 layout낀 화면 확인

이제 api 이용해서 data 뿌려봄

https://www.data.go.kr/dataset/15043025/openapi.do

 

공공데이터포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Dataset)와 Open API로 제공하는 사이트입니다.

www.data.go.kr

위 api를 가지고 테스트 해보기전에 로컬이니까 proxy설정해줘야함.

/api 패스를 마스크 api url로 proxy 설정해주고

// vue.config.js
module.exports = {
    "transpileDependencies": [
        "vuetify"
    ],
    devServer: {
        disableHostCheck: true,
        proxy: {
            '/api/': {
                target: "https://8oi9s0nnth.apigw.ntruss.com/corona19-masks/v1",
                changeOrigin: true,
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
};

 

 아래 mask객체의 fetchByAddr에 넘기는 url엔 api가 없지만

api/common.js에 작성한 request함수이용해서 호출앞 url에 /api 붙여주면 proxy될거임

* 빌드하고나면 proxy안되니 참고
// src/api/index.js
import api from '@/api/common';

function jsonToQueryString(json) {
    if (!json) return '';
    return '?' +
        Object.keys(json).map(function (key) {
            if (json[key] instanceof Array) {
                let query = [];
                for (let i = 0;i < json[key].length;i++) {
                    query.push(encodeURIComponent(key) + '=' +
                             encodeURIComponent(json[key][i]));
                }
                return query.join('&');
            } else {
                return encodeURIComponent(key) + '=' +
                    encodeURIComponent(json[key]);
            }
        }).join('&');
}

export const mask = {
    fetchByAddr(data) {
        return api.request({
            method: 'get',
            url: `/storesByAddr/json${jsonToQueryString(data)}`
        });
    }
};

export default mask;

 그럼 src/pages/Main.vue 에서 가져와보자..

mask 객체를 import해서 fetchByAddr을 실행해보자..

<template>
    <v-container fluid>
        {{result}}
    </v-container>
</template>

<script>
    import {mask} from '@/api';

    export default {
        name: "Main",
        data() {
            return {
              result: []
            };
        },
        created() {
            mask
                .fetchByAddr()
                .then(res => {
                    console.log(res.data);
                    this.result = res.data.stores;
                }).catch(console.log);
        }
    };
</script>

<style scoped>

</style>

음.. 잘가져온다..

res.data를 찍은 콘솔
vue data에 저장해본 res.data.stores

조금 보기좋게 바꿔보자..

v-list 사용하고 vuetify icon설정을 md로 세팅한다.

// src/plugins/vuetify.js
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
import 'material-design-icons-iconfont/dist/material-design-icons.css'; // Ensure you are using css-loader

Vue.use(Vuetify);

export default new Vuetify({
    icons: {
        iconfont: 'md',
    },
});

 

// Main.vue
<template>
    <v-container fluid>
        <v-list three-line>
            <v-subheader>마스크 판매처 정보</v-subheader>
            <template v-for="(item, index) in list.items">
                <v-list-item
                    :key="item.code"
                    @click="() => {}"
                >
                    <v-list-item-content>
                        <v-list-item-title>{{item.name}}</v-list-item-title>
                        <v-list-item-subtitle v-html="item.addr"></v-list-item-subtitle>
                    </v-list-item-content>
                    <v-list-item-action>
                        <v-list-item-action-text>{{item.remain_stat | formatStat}}</v-list-item-action-text>
                        <v-icon
                            v-if="getStatColor(item.remain_stat)"
                            :color="getStatColor(item.remain_stat)"
                        >
                            star_border
                        </v-icon>
                    </v-list-item-action>
                </v-list-item>
                <v-divider
                    :key="index"
                ></v-divider>
            </template>
        </v-list>
    </v-container>
</template>

<script>
    import {mask} from '@/api';

    export default {
        name: "Main",
        data() {
            return {
                list: {
                    items: []
                }
            };
        },
        filters: {
            formatStat(stat) {
                switch (stat) {
                    case "plenty": return '100개 이상';
                    case "some": return '30개이상';
                    case "few": return '2개이상';
                    case "empty": return '';
                }
            }
        },
        methods: {
            getStatColor(stat) {
                switch (stat) {
                    case "plenty": return 'green';
                    case "some": return 'yellow';
                    case "few": return 'red';
                    case "empty": return '';
                }
            }
        },
        created() {
            mask
                .fetchByAddr()
                .then(res => {
                    console.log(res.data);
                    this.list.items = res.data.stores;
                }).catch(console.log);
        }
    };
</script>

<style scoped>

</style>

리스트 형태로 출력 확인

리스트 형태로 개수확인해서 색표시까지 해보았다.. (디폴트로 "서울특별시 강남구" 가져옴)

근데 332개 가져오느라 시간이 꽤나 걸린다. 페이징이 없나.. (아직 api 잘 안살펴보긴했음)

 

lat, lng 도 있어서 지도에도 뿌릴수있을거고, 마커색상도 줄 수 있을것같다.

일단은 조회조건에 address (ex/ 서울특별시 강남구) 형태로 넘길수가 있으니,

조회조건을 ui에 추가해봐야 할듯 싶다.

반응형