Flask+Vue前后端分离疫情可视化系统

一、引言

在2020年初爆发的新型冠状病毒,是一种传染力极强的病毒。患者在感染了新型冠状病毒后,即使在潜伏期也很容易传染其他人,该病毒会导致人呼吸困难,严重的可能会导致死亡。时至今日,疫情仍未完全褪去,新冠疫情仍是全世界人民最关注的话题之一,特别是有些国家仍处于爆发期。因此,疫情的实时数据以及相关新闻报导受到了极大的关注。本系统利用数据爬虫技术,完成疫情数据以及疫苗接种数据的爬取经数据处理后形成数据集。利用数据可视化技术,对数据集进行可视化,实现疫情情况与疫苗接种情况的实时更新。帮助民众充分了解最新疫情数据、近期疫情发展趋势以及疫苗接种情况。


Flask 框架是一个轻量级的、便捷的、Python 所提供的 Web 框架,它更加的灵活、轻便、安全且容易上手,是目前主流的服务器框架,非常适合全队的分工 协作式开发,对一个小型团队而言,大大提升了开发的效率。利用 Flask框架,实现前后端的数据交互,其对应的前端 JinJa2的模板引擎,也极大地方便了前端的数据调用。

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。   与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用(SPA)提供驱动。简单小巧的核心,渐进式技术栈,足以应付任何规模的应用。

 本系统则采用后端Flask+前端Vue的开发模型进行开发。


二、现有技术研究

目前,比较成熟的疫情数据可视化平台有:网易可视化平台、腾讯疫情数据可视化平台、 百度疫情数据可视化平台。这三家数据可视化平台内容分析,如图1所示。

 现有技术的实现均是通过对大量的疫情数据进行 爬取、数据处理,利用可视化技术进行数据的可视化。 本系统集全国疫情数据于一个页面中,让用户可以更直观的观察到疫情信息。并且,本系统在疫情分布图上做出创新,在全国疫情分布图中点击各省份,直接可查看当前省份的疫情数据。用户可以由全国疫情分布图直接进入各省份疫情分布图,了解各省份的疫情分布。


三、系统架构和实现流程

 四、系统运行流程

 五、数据爬取与处理(网易接口)

说明

ChinaTotal

中国疫情总数据

Today

今日疫情数据

Total

总计疫情数据

Confirm

确证人数

Suspect

疑似病例

Heal

康复人数

Dead

死亡人数

Input

境外输入人数

NoSymptom

无症状感染者人数

IncrNosymptom

无症状感染者较昨日增加人数

curedCount

治愈总人数

curedIncr

较昨日治愈增长人数


六、部分代码展示

  • 后端(三个接口):

from flask import Flask,jsonify
import requests,json,time
app=Flask(__name__)
@app.route('/overall')
def get_data_overall():
    now = time.localtime()
    nowt = time.strftime("%Y-%m-%d %H:%M:%S", now)
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
        'referer': 'https://news.qq.com/',
    }
    url='https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=329222187209'
    res=requests.get(url=url,headers=headers).json()
    if res:
        json_overall={
            "success":True,
            "code": 200,
            "message": "操作成功",
            "data":{
                "confirmedCount": res.get('data').get('chinaTotal').get('total').get('confirm'),
                "confirmedIncr": res.get('data').get('chinaTotal').get('today').get('confirm'),
                "curedCount": res.get('data').get('chinaTotal').get('total').get('heal'),
                "curedIncr": res.get('data').get('chinaTotal').get('today').get('heal'),
                "currentConfirmedCount": res.get('data').get('chinaTotal').get('total').get('confirm')- res.get('data').get('chinaTotal').get('total').get('dead')-res.get('data').get('chinaTotal').get('total').get('heal'),
                "currentConfirmedIncr": res.get('data').get('chinaTotal').get('today').get('storeConfirm'),
                "deadCount": res.get('data').get('chinaTotal').get('total').get('dead'),
                "deadIncr": 0,
                "importedCount": res.get('data').get('chinaTotal').get('total').get('input'),
                "importedIncr": res.get('data').get('chinaTotal').get('today').get('input'),
                "noInFectCount": res.get('data').get('chinaTotal').get('extData').get('noSymptom'),
                "noInFectIncr": res.get('data').get('chinaTotal').get('extData').get('incrNoSymptom'),
                "suspectIncr": 0,
                "suspectCount": res.get('data').get('chinaTotal').get('total').get('suspect'),
                "updateTime": nowt,
                "curedRate": 92.7,
                "deadRate": 4.69
            }
        }
        with open('data/covid19-overall.json','w') as f:
            json.dump(json_overall,f)
            print("json_overall文件加载完成!")
    return json_overall
