feat: 可视化大屏

master
LCJ-MinYa 11 months ago
parent 4874a9abdc
commit 09453ae877

@ -0,0 +1,111 @@
<template>
<ul class="kanban-ul flex">
<li>
<CountUp
:endVal="rate.resourceAccessRate"
:duration="duration"
>
<template #suffix>
<span>%</span>
</template>
</CountUp>
<span>资源接入率</span>
</li>
<li>
<CountUp
:endVal="rate.resourceHealthRate"
:duration="duration"
>
<template #suffix>
<span>%</span>
</template>
</CountUp>
<span>资源健康率</span>
</li>
<li>
<CountUp
:endVal="rate.resourceRedundancyRate"
:duration="duration"
>
<template #suffix>
<span>%</span>
</template>
</CountUp>
<span>资源冗余率</span>
</li>
</ul>
</template>
<script setup>
import { ref, inject } from 'vue';
import CountUp from './common/count-up';
const currentOrg = inject('currentOrg');
const duration = 2;
const rate = ref({
resourceAccessRate: 0,
resourceHealthRate: 0,
resourceRedundancyRate: 0,
});
const getAccessStatusData = () => {
console.log('执行请求AccessStatus');
return new Promise((resolve) => {
setTimeout(() => {
if (currentOrg.value.id === 'all') {
resolve({
resourceAccessRate: 80,
resourceHealthRate: 70,
resourceRedundancyRate: 90,
});
} else {
resolve({
resourceAccessRate: 100,
resourceHealthRate: 90,
resourceRedundancyRate: 95,
});
}
}, 1000);
});
};
const initFN = () => {
getAccessStatusData().then((res) => {
for (const key in rate.value) {
rate.value[key] = res[key];
}
});
};
defineExpose({
name: 'AccessStatus',
init: initFN,
});
</script>
<style lang="scss" scoped>
.kanban-ul {
height: 100%;
li {
flex: 1;
width: 142px;
height: 100%;
background: url(../img/di.png) no-repeat;
background-position: center bottom 50px;
background-size: 115%;
text-align: center;
color: rgb(174, 224, 240);
.countup-wrap {
padding: 25px 20px 0;
font-size: 42px;
}
& > span {
font-size: 18px;
font-weight: bold;
}
}
}
</style>

@ -15,15 +15,38 @@
:orgList="orgList" :orgList="orgList"
@changeOrg="changeOrg" @changeOrg="changeOrg"
/> />
<div class="content_box">
<div class="content_left">
<ItemWrap
v-for="item in layoutData.left"
:key="item.componentName"
:class="[getComponentClass(item.componentName)]"
:title="item.title"
>
<component
:is="item.component"
:ref="(el) => setRef(el, item.componentName)"
/>
</ItemWrap>
</div>
<div class="content_center"></div>
<div class="content_right"></div>
</div>
</div> </div>
</scale-screen> </scale-screen>
</template> </template>
<script setup lang="jsx"> <script setup lang="jsx">
import { ref, provide } from 'vue'; import { ref, provide, computed, shallowRef, onMounted, nextTick, onBeforeUnmount } from 'vue';
import ScaleScreen from './components/common/scale-screen'; import ScaleScreen from './components/common/scale-screen';
import Headers from './components/header.vue'; import Headers from './components/Headers.vue';
import ItemWrap from './components/common/item-wrap';
import AccessStatus from './components/AccessStatus.vue';
/** 机构切换配置 */
const orgList = ref([ const orgList = ref([
{ {
id: 'all', id: 'all',
@ -42,10 +65,104 @@ const currentOrg = ref({
id: 'all', id: 'all',
name: '全局', name: '全局',
}); });
provide('currentOrg', currentOrg); provide('currentOrg', currentOrg); //currentOrg使currentOrg.value.value
const changeOrg = (item) => { const changeOrg = async (item) => {
clearTimer();
layoutData.value = await getLayout(item.id);
currentOrg.value = item; currentOrg.value = item;
refreshRequest();
setTimer();
};
/** 组件配置 */
const layoutData = ref({});
const getComponent = (componentName) => {
let component = null;
switch (componentName) {
case 'AccessStatus':
component = shallowRef(AccessStatus);
break;
}
return component;
};
const getComponentClass = computed(() => (componentName) => {
let className = '';
switch (componentName) {
case 'AccessStatus':
className = 'content_kb-item';
break;
}
return className;
});
const getLayout = (id) => {
return new Promise((resolve) => {
setTimeout(() => {
/** 模拟切换全局和不同机构获得不同的布局数据 */
let layoutDataValue = {};
switch (id) {
case 'all':
layoutDataValue = {
left: [{ title: '综合看板', componentName: 'AccessStatus' }],
center: [],
right: [],
};
break;
case 'org1':
layoutDataValue = {
left: [{ title: '综合看板', componentName: 'AccessStatus' }],
center: [],
right: [],
};
break;
}
for (const key in layoutDataValue) {
for (let index = 0; index < layoutDataValue[key].length; index++) {
layoutDataValue[key][index].component = getComponent(layoutDataValue[key][index].componentName);
}
}
resolve(layoutDataValue);
}, 500);
});
};
/** 组件的实例ref */
const refs = {};
const setRef = (el, componentName) => {
if (el) {
refs[componentName] = el;
}
};
const refreshRequest = () => {
nextTick(() => {
console.log(refs, '当前存在的refs');
Object.keys(refs).map((item) => {
// ref
refs[item].init();
});
});
};
/** 定时器每隔60s刷新一次数据 */
let timer = null;
const setTimer = () => {
timer = setInterval(() => {
refreshRequest();
});
}; };
const clearTimer = () => {
clearInterval(timer);
timer = null;
};
onMounted(async () => {
layoutData.value = await getLayout(currentOrg.value.id);
refreshRequest();
setTimer();
});
onBeforeUnmount(() => {
clearTimer();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -57,5 +174,56 @@ const changeOrg = (item) => {
background-image: url('./img/pageBg.png'); background-image: url('./img/pageBg.png');
background-size: cover; background-size: cover;
background-position: center center; background-position: center center;
.content_box {
width: 100%;
display: flex;
min-height: calc(100% - 64px);
justify-content: space-between;
//
.content_left,
.content_right {
display: flex;
flex-direction: column;
justify-content: space-around;
position: relative;
width: 520px;
box-sizing: border-box;
flex-shrink: 0;
}
.content_center {
flex: 1;
margin: 0 54px;
display: flex;
flex-direction: column;
justify-content: space-around;
overflow: hidden;
.content_center-bottom {
height: 315px;
}
}
.content_lr-item {
height: 310px;
}
.content_kb-item {
height: 310px;
}
.content_lb-item {
height: 560px;
}
.content_ct-item {
height: 510px;
}
.content_cb-item {
height: 400px;
}
}
} }
</style> </style>

Loading…
Cancel
Save