vue-admin-template+Datav实现可视化大屏
效果图:
DataV官网链接:http://datav.jiaminghi.com/guide/
vue-admin-template连接:https://github.com/PanJiaChen
下载基础版本的即可;vue-admin-template的下载配置就不说啦,整好后安装Datav:
npm install @jiaminghi/data-view
然后在vue-admin-template-master\src\main.js文件中注册
import Vue from 'vue'
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import locale from 'element-ui/lib/locale/lang/en' // lang i18n
//引入dataV样式
// 将自动注册所有组件为全局组件
import './assets/common.less'
import dataV from '@jiaminghi/data-view'
Vue.use(dataV)
然后直接写,我是在这个文件下面:vue-admin-template-master\src\views\visualization\index.vue
<template>
<div class="content bg">
<!-- 全屏容器 -->
<dv-full-screen-container>
<!-- 第一行 -->
<div class="module_box" style="height: 10vh;">
<div style="flex: 0 1 30%;">
<dv-decoration-10 style="width:100%;height:50px;" />
</div>
<div style="flex: 0 1 40%;">
<div style="display: flex;width: 100%;">
<dv-decoration-8 style="width:300px;height:50px;flex:1;transform: rotateY(180deg);" />
<dv-decoration-11 style="width:200px;height:60px;flex:1">肉鸡表型数据中心</dv-decoration-11>
<dv-decoration-8 style="width:300px;height:50px;flex:1" />
</div>
</div>
<div style="flex: 0 1 30%;">
<dv-decoration-10 style="width: 100%;height:50px;transform: rotateY(180deg);" />
</div>
</div>
<!-- 第二行 -->
<div class="module_box" style="height:60vh;">
<!-- flex布局 一行四个 各占25% -->
<!-- 左 -->
<div style="flex: 0 1 25%;">
<dv-border-box-1 style="width: 100%;height: 100%;">
<dv-capsule-chart v-if="!listLoading" :config="config2" style="width:90%;height:86%" />
</dv-border-box-1>
<!-- <dv-border-box-2 style="width: 100%;height: 40%;">
<dv-conical-column-chart :config="config5" style="width:90%;height:90%;" />
</dv-border-box-2> -->
</div>
<!-- 中 -->
<div style="flex: 0 1 50%;">
<dv-border-box-12 style="width: 100%;height: 100%">
<dv-active-ring-chart v-if="!listLoading" :config="config4" style="width:95%;height:95%" />
</dv-border-box-12>
</div>
<!-- 右 -->
<div style="flex: 0 1 25%;">
<dv-border-box-8 style="width: 100%;height: 100%">
<dv-scroll-ranking-board v-if="!listLoading" :config="config2" style="width:90%;height:90%" />
</dv-border-box-8>
</div>
</div>
<!-- 第三行 -->
<div class="module_box" style="height: 30vh;">
<!-- flex布局 一行四个 各占25% -->
<!-- 左 -->
<div style="flex: 0 1 75%;">
<dv-border-box-10 style="width: 100%;height: 200px;">
<dv-conical-column-chart v-if="!listLoading" :config="config2" style="width:90%;height:100%" />
</dv-border-box-10>
</div>
<!-- 中 -->
<!-- <div style="flex: 0 1 25%;">
<dv-border-box-13 style="width: 100%;height: 200px;">
<dv-active-ring-chart :config="config8" style="width:100%;height:100%" />
</dv-border-box-13>
</div> -->
<!-- 右 -->
<div style="flex: 0 1 25%;">
<dv-border-box-13 style="width: 100%;height: 200px;">
<dv-percent-pond v-if="!listLoading" :config="config3" style="width:200px;height:100px;"/>
</dv-border-box-13>
</div>
</div>
</dv-full-screen-container>
</div>
</template>
<script>
import api from '@/api/datav';
export default {
name: 'HomeView',
data() {
return {
listLoading: true,
config2: {
data: [
]
},
config3: {
value: 80,
borderWidth: 5,
borderRadius: 10,
borderGap: 5,
backgroundColor: '#0f0', // 添加背景颜色
borderColor: '#00f', // 添加边框颜色
fontColor: '#fff', // 添加字体颜色
fontSize: 30 // 添加字体大小
},
config4: {
radius: '65%',
activeRadius: '70%',
data: [
],
digitalFlopStyle: {
fontSize: 30,
lineWidth: 30,
showOriginValue: true
}
} // 确保 config4 被正确初始化,即使它现在可能是空的或未被使用
};
},
created() {
this.fetchData();
},
methods: {
fetchData() {
this.listLoading = true;
api.findAllInfoOrder().then(response => {
if (response && response.data && response.code === 200) {
console.log(response.data); // 打印数据
this.config2.data = this.formatData(response.data);
this.config4.data = this.formatData(response.data);
this.listLoading = false;
} else {
console.error('Failed to fetch data:', response.data ? response.message : 'No response data');
this.listLoading = false;
}
}).catch(error => {
console.error('Error during data fetch:', error);
this.listLoading = false;
});
},
formatData(rawData) {
if (Array.isArray(rawData)) {
// 如果原始数据已经是数组,则直接返回
return rawData;
} else {
// 否则,格式化数据
return Object.entries(rawData).map(([name, value]) => ({
name,
value
}));
}
}
}
}
</script>
<style>
.container {
width: 100vw;
height: 100vh;
box-sizing: border-box;
}
#dv-full-screen-container {
height: 100vh !important;
}
* {
margin: 0;
padding: 0;
}
/* 主体 */
.content {
color: #fff;
background: #000;
width: 100vw;
height: 100vh;
}
.bg {
background: url(../../assets/images/bg.jpg) center center;
background-size: cover;
}
.module_box {
display: flex;
justify-content: space-between;
margin: 5px;
}
.border-box-content {
display: flex;
justify-content: center;
align-items: center;
}
</style>
这个是一个全屏的可视化界面,我设置的都是width: 100vw、height: 100vh;但是vue-admin-template他自己带了原有的侧边栏和头部,写好后会导致有部分被遮挡,所以我们如果需要在大屏幕上展示的话,有两种方案:1、需要重新打开一个界面来进行展示;2、对界面进行调整,使其适应界面主主体主体的大小。我们依次介绍:
第一种方法:打开一个界面来进行展示:
由于vue-admin-template的侧边栏是通过路由直接控制注入的,因此可以通过在路由中添加一个属性来决定是否在新窗口中打开页面。可以在路由配置中添加 target 属性,并在 SidebarItem 组件中根据这个属性来决定是否在新窗口中打开链接。
在路由中vue-admin-template-master\src\router\index.js添加target属性
{
path: '/visualization',
name: 'Visualization',
component: () => import('@/views/visualization/index'),
meta: { title: '可视化-全屏', icon: 'dashboard', target: '_blank' }
},
修改 SidebarItem 组件:
在 SidebarItem 组件中,根据 target 属性决定链接的打开方式:
<template>
<div v-if="!item.hidden">
<template v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren) && !item.alwaysShow">
<Link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)" :target="onlyOneChild.meta.target">
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown': !isNest}">
<Item :icon="onlyOneChild.meta.icon || (item.meta && item.meta.icon)" :title="onlyOneChild.meta.title" />
</el-menu-item>
</Link>
</template>
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<Item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
</template>
<sidebar-item
v-for="child in item.children"
:key="child.path"
:is-nest="true"
:item="child"
:base-path="resolvePath(child.path)"
class="nest-menu"
/>
</el-submenu>
</div>
</template>
<script>
import path from 'path'
import { isExternal } from '@/utils/validate'
import Item from './Item'
import Link from './Link'
import FixiOSBug from './FixiOSBug'
export default {
name: 'SidebarItem',
components: { Item, Link },
mixins: [FixiOSBug],
props: {
item: {
type: Object,
required: true
},
isNest: {
type: Boolean,
default: false
},
basePath: {
type: String,
default: ''
}
},
data() {
this.onlyOneChild = null
return {}
},
methods: {
hasOneShowingChild(children = [], parent) {
const showingChildren = children.filter(item => {
if (item.hidden) {
return false
} else {
this.onlyOneChild = item
return true
}
})
if (showingChildren.length === 1) {
return true
}
if (showingChildren.length === 0) {
this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
return true
}
return false
},
resolvePath(routePath) {
if (isExternal(routePath)) {
return routePath
}
if (isExternal(this.basePath)) {
return this.basePath
}
return path.resolve(this.basePath, routePath)
}
}
}
</script>
修改 Link.vue 组件
在 Link.vue 组件中,根据 to 属性的值决定是否在新窗口中打开链接。
<template>
<component :is="type" v-bind="linkProps(to)">
<slot />
</component>
</template>
<script>
import { isExternal } from '@/utils/validate'
export default {
props: {
to: {
type: String,
required: true
},
target: {
type: String,
default: '_self'
}
},
computed: {
isExternal() {
return isExternal(this.to)
},
type() {
if (this.isExternal) {
return 'a'
}
return 'router-link'
}
},
methods: {
linkProps(to) {
if (this.isExternal) {
return {
href: to,
target: this.target,
rel: 'noopener'
}
}
return {
to: to,
target: this.target
}
}
}
}
</script>
第二种方法:对界面进行调整,使其适应vue-admin-template框架界面主体的大小。
这个直接上代码就行,修改点样式即可
<template>
<div class="app-container">
<div class="content bg">
<!-- 第一行 -->
<div class="module_box" style="height: 10%;">
<div style="flex: 0 1 30%;">
<dv-decoration-10 style="width:100%;height:50px;" />
</div>
<div style="flex: 0 1 40%;">
<div style="display: flex;width: 100%;">
<dv-decoration-8 style="width:300px;height:50px;flex:1;transform: rotateY(180deg);" />
<dv-decoration-11 style="width:200px;height:60px;flex:1">肉鸡表型数据中心</dv-decoration-11>
<dv-decoration-8 style="width:300px;height:50px;flex:1" />
</div>
</div>
<div style="flex: 0 1 30%;">
<dv-decoration-10 style="width: 100%;height:50px;transform: rotateY(180deg);" />
</div>
</div>
<!-- 第二行 -->
<div class="module_box" style="height:60%;">
<!-- flex布局 一行四个 各占25% -->
<!-- 左 -->
<div style="flex: 0 1 25%;">
<dv-border-box-1 style="width: 100%;height: 100%;">
<dv-capsule-chart v-if="!listLoading" :config="config2" style="width:90%;height:86%" />
</dv-border-box-1>
<!-- <dv-border-box-2 style="width: 100%;height: 40%;">
<dv-conical-column-chart :config="config5" style="width:90%;height:90%;" />
</dv-border-box-2> -->
</div>
<!-- 中 -->
<div style="flex: 0 1 50%;">
<dv-border-box-12 style="width: 100%;height: 100%">
<dv-active-ring-chart v-if="!listLoading" :config="config4" style="width:95%;height:95%" />
</dv-border-box-12>
</div>
<!-- 右 -->
<div style="flex: 0 1 25%;">
<dv-border-box-8 style="width: 100%;height: 100%">
<dv-scroll-ranking-board v-if="!listLoading" :config="config2" style="width:90%;height:90%" />
</dv-border-box-8>
</div>
</div>
<!-- 第三行 -->
<div class="module_box" style="height: 30%;">
<!-- flex布局 一行四个 各占25% -->
<!-- 左 -->
<div style="flex: 0 1 75%;">
<dv-border-box-10 style="width: 100%;height: 200px;">
<dv-conical-column-chart v-if="!listLoading" :config="config2" style="width:90%;height:100%" />
</dv-border-box-10>
</div>
<!-- 中 -->
<!-- <div style="flex: 0 1 25%;">
<dv-border-box-13 style="width: 100%;height: 200px;">
<dv-active-ring-chart :config="config8" style="width:100%;height:100%" />
</dv-border-box-13>
</div> -->
<!-- 右 -->
<div style="flex: 0 1 25%;">
<dv-border-box-13 style="width: 100%;height: 200px;">
<dv-percent-pond v-if="!listLoading" :config="config3" style="width:200px;height:100px;"/>
</dv-border-box-13>
</div>
</div>
</div>
</div>
</template>
<script>
import api from '@/api/datav';
export default {
name: 'HomeView',
data() {
return {
listLoading: true,
config2: {
data: [
]
},
config3: {
value: 80,
borderWidth: 5,
borderRadius: 10,
borderGap: 5,
backgroundColor: '#0f0', // 添加背景颜色
borderColor: '#00f', // 添加边框颜色
fontColor: '#fff', // 添加字体颜色
fontSize: 30 // 添加字体大小
},
config4: {
radius: '65%',
activeRadius: '70%',
data: [
],
digitalFlopStyle: {
fontSize: 30,
lineWidth: 30,
showOriginValue: true
}
} // 确保 config4 被正确初始化,即使它现在可能是空的或未被使用
};
},
created() {
this.fetchData();
},
methods: {
fetchData() {
this.listLoading = true;
api.findAllInfoOrder().then(response => {
if (response && response.data && response.code === 200) {
console.log(response.data); // 打印数据
this.config2.data = this.formatData(response.data);
this.config4.data = this.formatData(response.data);
this.listLoading = false;
} else {
console.error('Failed to fetch data:', response.data ? response.message : 'No response data');
this.listLoading = false;
}
}).catch(error => {
console.error('Error during data fetch:', error);
this.listLoading = false;
});
},
formatData(rawData) {
if (Array.isArray(rawData)) {
// 如果原始数据已经是数组,则直接返回
return rawData;
} else {
// 否则,格式化数据
return Object.entries(rawData).map(([name, value]) => ({
name,
value
}));
}
}
}
}
</script>
<style>
.container {
width: 100%;
height: calc(100vh - 84px);
box-sizing: border-box;
}
#dv-full-screen-container {
height: 100vh !important;
}
* {
margin: 0;
padding: 0;
}
/* 主体 */
.content {
color: #fff;
background: #000;
width: 100%;
height: calc(100vh - 84px);
}
.bg {
background: url(../../assets/images/bg.jpg) center center;
background-size: cover;
}
.module_box {
display: flex;
justify-content: space-between;
margin: 5px;
}
.border-box-content {
display: flex;
justify-content: center;
align-items: center;
}
</style>
效果: