vue全家桶+Echarts+百度地圖,搭建數(shù)據(jù)可視化系統(tǒng)(【續(xù)】接口篇)

接上篇

vue全家桶+Echarts+百度地圖,搭建數(shù)據(jù)可視化系統(tǒng)

1 前 言

1.1 業(yè)務(wù)場(chǎng)景

實(shí)現(xiàn)數(shù)據(jù)監(jiān)控的系統(tǒng)。有線圖、柱狀圖、地圖,并具有定時(shí)刷新的功能。

1.2 業(yè)務(wù)分析

上一篇分析的步驟大致有:

  1. 系統(tǒng)搭建vue-cli
  2. vuex記錄登錄信息
  3. vue-router路由跳轉(zhuǎn)
  4. 3個(gè)維度的頁(yè)面,提取出共用的組件
  5. 各個(gè)組件開(kāi)發(fā)
  6. 調(diào)節(jié)樣式,增加UI
  7. 加入后臺(tái)接口數(shù)據(jù)
  8. 優(yōu)化顯示
  9. 測(cè)試
  10. 上線

上一篇介紹了 1-6 部分。本篇將介紹一下剩下的 7-10 部分。

????

主要內(nèi)容是 <font color=red>對(duì)數(shù)據(jù)的處理方式</font> 和 <font color=red>整體的數(shù)據(jù)邏輯</font> 。

望各位看官多提 建議和不足 哈,也希望能本篇能給需要人帶來(lái) 啟發(fā)。

成品效果圖不方便發(fā),還是用上一篇,純前端的效果圖吧。

image

2 正 文

2.1 請(qǐng)求處理數(shù)據(jù)

Vue 中 與后臺(tái)交互通常使用的是 axios

2.1.1 安 裝

npm i axios

也可通過(guò)cdn引用

2.1.2 定 義

新建一個(gè)api.js

//  api.js
import axios from 'axios'
const http = axios.create ({
    baseURL : apiurl,       // 連接后端地址
    timeout : 1000 * 30,    // 超時(shí)時(shí)間,單位為毫秒
    headers : {},          // 請(qǐng)求頭,可添加'Authorization'、'X-Requested-With'、'Accept-Language'、'token'等
})

// 請(qǐng)求攔截
http.interceptors.request.use(config =>{
    // 可添加自己的設(shè)置,如修改參數(shù)、增加參數(shù)、修改headers
    return config
},error =>{
    // 可添加報(bào)錯(cuò)處理
    return Promise.reject(error)
})

// 響應(yīng)攔截
http.interceptors.response.use(response =>{
    // 可添加處理邏輯
    return response
},error =>{
    return Promise.reject(error)
})

export default http

同時(shí)可在main.js中添加一個(gè)自定義全局對(duì)象,或者可在單獨(dú)頁(yè)面中引用

// main.js
import http from './api.js'

Vue.prototype.$http = http

2.1.3 使 用

a. get請(qǐng)求

在頁(yè)面中處理時(shí)

query(){
    this.$http.get('/xxx/xxx?id='+id).then(res =>{
        // 返回的處理
        console.log(res)
        // res 一般包含code data
    },rej =>{
        // 報(bào)錯(cuò)的處理
        console.log(rej)
    })
}

b. post請(qǐng)求

new(){
    this.$http.post('/xxx/xxx',{
        id : '123',
    }).then(res =>{
        // 返回的處理
        console.log(res)
        // res 一般包含code data
    },rej =>{
        // 報(bào)錯(cuò)的處理
        console.log(rej)
    })
}

c. 其他請(qǐng)求

經(jīng)常使用到的還有

put 多用于更新操作

delete 多用于刪除操作

具體要看后臺(tái)提供的功能接口方式

d. 多個(gè)請(qǐng)求

比如,我在進(jìn)來(lái)頁(yè)面后,要同時(shí)獲取要2個(gè)線形圖、數(shù)字、地圖、柱狀圖、表格的數(shù)據(jù)

一般情況下,各個(gè)數(shù)據(jù)都是單獨(dú)的接口來(lái)提供的。這樣我們就需要至少6個(gè)接口。

async query(){
    let that = this
    await axios.all([that.get1(), that.get2(), that.get3()]).then(axios.spread((res1, res2, res3) =>{
        // res1 為 get1 的返回
        // res2 為 get2 的返回
        // res3 為 get3 的返回
    }))
}

get1(){
    return this.$http.get('/xxx/xxx')
}

get2(){
    return this.$http.get('/xxx/xxx')
}

get3(){
    return this.$http.get('/xxx/xxx')
}

2.2 登 錄

