<script lang="ts" setup>
import { ref, reactive, onUnmounted, computed, nextTick, watch, onMounted } from 'vue';
import { ISensorData, ISensor } from './model/sensor.datatype';
import { getSensorEchartOptions, getSensorEchartOptionsBack } from './utils/sensor.utils';
import '@/assets/common/style/echarts-gl-formatter-style/index.scss';
import useStore from '@/stores';
import { getErrorTranslate, traduction } from '@/utils/language';
import * as echarts from 'echarts/core';
import 'echarts-gl';
import {
TooltipComponent,
LegendComponent,
GridComponent,
MarkPointComponent,
MarkLineComponent,
VisualMapComponent
} from 'echarts/components';
import { GaugeChart, PieChart, LineChart } from 'echarts/charts';
import { LabelLayout, UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import { loading, showFailedMessage, showSuccessMessage } from '@/utils/composition';
import { useI18n } from 'vue-i18n';
import RightTabs from '@/components/RightTabs/RightTabs.vue';
import { getThermals } from '../Info/service/system.service';
import { Search } from '@element-plus/icons-vue';
import SearchIcon from '@/components/SearchIcon/SearchIcon.vue';
import SearchInput from '@/components/SearchInput/SearchInput.vue';
echarts.use([
TooltipComponent,
LegendComponent,
GridComponent,
MarkPointComponent,
MarkLineComponent,
VisualMapComponent,
GaugeChart,
LineChart,
PieChart,
CanvasRenderer,
LabelLayout,
UniversalTransition
]);
const store = useStore();
let pageSizeCount = ref(15);
const items = reactive([
{
label: '℃',
id: 'degrees-celsius'
},
{
label: '℉',
id: 'degree-fahrenheit'
}
]);
const itemsBack = reactive([
{
id: 1,
text: 'FRONT_PANEL_VIEW',
isBack: false,
src: '@/assets/common/image/back.png',
srcBack: '@/assets/common/image/front.png'
},
{
id: 2,
text: 'REAR_PANEL_VIEW',
isBack: true,
src: '@/assets/common/image/front.png',
srcBack: '@/assets/common/image/back.png'
}
]);
const inputValue1 = ref('');
const table = reactive({
displayed: [],
srcData: {
data: <ISensor[]>[],
state: {
searched: false,
sorted: false,
paginated: false
}
},
searchWords: [inputValue1.value],
searchKeys: ['Name']
});
let currentPage = ref(1);
let totalNumber: number = 0;
function pageChange() {
table.srcData.data = preData.value
.filter((item: any) => {
if (item.Name.toLowerCase().indexOf(inputValue1.value.toLowerCase()) !== -1) {
return item;
}
})
.slice((currentPage.value - 1) * pageSizeCount.value, pageSizeCount.value * currentPage.value);
}
// 第几页点击
const handleCurrentChange = (pageNumber: number) => {
currentPage.value = pageNumber;
pageChange();
};
// 框内页码范围
const handleSizeChange = (pageCount: number) => {
pageSizeCount.value = pageCount;
currentPage.value = 1;
pageChange();
};
const selected = ref('℃');
const selectedBack = ref(false);
const wallShow = ref(false);
const i18n = useI18n();
const preData = ref();
const chartOption = reactive({
option: {}
});
const chartOptionBack = reactive({
option: {}
});
let myChart: any = {};
let myChartBack: any = {};
function initSensorTable(data: ISensorData): void {
data.Sensors = data.Temperatures;
const srcData = renderTable(data.Sensors);
preData.value = JSON.parse(JSON.stringify(srcData));
table.srcData.data = srcData.slice(0, pageSizeCount.value);
currentPage.value = 1;
totalNumber = srcData.length;
table.displayed = [];
chartOption.option = getSensorEchartOptions(data, selected);
chartOptionBack.option = getSensorEchartOptionsBack(data, selected);
nextTick(() => {
const elem: HTMLElement = document.getElementById('frontId') as HTMLElement;
myChart = echarts.init(elem);
myChart.setOption(chartOption.option);
wallShow.value = true;
loading(false);
});
}
function initSensorData(): void {
loading(true);
getThermals()
.then((response: any) => {
initSensorTable(response.data.TemperaturesInfo as unknown as ISensorData);
loading(false);
})
.catch((error: any) => {
loading(false);
});
}
onMounted(() => {
initSensorData();
});
onUnmounted(() => {
echarts.dispose(myChart);
echarts.dispose(myChartBack);
});
function renderTable(data: ISensor[]): ISensor[] {
return data.map((e, i) => ({ Index: i + 1, ...e }));
}
function getF(value: any): number {
return (value * 9) / 5 + 32;
}
function setOneWordSearch(value: any) {
inputValue1.value = value;
pageChange();
}
function selectedBackChange() {
if (selectedBack.value) {
nextTick(() => {
const elemBack: HTMLElement = document.getElementById('frontBackId') as HTMLElement;
myChartBack = echarts.init(elemBack);
myChartBack.setOption(chartOptionBack.option);
});
}
}
</script>
<template>
<div id="container" class="container">
<div id="title" class="title">
<div id="left" class="left">{{ traduction('FAN_SENSOR_TAB') }}</div>
<div id="rightBox" class="rightBox">
<SearchInput
:id-str="'sensorSearchBox'"
:value="inputValue1"
:placeholder="$t('SENSOR_KEY_WORD')"
@input="setOneWordSearch"
@clear="setOneWordSearch"
/>
<el-icon id="searchIcon" name="search" class="searchIcon"></el-icon>
<el-radio-group id="searchBtnGroup" v-model="selected">
<el-radio-button
v-for="item of items"
id="searchBtn"
:key="item.id"
class="btnGroup"
:label="item.label"
></el-radio-button>
</el-radio-group>
</div>
</div>
<div id="content" class="content">
<div id="leftHalfContainer" class="leftHalfContainer">
<div>
<el-radio-group v-model="selectedBack">
<el-radio-button
id="btnGroup"
:key="itemsBack[0].id"
min-width="32px"
class="btnGroup"
:label="itemsBack[0].isBack"
>
<template #default>
<div id="btnContent" class="btnContent">
<img
v-show="selectedBack"
src="@/assets/common/image/back.png"
alt=""
class="img-css img-hover"
/>
<img
v-show="!selectedBack"
src="@/assets/common/image/front.png"
alt=""
class="img-css img-hover"
/>
<span style="margin-left: 10px">{{ traduction(itemsBack[0].text) }}</span>
</div>
</template>
</el-radio-button>
<el-radio-button
id="btnGroup"
:key="itemsBack[1].id"
min-width="32px"
class="btnGroup"
:label="itemsBack[1].isBack"
@change="selectedBackChange()"
>
<template #default>
<div id="btnContent" class="btnContent">
<img
v-show="selectedBack"
src="@/assets/common/image/front.png"
alt=""
class="img-css img-hover"
/>
<img
v-show="!selectedBack"
src="@/assets/common/image/back.png"
alt=""
class="img-css img-hover"
/>
<span style="margin-left: 10px">{{ traduction(itemsBack[1].text) }}</span>
</div>
</template>
</el-radio-button>
</el-radio-group>
</div>
<div v-show="!selectedBack" id="half-container" class="half-container">
<div v-show="wallShow">
<div id="wallFront" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="wallBack" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="wallLeft" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="wallRight" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
</div>
<div id="chart-container" class="chart-container">
<div id="frontId" class="sensorChart"></div>
</div>
</div>
<div v-show="selectedBack" id="half-containerBack" class="half-container">
<div id="wallFront" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="wallBack" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="wallLeft" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="wallRight" class="wallFront">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
<div id="chart-container" class="chart-container">
<div id="frontBackId" class="sensorChart"></div>
</div>
</div>
<div v-if="selected" id="temperature" class="temperature">
<div id="temperatureTop" class="temperatureTop">
<span>{{ selected === '℃' ? 0 : 32 }}{{ selected }}</span>
<span>{{ selected === '℃' ? 20 : 68 }}{{ selected }}</span>
<span>{{ selected === '℃' ? 40 : 104 }}{{ selected }}</span>
<span>{{ selected === '℃' ? 60 : 140 }}{{ selected }}</span>
<span>{{ selected === '℃' ? 80 : 176 }}{{ selected }}</span>
<span>{{ selected === '℃' ? 100 : 212 }}{{ selected }}</span>
<span>{{ selected === '℃' ? 120 : 248 }}{{ selected }}</span>
</div>
<div id="temperatureBottom" class="temperatureBottom">
<span id="temperatureText" class="temperatureText">
{{ traduction('FDM_TEMPERATURE') }}
</span>
<div id="temperatureColor" class="temperatureColor"></div>
</div>
</div>
</div>
<div id="rightHalf-container" class="rightHalf-container">
<div id="sensorTableComponent">
<el-table :data="table.srcData.data" border resizable>
<el-table-column min-width="5%" :label="$t('EVENT_ORDER')">
<template #default="scope">
<span class="id">{{ scope.row.Index }}</span>
</template>
</el-table-column>
<el-table-column min-width="10%" :label="$t('SENSOR_TITLE')">
<template #default="scope">
<span class="id">{{ scope.row.Name }}</span>
</template>
</el-table-column>
<el-table-column min-width="5%" :label="$t('SENSOR_CURRENT_VAL')">
<template #default="scope">
<span v-if="scope.row.ReadingValue || scope.row.ReadingValue === 0" class="subject">
<span v-if="selected === '℃'">
{{ `${scope.row.ReadingValue.toFixed(0)}℃` }}
</span>
<span v-if="selected === '℉'">
{{ `${getF(scope.row.ReadingValue).toFixed(0)}℉` }}
</span>
</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column min-width="10%" :label="$t('EVENT_STATUS')">
<template #default="scope">
<span v-if="scope.row.ReadingValue || scope.row.ReadingValue === 0">
<el-tag v-if="scope.row.Status === 'nr'" v-addTooltip.elTag type="danger">
{{ $t('ALARM_EVENT_CRITICAL') }}
</el-tag>
<el-tag v-if="scope.row.Status === 'nc'" v-addTooltip.elTag type="warning">
{{ $t('ALARM_EVENT_MINOR') }}
</el-tag>
<el-tag v-if="scope.row.Status === 'cr'" v-addTooltip.elTag type="major">
{{ $t('ALARM_EVENT_MAJOR') }}
</el-tag>
<el-tag v-if="scope.row.Status === 'ok'" v-addTooltip.elTag type="primary">
{{ $t('LICENSE_STATUS_NORMAL') }}
</el-tag>
</span>
<span v-else>--</span>
</template>
</el-table-column>
<el-table-column min-width="20%" :label="$t('MONITOR_THRESHOLD')">
<template #default="scope">
<span class="subject">
<span v-if="selected === '℃'">
{{ traduction('ALARM_EVENT_MINOR') }}:
{{ scope.row.UpperThreshold[0] ? `${scope.row.UpperThreshold[0]}℃` : 'N/A' }};
{{ traduction('ALARM_EVENT_MAJOR') }}:
{{ scope.row.UpperThreshold[1] ? `${scope.row.UpperThreshold[1]}℃` : 'N/A' }};{{
traduction('ALARM_EVENT_CRITICAL')
}}:
{{ scope.row.UpperThreshold[2] ? `${scope.row.UpperThreshold[2]}℃` : 'N/A' }}
</span>
<span v-if="selected === '℉'">
{{ traduction('ALARM_EVENT_MINOR') }}:
{{
scope.row.UpperThreshold[0] ? `${getF(scope.row.UpperThreshold[0])}℉` : 'N/A'
}}; {{ traduction('ALARM_EVENT_MAJOR') }}:
{{
scope.row.UpperThreshold[1] ? `${getF(scope.row.UpperThreshold[1])}℉` : 'N/A'
}};{{ traduction('ALARM_EVENT_CRITICAL') }}:
{{
scope.row.UpperThreshold[2] ? `${getF(scope.row.UpperThreshold[2])}℉` : 'N/A'
}}
</span>
</span>
</template>
</el-table-column>
<template #empty>
<TableNoData />
</template>
</el-table>
</div>
<div class="pagination">
<el-pagination
v-model="currentPage"
v-addId.pagination="'alarmPageNation'"
:page-sizes="[15, 30, 50]"
:page-size="pageSizeCount"
layout="total, sizes, prev, pager, next, jumper"
:total="totalNumber"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
></el-pagination>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
#searchBtnGroup {
width: 64px;
min-width: 64px;
#searchBtn {
margin: 0px !important;
width: 32px;
min-width: 0px;
:deep(.el-radio-button__original-radio) {
width: 0px;
}
:deep(.el-radio-button__inner) {
padding: 7px 0px !important;
width: 32px;
}
:deep(span) {
text-align: center;
min-width: 0px;
}
}
}
.noDataBox {
padding-top: 48px;
text-align: center;
font-size: 14px;
color: #727885;
.noData {
text-align: center;
background: url('@/assets/common/image/no-data.svg') no-repeat center center;
width: 100%;
height: 100px;
margin-bottom: 12px;
}
}
#saveBtn.saveBtn {
width: 98px;
height: 32px;
font-size: 14px;
color: #fff;
background: #6c92fa;
border-color: #6c92fa;
}
:deep(#eventTable) {
height: 748px;
overflow: auto;
}
#sensorTableComponent {
margin-top: 10px;
height: 784px;
overflow-y: scroll;
.pageNation {
margin-top: 20px;
}
}
.title {
display: flex;
font-size: 16px;
color: #282b33;
line-height: 32px;
font-weight: bold;
height: 32px;
padding-right: 24px;
justify-content: space-between;
.rightBox {
float: right;
display: flex;
.searchInput {
height: 34px;
line-height: 34px;
position: relative;
z-index: 1;
.searchInputText {
height: 32px;
padding-right: 16px;
}
.searchIcon {
position: absolute;
right: 0px;
padding-right: 8px;
top: 2px;
color: #8d98aa;
}
}
}
}
#btnGroup {
margin: 0;
}
.container {
background-color: #ffffff;
padding: 32px 0px 32px 24px;
min-height: calc(100vh - 224px);
width: 100%;
display: block;
height: 904px;
overflow-x: scroll;
overflow-y: hidden;
.content {
display: flex;
width: 100%;
.isBackBtn {
text-align: center;
}
.leftHalfContainer {
flex: 1;
text-align: center;
.btnGroup {
position: relative;
z-index: 1;
&:hover {
.img-css {
content: url('@/assets/common/image/front.png');
}
.btnContent {
span {
color: var(--el-color-white);
}
}
}
.btnContent {
display: flex;
align-items: center;
}
}
.temperature {
display: inline-block;
position: relative;
height: 30px;
padding-top: 50px;
.temperatureTop {
width: 490px;
padding-left: 76px;
display: flex;
justify-content: space-between;
font-family: HarmonyOS_Sans_SC;
font-size: 12px;
color: #8d98aa;
text-align: center;
line-height: 16px;
}
.temperatureBottom {
display: flex;
align-items: center;
.temperatureText {
width: 74px;
font-family: HarmonyOS_Sans_SC;
font-size: 12px;
color: #8d98aa;
line-height: 16px;
margin-left: -8px;
}
.temperatureColor {
margin-left: 8px;
background-image: linear-gradient(90deg, #5cffa2, #deff20, #ffaa00, #ff5e00, #ff0800);
height: 10px;
width: 401px;
}
}
}
}
.half-container {
width: 711px;
display: inline-block;
position: relative;
.wallFront {
position: absolute;
width: 200px;
height: 200px;
transform-style: preserve-3d;
transform: rotateX(-31deg) rotateY(-54deg);
z-index: 1;
top: 350px;
left: -30px;
div {
position: absolute;
width: 200px;
height: 200px;
opacity: 0.6;
transition: 0.4s;
}
.front {
transform: rotateY(0deg) translateZ(10px);
width: 500px;
background: #e6efff;
height: 60px;
}
.back {
transform: translateZ(-10px) rotateY(180deg);
background: #e6efff;
width: 500px;
height: 60px;
}
.left {
transform: rotateY(-90deg) translateZ(10px);
background: #e6efff;
width: 20px;
height: 60px;
}
.right {
transform: rotateY(90deg) translateZ(490px);
background: #e6efff;
width: 20px;
height: 60px;
}
.top {
transform: rotateX(90deg) translateZ(10px);
background: #fefefe;
width: 500px;
height: 20px;
}
.bottom {
transform: rotateX(-90deg) translateZ(50px);
background: #e6efff;
width: 500px;
height: 20px;
}
}
#wallBack {
top: 150px;
left: 370px;
z-index: 0;
transform: rotateX(-18deg) rotateY(-48deg);
.front {
transform: rotateY(0deg) translateZ(10px);
width: 440px;
background: #e6efff;
height: 60px;
}
.back {
transform: translateZ(-10px) rotateY(180deg);
background: #e6efff;
width: 440px;
height: 60px;
}
.left {
transform: rotateY(-90deg) translateZ(10px);
background: #e6efff;
width: 20px;
height: 60px;
}
.right {
transform: rotateY(90deg) translateZ(430px);
background: #e6efff;
width: 20px;
height: 60px;
}
.top {
transform: rotateX(90deg) translateZ(10px);
background: #fefefe;
width: 440px;
height: 20px;
}
.bottom {
transform: rotateX(-90deg) translateZ(50px);
background: #e6efff;
width: 440px;
height: 20px;
}
}
#wallLeft {
transform: rotateX(25deg) rotateY(-47deg);
z-index: 0;
top: 280px;
left: -35px;
.front {
width: 600px;
}
.back {
width: 600px;
}
.right {
transform: rotateY(90deg) translateZ(590px);
}
.top {
width: 600px;
}
.bottom {
width: 600px;
}
}
#wallRight {
transform: rotateX(31deg) rotateY(-57deg);
z-index: 1;
top: 480px;
left: 260px;
.front {
width: 700px;
}
.back {
width: 700px;
}
.right {
transform: rotateY(90deg) translateZ(690px);
}
.top {
width: 700px;
}
.bottom {
width: 700px;
}
}
.chart-container {
width: 100%;
height: 100%;
.sensorChart {
margin-top: -100px;
min-width: 800px;
min-height: 700px;
width: 800px;
height: 700px;
}
}
}
.rightHalf-container {
width: 692px;
height: 810px;
display: inline-block;
padding-right: 24px;
.chart-container {
width: 100%;
height: 100%;
.sensorChart {
width: 100%;
height: 100%;
min-width: 600px;
min-height: 600px;
}
}
}
}
.page {
width: 711px;
float: right;
padding-top: 24px;
}
}
</style>