fix: 测试
956
pnpm-lock.yaml
|
@ -1,119 +0,0 @@
|
|||
<template>
|
||||
<div class="center-container">
|
||||
<div class="item" :style="getItemStyle(index)" v-for="(item, index) in dcList" :key="item.type">
|
||||
<dv-decoration-9 class="active" v-if="!dcId || dcId === item.id"></dv-decoration-9>
|
||||
<span class="dc-name" @click="select(index)">{{item.name}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { ref, onUnmounted } from '@vue/composition-api'
|
||||
import { getDcs } from 'services/screen/outside'
|
||||
export default {
|
||||
setup(props, context) {
|
||||
const dcId = ref('');
|
||||
let currentIndex = -1;
|
||||
let timer = null;
|
||||
const startTimer = () => {
|
||||
// 如果timer存在先清除
|
||||
if (timer) clearTimer();
|
||||
timer = setInterval(() => {
|
||||
currentIndex++;
|
||||
select(currentIndex, 'auto');
|
||||
if (currentIndex === dcList.value.length - 1) currentIndex = -1;
|
||||
}, 1000 * 20)
|
||||
}
|
||||
const clearTimer = () => {
|
||||
clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
onUnmounted(() => {
|
||||
clearTimer();
|
||||
})
|
||||
const select = (index, way) => {
|
||||
// 手动触发重置定时器
|
||||
if (way !== 'auto') startTimer();
|
||||
currentIndex = index;
|
||||
// -1时为全部
|
||||
const id = currentIndex === -1 ? '' : dcList.value[index].id;
|
||||
dcId.value = id;
|
||||
context.emit('changeDc', id)
|
||||
};
|
||||
// 获取数据中心
|
||||
const dcList = ref([]);
|
||||
(async function() {
|
||||
const res = await getDcs();
|
||||
if (res.success) {
|
||||
dcList.value = res.data.rows;
|
||||
select(currentIndex);
|
||||
}
|
||||
})();
|
||||
// 获取每个数据中心的样式 横向每个加400,大于3个折行
|
||||
function getItemStyle(index) {
|
||||
const rows = Math.floor(index / 2);
|
||||
const style = {
|
||||
// left: `${index % 2 * 400 + 50}px`,
|
||||
// top: `${rows * 400}px`
|
||||
}
|
||||
return style
|
||||
}
|
||||
return {
|
||||
dcList,
|
||||
dcId,
|
||||
select,
|
||||
getItemStyle
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.center-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
}
|
||||
@keyframes item-animate {
|
||||
0% {
|
||||
top: 100px;
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.8;
|
||||
top: 80px;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
top: 100px;
|
||||
}
|
||||
}
|
||||
.item {
|
||||
position: relative;
|
||||
width: 430px;
|
||||
height: 430px;
|
||||
background: url('/scr-web/static/img/sip/bg_bottom.png');
|
||||
background-size: 100% 100% ;
|
||||
.active{
|
||||
width: 350px;
|
||||
height: 350px;
|
||||
position: absolute;
|
||||
bottom: -78px;
|
||||
left: 38px;
|
||||
transform: rotateX(115deg);
|
||||
}
|
||||
.dc-name {
|
||||
animation: item-animate 1.2s infinite linear;
|
||||
position: absolute;
|
||||
left: 110px;
|
||||
top: 100px;
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,327 @@
|
|||
<template>
|
||||
<div id="RealTimeUsed"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { getRealTimeUtilization } from './api.js'
|
||||
export default {
|
||||
name: 'UsedTrend',
|
||||
data() {
|
||||
return {
|
||||
myChart: null,
|
||||
used: 25.7,
|
||||
timer: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const chartDom = document.getElementById('RealTimeUsed')
|
||||
this.myChart = echarts.init(chartDom)
|
||||
this.getRealTimeUesdView()
|
||||
this.timer = setInterval(() => {
|
||||
this.getRealTimeData()
|
||||
}, 1000)
|
||||
},
|
||||
unmounted() {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
methods: {
|
||||
// 平台实用利用率
|
||||
async getRealTimeData() {
|
||||
const res = await getRealTimeUtilization()
|
||||
if (res.status !== 'success') return
|
||||
this.used = (res.data?.result?.[0]?.value[1] || 25.7).toFixed(2)
|
||||
},
|
||||
getRealTimeUesdView() {
|
||||
let angle = 0
|
||||
const value = this.used
|
||||
const option = {
|
||||
title: {
|
||||
text: '{a|' + value + '}{c|%}',
|
||||
x: 'center',
|
||||
y: 'center',
|
||||
textStyle: {
|
||||
rich: {
|
||||
a: {
|
||||
fontSize: 20,
|
||||
color: '#29EEF3'
|
||||
},
|
||||
|
||||
c: {
|
||||
fontSize: 18,
|
||||
color: '#ffffff'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'ring5',
|
||||
type: 'custom',
|
||||
coordinateSystem: 'none',
|
||||
renderItem: function(params, api) {
|
||||
return {
|
||||
type: 'arc',
|
||||
shape: {
|
||||
cx: api.getWidth() / 2,
|
||||
cy: api.getHeight() / 2,
|
||||
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6,
|
||||
startAngle: ((0 + angle) * Math.PI) / 180,
|
||||
endAngle: ((90 + angle) * Math.PI) / 180
|
||||
},
|
||||
style: {
|
||||
stroke: '#0CD3DB',
|
||||
fill: 'transparent',
|
||||
lineWidth: 1.5
|
||||
},
|
||||
silent: true
|
||||
}
|
||||
},
|
||||
data: [0]
|
||||
},
|
||||
{
|
||||
name: 'ring5',
|
||||
type: 'custom',
|
||||
coordinateSystem: 'none',
|
||||
renderItem: function(params, api) {
|
||||
return {
|
||||
type: 'arc',
|
||||
shape: {
|
||||
cx: api.getWidth() / 2,
|
||||
cy: api.getHeight() / 2,
|
||||
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.6,
|
||||
startAngle: ((180 + angle) * Math.PI) / 180,
|
||||
endAngle: ((270 + angle) * Math.PI) / 180
|
||||
},
|
||||
style: {
|
||||
stroke: '#0CD3DB',
|
||||
fill: 'transparent',
|
||||
lineWidth: 1.5
|
||||
},
|
||||
silent: true
|
||||
}
|
||||
},
|
||||
data: [0]
|
||||
},
|
||||
{
|
||||
name: 'ring5',
|
||||
type: 'custom',
|
||||
coordinateSystem: 'none',
|
||||
renderItem: function(params, api) {
|
||||
return {
|
||||
type: 'arc',
|
||||
shape: {
|
||||
cx: api.getWidth() / 2,
|
||||
cy: api.getHeight() / 2,
|
||||
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65,
|
||||
startAngle: ((270 + -angle) * Math.PI) / 180,
|
||||
endAngle: ((40 + -angle) * Math.PI) / 180
|
||||
},
|
||||
style: {
|
||||
stroke: '#0CD3DB',
|
||||
fill: 'transparent',
|
||||
lineWidth: 1.5
|
||||
},
|
||||
silent: true
|
||||
}
|
||||
},
|
||||
data: [0]
|
||||
},
|
||||
{
|
||||
name: 'ring5',
|
||||
type: 'custom',
|
||||
coordinateSystem: 'none',
|
||||
renderItem: function(params, api) {
|
||||
return {
|
||||
type: 'arc',
|
||||
shape: {
|
||||
cx: api.getWidth() / 2,
|
||||
cy: api.getHeight() / 2,
|
||||
r: (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65,
|
||||
startAngle: ((90 + -angle) * Math.PI) / 180,
|
||||
endAngle: ((220 + -angle) * Math.PI) / 180
|
||||
},
|
||||
style: {
|
||||
stroke: '#0CD3DB',
|
||||
fill: 'transparent',
|
||||
lineWidth: 1.5
|
||||
},
|
||||
silent: true
|
||||
}
|
||||
},
|
||||
data: [0]
|
||||
},
|
||||
{
|
||||
name: 'ring5',
|
||||
type: 'custom',
|
||||
coordinateSystem: 'none',
|
||||
renderItem: function(params, api) {
|
||||
const x0 = api.getWidth() / 2
|
||||
const y0 = api.getHeight() / 2
|
||||
const r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65
|
||||
const point = getCirlPoint(x0, y0, r, 90 + -angle)
|
||||
return {
|
||||
type: 'circle',
|
||||
shape: {
|
||||
cx: point.x,
|
||||
cy: point.y,
|
||||
r: 4
|
||||
},
|
||||
style: {
|
||||
stroke: '#0CD3DB', // 粉
|
||||
fill: '#0CD3DB'
|
||||
},
|
||||
silent: true
|
||||
}
|
||||
},
|
||||
data: [0]
|
||||
},
|
||||
{
|
||||
name: 'ring5', // 绿点
|
||||
type: 'custom',
|
||||
coordinateSystem: 'none',
|
||||
renderItem: function(params, api) {
|
||||
const x0 = api.getWidth() / 2
|
||||
const y0 = api.getHeight() / 2
|
||||
const r = (Math.min(api.getWidth(), api.getHeight()) / 2) * 0.65
|
||||
const point = getCirlPoint(x0, y0, r, 270 + -angle)
|
||||
return {
|
||||
type: 'circle',
|
||||
shape: {
|
||||
cx: point.x,
|
||||
cy: point.y,
|
||||
r: 4
|
||||
},
|
||||
style: {
|
||||
stroke: '#0CD3DB', // 绿
|
||||
fill: '#0CD3DB'
|
||||
},
|
||||
silent: true
|
||||
}
|
||||
},
|
||||
data: [0]
|
||||
},
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['58%', '45%'],
|
||||
silent: true,
|
||||
clockwise: true,
|
||||
startAngle: 90,
|
||||
z: 0,
|
||||
zlevel: 0,
|
||||
label: {
|
||||
normal: {
|
||||
position: 'center'
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: value,
|
||||
name: '',
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: {
|
||||
// 完成的圆环的颜色
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#4FADFD' // 0% 处的颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#28E8FA' // 100% 处的颜色
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
value: 100 - value,
|
||||
name: '',
|
||||
label: {
|
||||
normal: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: '#173164'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '',
|
||||
type: 'gauge',
|
||||
radius: '58%',
|
||||
center: ['50%', '50%'],
|
||||
startAngle: 0,
|
||||
endAngle: 359.9,
|
||||
splitNumber: 8,
|
||||
hoverAnimation: true,
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
length: 12,
|
||||
lineStyle: {
|
||||
width: 5,
|
||||
color: '#061740'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
show: false
|
||||
},
|
||||
pointer: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
opacity: 0
|
||||
}
|
||||
},
|
||||
detail: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: 0,
|
||||
name: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 获取圆上面某点的坐标(x0,y0表示坐标,r半径,angle角度)
|
||||
function getCirlPoint(x0, y0, r, angle) {
|
||||
const x1 = x0 + r * Math.cos((angle * Math.PI) / 180)
|
||||
const y1 = y0 + r * Math.sin((angle * Math.PI) / 180)
|
||||
return {
|
||||
x: x1,
|
||||
y: y1
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(() => {
|
||||
angle = angle + 3
|
||||
option.title.text = `{a|${this.used}}{c|%}`
|
||||
option.series[6].data[0].value = this.used
|
||||
option.series[6].data[1].value = 100 - parseFloat(this.used)
|
||||
this.myChart.setOption(option, true)
|
||||
}, 100)
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
this.myChart.resize()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
#RealTimeUsed {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,264 @@
|
|||
<template>
|
||||
<div id="UsedTrend"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import { getAverageUtilizationTrend } from './api.js'
|
||||
export default {
|
||||
name: 'UsedTrend',
|
||||
data() {
|
||||
return {
|
||||
myChart: null,
|
||||
timer: null,
|
||||
tableData7: [
|
||||
{
|
||||
data: 50,
|
||||
name: 1621300392
|
||||
},
|
||||
|
||||
{
|
||||
data: 90,
|
||||
name: 1691300392
|
||||
},
|
||||
{
|
||||
data: 70,
|
||||
name: 1729300392
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const chartDom = document.getElementById('UsedTrend')
|
||||
this.myChart = echarts.init(chartDom)
|
||||
this.getQueryRangeData()
|
||||
this.getQueryRangeView()
|
||||
},
|
||||
unmounted() {
|
||||
clearInterval(this.timer)
|
||||
},
|
||||
methods: {
|
||||
// 平台实用利用率
|
||||
async getQueryRangeData() {
|
||||
const res = await getAverageUtilizationTrend()
|
||||
if (res.status !== 'success') return
|
||||
this.tableData7 = res.data?.result?.[0]?.values?.map(v => {
|
||||
return {
|
||||
name: v[0],
|
||||
data: v[1]
|
||||
}
|
||||
})
|
||||
this.getQueryRangeView()
|
||||
},
|
||||
getQueryRangeView() {
|
||||
const ydata = this.tableData7.map(v => parseFloat(v.data).toFixed(2))
|
||||
const xdata = this.tableData7.map(v => {
|
||||
const date = new Date(v.name * 1000)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
const hours = String(date.getHours()).padStart(2, '0')
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||||
const seconds = String(date.getSeconds()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
})
|
||||
const option = {
|
||||
grid: {
|
||||
left: '0%', // 将 left 设置为 0 确保左边没有留白
|
||||
right: '0%',
|
||||
top: '20%',
|
||||
bottom: '0%',
|
||||
containLabel: true, // 确保标签不会被裁剪
|
||||
show: false
|
||||
},
|
||||
|
||||
tooltip: {
|
||||
formatter: '{b}: {c}',
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0, 82, 212,0.3)',
|
||||
type: 'dashed'
|
||||
}
|
||||
},
|
||||
backgroundColor: 'rgba(0, 82, 212,0.3)',
|
||||
padding: [5, 10],
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
right: 20,
|
||||
orient: 'vertical'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: xdata,
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: true,
|
||||
interval: 'auto',
|
||||
lineStyle: {
|
||||
color: 'rgba(0,0,0,0.06)'
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0,0,0,0.06)'
|
||||
}
|
||||
}
|
||||
// axisLabel: {
|
||||
// rotate: 45,
|
||||
// textStyle: {
|
||||
// color: '#fff'
|
||||
// }
|
||||
// }
|
||||
},
|
||||
yAxis: {
|
||||
// name: '出勤人数',
|
||||
nameTextStyle: {
|
||||
color: '#666'
|
||||
},
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 100,
|
||||
minInterval: 1, // 横坐标值为整数
|
||||
splitLine: {
|
||||
show: true,
|
||||
interval: 'auto',
|
||||
lineStyle: {
|
||||
color: 'rgba(0,0,0,0.06)'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(0,0,0,0.06)'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
margin: 1,
|
||||
textStyle: {
|
||||
fontSize: 10,
|
||||
color: '#FFF'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 2,
|
||||
data: ydata,
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgb(128, 255, 165)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgb(1, 191, 236, 0)'
|
||||
}
|
||||
],
|
||||
false
|
||||
)
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
borderWidth: 2,
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(0, 82, 212,0.7)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(0, 82, 212,0.4)'
|
||||
}
|
||||
],
|
||||
false
|
||||
)
|
||||
}
|
||||
},
|
||||
lineStyle: {
|
||||
globalCoord: false, // 缺省为 false
|
||||
normal: {
|
||||
width: 2,
|
||||
color: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(0, 82, 212,0.7)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(0, 82, 212,0.4)'
|
||||
}
|
||||
],
|
||||
false
|
||||
)
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
borderWidth: 2,
|
||||
borderColor: new echarts.graphic.LinearGradient(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
[
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(245,166,35,1)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(245,166,35,0.8)'
|
||||
}
|
||||
],
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
option && this.myChart.setOption(option)
|
||||
window.addEventListener('resize', () => {
|
||||
this.myChart.resize()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
#UsedTrend {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,98 @@
|
|||
import axios from 'axios'
|
||||
|
||||
// 单位机时统计
|
||||
export const getDepartDuration = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/findTopByOrg?startDate=2024-05-01&endDate=2024-06-30')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 软件机时统计
|
||||
export const getSoftwareDuration = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/findTopBySoft?startDate=2024-05-01&endDate=2024-06-30')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 当前在用软件
|
||||
export const getInUseSoftware = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/findTopSoftList?startDate=2024-05-01&endDate=2024-06-30')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 用户机时用量
|
||||
export const getUserUseTrend = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/findTopByUser?startDate=2024-05-01&endDate=2024-06-30')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
// 软件集成数量
|
||||
export const getSoftwareIntegrate = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/findSoftCount?startDate=2024-05-01&endDate=2024-06-30')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 查看帮助
|
||||
export const getHelp = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/help/query')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
// 实时利用率
|
||||
export const getRealTimeUtilization = () =>
|
||||
axios
|
||||
.get('/prometheus/api/v1/query?query=avg(1 - avg(rate(node_cpu_seconds_total{mode="idle"}[2m])) by (instance)) * 100')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 平均利用率趋势
|
||||
export const getAverageUtilizationTrend = () =>
|
||||
axios
|
||||
.get('/prometheus/api/v1/query_range')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
||||
|
||||
// 查询平台统计数据
|
||||
export const getPlateformSum = () =>
|
||||
axios
|
||||
.post('/screen_server/hpc/findSum')
|
||||
.then(function(response) {
|
||||
return response.data
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.log(error)
|
||||
})
|
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div class="full-screen-container" :style="style">
|
||||
<slot></slot>
|
||||
<div class="loading" v-if="loading">
|
||||
<dv-decoration-9 style="width:300px;height:300px;">数据加载中</dv-decoration-9>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { computed, onMounted, onUnmounted, reactive, toRefs } from '@vue/composition-api'
|
||||
import { debounce } from 'lodash-es'
|
||||
// import 'utils/rem'
|
||||
export default {
|
||||
props: {
|
||||
width: {
|
||||
type: Number,
|
||||
default: 1920
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 1080
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
setup(props, context) {
|
||||
const state = reactive({
|
||||
scale: null
|
||||
})
|
||||
const style = computed(() => {
|
||||
return {
|
||||
width: `${props.width}px`,
|
||||
height: `${props.height}px`,
|
||||
transform: `scale(${state.scale})`
|
||||
}
|
||||
})
|
||||
function getScale() {
|
||||
const { width, height } = props
|
||||
const wRatio = window.innerWidth / width
|
||||
const hRatio = window.innerHeight / height
|
||||
// return 1;
|
||||
return wRatio < hRatio ? wRatio : hRatio
|
||||
}
|
||||
function setScale() {
|
||||
state.scale = getScale()
|
||||
context.emit('getScale', state.scale)
|
||||
}
|
||||
const onResize = debounce(setScale, 10)
|
||||
onMounted(() => {
|
||||
setScale()
|
||||
window.addEventListener('resize', onResize)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', onResize)
|
||||
})
|
||||
return {
|
||||
style
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.full-screen-container {
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
overflow: hidden;
|
||||
transform-origin: left top;
|
||||
z-index: 999;
|
||||
.loading {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,104 @@
|
|||
<template>
|
||||
<div class="outside-header">
|
||||
<span class="pull-left">
|
||||
<img class="logo m-r" :src="logo" />
|
||||
<img class="m-r" :src="logo2" />
|
||||
<div class="inline-block left-title text-center sub-title">
|
||||
<div>国家能源集团科学技术研究院有限公司</div>
|
||||
<div>重点实验室</div>
|
||||
</div>
|
||||
</span>
|
||||
<span class="screen-title" @click="operateScreen">
|
||||
{{ title }}
|
||||
</span>
|
||||
<span class="pull-right">
|
||||
<span class="m-r-lg tips">系统使用手册下载</span>
|
||||
<span class="btn m-r">登录入口</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import useHeader from './useHeader.js'
|
||||
export default {
|
||||
setup() {
|
||||
const { operateScreen, logo, logo2, title } = useHeader()
|
||||
return {
|
||||
logo,
|
||||
logo2,
|
||||
title,
|
||||
operateScreen
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.m-r {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.m-r-lg {
|
||||
margin-right: 35px;
|
||||
}
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pull-left {
|
||||
text-align: left;
|
||||
}
|
||||
.inline-block {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.pull-right {
|
||||
text-align: right;
|
||||
}
|
||||
.outside-header {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 73px;
|
||||
display: flex;
|
||||
& > span {
|
||||
flex: 1;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.left-title {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
vertical-align: top;
|
||||
}
|
||||
.logo {
|
||||
margin: 0 0 0 20px;
|
||||
width: 54px;
|
||||
}
|
||||
.sub-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
.screen-title {
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-size: 28px;
|
||||
line-height: 42px;
|
||||
font-style: normal;
|
||||
text-transform: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tips {
|
||||
font-size: 16px;
|
||||
color: #b7b7b7;
|
||||
cursor: pointer;
|
||||
}
|
||||
.btn {
|
||||
padding: 5px;
|
||||
width: 30px;
|
||||
height: 20px;
|
||||
font-size: 18px;
|
||||
color: #03a9f4;
|
||||
cursor: pointer;
|
||||
background: url('../images/card_bg.png');
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,38 @@
|
|||
<template>
|
||||
<div class="table-td" :title="value" :style="style">
|
||||
<slot :value=value>
|
||||
<el-tooltip class="item" effect="dark" :content="value.toString()" placement="top-start">
|
||||
<span>{{value}}</span>
|
||||
</el-tooltip>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { computed } from '@vue/composition-api'
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
return {
|
||||
style: props.width ? { width: props.width, flex: 'none' } : {}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
div.table-td {
|
||||
flex: 1;
|
||||
// width: calc(100% / 7);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
padding: 8px 5px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<ul class="scroll-table">
|
||||
<li class="table-header">
|
||||
<div v-for="(item, index) in columns" :key="item" :title="item" :style="getStyle(index)">
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<div class="table-body">
|
||||
<li class="table-tr" v-for="(item, index) in data" :key="index">
|
||||
<slot :row="item"></slot>
|
||||
</li>
|
||||
<div v-if="!data.length"></div>
|
||||
</div>
|
||||
</ul>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
options: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
columns: {
|
||||
type: Array
|
||||
},
|
||||
columnWidth: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
data: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const getStyle = index => {
|
||||
const width = props.columnWidth[index]
|
||||
return width ? { width: width, flex: 'none' } : {}
|
||||
}
|
||||
return {
|
||||
getStyle
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.scroll-table {
|
||||
height: 100%;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
padding: 0 10px;
|
||||
list-style: none;
|
||||
.table-header {
|
||||
background: #152e6a;
|
||||
background: url('../../images/table-header.png');
|
||||
background-repeat: no-repeat;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
div {
|
||||
flex: 1;
|
||||
// width: calc(100% / 7);
|
||||
padding: 10px 5px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
.table-body {
|
||||
height: calc(100% - 50px);
|
||||
overflow-y: auto;
|
||||
|
||||
.table-tr {
|
||||
display: flex;
|
||||
background: url('../../images/table-row.png');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
}
|
||||
.table-body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,49 @@
|
|||
import logo from '../images/logo.png'
|
||||
import logo2 from '../images/logo2.png'
|
||||
export default function() {
|
||||
const title = '高性能数值模拟实验平台'
|
||||
|
||||
let isFull = false
|
||||
function operateScreen() {
|
||||
if (isFull) {
|
||||
disableFullScreen()
|
||||
} else {
|
||||
enableFullScreen()
|
||||
}
|
||||
isFull = !isFull
|
||||
}
|
||||
return {
|
||||
logo,
|
||||
logo2,
|
||||
title,
|
||||
operateScreen
|
||||
}
|
||||
}
|
||||
|
||||
export function enableFullScreen() {
|
||||
const docElm = document.documentElement
|
||||
// W3C
|
||||
if (docElm.requestFullscreen) {
|
||||
docElm.requestFullscreen()
|
||||
} else if (docElm.mozRequestFullScreen) {
|
||||
// FireFox
|
||||
docElm.mozRequestFullScreen()
|
||||
} else if (docElm.webkitRequestFullScreen) {
|
||||
// Chrome等
|
||||
docElm.webkitRequestFullScreen()
|
||||
} else if (docElm.msRequestFullscreen) {
|
||||
// IE11
|
||||
document.body.msRequestFullscreen()
|
||||
}
|
||||
}
|
||||
export function disableFullScreen() {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen()
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen()
|
||||
} else if (document.webkitCancelFullScreen) {
|
||||
document.webkitCancelFullScreen()
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen()
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 333 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 649 B |
|
@ -1,201 +1,264 @@
|
|||
<template>
|
||||
<full-screen-container :width="1920" :height="1080" :loading="loading">
|
||||
<Header code="COUNT_SCREEN"></Header>
|
||||
<FullScreenContainer :width="1920" :height="1080" :loading="loading">
|
||||
<Header> </Header>
|
||||
<div class="container">
|
||||
<el-row class="full">
|
||||
<el-col :span="8" class="left">
|
||||
<div class="card">
|
||||
<div class="card-title">资源总览</div>
|
||||
<el-row class="full" :gutter="10">
|
||||
<el-col :span="7" class="left">
|
||||
<div class="card mini-card card-border1">
|
||||
<div class="card-title card-title-border1">平台实时利用率</div>
|
||||
<div class="card-body">
|
||||
<el-row :gutter="15">
|
||||
<el-col :span="12">
|
||||
<ResourceCount title="云主机总数(台)" :value="overviewData.vms" color=""></ResourceCount>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ResourceCount title="CPU总量(核)" :value="overviewData.cpu" color="#18BE6A" icon="/scr-web/static/img/sip/cpu.png"></ResourceCount>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ResourceCount title="内存总量(TB)" :value="overviewData.mem" color="#1890FF" icon="/scr-web/static/img/sip/mem.png"></ResourceCount>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<ResourceCount title="存储总量(TB)" :value="overviewData.disk" color="#FF6600" icon="/scr-web/static/img/sip/storage.png"></ResourceCount>
|
||||
<RealTimeUsed></RealTimeUsed>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card card-border2">
|
||||
<div class="card-title card-title-border1">单位使用排名</div>
|
||||
<div class="card-body">
|
||||
<ScrollTable :data="departTrend" :column-width="['80px']" :columns="['排名', '单位名称', '机时']" :options="{ singleHeight: 32 }">
|
||||
<template v-slot="scope">
|
||||
<scroll-table-column :value="scope.row.rank" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<div class="square" :style="{ 'background-color': colorMap[scope.value - 1] || 'gray' }">{{ scope.value }}</div>
|
||||
</template>
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.org_name"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.calc_time"> </scroll-table-column>
|
||||
</template>
|
||||
</ScrollTable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card mini-card card-border3">
|
||||
<div class="card-title card-title-border1">应用软件使用排名</div>
|
||||
<div class="card-body">
|
||||
<ScrollTable :data="appTrend" :column-width="['80px']" :columns="['排名', '软件名称', '机时']" :options="{ singleHeight: 32 }">
|
||||
<template v-slot="scope">
|
||||
<scroll-table-column :value="scope.row.rank" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<div class="square" :style="{ 'background-color': colorMap[scope.value - 1] || 'gray' }">{{ scope.value }}</div>
|
||||
</template>
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.app_name"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.calc_time"> </scroll-table-column>
|
||||
</template>
|
||||
</ScrollTable>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="10" class="center">
|
||||
<div class="card intro-card card-border4">
|
||||
<div class="card-title card-title-border2">平台简介</div>
|
||||
<div class="card-body ">
|
||||
<img class="intro-img m-t" src="./images/plateform.png" />
|
||||
<div class="intro-text">
|
||||
<div>
|
||||
中科院高性能数值模拟实验平台是低碳智能燃煤发电与超净排放全国重点实验室的核心实验平台之-,以设计标准化、部署模块化,管理可视化,运维智能化为依托,打造满足中国机房设计标准、美国机房设计标准和Uptime
|
||||
Institue的创新性平台,致力于拓展科研手段、深化生产服务,为火力发电、新能源等领域的关键技术、核心装备、系统集成等相关科技研发提供有力支撑。
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
平台建筑面积200余平方米,硬件设施智能完善、软件系统高效便捷,主要开展火力发电固体燃料热解与燃烧、气体燃料燃烧、污染物生成与脱除、物质流能量流、全过程控制优化的数值模拟,以及综合能源系统仿真研究等八大研究方向。
|
||||
</div>
|
||||
</div>
|
||||
<el-row :gutter="32">
|
||||
<el-col :span="6" v-for="(item, index) in introItems" :key="index">
|
||||
<div class="intro-item text-right m-r " :style="{ 'background-image': `url(${item.img})` }">
|
||||
<div>
|
||||
<span class="intro-item-value" :style="{ color: introColorMap[index] }">{{ item.value }}</span>
|
||||
<span>{{ item.unit }}</span>
|
||||
</div>
|
||||
<div>{{ item.text }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-title">近30天云主机申请趋势</div>
|
||||
<div class="card mini-card card-border5">
|
||||
<div class="card-title card-title-border2">当前在用软件清单</div>
|
||||
<div class="card-body">
|
||||
<line-charts :data="vmApplyTrend" width="100%" height="100%">
|
||||
</line-charts>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-title">近30天云资源申请趋势</div>
|
||||
<div class="card-body">
|
||||
<line-charts :data="resourceApplyTrend" width="100%" height="100%">
|
||||
</line-charts>
|
||||
<ScrollTable :data="inUseApps" :column-width="['80px']" :columns="['序号', '软件名称', '使用人员', '单位名称']" :options="{ singleHeight: 32 }">
|
||||
<template v-slot="scope">
|
||||
<scroll-table-column :value="scope.row.rank" width="80px"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.app_name"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.combined_info"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.departName"> </scroll-table-column>
|
||||
</template>
|
||||
</ScrollTable>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8" class="center">
|
||||
<OneCenter @changeDc="change"></OneCenter>
|
||||
</el-col>
|
||||
<el-col :span="8" class="right">
|
||||
<div class="card">
|
||||
<div class="card-title">租户云资源统计</div>
|
||||
<el-col :span="7" class="right">
|
||||
<div class="card mini-card card-border1">
|
||||
<div class="card-title card-title-border1">平台利用率趋势</div>
|
||||
<div class="card-body">
|
||||
<scroll-table :data="tenantCount" :column-width="['80px']" :columns="['租户', 'CPU(核)' , '内存(GB)' , '存储(GB)']" :options="{singleHeight: 40}">
|
||||
<template v-slot="scope">
|
||||
<scroll-table-column :value="scope.row.name" width="80px">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.cpu">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.mem">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.disk">
|
||||
</scroll-table-column>
|
||||
</template>
|
||||
</scroll-table>
|
||||
<UsedTrend></UsedTrend>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-title">项目云资源统计</div>
|
||||
<div class="card card-border2">
|
||||
<div class="card-title card-title-border1">用户使用排名</div>
|
||||
<div class="card-body">
|
||||
<scroll-table :data="projectCount" :column-width="['80px']" :columns="['项目', 'CPU(核)' , '内存(GB)' , '存储(GB)']" :options="{singleHeight: 40}">
|
||||
<ScrollTable :data="userUseTrend" :column-width="['80px']" :columns="['排名', '人员姓名', '单位名称', '机时']" :options="{ singleHeight: 32 }">
|
||||
<template v-slot="scope">
|
||||
<scroll-table-column :value="scope.row.name" width="80px">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.cpu">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.mem">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.disk">
|
||||
<scroll-table-column :value="scope.row.rank" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<div class="square" :style="{ 'background-color': colorMap[scope.value - 1] || 'gray' }">{{ scope.value }}</div>
|
||||
</template>
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.full_name"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.org_name"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.calc_time"> </scroll-table-column>
|
||||
</template>
|
||||
</scroll-table>
|
||||
</ScrollTable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-title">业务云资源统计</div>
|
||||
<div class="card mini-card card-border3">
|
||||
<div class="card-title card-title-border1">应用软件集成需求</div>
|
||||
<div class="card-body">
|
||||
<scroll-table :data="businessCount" :column-width="['80px']" :columns="['业务', 'CPU(核)' , '内存(GB)' , '存储(GB)']" :options="{singleHeight: 40}">
|
||||
<ScrollTable :data="appDemandList" :column-width="['80px']" :columns="['排名', '软件名称', '需求频次']" :options="{ singleHeight: 32 }">
|
||||
<template v-slot="scope">
|
||||
<scroll-table-column :value="scope.row.name" width="80px">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.cpu">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.mem">
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.disk">
|
||||
<scroll-table-column :value="scope.row.rank" width="80px">
|
||||
<template slot-scope="scope">
|
||||
<div class="square" :style="{ 'background-color': colorMap[scope.value - 1] || 'gray' }">{{ scope.value }}</div>
|
||||
</template>
|
||||
</scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.app_name"> </scroll-table-column>
|
||||
<scroll-table-column :value="scope.row.cnum"> </scroll-table-column>
|
||||
</template>
|
||||
</scroll-table>
|
||||
</ScrollTable>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</full-screen-container>
|
||||
</FullScreenContainer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Header from 'components/ScreenWrapper/Header'
|
||||
import FullScreenContainer from './components/FullScreenContainer.vue'
|
||||
import Header from './components/Header.vue'
|
||||
import ScrollTable from './components/ScrollTable/index.vue'
|
||||
import ScrollTableColumn from './components/ScrollTable/TableColumn.vue'
|
||||
import { reactive, toRefs } from '@vue/composition-api'
|
||||
import OneCenter from './OneCenter'
|
||||
import ResourceCount from './ResourceCount'
|
||||
import {
|
||||
getOverview,
|
||||
getVmApplyTrend,
|
||||
getResourceApplyTrend,
|
||||
getTenantResource,
|
||||
getProjectResource,
|
||||
getBusinessResource
|
||||
} from 'services/screen/outside'
|
||||
|
||||
import subIcon1 from './images/sub-icon1.png'
|
||||
import subIcon2 from './images/sub-icon2.png'
|
||||
import subIcon3 from './images/sub-icon3.png'
|
||||
import subIcon4 from './images/sub-icon4.png'
|
||||
import RealTimeUsed from './RealTimeUsed'
|
||||
import UsedTrend from './UsedTrend.vue'
|
||||
import { getDepartDuration, getSoftwareDuration, getInUseSoftware, getUserUseTrend, getSoftwareIntegrate, getPlateformSum } from './api'
|
||||
export default {
|
||||
components: { Header, ResourceCount, OneCenter },
|
||||
components: { FullScreenContainer, Header, ScrollTable, ScrollTableColumn, RealTimeUsed, UsedTrend },
|
||||
setup() {
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
overviewData: {},
|
||||
vmApplyTrend: {},
|
||||
resourceApplyTrend: {},
|
||||
tenantCount: [],
|
||||
projectCount: [],
|
||||
businessCount: []
|
||||
colorMap: ['red', '#ffc107', 'blue'],
|
||||
introColorMap: ['#6be6f5', '#489ef1', '#6ce2bb', '#d09154'],
|
||||
loading: false,
|
||||
departTrend: [],
|
||||
appTrend: [],
|
||||
inUseApps: [],
|
||||
introItems: [
|
||||
{
|
||||
value: 0,
|
||||
unit: '人',
|
||||
text: '注册人数',
|
||||
img: subIcon1
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
unit: '家',
|
||||
text: '注册单位',
|
||||
img: subIcon2
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
unit: '个',
|
||||
text: '软件数量',
|
||||
img: subIcon3
|
||||
},
|
||||
{
|
||||
value: 0,
|
||||
unit: '小 时',
|
||||
text: '使用总时长',
|
||||
img: subIcon4
|
||||
}
|
||||
],
|
||||
userUseTrend: [],
|
||||
appDemandList: []
|
||||
})
|
||||
let dcId = ''
|
||||
// 资源概览
|
||||
const getOverviewData = async () => {
|
||||
const res = await getOverview(dcId)
|
||||
if (res.success) {
|
||||
state.overviewData = res.data
|
||||
}
|
||||
const getDepartDurationList = async () => {
|
||||
const res = await getDepartDuration()
|
||||
state.departTrend = res.data.map((item, index) => {
|
||||
return { ...item, rank: index + 1 }
|
||||
})
|
||||
}
|
||||
// 云主机申请趋势
|
||||
const getVmTrend = async () => {
|
||||
const res = await getVmApplyTrend(dcId)
|
||||
if (res.success) {
|
||||
state.vmApplyTrend = res.data
|
||||
}
|
||||
const getSoftwareDurationList = async () => {
|
||||
const res = await getSoftwareDuration()
|
||||
state.appTrend = res.data.map((item, index) => {
|
||||
return { ...item, rank: index + 1 }
|
||||
})
|
||||
}
|
||||
// 云资源申请趋势
|
||||
const getResourceTrend = async () => {
|
||||
const res = await getResourceApplyTrend(dcId)
|
||||
if (res.success) {
|
||||
state.resourceApplyTrend = res.data
|
||||
}
|
||||
|
||||
const getInUseSoftwareList = async () => {
|
||||
const res = await getInUseSoftware()
|
||||
state.inUseApps = res.data.map((item, index) => {
|
||||
return { ...item, rank: index + 1 }
|
||||
})
|
||||
}
|
||||
// 租户资源统计
|
||||
const getTenantCount = async () => {
|
||||
const res = await getTenantResource(dcId)
|
||||
if (res.success) {
|
||||
state.tenantCount = res.data
|
||||
}
|
||||
|
||||
const getUserUseTrendList = async () => {
|
||||
const res = await getUserUseTrend()
|
||||
state.userUseTrend = res.data.map((item, index) => {
|
||||
return { ...item, rank: index + 1 }
|
||||
})
|
||||
}
|
||||
// 项目资源统计
|
||||
const getProjectCount = async () => {
|
||||
const res = await getProjectResource(dcId)
|
||||
if (res.success) {
|
||||
state.projectCount = res.data
|
||||
}
|
||||
const getDemandList = async () => {
|
||||
const res = await getSoftwareIntegrate()
|
||||
state.appDemandList = res.data.map((item, index) => {
|
||||
return { ...item, rank: index + 1 }
|
||||
})
|
||||
}
|
||||
// 业务资源
|
||||
const getBusinessCount = async () => {
|
||||
const res = await getBusinessResource(dcId)
|
||||
if (res.success) {
|
||||
state.businessCount = res.data
|
||||
}
|
||||
const getPlateformSumList = async () => {
|
||||
const res = await getPlateformSum()
|
||||
|
||||
res.data.map(item => {
|
||||
if (item.keyName === 'userNum') {
|
||||
state.introItems[0].value = item.numValue
|
||||
}
|
||||
if (item.keyName === 'softNum') {
|
||||
state.introItems[1].value = item.numValue
|
||||
}
|
||||
if (item.keyName === 'orgNum') {
|
||||
state.introItems[2].value = item.numValue
|
||||
}
|
||||
|
||||
if (item.keyName === 'timeSum') {
|
||||
state.introItems[3].value = item.numValue
|
||||
}
|
||||
})
|
||||
}
|
||||
const change = async (id) => {
|
||||
dcId = id
|
||||
|
||||
const initData = async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
getOverviewData(),
|
||||
getVmTrend(),
|
||||
getResourceTrend(),
|
||||
getTenantCount(),
|
||||
getProjectCount(),
|
||||
getBusinessCount()
|
||||
])
|
||||
await Promise.all([getDepartDurationList(), getSoftwareDurationList(), getInUseSoftwareList(), getUserUseTrendList(), getDemandList(), getPlateformSumList()])
|
||||
} catch (error) {}
|
||||
state.loading = false
|
||||
}
|
||||
initData()
|
||||
return {
|
||||
...toRefs(state),
|
||||
change
|
||||
...toRefs(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url('/scr-web/static/img/sip/bg.png') no-repeat;
|
||||
padding: 100px 20px 20px 20px;
|
||||
background: url('./images/bg.png') no-repeat;
|
||||
padding: 90px 20px 20px 20px;
|
||||
box-sizing: border-box;
|
||||
color: #fff;
|
||||
}
|
||||
.full {
|
||||
height: 100%;
|
||||
|
@ -209,30 +272,108 @@ export default {
|
|||
width: 48%;
|
||||
height: 100%;
|
||||
}
|
||||
.loop-card {
|
||||
display: flex;
|
||||
.mini-card {
|
||||
height: 280px !important;
|
||||
}
|
||||
.card-border1 {
|
||||
background: url('./images/item-border1.png');
|
||||
background-size: 100% 85%;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: 43px;
|
||||
}
|
||||
.card-border2 {
|
||||
background: url('./images/item-border2.png');
|
||||
background-size: 100% 85%;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: 43px;
|
||||
}
|
||||
.card-border3 {
|
||||
background: url('./images/item-border3.png');
|
||||
background-size: 100% 85%;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: 43px;
|
||||
}
|
||||
.card-border4 {
|
||||
background: url('./images/item-border4.png');
|
||||
background-size: 100% 92%;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: 43px;
|
||||
}
|
||||
.card-border5 {
|
||||
background: url('./images/item-border5.png');
|
||||
background-size: 100% 85%;
|
||||
background-repeat: no-repeat;
|
||||
background-position-y: 43px;
|
||||
}
|
||||
.card-title-border1 {
|
||||
background: url('./images/item-header1.png');
|
||||
}
|
||||
.card-title-border2 {
|
||||
background: url('./images/item-header1.png');
|
||||
background-position-x: -33px !important;
|
||||
}
|
||||
.card {
|
||||
// height: calc((100% - 200px) / 3 - 20px);
|
||||
height: 310px;
|
||||
height: 350px;
|
||||
padding: 15px;
|
||||
padding-top: 0;
|
||||
box-sizing: border-box;
|
||||
background: url('/scr-web/static/img/sip/card_bg.png');
|
||||
background-size: 100% 100%;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
border-left: 3px solid #0089ff;
|
||||
font-weight: bold;
|
||||
color: #bbefff;
|
||||
padding-left: 5px;
|
||||
margin-bottom: 10px;
|
||||
padding-left: 70px;
|
||||
background-position-x: -40px;
|
||||
height: 60px;
|
||||
line-height: 75px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.card-body {
|
||||
height: calc(100% - 35px);
|
||||
height: calc(100% - 56px);
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.intro-card {
|
||||
height: 650px;
|
||||
.intro-img {
|
||||
width: 100%;
|
||||
height: 280px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.intro-text {
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
text-indent: 2em;
|
||||
}
|
||||
.intro-item {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
padding-top: 15px;
|
||||
& > div {
|
||||
padding-right: 20%;
|
||||
}
|
||||
.intro-item-value {
|
||||
margin-right: 10px;
|
||||
font-size: 32px;
|
||||
-webkit-text-stroke: 1px #fff;
|
||||
text-shadow: 0 0 2px #fff, 0 0 2px #fff, 0 0 2px #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
.square {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: gray;
|
||||
text-align: center;
|
||||
line-height: 20px;
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -45,6 +45,16 @@ module.exports = {
|
|||
pathRewrite: {
|
||||
'^/scr-web/static/img': '/static/img' // rewrite path
|
||||
}
|
||||
},
|
||||
'/screen_server': {
|
||||
target: 'http://gn.api.aipow.cn:8080',
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/screen_server': '/screen_server' }
|
||||
},
|
||||
'/prometheus': {
|
||||
target: 'http://gn.api.aipow.cn:8080',
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/prometheus': '/prometheus' }
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|