功能很簡(jiǎn)單,用戶輸入用戶名、密碼、驗(yàn)證碼,點(diǎn)擊登錄。

2.2.1 獲取uuid

出于對(duì)登錄時(shí)效以及安全性的考慮。在登錄驗(yàn)證時(shí),后臺(tái)根據(jù) uuid 和通過(guò) uuid 獲取到的驗(yàn)證碼進(jìn)行校驗(yàn)。

這里列出一些獲取 uuid 的方法。來(lái)源于:網(wǎng)絡(luò)。

方法一:

getUUID () {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
        return (c === 'x' ? (Math.random() * 16 | 0) : ('r&0x3' | '0x8')).toString(16)
    })
},

方法二:

generateUUID() { 
    var d = new Date().getTime()
    if (window.performance && typeof window.performance.now === "function") { 
        d += performance.now()
    }
    var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { 
        var r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16) 
        return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16)
    })
    return uuid
}

方法三:

guid() { 
    function S4() { 
        return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    } 
    return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4())
}

方法四:

/*
    指定長(zhǎng)度和基數(shù)
*/
function uuid2(len, radix) {
    var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
    var uuid = [],
        i;
    radix = radix || chars.length;

    if (len) {
        for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
    } else {
        var r;
        uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
        uuid[14] = '4';
        for (i = 0; i < 36; i++) {
            if (!uuid[i]) {
                r = 0 | Math.random() * 16;
                uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
            }
        }
    }
    return uuid.join('');
}

2.2.2 密碼加密

--input 
type="password" 可使輸入框中內(nèi)容隱藏

傳輸時(shí),我使用了md5加密

npm i -S js-md5
import md5 from 'js-md5'

let enCode = md(code)

然后就是調(diào)用后臺(tái)接口將你的用戶名、密碼、驗(yàn)證碼發(fā)送進(jìn)行驗(yàn)證登錄。

2.2.3 存儲(chǔ)登錄信息

使用過(guò) Vue 的童鞋都清楚,使用vuex的時(shí)候,進(jìn)行刷新頁(yè)面,store中的數(shù)據(jù)就會(huì)重置。

會(huì)防止用戶在刷新頁(yè)面后數(shù)據(jù)無(wú)法獲取的情況,一般會(huì)將數(shù)據(jù)同時(shí)儲(chǔ)存到 sessionStoragelocalStorage

兩者區(qū)別這里就不介紹了。

// 儲(chǔ)存session,具體放在哪個(gè)位置根據(jù)實(shí)際業(yè)務(wù)
// 我這里放在了登錄驗(yàn)證通過(guò)之后,當(dāng)然有很多參數(shù),可使用對(duì)象類型轉(zhuǎn)成json ----JSON.stringify(info)
sessionStorage.setItem('info', '123')
// store.js

store = {
    state : JSON.parse(sessionStorage.getItem('info')) || {}
}

這樣頁(yè)面刷新后,store 會(huì)從 sessionStorage 拿到我們的數(shù)據(jù)

2.3 業(yè)務(wù)頁(yè)面

業(yè)務(wù)頁(yè)面分了3個(gè)維度。

這里介紹2個(gè)維度的實(shí)現(xiàn)。

2.3.1 整體邏輯

單獨(dú)的組件只處理數(shù)據(jù)的展示

如線形圖單獨(dú)寫在一個(gè)組件中

我在需要的頁(yè)面中進(jìn)行引用,傳入數(shù)據(jù)進(jìn)行顯示。

  1. 用戶登錄驗(yàn)證后,儲(chǔ)存業(yè)務(wù) IDsession 中,從登錄頁(yè)面跳轉(zhuǎn)到 層級(jí)1 頁(yè)面。
  2. 進(jìn)入 層級(jí)1 后,created 中增加初始化方法。就是使用了上面介紹的 axios.all
  3. 拿到各數(shù)據(jù)后,分別渲染到各個(gè)組件中。
  4. 初始化完成后,觸發(fā)定時(shí)刷新開(kāi)發(fā)。
  5. 根據(jù)定時(shí)器的時(shí)間,觸發(fā)需要刷新的功能,同上 axios.all 和處理結(jié)果。
  6. 點(diǎn)擊層級(jí)1中某個(gè)數(shù)據(jù),記錄層級(jí)2需要的 ID2session中,關(guān)閉定時(shí)刷新,跳轉(zhuǎn)到 層級(jí)2 頁(yè)面。
  7. 進(jìn)入 層級(jí)2 后,同層級(jí)1,先進(jìn)行初始化,再進(jìn)行定時(shí)刷新。
  8. 層級(jí)3 以及 返回 的邏輯都基本和上面一樣。