@app.route('/daily')
def get_daily():
    now = time.localtime()
    nowt = time.strftime("%Y-%m-%d %H:%M:%S", now)
    today=time.strftime("%Y-%m-%d")

    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
        'referer': 'https://news.qq.com/',
    }
    url = 'https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=329222187209'
    res = requests.get(url=url, headers=headers).json()
    importedIncrList=[]
    curedCountList=[]
    confirmedCountList=[]
    importedCountList=[]
    currentConfirmedIncrList=[]
    noInFectCountList=[]
    currentConfirmedCountList=[]
    for i in res.get('data').get('chinaDayList'):
        importedIncrList.append([i.get('date'),i.get('today').get('input')])
        curedCountList.append([i.get('date'),i.get('today').get('confirm')])
        confirmedCountList.append([i.get('date'),i.get('total').get('confirm')])
        importedCountList.append([i.get('date'),i.get('total').get('input')])
        currentConfirmedIncrList.append([i.get('date'),i.get('total').get('heal')])
    # 无症状
    noInFectCountList.append([today,res.get('data').get('chinaTotal').get('extData').get('noSymptom')])
    if res:
        json_daily={
            "success":True,
            "code": 200,
            "message": "操作成功",
            "data": {
                # 境外输入
                "importedIncrList": importedIncrList,
                # 现有确诊
                "curedCountList": curedCountList,

                "confirmedCountList":confirmedCountList ,
                "currentConfirmedIncrList": currentConfirmedIncrList,
                "importedCountList": importedCountList,
                # 无症状
                "noInFectCountList":noInFectCountList ,
                "currentConfirmedCountList":currentConfirmedCountList
            }
        }
        with open('data/covid19-daily-list.json','w') as f:
            json.dump(json_daily,f)
            print("json_daily文件加载完成!")
    return json_daily
@app.route('/province')
def get_province():
    now = time.localtime()
    nowt = time.strftime("%Y-%m-%d %H:%M:%S", now)
    today = time.strftime("%Y-%m-%d")
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36',
        'referer': 'https://news.qq.com/',
    }
    url = 'https://c.m.163.com/ug/api/wuhan/app/data/list-total?t=329222187209'
    res = requests.get(url=url, headers=headers).json()
    data=[]
    province=res.get('data').get('areaTree')[2].get('children')
    for i in province:
        if i.get('total').get('dead')==0:
            province_dict = {
                "confirmedCount": i.get('total').get('confirm'),
                "countryLabel": "中国",
                "countryName": "China",
                "curedCount": i.get('today').get('heal'),
                "curedRate": i.get('today').get('heal') / i.get('total').get('heal'),
                "currentConfirmedCount": i.get('today').get('confirm'),
                "deadCount": i.get('today').get('dead'),
                "deadRate": 0 ,
                "provinceLabel": i.get('name'),
                "provinceName": None,
                "suspectCount": 0,
                "todayConfirmedCount": 0,
                "updateTime": None
            }
        else:
            province_dict = {
                "confirmedCount": i.get('total').get('confirm'),
                "countryLabel": "中国",
                "countryName": "China",
                "curedCount": i.get('today').get('heal'),
                "curedRate": i.get('today').get('heal') / i.get('total').get('heal'),
                "currentConfirmedCount": i.get('today').get('confirm'),
                "deadCount": i.get('today').get('dead')/i.get('total').get('dead'),
                "deadRate": 0,
                "provinceLabel": i.get('name'),
                "provinceName": None,
                "suspectCount": 0,
                "todayConfirmedCount": 0,
                "updateTime": None
            }
        data.append(province_dict)
    if res:
        json_province={
            "success": True,
            "code": 200,
            "message": "操作成功",
            "data":data
        }
        with open('data/covid19-province.json', 'w') as f:
            json.dump(json_province, f)
            print("json_province文件加载完成!")
    return json_province
if __name__ == '__main__':
    get_daily()
    get_province()
    get_data_overall()
    app.run(port=8080)
#前后端分离 首先启动后端 爬取当日的数据 由于腾讯接口使用的人比较多 所以我们这次选取的是网易接口

#然后启动前端 npm run dev 因为采用的vue
  •  前端(引用蓝伟洪先生​​​​​​​模板)

    <template>
      <div class="container">
        <!-- 顶部 -->
        <div class="top-header">
          <div class="title">
            <h1>{{ title }}</h1>
            <div class="top-header-tip">
              <div class="sub-title">此数据为实时真实数据,数据来源:网易新闻</div>
              <div class="last-update-time">
                更新时间:{{ basicData.updateTime }}
              </div>
            </div>
          </div>
        </div>
        <div class="main-content">
          <el-row>
            <el-col :span="18">
              <!-- 中间信息开始 -->
              <div class="statistics-content">
                <!-- 中间左侧开始 -->
                <div class="main-inner">
                  <el-row>
                    <el-col :span="7">
                      <chart-card
                        title="累计排名(TOP 10)"
                        :customClass="`chart-item-bottom-sep`"
                      >
                        <province-ranking-bar-chart
                          ref="topConfirmedCountRankChart"
                          :data="top10ProvinceData"
                          style="width: 100%; height: 380px"
                        />
                      </chart-card>
                      <!-- 占比 -->
                      <chart-card
                        title="占比"
                        :customClass="`chart-item-bottom-sep`"
                      >
                        <basic-proportion-chart
                          ref="basicProportionChart"
                          :data="basicData"
                          style="width: 100%; height: 120px"
                        />
                      </chart-card>
                      <chart-card title="最近一周累计治愈">
                        <current-confirmed-compare-bar-chart
                          ref="confirmSingleBarChart"
                          :data="confirmSingleBarChartData"
                          style="width: 100%; height: 310px"
                        />
                      </chart-card>
                    </el-col>
                    <el-col :span="17">
                      <!-- 顶部基本统计信息开始 -->
                      <div class="basic-header flex">
                        <!-- 顶部统计信息开始 -->
                        <div class="top-basic-info">
                          <basic-data-item-label
                            label="现有确诊"
                            :config="defaultDataConfig.currentConfirmedCount"
                            :inCrValue="basicData.currentConfirmedIncr"
                          />
                          <basic-data-item-label
                            label="累计确诊"
                            :config="defaultDataConfig.confirmedCount"
                            :inCrValue="basicData.confirmedIncr"
                          />
                          <!-- 境外输入 -->
                          <basic-data-item-label
                            label="境外输入"
                            :config="defaultDataConfig.importedCount"
                            :inCrValue="basicData.importedIncr"
                          />
                          <!-- 无症状感染者 -->
                          <basic-data-item-label
                            label="无症状感染者"
                            :config="defaultDataConfig.noInFectCount"
                            :inCrValue="basicData.noInFectIncr"
                          />
                          <!-- 累计治愈 -->
                          <basic-data-item-label
                            label="累计治愈"
                            :config="defaultDataConfig.curedCount"
                            :inCrValue="basicData.curedIncr"
                          />
                          <!-- 死亡人数 -->
    <!--                      <basic-data-item-label-->
    <!--                        label="累计死亡"-->
    <!--                        :config="defaultDataConfig.deadCount"-->
    <!--                        :inCrValue="basicData.deadIncr"-->
    <!--                      />-->
                        </div>
                        <!-- 顶部统计信息结束 -->
                      </div>
                      <!-- 顶部基本统计信息开始 -->
                      <div class="main-inner-map-wraper">
                        <!-- 地图 -->
                        <div class="map">
                          <data-map
                            ref="dataMap"
                            title=""
                            :list="mapDataList"
                            style="width: 100%; height: 100%"
                          />
                        </div>
                      </div>
                    </el-col>
                  </el-row>
                </div>
                <!-- 中间左侧结束 -->
              </div>
              <!-- 中间信息结束 -->
            </el-col>
            <el-col :span="6">
              <!-- 右侧区域开始 -->
              <div class="main-right">
                <!-- 治愈率和死亡率 -->
                <chart-card
                  title="治愈率和死亡率"
                  :innerClass="`cure-and-dead-rate-chart`"
                  :customClass="`chart-item-bottom-sep`"
                >
                  <cured-and-dead-rate-chart
                    ref="cureRateChart"
                    :data="rate"
                    title="治愈率"
                    style="width: 280px; height: 130px"
                  />
                </chart-card>
                <chart-card title="新增趋势" :customClass="`chart-item-bottom-sep`">
                  <basic-trend-chart
                    :data="basicIncrTrendData"
                    ref="confirmedCountTrendChart"
                    style="width: 100%; height: 320px"
                  />
                </chart-card>
                <chart-card title="">
                  <div slot="title" class="province-table-title flex">
                    各省累计确诊
                    <el-link
                      icon="el-icon-view"
                      style="color: #bcbcbf; padding-left: 10px"
                      :underline="false"
                      @click="provinceTableDialogShowHandler"
                      >详情</el-link
                    >
                  </div>
                   <dv-scroll-board
                      :config="provinceConfirmedCountBoardConfig"
                      style="width: 100%; height: 360px"
                    />
                </chart-card>
              </div>
              <!-- 右侧区域结束 -->
            </el-col>
          </el-row>
        </div>
        <!-- 其他页面 -->
        <div class="province-data-table-wrapper">
          <el-dialog
            :visible.sync="provinceTableDialogVisible"
            width="50%"
            :before-close="provinceTableDialogClose"
          >
            <div slot="title" class="province-data-modal-title">
              <p>各省数据表</p>
              <span class="province-data-modal-update-time"
                >(更新时间:{{ basicData.updateTime }})</span
              >
            </div>
            <div class="area-data-table-wrapper">
              <el-table
                class="area-data-table"
                :data="provinceDataList"
                style="width: 100%"
              >
                <el-table-column prop="provinceLabel" align="center" label="省份">
                </el-table-column>
                <el-table-column
                  prop="confirmedCount"
                  align="center"
                  label="累计确诊"
                >
                </el-table-column>
                <el-table-column
                  prop="currentConfirmedCount"
                  align="center"
                  label="现有确诊"
                >
                </el-table-column>
                <el-table-column prop="curedCount" align="center" label="累计治愈">
                </el-table-column>
                <el-table-column prop="deadCount" align="center" label="累计死亡">
                </el-table-column>
              </el-table>
            </div>
          </el-dialog>
          <!-- 关于弹窗 -->
          <el-dialog
            title="关于"
            :visible.sync="aboutDialogVisible"
            width="30%"
            :before-close="aboutDialogClose"
          >
            <about />
          </el-dialog>
          <!-- 关于图标 -->
          <div class="about-wraper">
            <i
              class="el-icon-info"
              style="font-size: 30px"
              @click="aboutDialogShowHandler"
            ></i>
          </div>
        </div>
      </div>
    </template>
    <script>
    import ChartCard from '../components/ChartCard'
    import DataMap from '../components/DataMap'
    import CuredAndDeadRateChart from '../components/CuredAndDeadRateChart'
    import BasicDataItemLabel from '../components/BasicDataItemLabel'
    import BasicTrendChart from '../components/BasicTrendChart'
    import ProvinceRankingBarChart from '../components/ProvinceRankingBarChart'
    import CurrentConfirmedCompareBarChart from '../components/CurrentConfirmedCompareBarChart'
    import About from '../components/About'
    import BasicProportionChart from '../components/BasicProportionChart'
    
    import covid19Service from '../api/covid19'
    
    const formatter = (number) => {
      const numbers = number.toString().split('').reverse()
      const segs = []
      while (numbers.length) segs.push(numbers.splice(0, 3).join(''))
      return segs.join(',').split('').reverse().join('')
    }
    // 数据样式
    const getNumberStyle = (color = '#E8EAF6', fontSize = 30, fontWeight = 'bolder') => {
      return {
        fontSize: fontSize,
        fill: color,
        fontWeight: fontWeight
      }
    }
    
    const initBasicConfig = (data = null) => {
      let currentConfirmedCount = data ? [data.currentConfirmedCount] : 0
      let confirmedCount = data ? [data.confirmedCount] : 0
      let importedCount = data ? [data.importedCount] : 0
      let noInFectCount = data ? [data.noInFectCount] : 0
      let deadCount = data ? [data.deadCount] : 0
      let curedCount = data ? [data.curedCount] : 0
      return {
        confirmedCount: {
          number: [confirmedCount],
          content: '{nt}',
          formatter,
          style: getNumberStyle()
        },
        currentConfirmedCount: {
          number: [currentConfirmedCount],
          content: '{nt}',
          formatter,
          style: getNumberStyle('#2E8EEA')
        },
        importedCount: {
          number: [importedCount],
          content: '{nt}',
          formatter,
          style: getNumberStyle()
        },
        noInFectCount: {
          number: [noInFectCount],
          content: '{nt}',
          formatter,
          style: getNumberStyle()
        },
        deadCount: {
          number: [deadCount],
          content: '{nt}',
          formatter,
          style: getNumberStyle('#D32E58')
        },
        curedCount: {
          number: [curedCount],
          content: '{nt}',
          formatter,
          style: getNumberStyle()
        }
      }
    }
    
    const initProvinceConfirmedCountBoardConfig = (resultList = []) => {
      return {
        header: ['省份', '累计确诊', '累计治愈', '累计死亡'],
        headerHeight: 30,
        data: resultList,
        align: ['center'],
        rowNum: 10,
        index: true,
        indexHeader: '排名',
        headerBGC: '',
        oddRowBGC: '',
        evenRowBGC: '',
        carousel: 'single'
      }
    }
    export default {
      components: {
        ChartCard,
        DataMap,
        CuredAndDeadRateChart,
        BasicDataItemLabel,
        BasicTrendChart,
        ProvinceRankingBarChart,
        CurrentConfirmedCompareBarChart,
        About,
        BasicProportionChart
      },
      data () {
        return {
          title: '全国新冠肺炎疫情数据大屏',
          provinceTableDialogVisible: false,
          aboutDialogVisible: false,
          commonData: {},
          basicData: {
            currentConfirmedCount: 0,
            currentConfirmedIncr: 0,
            confirmedCount: 0,
            confirmedIncr: 0,
            curedCount: 0,
            curedIncr: 0,
            deadCount: 0,
            deadIncr: 0,
            sure: 0,
            sureAdd: 0,
            importedCount: 0,
            importedIncr: 0,
            noInFectCount: 0,
            noInFectIncr: 0,
            suspectCount: 0,
            suspectIncr: 0,
            updateTime: '2022-3-1'
          },
          defaultDataConfig: initBasicConfig(),
          cureRateConfig: {
            data: [0],
            shape: 'round'
          },
          deadRateConfig: {
            data: [0],
            shape: 'round'
          },
          countryRankingTakeTurnChartConfig: {
            data: [],
            waitTime: 2000,
            unit: '单位',
            valueFormatter ({ value }) {
              const reverseNumber = (value + '').split('').reverse()
              let valueStr = ''
    
              while (reverseNumber.length) {
                const seg = reverseNumber.splice(0, 3).join('')
                valueStr += seg
                if (seg.length === 3) valueStr += ','
              }
    
              return valueStr.split('').reverse().join('')
            }
          },
          provinceConfirmedCountBoardConfig: initProvinceConfirmedCountBoardConfig(),
          provinceDataList: [],
          trendDataList: [],
          confirmedCountList: [],
          top10ProvinceData: {
            provinceList: [],
            valueList: []
          },
          basicIncrTrendData: {
            dateList: [],
            importedIncrDataList: [],
            currentConfirmedIncrDataList: []
          },
          confirmSingleBarChartData: {
            dateList: [],
            currentConfirmedCountList: [],
            confirmedCountList: []
          },
          rate: {
            curedRate: 0,
            deadRate: 0
          },
          areaData: {},
          mapDataList: []
        }
      },
      methods: {
        queryBasicData () {
          let self = this
          covid19Service.getOverall().then((res) => {
            if (!res.success) {
              console.log('错误:' + res.info)
              return
            }
            self.basicData = res.data
            self.setBasicData(res.data)
          })
        },
        queryProvinceDataList () {
          let self = this
          covid19Service.getProvinceDataList().then((res) => {
            if (!res.success) {
              // TODO 错误处理...
              console.log('错误:' + res.info)
              return
            }
            self.provinceDataList = res.data
            self.setAreaChartData(res.data)
            // 设置累计排名数据
            self.setProvinceRankingData(res.data)
            // 设置各省累计确诊轮播表格数据
            self.setProvinceComfirmedCountBoardData(res.data)
            // 设置地图数据
            self.setMapData(res.data)
          })
        },
        queryTrendDataList () {
          let self = this
          covid19Service.getDailyList().then((res) => {
            if (!res.success) {
              // TODO 错误处理...
              console.log('错误:' + res.info)
              return
            }
            self.trendDataList = res.data
            // 重置图表数据
            self.setBasicIncrTrendData(res.data)
          })
        },
        setProvinceRankingData (areaList) {
          let provinceList = []
          let dataValueList = []
          for (let i = 0; i < 10; i++) {
            provinceList.push(areaList[i].provinceLabel)
            dataValueList.push(areaList[i].confirmedCount)
          }
          let data = {
            provinceList: provinceList,
            valueList: dataValueList
          }
          this.top10ProvinceData = data
        },
        setBasicIncrTrendData (data) {
          let dateList = []
          let currentConfirmedIncrList = []
          let importedIncrList = []
    
          let sevenDayDateList = []
          // 仅显示一周条数据
          let confirmedCountList = []
          let curedCountList = []
          // 仅获取7条数据
          let count = 7
          let noInFectDataList = []
    
          for (let i = data.currentConfirmedIncrList.length - 1; i >= 0; i--) {
            dateList.push(data.currentConfirmedIncrList[i][0])
            currentConfirmedIncrList.push(data.currentConfirmedIncrList[i][1])
          }
          for (let i = data.importedIncrList.length - 1; i >= 0; i--) {
            importedIncrList.push(data.importedIncrList[i][1])
          }
          for (let i = data.noInFectCountList.length - 1; i >= 0; i--) {
            noInFectDataList.push(data.noInFectCountList[i][1])
          }
    
          for (let i = count; i >= 0; i--) {
            if (confirmedCountList.length >= count) {
              break
            }
            sevenDayDateList.push(data.confirmedCountList[i][0])
            confirmedCountList.push(data.confirmedCountList[i][1])
          }
          for (let i = count; i >= 0; i--) {
            if (curedCountList.length >= count) {
              break
            }
            curedCountList.push(data.curedCountList[i][1])
          }
    
          this.basicIncrTrendData = {
            dateList: dateList,
            importedIncrDataList: importedIncrList,
            currentConfirmedIncrDataList: currentConfirmedIncrList,
            noInFectDataList: noInFectDataList
          }
          this.confirmSingleBarChartData = {
            dateList: sevenDayDateList,
            curedCountList: curedCountList,
            confirmedCountList: confirmedCountList
          }
        },
        setProvinceComfirmedCountBoardData (areaList) {
          let resultList = areaList.map(item => {
            return [item.provinceLabel, item.confirmedCount, item.curedCount, item.deadCount]
          })
          // 重新生成,否则无法刷新状态
          this.provinceConfirmedCountBoardConfig = initProvinceConfirmedCountBoardConfig(resultList)
        },
        setAreaChartData (areaList) {
          let confirmedCountList = []
          let provinceList = []
          let curedCountList = []
          let deadCountList = []
          areaList.forEach(item => {
            provinceList.push(item.provinceLabel)
            confirmedCountList.push(item.confirmedCount)
            curedCountList.push(item.curedCount)
            deadCountList.push(item.deadCount)
          })
          this.areaData = {
            provinceList: provinceList,
            confirmedCountList: confirmedCountList,
            curedCountList: curedCountList,
            deadCountList: deadCountList
          }
        },
        setMapData (dataList) {
          let list = dataList.map(item => {
            return {
              name: item.provinceLabel,
              value: item.confirmedCount
            }
          })
          this.mapDataList = list
        },
        provinceTableDialogShowHandler () {
          this.provinceTableDialogVisible = true
        },
        provinceTableDialogClose () {
          this.provinceTableDialogVisible = false
        },
        aboutDialogShowHandler () {
          this.aboutDialogVisible = true
        },
        aboutDialogClose () {
          this.aboutDialogVisible = false
        },
        setBasicData (data) {
          // 重新生成,否则视图不更新
          let config = initBasicConfig(data)
          this.defaultDataConfig = config
          // 处理治愈率和死亡率
          this.rate = {
            curedRate: data.curedRate / 100,
            deadRate: data.deadRate / 100
          }
        },
        startQueryData () {
          this.queryBasicData()
          this.queryProvinceDataList()
          this.queryTrendDataList()
        },
        initAllChart() {
          this.$refs.dataMap.initChart()
          this.$refs.cureRateChart.initChart()
          this.$refs.confirmedCountTrendChart.initChart()
          this.$refs.topConfirmedCountRankChart.initChart()
          this.$refs.confirmSingleBarChart.initChart()
          this.$refs.basicProportionChart.initChart()
        }
      },
      mounted () {
        this.initAllChart()
        this.startQueryData()
    
        let self = this
        // 定义定时器,隔 5 秒刷新一次
        this.timer = setInterval(() => {
          self.startQueryData()
        }, 5000)
      },
      beforeDestroy() {
        clearInterval(this.timer)
      }
    }
    </script>
    <style>
    .container {
      position: relative;
    }
    h1 {
      font-size: 35px;
      font-weight: bold;
      padding: 20px;
    }
    .flex {
      display: flex;
    }
    .top-header {
      position: relative;
      margin-bottom: 10px;
    }
    .top-header-tip {
      font-size: 14px;
      position: absolute;
      padding: 20px 20px;
      text-align: right;
      top: 0;
      right: 0;
    }
    .title {
      min-width: 350px;
    }
    .chart-card {
      background: #0f142b;
      border-radius: 10px;
      margin: 0 20px;
    }
    .main-inner-map-wraper {
      height: 100%;
      margin: 0 20px;
    }
    .map {
      width: 99%;
      height: 840px;
      padding: 20px 10px 10px 10px;
    }
    .province-scroll-board-wrapper {
      padding-top: 10px;
      padding-bottom: 10px;
    }
    .chart-item-bottom-sep {
      margin-bottom: 20px;
    }
    .province-table-title {
      color: #fff;
      font-size: 16px;
      font-weight: bold;
      padding: 10px 10px 10px 20px;
      text-align: left;
    }
    .basic-incr-trend-chart-wrapper {
      padding-bottom: 10px;
    }
    .sub-title,
    .last-update-time,
    .province-scroll-board-wrapper ::v-deep .dv-scroll-board .header,
    .province-scroll-board-wrapper ::v-deep .dv-scroll-board .rows {
      font-size: 14px;
    }
    .province-scroll-board-wrapper ::v-deep .dv-scroll-board .rows {
      color: #bcbcbf;
    }
    .province-data-modal-title {
      color: #000;
      font-size: 20px;
      font-weight: bold;
    }
    .province-data-modal-update-time {
      color: #58585a;
      font-size: 16px;
      font-weight: normal;
      padding-top: 10px;
      display: block;
    }
    .cure-and-dead-rate-chart {
      display: flex;
      justify-content: space-around;
    }
    .top-basic-info {
      display: flex;
    }
    .dv-scroll-ranking-board .ranking-column .inside-column {
      background: linear-gradient(90deg, #29bfff, #a231ff, #0deccd, #29bfff);
    }
    .chart-item-container {
      margin: 0 10px;
    }
    .about-wraper {
      position: fixed;
      bottom: 20px;
      right: 20px;
    }
    </style>

    七、成品展示

 

 

 

 

 结束语

截至到 2022年 3 月,疫情仍未完全褪去,民众最为关心的是疫苗接种情况。本系统基于疫情数据显 示的基础上,增加疫苗数据显示功能。利用数据爬虫 技术完成数据的获取与下载,经数据处理后形成数据 集,数据可视化阶段利用 Python 语言的 Flask 框架、 Vue、ECharts可视化等可视化技术,对疫情数据以及疫苗数据进行数据可视化。经过对现有技术的分析,并在可 视化内容上做出创新。集可视化内容于一个页面中, 疫情数据与疫苗数据一目了然,用户可以从多方面,多角度,全方位直观的观察到疫情数据、疫情发展 趋势,以及疫苗接种情况。本系统的开发是用来帮助 民众充分了解全国各地的疫情情况、近期的疫情发展 趋势以及疫苗接种情况。

  • 17
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值