# NewCoronetDigitalLargeScreen **Repository Path**: renyumeng0301/NewCoronetDigitalLargeScreenFrontend ## Basic Information - **Project Name**: NewCoronetDigitalLargeScreen - **Description**: 新冠疫情相关的可视化大屏 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2022-04-22 - **Last Updated**: 2025-08-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # frontend ## 1.Project setup ``` npm install ``` ### 2.Compiles and hot-reloads for development ``` npm run serve ``` ### 3.Compiles and minifies for production ``` npm run build ``` ### 4.Technology stack 前端:Vue+data-V+axios+echarts+flexible 脚手架:Vue cli 后端:flask 数据来源:新浪和网易的疫情数据api ### 5.Frontend and backend structure 项目结构(组件部分): ``` components. │ AllCharts.vue │ Header.vue │ Left.vue │ Middle.vue │ Right.vue │ Time.vue │ ├───LeftPanel │ PanelBar.vue │ PanelLine.vue │ Shuffling.vue │ ├───MiddlePanel │ Map.vue │ Total.vue │ └───RightPanel PanelBar.vue PanelLine.vue PanelPie.vue ``` 设计思路: 用flexible将页面分割成24个部分,然后将整体元素拆分成两个大的组件: 1. Header部分 2. AllCharts部分 #### 5.1 Header部分设计思路 为了方便维护代码,将Header的时间显示拆分成Header的一个子组件,所以现在Header的结构为(css部分忽略): ```vue //Header.vue ``` Time组件为Header组件的子组件,我们要**做到时间实时刷新,并且要与现在的时间同步**,那么可以使用`Date.parse(new Date())`获取当前时间戳,并且通过dayjs这个第三方库将时间转换成`YYYY年MM月DD日 hh:mm:ss`,然后在`mounted`这个生命周期钩子里面开启定时器,并在`beforeDestroy`这个生命周期钩子里面摧毁定时器,此时Time的结构为(css部分忽略): ```vue //Time.vue ``` 此时Header部分已经开发完成,但是我们还没有向后端请求数据,也没有开始设计后端数据接口。(统计截止时间是别的组件(leftPanelPie)传过来的数据) #### 5.2 allCharts部分设计思路 `allCharts.vue`抽象出了三个子组件,`Left.vue`,`Middle.vue`,`Right.vue`,这三个部分分别是:页面中最左侧的图表,中间的图表,和右边的图表,此时,`allCharts.vue`的结构为(css部分忽略): ```vue // allCharts.vue ``` ##### 5.2.1 准备工作 1. 可视化部分:用到了echarts,但要在Vue中全局使用echarts需要在`main.js`文件中引用echarts并且在Vue的`protptype`属性中挂载一个全局变量`$echart`为echarts即`Vue.prototype.$echart = echarts`,这样所有组件都能使用`this.$echart`访问到echarts 2. 全局事件总线:在Vue中不使用Vuex实现组件间通信是一件很麻烦的事,但是在一个小项目中,又没有必要使用Vuex,所以,我们可以找一个中间量,存储需要传递的数据。在Vue的虚拟dom中,每一个组件都是一个新的VueComponent对象,而每一个VueComponent对象的原型对象的属性,都指向了VueModel原型对象,所以我们可以在Vue的原型对象上绑定一个`$bus`属性指向了Vue本身,那么,这个中间变量就实现了。即在`main.js`中,在Vue的beforeCreate这个生命周期钩子中`Vue.prototype.$bus = this` ```vue new Vue({ render: h => h(App), beforeCreate() { Vue.prototype.$bus = this } ``` 3. 引入data-v: ```vue import dataV from '@jiaminghi/data-view' Vue.use(dataV) ``` `main.js`完整代码 ```javascript import Vue from 'vue' import App from './App.vue' import 'lib-flexible/flexible' import eCharts from 'echarts' import dataV from '@jiaminghi/data-view' Vue.use(dataV) Vue.config.productionTip = false Vue.prototype.$echart = eCharts new Vue({ render: h => h(App), beforeCreate() { Vue.prototype.$bus = this } }).$mount('#app') ``` ##### 5.2.2 `Left.vue`组件 `Left.vue`包含了三个部分,分别是三个图表:内容为中国新冠Top10的柱状图,内容为中国近一个月新冠(感染人数,治愈人数,死亡人数,无症状感染者人数)的折线图,和一个各个省份中**各个城市**的疫情数据(感染人数,治愈人数,死亡人数,无症状感染者人数)轮播图,所以,Left组件又抽象出了三个子组件 1. PannelBar.vue 2. PanelLine.vue 3. Shuffling.vue 此目录的结构为 ``` G:. ├───LeftPanel │ PanelBar.vue │ PanelLine.vue │ Shuffling.vue ``` Left.vue的结构为: ```vue ``` ###### 5.2.2.1 `PannelBar.vue` 这个组件展示的是关于中国疫情最多的10个城市,现在,开始设计后端的api。通过翻看echarts的文档,我们可以查到,在echarts中,柱状图的数据,需要传入两个array类型的data,所以在设计后端api时,需要返回的数据为如下格式: ```json { cityName:[array], cityData:[array], } ``` 在flask框架中,使用requests这个库,向新浪的api(https://interface.sina.cn/news/wap/fymap2020_data.d.json)发送一个get请求,然后我们就拿回了我们需要的所有数据,然后通过json库将json格式的数据反序列化成python的字典。 ```python url_xinlang = "https://interface.sina.cn/news/wap/fymap2020_data.d.json" r1 = requests.get(url=url_xinlang) data_get_xinlang = json.loads(r1.text) data_xinlang = data_get_xinlang["data"] ``` 接下来都是繁琐的数据处理过程,详见代码(PannelBar部分后端代码): ```python # left_pie_panel topData = data_xinlang["jwsrTop"] # top10数据 topCityName = [] # top10城市名字 topCityData = [] # top10城市数据 for i in range(len(topData)): topCityName.append(topData[i]['name']) topCityData.append(int(topData[i]['jwsrNum'])) ``` 然后将处理好的数据封装到data_total这个字典里,配置后端的路由为`'/api/total/'`,再返回JSON给前端。 ```python @app.route('/api/total/') def total_number(): data_total = { 'gnTotal': gnTotal, 'deathTotal': deathTotal, 'times': times, 'addConNew': addConNew, 'addDeathNew': addDeathNew } return jsonify(data_total) ``` 在PanelBar组件中,通过**mounted这个生命周期钩子**,使用axios向后端发送一个get请求,就可以请求回后端封装的api,我们要做到响应式,就必须得在这个组件监测到数据变化的时候重新渲染页面,而Vue这个框架恰好就能实现这个过程,所以我们现在要做的就是这两步:让Vue监测到数据改变-->重新渲染页面,那么Vue是怎么实现这个过程的呢?Vue是**一个半编译半运行的框架**,在一个xxx.vue文件中,Vue首先通过编译器编译``标签下的内容,编译成Vue的渲染器能识别的虚拟DOM(**用javascript描述的DOM节点**)然后通过Vue的渲染器,让他**递归的**生成真实DOM,这里就只简单说一下Vue的响应式系统。当你在data这个配置项中配置好了数据之后,Vue就会为他代理一个全新的数据,为了方便描述,使用**objectData**来描述这个被代理的对象。(ps:在Vue2中采用了`Object.defineProperty`(对象属性拦截),在Vue3中采用了`Proxy`(对象整体拦截))然后我们把渲染页面这一系列操作统称为:**副作用函数**(副作用函数指的就是,当这个函数被调用之后会对**整个页面产生影响的函数**,例如:修改了文本内容,样式,页面上的某一个元素....) 当我访问`objectData`中的某个字段时,Vue就会通过`Proxy`的`get`拦截我这个访问,然后将**副作用函数**放在一个bucket(可以简单的抽象成一个桶)里,然后当用户修改`objectData`的某个字段时,Vue也会通过`Proxy`的`set`拦截这个访问,最后在**用户修改之后重新调用副作用函数。**接下来是**响应式系统的简单实现**: ```javascript //副作用函数 function effect() { document.body.innerText = obj.text } const bucket = new Set() const data = { text: 'hello world' } //数据代理 const obj = new Proxy(data, { get(target, key) { bucket.add(effect) return target[key] }, set(target, key, newValue) { target[key] = newValue bucket.forEach(fn => fn()) } }) effect() //m setTimeout(() => { obj.text = 'hello vue' }, 1000) ``` 当我们请求回后端的数据之后,就可以将请求回的数据挂载到data中配置好的数据项上(Vue会事先将在data这个配置项中的配置的引用,进行数据代理了之后,再**挂载到VueComponent**上,所以我们就可以使用`this.dataName`访问到这些引用),此后,调用在methods里配置好的`myChartBar`函数(methods里配置好的函数同样会被挂载到`VueComponent`上),并且将这些数据作为参数传进这个函数,此时,Vue就会为我们重新渲染一次页面,并且把这个柱状图渲染到容器里。`PannelBar`的完整代码如下(css部分忽视): ```vue ``` 这个组件还有个部分,在打开这个可视化大屏时,如果数据还没有请求回来,页面就会显示Loading。我在`watch`里配置了一个`tempBar`(boolean),监测数据的请求情况,如果请求回了数据,`tempBar`就会被修改为`false`,当`tempBar`的值改变了之后,就会触发`watch`里的`tempBar`函数,那么就会延时2秒向`App.Vue`传递`tempBar`,此时Vue的一个指令,`v-if`就派上用场了,他可以显示(隐藏)一个DOM节点,`app.vue`组件代码如下: ```vue ``` ###### 5.2.2.2 `PannelLine.vue` `PannelLine`的前端部分的设计思路和`PannelBar`差不多,不同就是封装的数据类型不一样,`PannelLine`需要的是如下数据: ```javascript data() { return { confirms: '', dates: '', deads: '', heals: '', storeConfirms: '', } } ``` 分别是无症状人数,治愈人数,日期,死亡人数和确诊人数。通过`axios`异步往后端的`'/api/left/line/'`请求回需要的设计,这部分组件就完成了。 ###### 5.2.2.3 `Shuffling.vue` 这个组件展示的是全国各省各市疫情的情况,但默认他是展示一个省的所有市的,所以,他和中间疫情分布图部分做了交互,即,点击了地图上某一个省,就展示某个省所有市的情况。 在这个组件中,用到了`dataV`的`dv-scroll-board`组件,这个组件为我们封装好展示轮播表的所有代码,我们只用使用`Vue`的`prop`属性往组件里传参就行了。代码如下 ```vue