下面介紹一些可能會(huì)有 疑問(wèn) 的地方

2.3.2 層級(jí)頁(yè)面舉例

相當(dāng)于介紹了一些父子組件的一些處理。

// 層級(jí)1.vue
<template>
    <div id="xxx">
        <a-com ref="aRef" :args="argA"/>
        <b-com ref="bRef" :args="argB"/>
    </div>
</template>

<script>
    import Acom from './a.vue'
    import Bcom from './b.vue'
    import store from './store.js'
    
    export default {
        components : {
            'a-com':Acom,
            'b-com':Bcom,
        },
        
        created(){
            //  初始化方法
            this.init()
        },
        
        mounted(){
            //  定時(shí)查詢方法
            this.timeq()
        },
        
        data() {
            return {
                //  傳入子組件的數(shù)據(jù),可可以使用store
                argA : {},
                argB : {},
                
                // 定時(shí)開(kāi)關(guān)
                timimg : false,
            }
        },
        
        methods: {
            async init(){
                let id1 = store.state.info.id1
                await this.query(id1)
                this.timimg = true
            },
            
            timeq(){
                //  這里定義了 5S 刷新一次
                let that = this
                this.timequery = setInterval(() =>{
                    if(timimg){
                        that.querytime(store.state.info.id1)
                    }
                },5000)
            },
            
            async query(id){
                let that = this
                await axios.all([that.get1(id), that.get2(id)]).then(axios.spread((res1, res2) =>{
                    // 數(shù)據(jù)傳入組件a,觸發(fā)組件a的初始化方法
                    that.argA = res1.data
                    that.$refs.aRef.init();
                    
                    // 數(shù)據(jù)傳入組件b,觸發(fā)組件b的初始化方法
                    that.argB = res2.data
                    that.$refs.bRef.init();
                }))
            },
            
            querytime(id){
                //  同 query()  
            },
            
            get1(id){
                return this.$http.get('xxx')    
            },
            
            get2(id){
                return this.$http.get('xxx')
            },
            
            //  跳轉(zhuǎn)第二層級(jí)
            goto2(){
                this.timing = false
                if(this.timequery){
                    clearInterval(this.timequery)
                }
                // replace、push, 也可以使用name 
                this.$router.replace('./path2')
            },
        }
    }
</script>

2.3.3 組件頁(yè)面舉例

// 如果使用了父組件向子組件傳值的方式,需在子組件的 data 中 定義 props 用于接收

// echarts 初始化
init(){
    // 和上篇介紹 echarts 中定義差不多
    var myChart = this.$echarts.init(document.getElementById("id"),'temp')
    let option = {}
    option = {
        // 吧啦吧啦 一頓操作和配置
        // 可參考上一篇文章,更多參考 官網(wǎng)配置頁(yè)面
        myChart.setOption(option, true)
    }
}

這里有一個(gè)需要注意的地方就是

image

橫向柱狀圖,最下方 是第一條,我們自定義標(biāo)題的時(shí)候,就要顛倒過(guò)來(lái)使用。

同時(shí)會(huì)根據(jù)條數(shù)自動(dòng)切換位置,我們的表頭也需要根據(jù)數(shù)量進(jìn)行位置調(diào)整。

2.4 測(cè) 試

說(shuō)實(shí)話,這方面一直都沒(méi)認(rèn)真寫過(guò)。。。

一般業(yè)務(wù)變動(dòng)的情況下,邏輯也會(huì)變動(dòng)頻繁。

但編寫測(cè)試代碼還是很重要的。

Vue 官方推薦的是使用 karmamochachai 等。

感興趣的 可以 專門去了解學(xué)習(xí)下

這一大塊不亞于 編寫 業(yè)務(wù)代碼 ??????

這里不多介紹了哈。

2.5 打 包

npm run build

可在根目錄中 新建 vue.config.js

官方文檔: https://cli.vuejs.org/zh/config/

//  官方文檔: https://cli.vuejs.org/zh/config/
module.exports = {
    baseUrl: process.env.NODE_ENV === 'production' ? './' : '/',
}

3 后 記

感謝支持。若不足之處,歡迎大家指出,共勉。

如果覺(jué)得不錯(cuò),記得 點(diǎn)贊,謝謝大家 ??

歡迎關(guān)注 我的: 【Github】 【掘 金】 【簡(jiǎn) 書(shū)】

本文章采用 知識(shí)共享署名-非商業(yè)性使用-相同方式共享 4.0 國(guó)際許可協(xié)議 進(jìn)行許可。

出處為:https://github.com/xrkffgg/Tools

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容