新增数据可视化大屏案例
This commit is contained in:
parent
7bd8f8c907
commit
5b8473d1ca
@ -26,6 +26,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@amap/amap-jsapi-loader": "^1.0.1",
|
"@amap/amap-jsapi-loader": "^1.0.1",
|
||||||
"@iconify/iconify": "^3.0.0",
|
"@iconify/iconify": "^3.0.0",
|
||||||
|
"@kjgl77/datav-vue3": "^1.3.3",
|
||||||
"@vueuse/core": "^9.5.0",
|
"@vueuse/core": "^9.5.0",
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.10",
|
"@wangeditor/editor-for-vue": "^5.1.10",
|
||||||
@ -40,6 +41,7 @@
|
|||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"mitt": "^3.0.0",
|
"mitt": "^3.0.0",
|
||||||
"mockjs": "^1.1.0",
|
"mockjs": "^1.1.0",
|
||||||
|
"moment": "^2.29.4",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.0.23",
|
"pinia": "^2.0.23",
|
||||||
"pinia-plugin-persist": "^1.0.0",
|
"pinia-plugin-persist": "^1.0.0",
|
||||||
|
BIN
kinit-admin/src/assets/imgs/bg.png
Normal file
BIN
kinit-admin/src/assets/imgs/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 195 KiB |
BIN
kinit-admin/src/assets/imgs/bg1.png
Normal file
BIN
kinit-admin/src/assets/imgs/bg1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 202 KiB |
@ -28,6 +28,8 @@ import { setupRouter } from './router'
|
|||||||
// 权限
|
// 权限
|
||||||
import { setupPermission } from './directives'
|
import { setupPermission } from './directives'
|
||||||
|
|
||||||
|
import DataVVue3 from '@kjgl77/datav-vue3'
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
|
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
@ -49,6 +51,8 @@ const setupAll = async () => {
|
|||||||
|
|
||||||
setupPermission(app)
|
setupPermission(app)
|
||||||
|
|
||||||
|
app.use(DataVVue3)
|
||||||
|
|
||||||
app.mount('#app')
|
app.mount('#app')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,63 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { reactive, PropType, ref, watch } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
centerBottomData: {
|
||||||
|
type: Array as PropType<string[][]>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const scrollBoardRef = ref<any>(null)
|
||||||
|
|
||||||
|
const centerBottomData = ref(props.centerBottomData)
|
||||||
|
|
||||||
|
const config = reactive({
|
||||||
|
header: ['部门名称', '甲醛', 'PM2.5', 'PM10', '温度', '湿度', '更新时间'],
|
||||||
|
data: centerBottomData.value,
|
||||||
|
index: true,
|
||||||
|
columnWidth: [50],
|
||||||
|
align: ['center'],
|
||||||
|
rowNum: 6,
|
||||||
|
waitTime: 2000,
|
||||||
|
headerHeight: 40
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.centerBottomData,
|
||||||
|
(val: string[][]) => {
|
||||||
|
scrollBoardRef.value.updateRows(val)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="center-bottom-view">
|
||||||
|
<dv-scroll-board ref="scrollBoardRef" :config="config" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.center-bottom-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.dv-scroll-board {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rows .row-item {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
151
kinit-admin/src/views/vadmin/screen/air/components/CenterTop.vue
Normal file
151
kinit-admin/src/views/vadmin/screen/air/components/CenterTop.vue
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { Echart } from '@/components/Echart'
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import { EChartsOption } from 'echarts'
|
||||||
|
import { PropType, ref, watch, reactive } from 'vue'
|
||||||
|
import { CenterTopPropsType } from '../typers'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
centerTopData: {
|
||||||
|
type: Object as PropType<CenterTopPropsType>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
activeMenuName: propTypes.string
|
||||||
|
})
|
||||||
|
|
||||||
|
const lineOptions = ref({})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.centerTopData,
|
||||||
|
(val: CenterTopPropsType) => {
|
||||||
|
lineOptions.value = {
|
||||||
|
xAxis: {
|
||||||
|
data: [
|
||||||
|
'6H',
|
||||||
|
'7H',
|
||||||
|
'8H',
|
||||||
|
'9H',
|
||||||
|
'10H',
|
||||||
|
'11H',
|
||||||
|
'12H',
|
||||||
|
'13H',
|
||||||
|
'14H',
|
||||||
|
'15H',
|
||||||
|
'16H',
|
||||||
|
'17H',
|
||||||
|
'18H',
|
||||||
|
'19H'
|
||||||
|
],
|
||||||
|
type: 'category'
|
||||||
|
},
|
||||||
|
textStyle: {
|
||||||
|
fontFamily: 'Microsoft YaHei',
|
||||||
|
fontSize: 20,
|
||||||
|
fontStyle: 'normal',
|
||||||
|
fontWeight: 'normal',
|
||||||
|
color: '#ecc460'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 20,
|
||||||
|
top: 80,
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross'
|
||||||
|
},
|
||||||
|
padding: [5, 10]
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '',
|
||||||
|
min: 0,
|
||||||
|
axisLabel: {
|
||||||
|
formatter: '{value}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
legend: {
|
||||||
|
data: ['PM2.5', '甲醛', '温度', '湿度'],
|
||||||
|
// top: 50,
|
||||||
|
textStyle: {
|
||||||
|
color: '#c3f19d'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'PM2.5',
|
||||||
|
type: 'bar',
|
||||||
|
color: '#bbff67',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: val.pm25,
|
||||||
|
showBackground: false,
|
||||||
|
barGap: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '甲醛',
|
||||||
|
type: 'bar',
|
||||||
|
color: '#6deedf',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: val.hcho,
|
||||||
|
showBackground: false,
|
||||||
|
barGap: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '温度',
|
||||||
|
type: 'line',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: val.temp
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '湿度',
|
||||||
|
type: 'line',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: val.hum
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// const lineOptions: EChartsOption = reactive()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="center-top-view">
|
||||||
|
<span class="text-3xl font-bold">{{ props.activeMenuName }}</span>
|
||||||
|
<div>
|
||||||
|
<Echart :options="lineOptions" :height="400" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.center-top-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 3px blue;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: rgba(6, 30, 93, 0.5);
|
||||||
|
border-top: 2px solid rgba(1, 153, 209, 0.5);
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
</style>
|
95
kinit-admin/src/views/vadmin/screen/air/components/Left.vue
Normal file
95
kinit-admin/src/views/vadmin/screen/air/components/Left.vue
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import { PropType } from 'vue'
|
||||||
|
import { LeftPropsType } from '../typers/index'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
leftData: {
|
||||||
|
type: Object as PropType<LeftPropsType>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
activeMenuName: propTypes.string
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="left-view">
|
||||||
|
<span class="text-3xl font-bold">{{ props.activeMenuName }}</span>
|
||||||
|
<div class="main-content">
|
||||||
|
<dv-border-box11 title="室内甲醛">
|
||||||
|
<div class="data-view">
|
||||||
|
<span class="data-title">{{ props.leftData.hcho }}ug/m³</span>
|
||||||
|
<span class="data-desc">提示:低于80ug/m³适合长期居住</span>
|
||||||
|
</div>
|
||||||
|
</dv-border-box11>
|
||||||
|
<dv-border-box11 title="室内PM2.5">
|
||||||
|
<div class="data-view">
|
||||||
|
<span class="data-title">{{ props.leftData.pm25 }}ug/m³</span>
|
||||||
|
<span class="data-desc">提示:低于75ug/m³适合长期居住</span>
|
||||||
|
</div>
|
||||||
|
</dv-border-box11>
|
||||||
|
<dv-border-box11 title="室内温度">
|
||||||
|
<div class="data-view">
|
||||||
|
<span class="data-title">{{ props.leftData.temp }}°C</span>
|
||||||
|
<span class="data-desc">提示:当前室外温度为25°C</span>
|
||||||
|
</div>
|
||||||
|
</dv-border-box11>
|
||||||
|
<dv-border-box11 title="室内湿度">
|
||||||
|
<div class="data-view">
|
||||||
|
<span class="data-title">{{ props.leftData.hum }}%RH</span>
|
||||||
|
<span class="data-desc">提示:当前室外湿度为38%RH</span>
|
||||||
|
</div>
|
||||||
|
</dv-border-box11>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.left-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-shadow: 0 0 3px blue;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: rgba(6, 30, 93, 0.5);
|
||||||
|
border-top: 2px solid rgba(1, 153, 209, 0.5);
|
||||||
|
padding: 10px 20px;
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
.dv-border-box-11 {
|
||||||
|
.border-box-content {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: -webkit-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-view {
|
||||||
|
position: relative;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
display: -webkit-flex;
|
||||||
|
|
||||||
|
.data-title {
|
||||||
|
font-size: 35px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-desc {
|
||||||
|
font-size: 14px;
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,55 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { propTypes } from '@/utils/propTypes'
|
||||||
|
import { PropType } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
menus: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
activeIndex: propTypes.number
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="top-menu-view">
|
||||||
|
<dv-border-box10>
|
||||||
|
<div class="menu-item-view" v-for="(item, index) in props.menus" :key="index">
|
||||||
|
<dv-decoration7
|
||||||
|
class="animate__animated animate__fadeInDown"
|
||||||
|
v-if="index === props.activeIndex"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</dv-decoration7>
|
||||||
|
<span v-else>{{ item }}</span>
|
||||||
|
</div>
|
||||||
|
</dv-border-box10>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.top-menu-view {
|
||||||
|
.dv-border-box-10 {
|
||||||
|
height: 80px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.menu-item-view {
|
||||||
|
float: left;
|
||||||
|
line-height: 80px;
|
||||||
|
margin: 0 30px;
|
||||||
|
font-size: 22px;
|
||||||
|
color: #909399;
|
||||||
|
font-weight: bold;
|
||||||
|
|
||||||
|
&:first-of-type {
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dv-decoration-7 {
|
||||||
|
height: 100%;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
139
kinit-admin/src/views/vadmin/screen/air/index.vue
Normal file
139
kinit-admin/src/views/vadmin/screen/air/index.vue
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import Left from './components/Left.vue'
|
||||||
|
import CenterTop from './components/CenterTop.vue'
|
||||||
|
import CenterBottom from './components/CenterBottom.vue'
|
||||||
|
import TopMenu from './components/TopMenu.vue'
|
||||||
|
import { LeftPropsType, CenterTopPropsType } from './typers/index'
|
||||||
|
import { ref, onBeforeUnmount } from 'vue'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
const randomNumber = (min: number, max: number) => {
|
||||||
|
return Math.floor(Math.random() * (max - min)) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
const randomNumberStr = (min: number, max: number) => {
|
||||||
|
return randomNumber(min, max).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
const randArray = (len: number, min: number, max: number) => {
|
||||||
|
return Array(len)
|
||||||
|
.fill(1)
|
||||||
|
.map(() => randomNumber(min, max))
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftData = ref({} as LeftPropsType)
|
||||||
|
const centerBottomData = ref([] as string[][])
|
||||||
|
const centerTopData = ref({} as CenterTopPropsType)
|
||||||
|
const menus = ref([] as string[])
|
||||||
|
const activeIndex = ref(-1)
|
||||||
|
const activeMenuName = ref('')
|
||||||
|
|
||||||
|
const generateData = () => {
|
||||||
|
leftData.value = {
|
||||||
|
pm25: randomNumberStr(5, 50),
|
||||||
|
temp: randomNumberStr(5, 50),
|
||||||
|
hum: randomNumberStr(5, 50),
|
||||||
|
hcho: randomNumberStr(5, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
menus.value = [
|
||||||
|
'技术1部',
|
||||||
|
'技术2部',
|
||||||
|
'运营部',
|
||||||
|
'销售部',
|
||||||
|
'人力资源部',
|
||||||
|
'技术支持部',
|
||||||
|
'客服部',
|
||||||
|
'老板办公室'
|
||||||
|
]
|
||||||
|
|
||||||
|
centerBottomData.value = []
|
||||||
|
|
||||||
|
for (let item of menus.value) {
|
||||||
|
centerBottomData.value.push([
|
||||||
|
item,
|
||||||
|
randomNumberStr(5, 50),
|
||||||
|
randomNumberStr(5, 50),
|
||||||
|
randomNumberStr(5, 50),
|
||||||
|
randomNumberStr(5, 50),
|
||||||
|
randomNumberStr(5, 50),
|
||||||
|
moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
centerTopData.value = {
|
||||||
|
pm25: randArray(14, 10, 50),
|
||||||
|
temp: randArray(14, 10, 50),
|
||||||
|
hum: randArray(14, 10, 50),
|
||||||
|
hcho: randArray(14, 10, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
activeIndex.value++
|
||||||
|
if (activeIndex.value === menus.value.length) {
|
||||||
|
activeIndex.value = 0
|
||||||
|
}
|
||||||
|
activeMenuName.value = menus.value[activeIndex.value]
|
||||||
|
}
|
||||||
|
|
||||||
|
generateData()
|
||||||
|
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
generateData()
|
||||||
|
}, 0)
|
||||||
|
}, 6000)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
console.log('已清除定时器')
|
||||||
|
clearInterval(timer)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div id="data-view">
|
||||||
|
<dv-full-screen-container>
|
||||||
|
<div class="flex justify-between">
|
||||||
|
<div small-bg>
|
||||||
|
<dv-decoration8 style="width: 500px; height: 60px" />
|
||||||
|
</div>
|
||||||
|
<div class="text-4xl leading-80px font-bold">
|
||||||
|
<span>办公室空气质量实时检测</span>
|
||||||
|
</div>
|
||||||
|
<div small-bg>
|
||||||
|
<dv-decoration8 :reverse="true" style="width: 500px; height: 60px" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mx-10px my-15px">
|
||||||
|
<TopMenu :menus="menus" :activeIndex="activeIndex" />
|
||||||
|
</div>
|
||||||
|
<div class="h-1/1 overflow-hidden mb-10px ml-10px">
|
||||||
|
<div class="float-left w-20/100 h-1/1 mr-20px">
|
||||||
|
<Left :leftData="leftData" :activeMenuName="activeMenuName" />
|
||||||
|
</div>
|
||||||
|
<div class="float-left w-78/100 h-5/10">
|
||||||
|
<CenterTop :centerTopData="centerTopData" :activeMenuName="activeMenuName" />
|
||||||
|
</div>
|
||||||
|
<div class="float-left w-78/100 h-48/100">
|
||||||
|
<CenterBottom :centerBottomData="centerBottomData" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dv-full-screen-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
#data-view {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #030409;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
#dv-full-screen-container {
|
||||||
|
background-image: url('@/assets/imgs/bg.png');
|
||||||
|
background-size: 100% 100%;
|
||||||
|
box-shadow: 0 0 3px blue;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
13
kinit-admin/src/views/vadmin/screen/air/typers/index.d.ts
vendored
Normal file
13
kinit-admin/src/views/vadmin/screen/air/typers/index.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
export type LeftPropsType = {
|
||||||
|
pm25: string
|
||||||
|
temp: string
|
||||||
|
hum: string
|
||||||
|
hcho: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CenterTopPropsType = {
|
||||||
|
pm25: number[]
|
||||||
|
temp: number[]
|
||||||
|
hum: number[]
|
||||||
|
hcho: number[]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user