{{ provinceName }}省各市疫情累计情况

``` `config`是传入的配置对象,包含展示的数据和对轮播表的调整,具体参数可以去官方文档查阅。与`Map`组件的交互部分的设计思路如下: 当`Map`组件监测到用户点击了地图上的某一个省份时,`Map`组件就会把点击的省份的`provinceName`传递给`Shuffling`组件,同样`Shuffling`也监测着`provinceName`的变化,当接收到`Map`组件的数据时,意味着`Shuffling`组件的`provinceName`发生了变化,这个时候,再把这个`provinceName`发送给后端,而后端接收到请求之后,检索这个`provinceName`然后再将包含这个`provinceName`的所有字段的数据封装成`JSON`再传回给前端。 前端部分代码如下: ```javascript methods: { getAlldata() { axios .get('/api/right/shuffling/') .then(response => { this.config = { data: response.data.PanelShufflingData, waitTime: 1500, header: ['城市名', '确诊', '治愈', '死亡'], //headerBGC: "FFFFFF0A", oddRowBGC: "FFFFFF0A", } }) }, getProvince(provinceName) { this.provinceName = provinceName } }, mounted() { this.getAlldata() this.$bus.$on('sendProvinceName', this.getProvince) }, watch: { provinceName(data) { axios .post('/api/left/shuffling/change/', JSON.stringify({ provinceName: data })) .then(response => { this.config = { data: response.data.newData, waitTime: 1500, header: ['城市名', '确诊', '治愈', '死亡'], oddRowBGC: "FFFFFF0A", } }) .catch(error => { console.log(error.message) }) } }, beforeDestroy() { this.$bus.$off('sendProvinceName') } ``` 后端部分代码如下: ```python @app.route('/api/left/shuffling/change/', methods=['POST']) def change_right_shuffling(): provinceName = request.get_data() provinceName = json.loads(provinceName) provinceName = provinceName['provinceName'] city_data = filter_data(provinceName) city_value = get_shuffling_data(city_data) data_total = { "provinceName": provinceName, "newData": city_value } return jsonify(data_total) ``` ##### 5.2.3 `Middle.vue`组件 这个组件包含两个子组件: 1. `Map.vue`组件 2. `Total.vue`组件 ###### 5.2.3.1 `Map.vue` 这个组件是在地图上展示中国疫情的分布图,同时也和轮播表,饼状图做了交互,部分代码如下: ```vue ``` ###### 5.2.3.2 `Total.vue` 这个组件是为了展示中国现有疫情情况,部分代码如下: ```vue ``` ##### 5.2.3 `right.vue`组件 这个组件包含两个部分: `PannelBar.vue`:和地图做了交互的饼状图。 `Top.vue`:和地图做了交互的各省各市的已确诊人数排名轮播表。 设计思路参考**5.2.2.3**