Files
sk_fems_ui/components/widget/PeakWidget.vue
2025-07-12 15:13:46 +09:00

525 lines
13 KiB
Vue

<template>
<div class="l-layout">
<v-row ref="rowParent">
<v-col :cols="12">
<v-card class="pa-3 widget-card">
<div class="d-flex align-center justify-space-between">
<v-card-title class="pa-0">전력피크</v-card-title>
<v-card-subtitle class="mt-0 pa-0">
<v-icon
v-show="widgetPrgmId"
class="mr-1"
size="25"
@click="btnAction('widgetCallPage')"
>mdi-note-search</v-icon
>
<v-icon
v-show="widgetPopFg"
size="25"
@click="btnAction('popWidget')"
>mdi-plus-box-multiple</v-icon
>
</v-card-subtitle>
</div>
<div class="d-flex align-center justify-space-between mt-1">
<div class="mr-2">
<div :style="{ width: '220px', height: '170px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'peakWidget'"
:widgetData="'peakWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</div>
<p class="custom-title-3 text-center">{{ elecContNm }}</p>
</div>
<div class="container">
<v-card-subtitle class="mt-0 mb-1 pa-0 text-right">
<span class="subtitle-2 mr-2"
>현재온도
<span :style="{ color: isDarkMode ? '#2d8cf6' : '#366dbe' }"
>{{ curTmpr }} </span
></span
>
{{ blocNm }} {{ dtToday }} 기준
</v-card-subtitle>
<div class="row">
<div class="col-4">
<div class="v-box-widget">
<v-icon
size="42"
:color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashChargeWidget</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ chargedPower }}
<span class="body-2">kW</span></strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
요금 적용전력
</p>
</div>
</div>
</div>
<div class="col-4">
<div class="v-box-widget">
<v-icon
size="42"
:color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashPeakWidget</v-icon
>
<div class="text-right">
<strong class="custom-title-3"
>{{ seasnNm }}/{{ peakNm }}</strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
현재부하
</p>
</div>
</div>
</div>
<div class="col-4">
<div class="v-box-widget">
<v-icon
size="42"
:color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashChargeWidget</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ unitPrce }} <span class="body-2"></span></strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
전력 부하단가
</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-4">
<div class="v-box-widget">
<v-icon
size="42"
:color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashPeakWidget</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ curPeakVal }} <span class="body-2">kW</span></strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
현재 피크전력
</p>
</div>
</div>
</div>
<div class="col-4">
<div class="v-box-widget">
<v-icon
size="42"
:color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashPeakWidget</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ curPeakFcstVal }}
<span class="body-2">kW</span></strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
예상 피크전력
</p>
</div>
</div>
</div>
<div class="col-4">
<div
id="mmPeakDt"
class="v-box-widget"
hover-tooltip="123"
tooltip-position="top"
>
<v-icon
size="42"
:color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashPeakWidget</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ mmPeakVal }}<span class="body-2">kW</span></strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
당월 최대부하
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</v-card>
</v-col>
</v-row>
</div>
</template>
<script>
import { mapActions, mapMutations, mapState } from 'vuex'; // , mapActions
import Vue from 'vue';
import DateUtility from '~/plugins/dateUtility';
import Utility from '~/plugins/utility';
import Chart from '~/components/common/Chart';
export default {
props: {
parentPrgmId: {
type: String,
require: true,
},
widgetId: {
type: String,
require: true,
},
widgetPrgmId: {
type: Boolean,
default: true,
},
widgetPopFg: {
type: Boolean,
default: true,
},
widgetReflashMm: {
type: Number,
require: true,
},
},
components: {
DateUtility,
Chart,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
peakWidget: { peakWidgetData },
});
// console.log("2.vue::beforeCreate");
},
created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
dtToday: Utility.setFormatDate(new Date(), 'YYYY-MM-DD HH:mm'),
dtYr: '1/1~' + Utility.setFormatDate(new Date(), 'M/D'),
dtBf:
DateUtility.addMonth(-1, 'M', new Date()) +
'/1~' +
DateUtility.addMonth(-1, 'M/D', new Date()),
dtMm:
Utility.setFormatDate(new Date(), 'M') +
'/1~' +
Utility.setFormatDate(new Date(), 'M/D'),
currHour: '0시-' + Utility.setFormatDate(new Date(), 'H') + '시',
blocNm: '',
//차트
chart_01: 'peakGauge',
loadChart_01: false,
//바인딩
curTmpr: 0, //현재 외기온도
chargedPower: 0, //요금 적용전력
curPeakVal: 0, //현재 피크전력
curPeakFcstVal: 0, //예상 피크전력
elecContNm: '', //전력계약
peakNm: '', //현재 부하
seasnNm: '', //현재 계절
unitPrce: 0, //전력 부하단가
mmPeakVal: 0, //당월 최대부하
peakDt: '', //당월 최대부하 일시
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
setWidgetInterval: 'setWidgetInterval',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
async search() {
this.setBlocNm();
this.dtToday = Utility.setFormatDate(new Date(), 'YYYY-MM-DD HH:mm');
this.dtYr = '1/1~' + Utility.setFormatDate(new Date(), 'M/D');
this.dtBf =
DateUtility.addMonth(-1, 'M', new Date()) +
'/1~' +
DateUtility.addMonth(-1, 'M/D', new Date());
this.dtMm =
Utility.setFormatDate(new Date(), 'M') +
'/1~' +
Utility.setFormatDate(new Date(), 'M/D');
this.currHour = '0시-' + Utility.setFormatDate(new Date(), 'H') + '시';
//현재 외기온도
await this.getOutside();
//피크전력, 예상피크전력
await this.getElecPeakRead();
//부하단가, 전력부하
await this.getElecPowChrg();
//당월최대부하
await this.getPeakPowMonth();
},
async getElecPeakRead() {
this.loadChart_01 = false;
const res = await this.postApiReturn({
apiKey: 'selectElecPeakRead',
resKey: 'elecPeakReadData',
sendParam: {},
});
res.forEach((item, idx) => {
this.chargedPower = Utility.setFormatInt(item.peakVal);
this.curPeakVal = Utility.setFormatInt(item.curPeakVal);
this.curPeakFcstVal = Utility.setFormatInt(item.curPeakFcstVal);
});
this.$nextTick(() => {
this.setChart01Data(res);
});
},
async getElecPowChrg() {
const res = await this.postApiReturn({
apiKey: 'selectElecPowChrg',
resKey: 'elecPowChrgData',
sendParam: {
readDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
readDtMm: Utility.setFormatDate(new Date(), 'MM'),
},
});
res.forEach((item, idx) => {
this.elecContNm = item.elecContNm;
this.peakNm = item.peakNm;
this.seasnNm = item.seasnNm;
this.unitPrce = Utility.setFormatInt(item.unitPrce);
});
},
async getOutside() {
const res = await this.postApiReturn({
apiKey: 'selectOutside',
resKey: 'dayOutsideData',
sendParam: {},
});
res.forEach((item, idx) => {
this.curTmpr = item.val;
});
},
async getPeakPowMonth() {
const res = await this.postApiReturn({
apiKey: 'selectPeakPowAndChargedPower',
resKey: 'peakData',
sendParam: {
cmCycle: 'CYC_MONTH',
fromObjDt: Utility.setFormatDate(new Date(), 'YYYYMM'),
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMM'),
},
});
res.forEach((item, idx) => {
this.peakDt = Utility.setFormatDate(item.date, 'YYYY/MM/DD HH');
this.mmPeakVal = item.curPeakVal;
});
if (this.peakDt != '' || this.peakDt != undefined)
$('#mmPeakDt').attr('hover-tooltip', this.peakDt);
},
//차트Setting
async setChart01Data(data) {
this.$store.state.pageData[
this.parentPrgmId
].peakWidget.peakWidgetData.series = [];
if (!data.length) {
return;
}
const arrDarkColors = {
정상: '#01ae6a',
주의: '#ffb046',
위험: '#f6637b',
};
const arrLightColors = {
정상: '#01ae6a',
주의: '#ffb046',
위험: '#f6637b',
};
const darkGaugeColors = [
[0.125, '#009245'],
[0.25, '#39b54a'],
[0.375, '#d9e021'],
[0.5, '#fcee21'],
[0.625, '#fbb03b'],
[0.75, '#f7931e'],
[0.875, '#f15a24'],
[1.0, '#ed1c24'],
];
const lightGaugeColors = [
[0.125, '#58c06f'],
[0.25, '#7cd574'],
[0.375, '#fbe462'],
[0.5, '#ffd771'],
[0.625, '#ffad7f'],
[0.75, '#ff966e'],
[0.875, '#ff706e'],
[1.0, '#ff6689'],
];
var chartOption = {
series: [
{
type: 'gauge',
startAngle: 180,
endAngle: 0,
min: 0,
max: 100,
radius: '100%',
center: ['50%', '60%'],
splitNumber: 8,
axisLine: {
lineStyle: {
width: 30,
color: this.isDarkMode ? darkGaugeColors : lightGaugeColors,
},
},
splitLine: {
show: false,
},
axisTick: {
show: false,
},
axisLabel: {
show: false,
},
pointer: {
length: '80%',
width: 5,
itemStyle: {
color: this.isDarkMode ? '#fff' : '#333333',
},
},
anchor: {
show: true,
showAbove: true,
size: 10,
itemStyle: {
borderWidth: 10,
borderColor: this.isDarkMode ? '#fff' : '#333333',
},
},
title: {
offsetCenter: ['90%', '30%'],
fontSize: 20,
color: this.isDarkMode
? arrDarkColors[data[0].peakStat]
: arrLightColors[data[0].peakStat],
fontWeight: 'bold',
},
detail: {
fontSize: 20,
offsetCenter: ['-75%', '30%'],
valueAnimation: true,
formatter: function(value) {
return '{value|' + value.toFixed(2) + '}{unit|%}';
},
rich: {
value: {
fontSize: 20,
color: this.isDarkMode ? '#fff' : '#111111',
fontWeight: 'bolder',
},
unit: {
fontSize: 14,
color: this.isDarkMode ? '#fff' : '#111111',
fontWeight: 'bolder',
padding: [0, 0, -5, 0],
},
},
},
data: [
{
name: data[0].peakStat,
value: data[0].peakRto,
},
],
},
],
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'peakWidget',
widgetData: 'peakWidgetData',
chartKey: 'peakGauge',
value: chartOption,
});
this.loadChart_01 = true;
},
btnAction(action) {
switch (action) {
case 'popWidget':
this.openDashboardWidget({
prgmId: this.$route.query.prgmId,
widgetId: this.widgetId,
});
break;
case 'widgetCallPage':
this.$parent.$parent.$parent.openWidgetPrgm(this.widgetId);
break;
}
},
},
};
const peakWidgetData = {
peakGauge: Utility.defaultChartOption(true),
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>