fix: 测试

sqltest
时启龙 2024-07-18 20:02:21 +08:00
parent a9313551b0
commit ffa6c51ff2
31 changed files with 1958 additions and 626 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
})();
// 4003
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>

View File

@ -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,y0rangle)
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>

View File

@ -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>

View File

@ -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)
})

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

View File

@ -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>
<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="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>
<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>
<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>
</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>
</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>
<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>
</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>
</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: []
})
const getDepartDurationList = async () => {
const res = await getDepartDuration()
state.departTrend = res.data.map((item, index) => {
return { ...item, rank: index + 1 }
})
let dcId = ''
//
const getOverviewData = async () => {
const res = await getOverview(dcId)
if (res.success) {
state.overviewData = res.data
}
const getSoftwareDurationList = async () => {
const res = await getSoftwareDuration()
state.appTrend = 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 getInUseSoftwareList = async () => {
const res = await getInUseSoftware()
state.inUseApps = res.data.map((item, index) => {
return { ...item, rank: index + 1 }
})
}
const getUserUseTrendList = async () => {
const res = await getUserUseTrend()
state.userUseTrend = 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 getDemandList = async () => {
const res = await getSoftwareIntegrate()
state.appDemandList = res.data.map((item, index) => {
return { ...item, rank: index + 1 }
})
}
const getPlateformSumList = async () => {
const res = await getPlateformSum()
res.data.map(item => {
if (item.keyName === 'userNum') {
state.introItems[0].value = item.numValue
}
//
const getTenantCount = async () => {
const res = await getTenantResource(dcId)
if (res.success) {
state.tenantCount = res.data
if (item.keyName === 'softNum') {
state.introItems[1].value = item.numValue
}
if (item.keyName === 'orgNum') {
state.introItems[2].value = item.numValue
}
//
const getProjectCount = async () => {
const res = await getProjectResource(dcId)
if (res.success) {
state.projectCount = res.data
if (item.keyName === 'timeSum') {
state.introItems[3].value = item.numValue
}
})
}
//
const getBusinessCount = async () => {
const res = await getBusinessResource(dcId)
if (res.success) {
state.businessCount = res.data
}
}
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>

View File

@ -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' }
}
}
},