sk_fems_ui commit

This commit is contained in:
unknown
2025-07-12 15:13:46 +09:00
commit ffdf5ccb66
380 changed files with 137913 additions and 0 deletions

View File

@ -0,0 +1,77 @@
<template>
<div class="l-layout">
<v-row ref="rowParent">
<v-col :cols="12">
<v-card class="pa-5" style="min-height: 284px;"> </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 Grid from '~/components/common/Grid';
import Chart from '~/components/common/Chart';
export default {
props: {
parentPrgmId: {
type: String,
require: true,
},
},
components: {
DateUtility,
Grid,
Chart,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
blankWidget: { blankWidgetData },
});
// console.log("2.vue::beforeCreate");
},
created() {},
mounted() {},
data() {
return {
pop: null,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
}),
},
};
const blankWidgetData = {};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>

View File

@ -0,0 +1,343 @@
<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"
>캘린더
<span class="pl-2"
>{{ selectedYear }} {{ selectedMonth }}</span
></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-2">
<div class="weekday redDay"></div>
<div class="weekday"></div>
<div class="weekday"></div>
<div class="weekday"></div>
<div class="weekday"></div>
<div class="weekday"></div>
<div class="weekday blueDay"></div>
</div>
<div class="d-flex align-center justify-space-between">
<div class="weekdayForm redDay"><span id="day0"></span></div>
<div class="weekdayForm"><span id="day1"></span></div>
<div class="weekdayForm"><span id="day2"></span></div>
<div class="weekdayForm"><span id="day3"></span></div>
<div class="weekdayForm"><span id="day4"></span></div>
<div class="weekdayForm"><span id="day5"></span></div>
<div class="weekdayForm blueDay"><span id="day6"></span></div>
</div>
<div class="d-flex align-center justify-space-between">
<div class="weekdayForm redDay"><span id="day7"></span></div>
<div class="weekdayForm"><span id="day8"></span></div>
<div class="weekdayForm"><span id="day9"></span></div>
<div class="weekdayForm"><span id="day10"></span></div>
<div class="weekdayForm"><span id="day11"></span></div>
<div class="weekdayForm"><span id="day12"></span></div>
<div class="weekdayForm blueDay"><span id="day13"></span></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 Grid from '~/components/common/Grid';
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,
Grid,
Chart,
Utility,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {},
beforeMounted() {},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
caldWidget: { caldWidgetData },
});
},
created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
pop: null,
selectedYear: this.convertStringToDateFormat(new Date()).substr(0, 4),
selectedMonth: this.convertStringToDateFormat(new Date()).substr(5, 2),
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
}),
convertStringToDateFormat(val) {
var result = '';
result = Utility.setFormatDate(val, 'YYYY-MM-DD');
return result;
},
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;
}
},
async search() {
const res = await this.postApiReturn({
apiKey: 'selectWeekWorkCald',
resKey: 'workcaldData',
sendParam: {},
});
const res2 = await this.postApiReturn({
apiKey: 'selectWeekWorkCaldDetl',
resKey: 'workcaldData',
sendParam: {},
});
for (var i = 0; i < res.length; i++) {
var hldyNm = res[i].hldyNm == null ? '' : res[i].hldyNm;
eval(
"document.getElementById('day" +
i +
"').innerHTML = res[" +
i +
"].day + ' ' +hldyNm",
);
if (res[i].hldyFg == '1') {
eval(
"document.getElementById('day" + i + "').className += ' redDay'",
);
}
for (var j = 0; j < res2.length; j++) {
if (res[i].day == res2[j].day && res2[j].planTitle != null) {
var tmpHtml =
"<p class ='" +
res2[j].planColor +
"Plan'>" +
res2[j].planTitle +
'</p>';
if (i == 0) {
document.getElementById('day0').innerHTML += tmpHtml;
} else if (i == 1) {
document.getElementById('day1').innerHTML += tmpHtml;
} else if (i == 2) {
document.getElementById('day2').innerHTML += tmpHtml;
} else if (i == 3) {
document.getElementById('day3').innerHTML += tmpHtml;
} else if (i == 4) {
document.getElementById('day4').innerHTML += tmpHtml;
} else if (i == 5) {
document.getElementById('day5').innerHTML += tmpHtml;
} else if (i == 6) {
document.getElementById('day6').innerHTML += tmpHtml;
} else if (i == 7) {
document.getElementById('day7').innerHTML += tmpHtml;
} else if (i == 8) {
document.getElementById('day8').innerHTML += tmpHtml;
} else if (i == 9) {
document.getElementById('day9').innerHTML += tmpHtml;
} else if (i == 10) {
document.getElementById('day10').innerHTML += tmpHtml;
} else if (i == 11) {
document.getElementById('day11').innerHTML += tmpHtml;
} else if (i == 12) {
document.getElementById('day12').innerHTML += tmpHtml;
} else if (i == 13) {
document.getElementById('day13').innerHTML += tmpHtml;
}
}
}
}
},
},
};
const caldWidgetData = {};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
.weekday {
background-color: #383f5d;
border-right: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
height: 26px;
width: 15%;
padding: 0;
font-size: 0.9rem;
}
.weekdayForm {
border-right: 1px solid rgba(255, 255, 255, 0.1);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
height: 7.6vh;
min-height: 80px;
box-sizing: border-box;
width: 15%;
overflow-y: auto;
font-size: 14px;
// padding-left: 3px;
// padding-right: 6px;
padding: 3px 4px;
}
.redDay {
color: #fb5a83;
border-left: 1px solid rgba(255, 255, 255, 0.1);
}
.blueDay {
color: #2d8cf6;
}
.redPlan {
//background-color: rgba(229,62,62,var(--bg-opacity));
background-color: #e53e3e !important;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
.bluePlan {
//background-color: rgba(66,153,225,var(--bg-opacity));
background-color: #4299e1 !important;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
.puplePlan {
//background-color: rgba(102,126,234,var(--bg-opacity));
background-color: #667eea !important;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
.greenPlan {
//background-color: rgba(56,178,172,var(--bg-opacity));
background-color: #38b2ac !important;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
.orangePlan {
//background-color: rgba(237,137,54,var(--bg-opacity));
background-color: #ed8936 !important;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
.pinkPlan {
//background-color: rgba(237,100,166,var(--bg-opacity));
background-color: #ed64a6 !important;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
.greyPlan {
background-color: #6d6d6d;
color: #fff;
border-radius: 0.125rem;
font-size: 0.75rem;
line-height: 1.25;
text-align: left;
margin-bottom: 0.25rem;
}
</style>

View File

@ -0,0 +1,359 @@
<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-btn :ripple="false" @click="btnAction('popWidget')">화면</v-btn>
<v-card-subtitle class="mt-0 pa-0">
{{ blocNm }} {{ dtToday }} 기준</v-card-subtitle
>
</div>
<div class="d-flex align-center justify-space-between mt-8">
<div class="mr-5" :style="{ width: '240px', height: '170px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'peakWidget'"
:widgetData="'peakWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</div>
<div>
<div class="v-box">
<v-icon size="48" :color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashCharge</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 class="v-box">
<v-icon size="48" :color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashPeak</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ nowPeakVal }} <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 class="v-box">
<v-icon size="48" :color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashCharge</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 class="v-box">
<v-icon size="48" :color="isDarkMode ? '#22273c' : '#4a568d'"
>$darkDashPeak</v-icon
>
<div class="text-right">
<strong class="custom-title-2"
>{{ nowPeakVal }} <span class="body-2">kW</span></strong
>
<p class="body-2 mt-1 mb-0 text-color--non-activate">
현재 피크전력
</p>
</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 Grid from '~/components/common/Grid';
import Chart from '~/components/common/Chart';
export default {
props: {
parentPrgmId: {
type: String,
require: true,
},
},
components: {
DateUtility,
Grid,
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();
},
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,
//바인딩
chargedPower: 0,
nowPeakVal: 0,
rdbEnrgUsage: 'hour',
rdbElecQual: 'Kw',
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...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.getUseWithPeak();
},
async getUseWithPeak() {
this.loadChart_01 = false;
const res = await this.postApiReturn({
apiKey: 'selectUseWithPeak',
resKey: 'peakData',
sendParam: {},
});
res.forEach((item, idx) => {
this.chargedPower = Utility.setFormatInt(item.peakVal);
this.nowPeakVal = Utility.setFormatInt(item.curPeakVal);
});
this.$nextTick(() => {
this.setChart01Data(res);
});
},
//차트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%',
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: 'PeakWidget',
});
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>

View File

@ -0,0 +1,351 @@
<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="row pt-2 px-2">
<v-col :cols="3">
<v-banner>
<div class="d-flex align-center justify-space-between">
<v-card-subtitle class="pa-0">전체검침개소</v-card-subtitle>
<v-avatar
size="36"
:color="isDarkMode ? '#2fad35' : '#00c875'"
min-width="72"
class="font-weight-bold text-color--white-0"
>{{ pointUse }}</v-avatar
>
</div>
</v-banner>
<component
:is="'UnusedStatPopPage'"
:parentPrgmId="parentPrgmId"
:pointNoUse="pointNoUse"
/>
<component
:is="'EtcStatPopPage'"
:parentPrgmId="parentPrgmId"
:pointEtc="pointEtc"
/>
</v-col>
<v-col :cols="4">
<component
:ref="gridName01"
:is="loadGrid01 ? 'Grid' : null"
:gridName="gridName01"
:parentPrgmId="parentPrgmId"
:dataPath="searchParam.ComcUseReptWidget.ComcUseReptWidgetData"
/>
</v-col>
<v-col :cols="5">
<div>
<component
:ref="gridName02"
:is="loadGrid02 ? 'Grid' : null"
:gridName="gridName02"
:parentPrgmId="parentPrgmId"
:dataPath="
searchParam.ComcUseReptWidget.ComcUseReptWidgetData
"
/>
</div>
</v-col>
</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 Grid from '~/components/common/Grid';
import UnusedStatPopPage from '~/components/common/modal/UnusedStatPopPage';
import EtcStatPopPage from '~/components/common/modal/EtcStatPopPage';
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,
Grid,
UnusedStatPopPage,
EtcStatPopPage,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
// defaultData: defaultData,
ComcUseReptWidget: { ComcUseReptWidgetData: ComcUseReptWidgetData },
});
},
created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
pointUse: 0,
pointNoUse: 0,
pointEtc: 0,
gridName01: 'grid01',
gridName02: 'grid02',
loadGrid01: false,
loadGrid02: false,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
setWidgetGridData: 'setWidgetGridData',
setWidgetGridColumn: 'setWidgetGridColumn',
setWidgetGridOption: 'setWidgetGridOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
}),
async search() {
await this.getReadplcStatus();
this.gridInit();
},
async gridInit() {
this.loadGrid01 = false;
this.loadGrid02 = false;
const gridHeight = 180;
const myOptions = {
scrollX: false,
};
var gridOptions = Utility.defaultGridOption(gridHeight);
gridOptions.columnOptions.minWidth = 10;
gridOptions.columnOptions.maxWidth = 200;
this.setWidgetGridOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'ComcUseReptWidget',
widgetData: 'ComcUseReptWidgetData',
gridKey: this.gridName01,
value: gridOptions,
});
this.setWidgetGridOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'ComcUseReptWidget',
widgetData: 'ComcUseReptWidgetData',
gridKey: this.gridName02,
value: gridOptions,
});
var columnList01 = [
// {header:'No', name:"No", width:50, align:"center"},
{
header: 'readplcId',
name: 'readPlcId',
align: 'center',
hidden: true,
},
{ header: '미사용개소 ', name: 'readPlcNm', align: 'left' },
];
var columnList02 = [
// {header:'No', name:"No", width:50, align:"center"},
{
header: 'readplcId',
name: 'readPlcId',
align: 'center',
hidden: true,
},
{ header: '통신이상개소', name: 'readPlcNm', align: 'left' },
{ header: '최종검침시간', name: 'readTm', width: 90, align: 'center' },
];
this.setWidgetGridColumn({
prgmId: this.$route.query.prgmId,
widgetKey: 'ComcUseReptWidget',
widgetData: 'ComcUseReptWidgetData',
gridKey: this.gridName01,
value: columnList01,
});
this.setWidgetGridColumn({
prgmId: this.$route.query.prgmId,
widgetKey: 'ComcUseReptWidget',
widgetData: 'ComcUseReptWidgetData',
gridKey: this.gridName02,
value: columnList02,
});
await this.getGridData();
this.loadGrid01 = true;
this.loadGrid02 = true;
},
async getGridData() {
// var res1 = [
// {"No":1, "readplcId":123, "readPlcNm":"abc"},
// {"No":2, "readplcId":123, "readPlcNm":"bcd"},
// {"No":3, "readplcId":123, "readPlcNm":"cde"},
// ];
// var res2 = [
// {"No":1, "readplcId":123, "readPlcNm":"aaa"},
// {"No":2, "readplcId":123, "readPlcNm":"bbb"},
// {"No":3, "readplcId":123, "readPlcNm":"ccc"},
// ];
var res1;
var res2;
res1 = await this.postApiReturn({
apiKey: 'selectUnusedReadPlc',
resKey: 'unusedData',
sendParam: {},
});
res2 = await this.postApiReturn({
apiKey: 'selectEtcReadPlc',
resKey: 'etcData',
sendParam: {},
});
res1.map((item, index) => {
item.No = index + 1;
});
res2.map((item, index) => {
item.No = index + 1;
});
this.setWidgetGridData({
prgmId: this.$route.query.prgmId,
widgetKey: 'ComcUseReptWidget',
widgetData: 'ComcUseReptWidgetData',
gridKey: this.gridName01,
value: res1,
});
this.setWidgetGridData({
prgmId: this.$route.query.prgmId,
widgetKey: 'ComcUseReptWidget',
widgetData: 'ComcUseReptWidgetData',
gridKey: this.gridName02,
value: res2,
});
},
async getReadplcStatus() {
const res = await this.postApiReturn({
apiKey: 'selectReadplcStatus',
resKey: 'pointData',
sendParam: {},
});
res.forEach((item, idx) => {
if (item.type == 'ALL') {
this.pointUse = item.cnt;
}
if (item.type == 'UNUSED') {
this.pointNoUse = item.cnt;
}
if (item.type == 'ABNORMAL') {
this.pointEtc = item.cnt;
}
});
},
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 ComcUseReptWidgetData = {
grid01: {
data: [],
column: [],
option: {},
},
grid02: {
data: [],
column: [],
option: {},
},
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>

View File

@ -0,0 +1,340 @@
<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">
<div hidden>
<component
:is="'SelectBlocMstr'"
ref="SelectBlocMstr"
:parentPrgmId="parentPrgmId"
:hidden="true"
/>
</div>
<component
ref="MainReadReptReadObjMultiPop"
:is="'MainReadReptReadObjMultiPop'"
:parentPrgmId="parentPrgmId"
:eqpmYn="0"
:labelCols="2"
:textCols="10"
:popTitle="'검침대상 목록'"
:widgetId="'ElecQualWidget'"
@chDialogViewElecQualWidget="dialogViewChange"
/>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-icon
class="mr-1"
size="25"
v-bind="attrs"
v-on="on"
@click="readObjDialog"
>mdi-tooltip-plus</v-icon
>
</template>
<span>품질</span>
</v-tooltip>
<component
:is="'ReadPlcWidgetPop'"
:parentPrgmId="parentPrgmId"
:widGetKey="'ElecQualWidget'"
:widgetDataKey="'ElecQualWidgetData'"
:isMulti="true"
@chDialogViewElecQualWidget="dialogViewChange"
:mntrFg="'1'"
/>
<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="row">
<div :style="{ width: '100%', height: '230px' }">
<component
class="w100 h100"
:is="loadChart ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:chartName="chartName"
:widgetId="'ElecQualWidget'"
:widgetData="'ElecQualWidgetData'"
ref="chart"
/>
</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';
import ReadPlcWidgetPop from '~/components/common/modal/ReadPlcWidgetPop';
import MainReadReptReadObjMultiPop from '~/components/common/modal/MainReadReptReadObjMultiPop';
import SelectBlocMstr from '@/components/common/select/SelectBlocMstr';
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,
ReadPlcWidgetPop,
SelectBlocMstr,
MainReadReptReadObjMultiPop,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
// defaultData: defaultData,
ElecQualWidget: { ElecQualWidgetData: ElecQualWidget },
});
},
created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
loadChart: false,
selectedQualityKind: null,
selectedReadPlcId: null,
paramReadObjId: 'ROI00005',
chartName: 'elecQualityChart',
// readPlcPopItem:readPlcPopItem,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
}),
async search() {
await this.getElecQuality();
},
async getElecQuality() {
this.loadChart = false;
var plcKindList =
this.searchParam['ElecQualWidget']['ElecQualWidgetData'].plcKindList
.length > 0
? this.searchParam['ElecQualWidget'][
'ElecQualWidgetData'
].plcKindList.map(item => {
return item.readPlcId;
})
: null;
var readObjId =
this.searchParam['ElecQualWidget']['ElecQualWidgetData'].readObjList
.length > 0
? this.searchParam['ElecQualWidget']['ElecQualWidgetData']
.readObjList[0].readObjId
: 'ROI000005';
//console.log('plcKindList : ', plcKindList);
const res = await this.postApiReturn({
apiKey: 'selectWidgetElecQuality',
resKey: 'elecQualData',
sendParam: {
readObjId: readObjId,
readPlcIdList: plcKindList,
},
});
await this.setChartData(res);
},
async setChartData(data) {
this.$store.state.pageData[
this.parentPrgmId
].ElecQualWidget.ElecQualWidgetData.series = [];
//console.log('res : ', data);
if (!data.length) {
return;
}
var xAxisData = [];
var seriesData = [];
var legendData = [];
var yName = data[0]['readObjUnit'];
var readPlcIdChk = data[0]['readPlcId'];
for (var i = 0; i < data.length; i++) {
if (readPlcIdChk == data[i]['readPlcId']) {
xAxisData.push(
data[i]['readDttm']
? Utility.setFormatDate(data[i]['readDttm'], 'HH:mm')
: '',
);
}
}
var tempObj = {};
tempObj['data'] = [];
for (var i = 0; i < data.length; i++) {
if (i > 0) {
if (readPlcIdChk == data[i]['readPlcId']) {
tempObj['data'].push(data[i]['readVal']);
if (i == data.length - 1) {
seriesData.push(tempObj);
}
} else {
seriesData.push(tempObj);
//비교 readPlc 변경
readPlcIdChk = data[i]['readPlcId'];
tempObj = {};
tempObj['data'] = [];
tempObj['name'] = data[i]['readPlcNm'];
tempObj['type'] = 'line';
tempObj['data'].push(data[i]['readVal']);
legendData.push(data[i]['readPlcNm']);
}
} else {
tempObj['name'] = data[i]['readPlcNm'];
tempObj['type'] = 'line';
tempObj['data'].push(parseFloat(data[i]['readVal']));
legendData.push(data[i]['readPlcNm']);
}
}
var chartOption = {
grid: {
top: '15%',
bottom: '15%',
},
legend: {
type: 'scroll',
pageIconColor: '#18579e',
pageIconInactiveColor: '#ffffff66',
pageTextStyle: { color: '#fff' },
data: legendData,
},
xAxis: {
data: xAxisData,
},
yAxis: {
name: yName,
splitLine: {
show: true,
lineStyle: {
color: this.isDarkMode ? '#fff' : '#cccccc',
opacity: this.isDarkMode ? 0.2 : 1,
type: 'dotted',
width: 2,
},
},
},
series: seriesData,
};
// console.log('utility chartoption : ', Utility.defaultChartOption());
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'ElecQualWidget',
widgetData: 'ElecQualWidgetData',
chartKey: 'elecQualityChart',
value: chartOption,
});
this.loadChart = true;
},
async dialogViewChange() {
await this.search();
},
readObjDialog() {
this.$store.state.pageData[this.parentPrgmId]['ElecQualWidget'][
'ElecQualWidgetData'
].enrgDiv = 'MTT_ELEC';
this.$refs['MainReadReptReadObjMultiPop'].dialog = 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 ElecQualWidget = {
elecQualityChart: Utility.defaultChartOption(true),
blocId: 0,
blocMstrList: [],
modalData: {},
rowGridSelectData: null,
rowGridSelectKey: 0,
plcKindList: [],
isMulti: false,
readObjList: [],
readObj: null,
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>

View File

@ -0,0 +1,346 @@
<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">
<component
ref="MainReadReptReadObjMultiPop"
:is="'MainReadReptReadObjMultiPop'"
:parentPrgmId="parentPrgmId"
:eqpmYn="0"
:popTitle="'검침대상 목록'"
:widgetId="this.widgetId"
@chDialogViewmainReadReptWidget="dialogViewChange"
/>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-icon
class="mr-1"
size="25"
v-bind="attrs"
v-on="on"
@click="readObjDialog"
>mdi-tooltip-plus</v-icon
>
</template>
<span>품질</span>
</v-tooltip>
<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="px-2 pt-2">
<v-banner single-line :style="{ paddingRight: '10px' }">
<v-row justify="space-between" align="center" no-gutters>
<v-col cols="auto" align="center">
<p class="body-2 mb-0">No</p>
</v-col>
<v-col cols="4" align="center">
검침개소
</v-col>
<v-col cols="2" align="center">
<p class="body-2 mb-0">kW</p>
</v-col>
<v-col cols="2" align="center">
상태
</v-col>
<v-col
cols="2"
align="center"
v-for="(item, index) in readObjIdList"
:key="item.readPlcId"
:class="{
'v-banner--last': index === readObjIdList.length - 1,
}"
>
{{ item.readObjNm }}
</v-col>
</v-row>
</v-banner>
<div
class="v-virtual-scroll-wrapper"
style="padding-right: '5px'; overflow-y: auto; max-height:185px"
>
<v-banner
single-line
v-for="(item, index) in mainReadPlcData"
:key="item.readPlcId"
:class="{
'v-banner--last': index === mainReadPlcData.length - 1,
}"
>
<v-row justify="space-between" align="center" no-gutters>
<v-col cols="auto">
<p class="body-2 mb-0">{{ item.rowNum }}</p>
</v-col>
<v-col cols="4">
<div
class="d-flex align-center"
style="white-space: normal"
>
<p class="body-2 mb-0 ml-2">{{ item.readPlcNm }}</p>
</div>
</v-col>
<v-col cols="2" align="center">
<p class="body-2 mb-0">
{{
String(Math.floor(item.instantVal)).replace(
/\B(?=(\d{3})+(?!\d))/g,
',',
)
}}
</p>
</v-col>
<v-col cols="2" align="center">
<v-icon
:color="
isDarkMode
? tableDataGetDarkColorByState(item.stat)
: tableDataGetLightColorByState(item.stat)
"
size="8"
class="mr-1"
>mdi-circle</v-icon
>
<span class="body-2">{{ item.stat }}</span>
</v-col>
<v-col
cols="2"
align="center"
v-for="(item2, index) in readObjIdList"
:key="item2.readPlcId"
:class="{
'v-banner--last': index === readObjIdList.length - 1,
}"
>
<span class="body-2">{{ item[item2.readObjId] }}</span>
</v-col>
</v-row>
</v-banner>
</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';
import MainReadReptReadObjMultiPop from '~/components/common/modal/MainReadReptReadObjMultiPop';
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,
MainReadReptReadObjMultiPop,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId][this.widgetId][
this.widgetId + 'Data'
];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {
energyCd() {
this.getMainReadPlcStat();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
ElecReadReptWidget: { ElecReadReptWidgetData },
});
},
async created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
blocNm: '',
mainReadPlcData: [],
//widgetId:"ElecReadReptWidget",
dialogView: false,
readObjIdList: [],
readPlcIdList: [],
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
dialogViewChange() {
this.getMainReadPlcStat();
},
async search() {
this.setBlocNm();
await this.getMainReadPlcStat();
},
async getMainReadPlcStat() {
if (
this.$store.state.pageData[this.parentPrgmId].ElecReadReptWidget
.ElecReadReptWidgetData.readObjList.length > 0
) {
this.readObjIdList = this.$store.state.pageData[
this.parentPrgmId
].ElecReadReptWidget.ElecReadReptWidgetData.readObjList.map(item => {
return { readObjId: item.readObjId, readObjNm: item.readObjNm };
});
}
if (
this.$store.state.pageData[this.parentPrgmId].ElecReadReptWidget
.ElecReadReptWidgetData.plcKindList.length > 0
) {
this.readPlcIdList = this.$store.state.pageData[
this.parentPrgmId
].ElecReadReptWidget.ElecReadReptWidgetData.plcKindList.map(item => {
return item.readPlcId;
});
}
this.mainReadPlcData = await this.postApiReturn({
apiKey: 'selectMainReadPlcStat',
resKey: 'mainReadPlcData',
sendParam: {
readObjIdList: this.readObjIdList,
},
});
// this.mainReadPlcData = [
// {
// "rowNum" : 1,
// "comId" : "CDR00",
// "readPlcId" : "RPC000002",
// "readPlcNm" : "[전력] LP-1_A동메인",
// "readObjNm" : "Heartbit",
// "readObjId" : "ROI000040",
// "instantVal" : 11239.0,
// "volt" : 228.9,
// "ampr" : 55.1,
// "ROI000001" : 93613.1,
// "ROI000005" : 229.7,
// "ROI000006" : 81.8,
// "ROI000008" : 1,
// "stat" : "가동중"
// }
// ]
},
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;
}
},
tableDataGetDarkColorByState: state => {
return {
가동중: '#01ae6a',
미사용: '#ffb046',
비정상: '#f6637b',
}[state];
},
tableDataGetLightColorByState: state => {
return {
가동중: '#3cc380',
미사용: '#ffb13b',
비정상: '#f98694',
}[state];
},
readObjDialog() {
this.$store.state.pageData[
this.parentPrgmId
].ElecReadReptWidget.ElecReadReptWidgetData.enrgDiv = 'MTT_ELEC';
this.$store.state.pageData[
this.parentPrgmId
].ElecReadReptWidget.ElecReadReptWidgetData.grpCd = 'MTT_STAT';
this.$refs['MainReadReptReadObjMultiPop'].dialog = true;
},
},
};
const ElecReadReptWidgetData = {
readObjModalData: {},
isMulti: true,
blocId: 0,
blocMstrList: [],
readObjList: [],
readObj: {},
enrgDiv: '',
plcKindList: [],
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
</style>

View File

@ -0,0 +1,413 @@
<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>
<v-card-actions class="d-flex justify-sm-end pb-0 pr-0 pt-1">
<v-row>
<v-col sm="7" lg="8"></v-col>
<v-col sm="5" lg="4" class="d-flex align-center justify-end">
<v-radio-group
v-model="rdbElecUsage"
hide-details
dense
row
class="mt-0"
>
<v-radio
label="금일"
value="hour"
:color="isDarkMode ? '#2d8cf6' : '#4777d9'"
on-icon="mdi-record-circle"
:ripple="false"
></v-radio>
<v-radio
label="금월"
value="month"
:color="isDarkMode ? '#2d8cf6' : '#4777d9'"
on-icon="mdi-record-circle"
:ripple="false"
></v-radio>
</v-radio-group>
</v-col>
</v-row>
</v-card-actions>
<div class="d-flex align-center justify-space-between">
<div :style="{ width: '100%', height: '200px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'ElecUseReptWidget'"
:widgetData="'ElecUseReptWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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: {
rdbElecUsage() {
this.getElecUsage();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
ElecUseReptWidget: { ElecUseReptWidgetData },
});
},
async created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
blocNm: '',
//차트
chart_01: 'elecUsage',
loadChart_01: false,
//바인딩
rdbElecUsage: 'hour',
rdbElecQual: 'Kw',
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
async search() {
this.setBlocNm();
await this.getElecUsage();
},
async getElecUsage() {
this.loadChart_01 = false;
let paramApiKey = '';
let markAreaData = [];
let markColor = {
MAX: 'rgba(238, 102, 102, 0.1)',
MID: 'rgba(250, 200, 88, 0.1)',
MIN: 'rgba(145, 204, 117, 0.1)',
};
if (this.rdbElecUsage == 'hour') {
paramApiKey = 'selectEnrgUsageHour';
// 부하시간 가져오기
let res3 = [];
res3 = await this.postApiReturn({
apiKey: 'selectPeakKine',
resKey: 'peakData',
sendParam: {
readObjId: 'ROI000001',
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
},
});
markAreaData = res3.map(item => [
{
name: item.commCdNm,
xAxis:
parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')) == 23
? 0
: parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')),
itemStyle: {
color: markColor[item.peakKine],
},
label: {
distance: [0],
fontSize: 9,
fontWeight: 'lighter',
color: '#fff',
},
},
{
xAxis: parseInt(item.endTm.split(':')[0].replace(/(^0+)/, '')),
},
]);
} else {
paramApiKey = 'selectEnrgUsageMonth';
}
let res = await this.postApiReturn({
apiKey: paramApiKey,
resKey: 'enrgUsageData',
sendParam: {
readObjId: 'ROI000001',
},
});
this.$nextTick(() => {
this.setChart01Data(res, markAreaData);
});
},
//차트Setting
async setChart01Data(data, markAreaData) {
this.$store.state.pageData[
this.parentPrgmId
].ElecUseReptWidget.ElecUseReptWidgetData.series = [];
if (!data.length) {
return;
}
let xAxisData = [];
let seriesData = [];
let legendData = [];
let arrDarkColors = ['rgba(1, 174, 106, 0.7)', 'rgba(67, 133, 227, 0.7)'];
let arrLightColors = [
'rgba(207, 116, 229, 0.7)',
'rgba(106, 155, 244, 0.7)',
];
const arrColors = this.isDarkMode ? arrDarkColors : arrLightColors;
if (this.rdbElecUsage == 'month') {
var qtyNumber, qtyStr;
for (var i = 1; i < 32; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '일');
}
for (var i = 0; i < data.length; i++) {
var tempObj = {};
tempObj['name'] = data[i]['type'];
if (data[i]['type'] == '금월 사용량') {
tempObj['type'] = 'bar';
} else {
tempObj['type'] = 'line';
}
tempObj['data'] = [];
tempObj['color'] = arrColors[i];
tempObj['lineStyle'] = { width: 2 };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
legendData.push(data[i]['type']);
for (var j = 0; j < 31; j++) {
qtyNumber = (j + 1).toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
tempObj['data'].push(
parseFloat(
Utility.setFormatIntDecimal(
parseFloat(data[i][qtyStr]),
2,
).replace(',', ''),
),
);
// tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
seriesData.push(tempObj);
}
} else if (this.rdbElecUsage == 'hour') {
var qtyNumber, qtyStr;
for (var i = 0; i < 24; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '시');
}
for (var i = 0; i < data.length; i++) {
var tempObj = {};
tempObj['name'] = data[i]['type'];
if (data[i]['type'] == '금일 사용량') {
tempObj['type'] = 'bar';
} else {
tempObj['type'] = 'line';
}
tempObj['data'] = [];
tempObj['color'] = arrColors[i];
tempObj['lineStyle'] = { width: 2 };
if (markAreaData != null) {
tempObj['markArea'] = {
data: markAreaData,
};
}
// tempObj['areaStyle'] = {
// opacity: 0.5,
// color: arrColors[i]
// };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
legendData.push(data[i]['type']);
for (var j = 0; j < 24; j++) {
qtyNumber = j.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
tempObj['data'].push(
Utility.setFormatIntDecimal(
parseFloat(data[i][qtyStr]),
2,
).replace(',', ''),
);
// tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
//console.log("data : " ,tempObj);
seriesData.push(tempObj);
}
}
var chartOption = {
series: seriesData,
grid: {
left: '1%',
right: '2%',
top: '15%',
bottom: '15%',
containLabel: true,
},
legend: {
data: legendData,
bottom: 'bottom',
icon: 'bar',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
},
yAxis: {
type: 'value',
name: 'kWh',
splitLine: false,
axisLabel: {
color: '#767D83',
fontSize: 10,
},
},
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'ElecUseReptWidget',
widgetData: 'ElecUseReptWidgetData',
chartKey: 'elecUsage',
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 ElecUseReptWidgetData = {
elecUsage: 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>

View File

@ -0,0 +1,685 @@
<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 text-right">
<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="row wrapper">
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseQty }}
<span class="font-weight-regular custom-text-2"
>kWh</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비({{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseQty
}}</strong>
<span class="caption mr-1">kWh</span>
<v-icon
small
:color="
isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875'
"
>{{ useQtyStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseCost }}
<span class="font-weight-regular custom-text-2"
>천원</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비(0-{{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseCost
}}</strong>
<span class="caption mr-1">천원</span>
<v-icon
small
:color="
isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875'
"
>{{ useCostStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex align-center justify-space-between mt-2">
<div :style="{ width: '100%', height: '160px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'EnrgUseRsltWidget'"
:widgetData="'EnrgUseRsltWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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: {
// rdbEnrgUsage(){
// this.getEnrgUsage();
// },
energyCd() {
this.getEnrgUsage();
this.getChartData();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
EnrgUseRsltWidget: { EnrgUseRsltWidgetData },
});
},
async created() {
this.energyList = await this.postApiReturn({
apiKey: 'selectEnergy',
resKey: 'energyData',
sendParam: {
useFg: 1,
},
});
this.energyList.filter(item => {
if (item.readObjCd == 'ELEC') {
//전력
this.energyCd = item.cd;
this.unit = item.unit;
}
});
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
// blocNm:'',
//바인딩
energyCd: '',
energyList: [],
unit: '',
currHour: Utility.setFormatDate(new Date(), 'H') + '시 기준',
isUseQtyStat: true,
isUseCostStat: true,
dayUseQty: 0,
compareUseQty: 0,
useQtyStat: null,
dayUseCost: 0,
compareUseCost: 0,
useCostStat: null,
// 차트
chart_01: 'enrgUsageChart',
loadChart_01: false,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
setWidgetChartYaxisData: 'setWidgetChartYaxisData',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
async search() {
// this.setBlocNm();
await this.getEnrgUsage();
await this.getChartData();
},
async getEnrgUsage() {
const res = await this.postApiReturn({
apiKey: 'selectUseCostDay',
resKey: 'dayUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
const res2 = await this.postApiReturn({
apiKey: 'selectUseCostPast',
resKey: 'pastUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
res.forEach((item, idx) => {
this.dayUseQty = Utility.setFormatInt(item.qty);
this.dayUseCost = Utility.setFormatInt(item.cost);
});
let dayUseQty,
dayUseQtyAvg,
dayUseCost,
dayUseCostAvg,
dayUseMaxQty,
dayUseMaxCost = 0;
if (res.length > 0) {
dayUseQty = res[0].qty;
dayUseCost = res[0].cost;
}
if (res2.length > 0) {
dayUseQtyAvg = res2[0].qtyAvg;
dayUseCostAvg = res2[0].costAvg;
dayUseMaxQty = res2[0].maxQty;
dayUseMaxCost = res2[0].maxCost;
}
this.compareUseQty = Utility.setFormatInt(dayUseQty - dayUseQtyAvg);
this.compareUseCost = Utility.setFormatInt(dayUseCost - dayUseCostAvg);
this.useQtyStat =
dayUseQty > dayUseQtyAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.useCostStat =
dayUseCost > dayUseCostAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.isUseQtyStat = this.useQtyStat == 'mdi-arrow-up' ? true : false;
this.isUseCostStat = this.useCostStat == 'mdi-arrow-up' ? true : false;
},
setChartData(data, markAreaData) {
let xAxisData = [];
let seriesData = [];
let legendData = [];
let arrDarkColors = ['rgba(1, 174, 106, 0.7)', 'rgba(67, 133, 227, 0.7)'];
let arrLightColors = [
'rgba(207, 116, 229, 0.7)',
'rgba(106, 155, 244, 0.7)',
];
const arrColors = this.isDarkMode ? arrDarkColors : arrLightColors;
// chart x축 data
var qtyNumber, qtyStr;
for (var i = 0; i < 24; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '시');
}
// chart_data 중 누적 사용량과 누적 금액 구분
for (var i = 0; i < data.length; i++) {
var tempObj = { data: [] };
tempObj['type'] = 'line';
tempObj['lineStyle'] = { width: 2 };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
tempObj['color'] = arrColors[i];
if (data[i]['type'] == 'use') {
tempObj['name'] = '누적 사용량';
legendData.push('누적 사용량');
tempObj['areaStyle'] = {
opacity: 0.5,
color: arrColors[i],
};
tempObj['yAxisIndex'] = 0;
tempObj['markArea'] = { data: markAreaData };
} else if (data[i]['type'] == 'cost') {
tempObj['name'] = '누적 금액';
legendData.push('누적 금액');
tempObj['yAxisIndex'] = 1;
} else if (data[i]['type'] == 'week') {
tempObj['name'] = '전주 평균 누적 사용량';
legendData.push('전주 평균 누적 사용량');
tempObj['yAxisIndex'] = 0;
}
// 0~23시 까지의 데이터 seriesData 넣기
for (var j = 0; j < 24; j++) {
qtyNumber = j.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
// tempObj['data'].push(Utility.setFormatIntDecimal(parseFloat(data[i][qtyStr]), 2).replace(',',''));
tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
seriesData.push(tempObj);
}
const yAxisData = [
{
type: 'value',
name: this.unit,
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
{
type: 'value',
name: '원',
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
];
var chartOption = {
series: seriesData,
grid: {
left: '1%',
right: '2%',
top: '20%',
bottom: '15%',
containLabel: true,
},
legend: {
data: legendData,
bottom: 'bottom',
icon: 'bar',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
axisLabel: {
fontSize: 9,
},
},
// yAxis: [
// {
// type: 'value',
// name: this.unit,
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// },
// {
// type: 'value',
// name: '원',
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// }
// ],
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'EnrgUseRsltWidget',
widgetData: 'EnrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: chartOption,
});
this.setWidgetChartYaxisData({
prgmId: this.$route.query.prgmId,
widgetKey: 'EnrgUseRsltWidget',
widgetData: 'EnrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: yAxisData,
});
this.loadChart_01 = true;
},
async getChartData() {
this.loadChart_01 = false;
var root_info = null;
var res_useage = null;
var res_cost = null;
var facList = null;
var filtered_res = null;
var apiParameters = {
blocId: 'BL0001',
readObjId: this.energyCd,
locKind: '',
upEccId: '',
};
var sendParam_chart_data = {
blocId: 'BL0001',
eccId: [],
eccNm: [],
fromObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
lockKind: '',
readObjId: this.energyCd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
upEccId: '',
};
var check_flag = true;
// 공정/설비 트리리스트 중 에너지원에 따른 최상위 정보 가져오기
try {
root_info = await this.postApiReturn({
apiKey: 'selectFtnPlcListTree',
resKey: 'ftnPlcTreeDatas',
sendParam: {
blocId: 'BL0001',
roiId: this.energyCd,
eqpmYn: 1,
// search:this.searchWord
},
});
filtered_res = root_info.filter(item => item.upEccId == 'ROOT');
apiParameters['locKind'] = filtered_res[0].locKind;
apiParameters['upEccId'] = filtered_res[0].eccId;
sendParam_chart_data['lockKind'] = filtered_res[0].locKind;
} catch (error) {
root_info = [];
filtered_res = [];
}
// 위의 정보로 해당 검침개소 정보 가져오기
try {
facList = await this.postApiReturn({
apiKey: 'selectEnergyUseReadDnPlc',
resKey: 'energyUseReadDnPlc',
sendParam: apiParameters,
});
for (var i in facList) {
sendParam_chart_data['eccId'].push(facList[i]['eccId']);
sendParam_chart_data['eccNm'].push(facList[i]['eccNm']);
}
// sendParam_chart_data['eccId'].push(facList[0]['eccId']);
// sendParam_chart_data['eccNm'].push(facList[0]['eccNm']);
sendParam_chart_data['upEccId'] = facList[0]['upEccId'];
} catch (error) {
check_flag = false;
}
// 위의 정보로 검침개소 시간별 사용량 가져오기
var final_chart_data = [];
if (check_flag) {
try {
res_useage = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM 안했을 경우 사용)
// var sum_data = {};
// for (var i in res_useage){
// res_useage[i]['type'] = 'use'
// for (var key in res_useage[i]){
// if(key.includes('qty')){
// if(sum_data[key] == undefined){
// sum_data[key] = res_useage[i][key]
// }else{
// sum_data[key] += res_useage[i][key]
// }
// }
// }
// // final_chart_data.push(res_useage[i])
// }
// final_chart_data.push({'type' : 'use', ...sum_data})
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM을 했을 경우 사용)
res_useage[0]['type'] = 'use';
final_chart_data.push(res_useage[0]);
} catch (error) {
res_useage = [];
}
try {
res_cost = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourCostAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
res_cost[0]['type'] = 'cost';
final_chart_data.push(res_cost[0]);
} catch (error) {
res_cost = [];
}
} else {
res_useage = [];
res_cost = [];
}
// 전주 평균 누적 사용량
let res_week_read = [];
res_week_read = await this.postApiReturn({
apiKey: 'selectEnergyUseReadLastWeekAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
if (res_week_read.length != 0) {
res_week_read[0]['type'] = 'week';
final_chart_data.push(res_week_read[0]);
}
let res3 = [];
let markAreaData = [];
let markColor = {
MAX: 'rgba(238, 102, 102, 0.1)',
MID: 'rgba(250, 200, 88, 0.1)',
MIN: 'rgba(145, 204, 117, 0.1)',
};
res3 = await this.postApiReturn({
apiKey: 'selectPeakKine',
resKey: 'peakData',
sendParam: {
readObjId: this.energyCd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
},
});
markAreaData = res3.map(item => [
{
name: item.commCdNm,
xAxis:
parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')) == 23
? 0
: parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')),
itemStyle: {
color: markColor[item.peakKine],
},
label: {
distance: [0],
fontSize: 9,
fontWeight: 'lighter',
color: '#fff',
},
},
{
xAxis: parseInt(item.endTm.split(':')[0].replace(/(^0+)/, '')),
},
]);
// char data 넣기
this.$nextTick(() => {
this.setChartData(final_chart_data, markAreaData);
});
},
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 EnrgUseRsltWidgetData = {
isFind: false,
enrgUsageChart: 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;
}
.v-radio > label {
font-size: 0.8rem;
}
.v-list-item {
min-height: 30px;
line-height: 1;
}
.v-list-item__content > * {
line-height: 1;
}
.v-select__widget > .v-input__control > .v-input__slot {
min-width: 60%;
}
.wrapper {
padding: 5px 10px 0px 10px !important;
border-bottom: thin solid rgba(255, 255, 255, 0.12);
}
</style>

View File

@ -0,0 +1,488 @@
<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>
<v-card-actions class="d-flex justify-sm-end pb-0 pr-0 pt-1">
<v-row>
<v-col cols="3" sm="3" md="4" lg="6"></v-col>
<v-col
cols="6"
sm="6"
md="5"
lg="4"
class="d-flex align-center justify-end"
>
<v-radio-group
v-model="rdbEnrgUsage"
hide-details
dense
row
class="mt-0"
style="float:right"
>
<v-radio
label="금일"
value="hour"
:color="isDarkMode ? '#2d8cf6' : '#4777d9'"
on-icon="mdi-record-circle"
:ripple="false"
></v-radio>
<v-radio
label="금월"
value="month"
:color="isDarkMode ? '#2d8cf6' : '#4777d9'"
on-icon="mdi-record-circle"
:ripple="false"
></v-radio>
</v-radio-group>
</v-col>
<v-col cols="3" sm="3" md="3" lg="2">
<v-select
v-model="selectValue"
:items="this.energyList"
item-text="enrgNm"
item-value="cd"
solo
outlined
:hide-details="true"
append-icon="mdi-chevron-down"
class="v-select__widget pr-2"
></v-select>
</v-col>
</v-row>
</v-card-actions>
<div class="d-flex align-center justify-space-between">
<div :style="{ width: '100%', height: '200px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'EnrgUseReptWidget'"
:widgetData="'EnrgUseReptWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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',
}),
selectValue: {
get() {
return this.energyCd;
},
set(value) {
this.energyCd = value;
},
},
},
watch: {
rdbEnrgUsage() {
this.getEnrgUsage();
},
energyCd() {
this.setUnitLabel();
this.getEnrgUsage();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
EnrgUseReptWidget: { EnrgUseReptWidgetData },
});
},
async created() {
this.energyList = await this.postApiReturn({
apiKey: 'selectEnergy',
resKey: 'energyData',
sendParam: {
useFg: 1,
},
});
this.energyCd = this.energyList[0].cd;
this.unit = this.energyList[0].unit;
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
blocNm: '',
//차트
chart_01: 'enrgUsage',
loadChart_01: false,
//바인딩
rdbEnrgUsage: 'hour',
rdbElecQual: 'Kw',
energyCd: '',
energyList: [],
unit: '',
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
setUnitLabel() {
this.energyList.filter(item => {
if (item.cd == this.energyCd) {
this.unit = item.unit;
}
});
},
async search() {
this.setBlocNm();
await this.getEnrgUsage();
},
async getEnrgUsage() {
this.loadChart_01 = false;
let paramApiKey = '';
let markAreaData = [];
let markColor = {
MAX: 'rgba(238, 102, 102, 0.1)',
MID: 'rgba(250, 200, 88, 0.1)',
MIN: 'rgba(145, 204, 117, 0.1)',
};
if (this.rdbEnrgUsage == 'hour') {
paramApiKey = 'selectEnrgUsageHour';
if (this.energyCd == 'ROI000001') {
let res3 = [];
// 부하시간 가져오기
res3 = await this.postApiReturn({
apiKey: 'selectPeakKine',
resKey: 'peakData',
sendParam: {
readObjId: this.energyCd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
},
});
markAreaData = res3.map(item => [
{
name: item.commCdNm,
xAxis:
parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')) == 23
? 0
: parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')),
itemStyle: {
color: markColor[item.peakKine],
},
label: {
distance: [0],
fontSize: 9,
color: '#fff',
},
},
{
xAxis: parseInt(item.endTm.split(':')[0].replace(/(^0+)/, '')),
},
]);
}
} else {
paramApiKey = 'selectEnrgUsageMonth';
}
let res = await this.postApiReturn({
apiKey: paramApiKey,
resKey: 'enrgUsageData',
sendParam: {
readObjId: this.energyCd,
},
});
this.$nextTick(() => {
this.setChart01Data(res, markAreaData);
});
},
//차트Setting
async setChart01Data(data, markAreaData) {
this.$store.state.pageData[
this.parentPrgmId
].EnrgUseReptWidget.EnrgUseReptWidgetData.series = [];
if (!data.length) {
return;
}
let xAxisData = [];
let seriesData = [];
let legendData = [];
let arrDarkColors = ['rgba(1, 174, 106, 0.7)', 'rgba(67, 133, 227, 0.7)'];
let arrLightColors = [
'rgba(207, 116, 229, 0.7)',
'rgba(106, 155, 244, 0.7)',
];
const arrColors = this.isDarkMode ? arrDarkColors : arrLightColors;
if (this.rdbEnrgUsage == 'month') {
var qtyNumber, qtyStr;
for (var i = 1; i < 32; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '일');
}
for (var i = 0; i < data.length; i++) {
var tempObj = {};
tempObj['name'] = data[i]['type'];
if (data[i]['type'] == '금월 사용량') {
tempObj['type'] = 'bar';
} else {
tempObj['type'] = 'line';
}
tempObj['data'] = [];
tempObj['color'] = arrColors[i];
tempObj['lineStyle'] = { width: 2 };
// tempObj['areaStyle'] = {
// opacity: 0.5,
// color: arrColors[i]
// };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
legendData.push(data[i]['type']);
for (var j = 0; j < 31; j++) {
qtyNumber = (j + 1).toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
tempObj['data'].push(
parseFloat(
Utility.setFormatIntDecimal(
parseFloat(data[i][qtyStr]),
2,
).replace(',', ''),
),
);
// tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
seriesData.push(tempObj);
}
} else if (this.rdbEnrgUsage == 'hour') {
var qtyNumber, qtyStr;
for (var i = 0; i < 24; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '시');
}
for (var i = 0; i < data.length; i++) {
var tempObj = {};
tempObj['name'] = data[i]['type'];
if (data[i]['type'] == '금일 사용량') {
tempObj['type'] = 'bar';
} else {
tempObj['type'] = 'line';
}
tempObj['data'] = [];
tempObj['color'] = arrColors[i];
tempObj['lineStyle'] = { width: 2 };
if (markAreaData != null) {
tempObj['markArea'] = {
data: markAreaData,
};
}
// tempObj['areaStyle'] = {
// opacity: 0.5,
// color: arrColors[i]
// };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
legendData.push(data[i]['type']);
for (var j = 0; j < 24; j++) {
qtyNumber = j.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
tempObj['data'].push(
Utility.setFormatIntDecimal(
parseFloat(data[i][qtyStr]),
2,
).replace(',', ''),
);
// tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
//console.log("data : " ,tempObj);
seriesData.push(tempObj);
}
}
var chartOption = {
series: seriesData,
grid: {
left: '1%',
right: '2%',
top: '15%',
bottom: '15%',
containLabel: true,
},
legend: {
data: legendData,
bottom: 'bottom',
icon: 'bar',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
axisLabel: {
fontSize: 9,
},
},
yAxis: {
type: 'value',
name: this.unit,
splitLine: false,
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
},
},
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'EnrgUseReptWidget',
widgetData: 'EnrgUseReptWidgetData',
chartKey: 'enrgUsage',
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 EnrgUseReptWidgetData = {
enrgUsage: 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;
}
.v-radio > label {
font-size: 0.8rem;
}
.v-list-item {
min-height: 30px;
line-height: 1;
}
.v-list-item__content > * {
line-height: 1;
}
.v-select__widget > .v-input__control > .v-input__slot {
min-width: 60%;
}
</style>

View File

@ -0,0 +1,725 @@
<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 text-right">
<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>
<v-card-actions class="d-flex justify-sm-end pb-0 pr-0 pt-1">
<v-row>
<v-col cols="9" sm="9" md="9" lg="10"></v-col>
<v-col cols="3" sm="3" md="3" lg="2">
<v-select
v-model="selectValue"
:items="this.energyList"
item-text="enrgNm"
item-value="cd"
solo
outlined
:hide-details="true"
append-icon="mdi-chevron-down"
class="v-select__widget"
></v-select>
</v-col>
</v-row>
</v-card-actions>
<div class="row wrapper">
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseQty }}
<span class="font-weight-regular custom-text-2"
>kWh</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비({{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseQty
}}</strong>
<span class="caption mr-1">kWh</span>
<v-icon
small
:color="
isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875'
"
>{{ useQtyStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseCost }}
<span class="font-weight-regular custom-text-2"
>천원</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비(0-{{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseCost
}}</strong>
<span class="caption mr-1">천원</span>
<v-icon
small
:color="
isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875'
"
>{{ useCostStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex align-center justify-space-between mt-2">
<div :style="{ width: '100%', height: '130px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'EnrgUseRsltWidget'"
:widgetData="'EnrgUseRsltWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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',
}),
selectValue: {
get() {
return this.energyCd;
},
set(value) {
this.energyCd = value;
},
},
},
watch: {
// rdbEnrgUsage(){
// this.getEnrgUsage();
// },
energyCd() {
this.setUnitLabel();
this.getEnrgUsage();
this.getChartData();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
EnrgUseRsltWidget: { EnrgUseRsltWidgetData },
});
},
async created() {
this.energyList = await this.postApiReturn({
apiKey: 'selectEnergy',
resKey: 'energyData',
sendParam: {
useFg: 1,
},
});
this.energyCd = this.energyList[0].cd;
this.unit = this.energyList[0].unit;
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
// blocNm:'',
//바인딩
energyCd: '',
energyList: [],
unit: '',
currHour: Utility.setFormatDate(new Date(), 'H') + '시 기준',
isUseQtyStat: true,
isUseCostStat: true,
dayUseQty: 0,
compareUseQty: 0,
useQtyStat: null,
dayUseCost: 0,
compareUseCost: 0,
useCostStat: null,
// 차트
chart_01: 'enrgUsageChart',
loadChart_01: false,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
setWidgetChartYaxisData: 'setWidgetChartYaxisData',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
// setBlocNm(){
// this.blocNm = this.$store.state.userInfo.blocNm;
// if (this.blocNm != ''){
// this.blocNm = '[' + this.blocNm + ']'
// }
// },
setUnitLabel() {
this.energyList.filter(item => {
if (item.cd == this.energyCd) {
this.unit = item.unit;
}
});
},
async search() {
// this.setBlocNm();
await this.getEnrgUsage();
await this.getChartData();
},
async getEnrgUsage() {
const res = await this.postApiReturn({
apiKey: 'selectUseCostDay',
resKey: 'dayUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
const res2 = await this.postApiReturn({
apiKey: 'selectUseCostPast',
resKey: 'pastUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
res.forEach((item, idx) => {
this.dayUseQty = Utility.setFormatInt(item.qty);
this.dayUseCost = Utility.setFormatInt(item.cost);
});
let dayUseQty,
dayUseQtyAvg,
dayUseCost,
dayUseCostAvg,
dayUseMaxQty,
dayUseMaxCost = 0;
if (res.length > 0) {
dayUseQty = res[0].qty;
dayUseCost = res[0].cost;
}
if (res2.length > 0) {
dayUseQtyAvg = res2[0].qtyAvg;
dayUseCostAvg = res2[0].costAvg;
dayUseMaxQty = res2[0].maxQty;
dayUseMaxCost = res2[0].maxCost;
}
this.compareUseQty = Utility.setFormatInt(dayUseQty - dayUseQtyAvg);
this.compareUseCost = Utility.setFormatInt(dayUseCost - dayUseCostAvg);
this.useQtyStat =
dayUseQty > dayUseQtyAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.useCostStat =
dayUseCost > dayUseCostAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.isUseQtyStat = this.useQtyStat == 'mdi-arrow-up' ? true : false;
this.isUseCostStat = this.useCostStat == 'mdi-arrow-up' ? true : false;
},
setChartData(data, markAreaData) {
let xAxisData = [];
let seriesData = [];
let legendData = [];
let arrDarkColors = ['rgba(1, 174, 106, 0.7)', 'rgba(67, 133, 227, 0.7)'];
let arrLightColors = [
'rgba(207, 116, 229, 0.7)',
'rgba(106, 155, 244, 0.7)',
];
const arrColors = this.isDarkMode ? arrDarkColors : arrLightColors;
// chart x축 data
var qtyNumber, qtyStr;
for (var i = 0; i < 24; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '시');
}
// chart_data 중 누적 사용량과 누적 금액 구분
for (var i = 0; i < data.length; i++) {
var tempObj = { data: [] };
tempObj['type'] = 'line';
tempObj['lineStyle'] = { width: 2 };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
tempObj['color'] = arrColors[i];
if (data[i]['type'] == 'use') {
tempObj['name'] = '누적 사용량';
legendData.push('누적 사용량');
tempObj['areaStyle'] = {
opacity: 0.5,
color: arrColors[i],
};
tempObj['yAxisIndex'] = 0;
// markAreaData 추가
if (markAreaData.length > 0) {
tempObj['markArea'] = { data: markAreaData };
}
} else if (data[i]['type'] == 'cost') {
tempObj['name'] = '누적 금액';
legendData.push('누적 금액');
tempObj['yAxisIndex'] = 1;
} else if (data[i]['type'] == 'week') {
tempObj['name'] = '전주 평균 누적 사용량';
legendData.push('전주 평균 누적 사용량');
tempObj['yAxisIndex'] = 0;
}
// 0~23시 까지의 데이터 seriesData 넣기
for (var j = 0; j < 24; j++) {
qtyNumber = j.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
// tempObj['data'].push(Utility.setFormatIntDecimal(parseFloat(data[i][qtyStr]), 2).replace(',',''));
tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
seriesData.push(tempObj);
}
const yAxisData = [
{
type: 'value',
name: this.unit,
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
{
type: 'value',
name: '원',
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
];
var chartOption = {
series: seriesData,
grid: {
left: '1%',
right: '2%',
top: '23%',
bottom: '15%',
containLabel: true,
},
legend: {
data: legendData,
bottom: 'bottom',
icon: 'bar',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
axisLabel: {
fontSize: 9,
},
},
// yAxis: [
// {
// type: 'value',
// name: this.unit,
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// },
// {
// type: 'value',
// name: '원',
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// }
// ],
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'EnrgUseRsltWidget',
widgetData: 'EnrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: chartOption,
});
this.setWidgetChartYaxisData({
prgmId: this.$route.query.prgmId,
widgetKey: 'EnrgUseRsltWidget',
widgetData: 'EnrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: yAxisData,
});
this.loadChart_01 = true;
},
async getChartData() {
this.loadChart_01 = false;
var root_info = null;
var res_useage = null;
var res_cost = null;
var facList = null;
var filtered_res = null;
var apiParameters = {
blocId: 'BL0001',
readObjId: this.energyCd,
locKind: '',
upEccId: '',
};
var sendParam_chart_data = {
blocId: 'BL0001',
eccId: [],
eccNm: [],
fromObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
lockKind: '',
readObjId: this.energyCd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
upEccId: '',
};
var check_flag = true;
// 공정/설비 트리리스트 중 에너지원에 따른 최상위 정보 가져오기
try {
root_info = await this.postApiReturn({
apiKey: 'selectFtnPlcListTree',
resKey: 'ftnPlcTreeDatas',
sendParam: {
blocId: 'BL0001',
roiId: this.energyCd,
eqpmYn: 1,
// search:this.searchWord
},
});
filtered_res = root_info.filter(item => item.upEccId == 'ROOT');
apiParameters['locKind'] = filtered_res[0].locKind;
apiParameters['upEccId'] = filtered_res[0].eccId;
sendParam_chart_data['lockKind'] = filtered_res[0].locKind;
} catch (error) {
root_info = [];
filtered_res = [];
}
// 위의 정보로 해당 검침개소 정보 가져오기
try {
facList = await this.postApiReturn({
apiKey: 'selectEnergyUseReadDnPlc',
resKey: 'energyUseReadDnPlc',
sendParam: apiParameters,
});
for (var i in facList) {
sendParam_chart_data['eccId'].push(facList[i]['eccId']);
sendParam_chart_data['eccNm'].push(facList[i]['eccNm']);
}
// sendParam_chart_data['eccId'].push(facList[0]['eccId']);
// sendParam_chart_data['eccNm'].push(facList[0]['eccNm']);
sendParam_chart_data['upEccId'] = facList[0]['upEccId'];
} catch (error) {
check_flag = false;
}
// 위의 정보로 검침개소 시간별 사용량 가져오기
var final_chart_data = [];
if (check_flag) {
try {
res_useage = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM 안했을 경우 사용)
// var sum_data = {};
// for (var i in res_useage){
// res_useage[i]['type'] = 'use'
// for (var key in res_useage[i]){
// if(key.includes('qty')){
// if(sum_data[key] == undefined){
// sum_data[key] = res_useage[i][key]
// }else{
// sum_data[key] += res_useage[i][key]
// }
// }
// }
// // final_chart_data.push(res_useage[i])
// }
// final_chart_data.push({'type' : 'use', ...sum_data})
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM을 했을 경우 사용)
res_useage[0]['type'] = 'use';
final_chart_data.push(res_useage[0]);
} catch (error) {
res_useage = [];
}
try {
res_cost = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourCostAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
res_cost[0]['type'] = 'cost';
final_chart_data.push(res_cost[0]);
} catch (error) {
res_cost = [];
}
} else {
res_useage = [];
res_cost = [];
}
// 전주 평균 누적 사용량
let res_week_read = [];
res_week_read = await this.postApiReturn({
apiKey: 'selectEnergyUseReadLastWeekAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
if (res_week_read.length != 0) {
res_week_read[0]['type'] = 'week';
final_chart_data.push(res_week_read[0]);
}
// markAreaData 가져오기
let res3 = [];
let markAreaData = [];
let markColor = {
MAX: 'rgba(238, 102, 102, 0.1)',
MID: 'rgba(250, 200, 88, 0.1)',
MIN: 'rgba(145, 204, 117, 0.1)',
};
const result = this.energyList.filter(
energy => energy.cd == this.energyCd,
);
if (result[0].enrgNm == '전력') {
res3 = await this.postApiReturn({
apiKey: 'selectPeakKine',
resKey: 'peakData',
sendParam: {
readObjId: result[0].cd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
},
});
markAreaData = res3.map(item => [
{
name: item.commCdNm,
xAxis:
parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')) == 23
? 0
: parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')),
itemStyle: {
color: markColor[item.peakKine],
},
label: {
distance: [0],
fontSize: 9,
fontWeight: 'lighter',
color: '#fff',
},
},
{
xAxis: parseInt(item.endTm.split(':')[0].replace(/(^0+)/, '')),
},
]);
}
// char data 넣기
this.$nextTick(() => {
this.setChartData(final_chart_data, markAreaData);
});
},
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 EnrgUseRsltWidgetData = {
isFind: false,
enrgUsageChart: 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;
}
.v-radio > label {
font-size: 0.8rem;
}
.v-list-item {
min-height: 30px;
line-height: 1;
}
.v-list-item__content > * {
line-height: 1;
}
.v-select__widget > .v-input__control > .v-input__slot {
min-width: 60%;
}
.wrapper {
padding: 5px 10px 0px 10px !important;
border-bottom: thin solid rgba(255, 255, 255, 0.12);
}
</style>

View File

@ -0,0 +1,350 @@
<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">
<component
ref="MainReadReptReadObjMultiPop"
:is="'MainReadReptReadObjMultiPop'"
:parentPrgmId="parentPrgmId"
:eqpmYn="0"
:popTitle="'검침대상 목록'"
:widgetId="this.widgetId"
@chDialogViewmainReadReptWidget="dialogViewChange"
/>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-icon
class="mr-1"
size="25"
v-bind="attrs"
v-on="on"
@click="readObjDialog"
>mdi-tooltip-plus</v-icon
>
</template>
<span>품질</span>
</v-tooltip>
<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="px-2 pt-3">
<v-banner single-line :style="{ paddingRight: '10px' }">
<v-row justify="space-between" align="center" no-gutters>
<v-col cols="auto" align="center">
<p class="body-2 mb-0">No</p>
</v-col>
<v-col cols="4" align="center">
검침개소
</v-col>
<v-col cols="2" align="center">
<p class="body-2 mb-0">kW</p>
</v-col>
<v-col cols="2" align="center">
상태
</v-col>
<v-col
cols="2"
align="center"
v-for="(item, index) in readObjIdList"
:key="item.readPlcId"
:class="{
'v-banner--last': index === readObjIdList.length - 1,
}"
>
{{ item.readObjNm }}
</v-col>
</v-row>
</v-banner>
<div
class="v-virtual-scroll-wrapper"
:style="{ paddingRight: '5px' }"
>
<v-banner
single-line
v-for="(item, index) in mainReadPlcData"
:key="item.readPlcId"
:class="{
'v-banner--last': index === mainReadPlcData.length - 1,
}"
>
<v-row justify="space-between" align="center" no-gutters>
<v-col cols="auto">
<p class="body-2 mb-0">{{ item.rowNum }}</p>
</v-col>
<v-col cols="4">
<div
class="d-flex align-center"
style="white-space: normal"
>
<p class="body-2 mb-0 ml-2">{{ item.readPlcNm }}</p>
</div>
</v-col>
<v-col cols="2" align="center">
<p class="body-2 mb-0">
{{
String(Math.floor(item.instantVal)).replace(
/\B(?=(\d{3})+(?!\d))/g,
',',
)
}}
</p>
</v-col>
<v-col cols="2" align="center">
<v-icon
:color="
isDarkMode
? tableDataGetDarkColorByState(item.stat)
: tableDataGetLightColorByState(item.stat)
"
size="8"
class="mr-1"
>mdi-circle</v-icon
>
<span class="body-2">{{ item.stat }}</span>
</v-col>
<v-col
cols="2"
align="center"
v-for="(item2, index) in readObjIdList"
:key="item2.readPlcId"
:class="{
'v-banner--last': index === readObjIdList.length - 1,
}"
>
<span class="body-2">{{ item[item2.readObjId] }}</span>
</v-col>
</v-row>
</v-banner>
</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';
import MainReadReptReadObjMultiPop from '~/components/common/modal/MainReadReptReadObjMultiPop';
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,
MainReadReptReadObjMultiPop,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId][this.widgetId][
this.widgetId + 'Data'
];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {
energyCd() {
this.getMainReadPlcStat();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
gasReadReptWidget: { gasReadReptWidgetData },
});
},
async created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
blocNm: '',
mainReadPlcData: [],
widgetId: 'gasReadReptWidget',
dialogView: false,
readObjIdList: [],
readPlcIdList: [],
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
dialogViewChange() {
this.getMainReadPlcStat();
},
async search() {
this.setBlocNm();
await this.getMainReadPlcStat();
},
async getMainReadPlcStat() {
if (
this.$store.state.pageData[this.parentPrgmId].gasReadReptWidget
.gasReadReptWidgetData.readObjList.length > 0
) {
this.readObjIdList = this.$store.state.pageData[
this.parentPrgmId
].gasReadReptWidget.gasReadReptWidgetData.readObjList.map(item => {
return { readObjId: item.readObjId, readObjNm: item.readObjNm };
});
}
if (
this.$store.state.pageData[this.parentPrgmId].gasReadReptWidget
.gasReadReptWidgetData.plcKindList.length > 0
) {
this.readPlcIdList = this.$store.state.pageData[
this.parentPrgmId
].gasReadReptWidget.gasReadReptWidgetData.plcKindList.map(item => {
return item.readPlcId;
});
}
this.mainReadPlcData = await this.postApiReturn({
apiKey: 'selectMainReadPlcStat',
resKey: 'mainReadPlcData',
sendParam: {
readObjIdList: this.readObjIdList,
},
});
// this.mainReadPlcData = [
// {
// "rowNum" : 1,
// "comId" : "CDR00",
// "readPlcId" : "RPC000002",
// "readPlcNm" : "[전력] LP-1_A동메인",
// "readObjNm" : "Heartbit",
// "readObjId" : "ROI000040",
// "instantVal" : 11239.0,
// "volt" : 228.9,
// "ampr" : 55.1,
// "ROI000001" : 93613.1,
// "ROI000005" : 229.7,
// "ROI000006" : 81.8,
// "ROI000008" : 1,
// "stat" : "가동중"
// }
// ]
},
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;
}
},
tableDataGetDarkColorByState: state => {
return {
가동중: '#01ae6a',
미사용: '#ffb046',
비정상: '#f6637b',
}[state];
},
tableDataGetLightColorByState: state => {
return {
가동중: '#3cc380',
미사용: '#ffb13b',
비정상: '#f98694',
}[state];
},
readObjDialog() {
this.$store.state.pageData[
this.parentPrgmId
].gasReadReptWidget.gasReadReptWidgetData.enrgDiv = 'MTT_FUEL';
this.$store.state.pageData[
this.parentPrgmId
].gasReadReptWidget.gasReadReptWidgetData.grpCd = 'MTT_STAT';
this.$refs['MainReadReptReadObjMultiPop'].dialog = true;
},
},
};
const gasReadReptWidgetData = {
readObjModalData: {},
isMulti: true,
blocId: 0,
blocMstrList: [],
readObjList: [],
readObj: {},
enrgDiv: '',
plcKindList: [],
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>

View File

@ -0,0 +1,646 @@
<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 text-right">
<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="row wrapper">
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseQty }}
<span class="font-weight-regular custom-text-2"
>kWh</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비({{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseQty
}}</strong>
<span class="caption mr-1">kWh</span>
<v-icon
small
:color="
isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875'
"
>{{ useQtyStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseCost }}
<span class="font-weight-regular custom-text-2"
>천원</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비(0-{{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseCost
}}</strong>
<span class="caption mr-1">천원</span>
<v-icon
small
:color="
isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875'
"
>{{ useCostStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex align-center justify-space-between mt-2">
<div :style="{ width: '100%', height: '160px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'enrgUseRsltWidget'"
:widgetData="'enrgUseRsltWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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: {
// rdbEnrgUsage(){
// this.getEnrgUsage();
// },
energyCd() {
this.getEnrgUsage();
this.getChartData();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
enrgUseRsltWidget: { enrgUseRsltWidgetData },
});
},
async created() {
this.energyList = await this.postApiReturn({
apiKey: 'selectEnergy',
resKey: 'energyData',
sendParam: {
useFg: 1,
},
});
this.energyList.filter(item => {
if (item.readObjCd == 'GAS_LNG') {
//가스
this.energyCd = item.cd;
this.unit = item.unit;
}
});
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
// blocNm:'',
//바인딩
energyCd: '',
energyList: [],
unit: '',
currHour: Utility.setFormatDate(new Date(), 'H') + '시 기준',
isUseQtyStat: true,
isUseCostStat: true,
dayUseQty: 0,
compareUseQty: 0,
useQtyStat: null,
dayUseCost: 0,
compareUseCost: 0,
useCostStat: null,
// 차트
chart_01: 'enrgUsageChart',
loadChart_01: false,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
setWidgetChartYaxisData: 'setWidgetChartYaxisData',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
async search() {
// this.setBlocNm();
await this.getEnrgUsage();
await this.getChartData();
},
async getEnrgUsage() {
const res = await this.postApiReturn({
apiKey: 'selectUseCostDay',
resKey: 'dayUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
const res2 = await this.postApiReturn({
apiKey: 'selectUseCostPast',
resKey: 'pastUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
res.forEach((item, idx) => {
this.dayUseQty = Utility.setFormatInt(item.qty);
this.dayUseCost = Utility.setFormatInt(item.cost);
});
let dayUseQty,
dayUseQtyAvg,
dayUseCost,
dayUseCostAvg,
dayUseMaxQty,
dayUseMaxCost = 0;
if (res.length > 0) {
dayUseQty = res[0].qty;
dayUseCost = res[0].cost;
}
if (res2.length > 0) {
dayUseQtyAvg = res2[0].qtyAvg;
dayUseCostAvg = res2[0].costAvg;
dayUseMaxQty = res2[0].maxQty;
dayUseMaxCost = res2[0].maxCost;
}
this.compareUseQty = Utility.setFormatInt(dayUseQty - dayUseQtyAvg);
this.compareUseCost = Utility.setFormatInt(dayUseCost - dayUseCostAvg);
this.useQtyStat =
dayUseQty > dayUseQtyAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.useCostStat =
dayUseCost > dayUseCostAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.isUseQtyStat = this.useQtyStat == 'mdi-arrow-up' ? true : false;
this.isUseCostStat = this.useCostStat == 'mdi-arrow-up' ? true : false;
},
setChartData(data) {
let xAxisData = [];
let seriesData = [];
let legendData = [];
let arrDarkColors = ['rgba(1, 174, 106, 0.7)', 'rgba(67, 133, 227, 0.7)'];
let arrLightColors = [
'rgba(207, 116, 229, 0.7)',
'rgba(106, 155, 244, 0.7)',
];
const arrColors = this.isDarkMode ? arrDarkColors : arrLightColors;
// chart x축 data
var qtyNumber, qtyStr;
for (var i = 0; i < 24; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '시');
}
// chart_data 중 누적 사용량과 누적 금액 구분
for (var i = 0; i < data.length; i++) {
var tempObj = { data: [] };
tempObj['type'] = 'line';
tempObj['lineStyle'] = { width: 2 };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
tempObj['color'] = arrColors[i];
if (data[i]['type'] == 'use') {
tempObj['name'] = '누적 사용량';
legendData.push('누적 사용량');
tempObj['areaStyle'] = {
opacity: 0.5,
color: arrColors[i],
};
tempObj['yAxisIndex'] = 0;
} else if (data[i]['type'] == 'cost') {
tempObj['name'] = '누적 금액';
legendData.push('누적 금액');
tempObj['yAxisIndex'] = 1;
} else if (data[i]['type'] == 'week') {
tempObj['name'] = '전주 평균 누적 사용량';
legendData.push('전주 평균 누적 사용량');
tempObj['yAxisIndex'] = 0;
}
// 0~23시 까지의 데이터 seriesData 넣기
for (var j = 0; j < 24; j++) {
qtyNumber = j.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
// tempObj['data'].push(Utility.setFormatIntDecimal(parseFloat(data[i][qtyStr]), 2).replace(',',''));
tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
seriesData.push(tempObj);
}
const yAxisData = [
{
type: 'value',
name: this.unit,
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
{
type: 'value',
name: '원',
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
];
var chartOption = {
series: seriesData,
grid: {
left: '1%',
right: '2%',
top: '20%',
bottom: '15%',
containLabel: true,
},
legend: {
data: legendData,
bottom: 'bottom',
icon: 'bar',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
axisLabel: {
fontSize: 9,
},
},
// yAxis: [
// {
// type: 'value',
// name: this.unit,
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// },
// {
// type: 'value',
// name: '원',
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// }
// ],
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'enrgUseRsltWidget',
widgetData: 'enrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: chartOption,
});
this.setWidgetChartYaxisData({
prgmId: this.$route.query.prgmId,
widgetKey: 'enrgUseRsltWidget',
widgetData: 'enrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: yAxisData,
});
this.loadChart_01 = true;
},
async getChartData() {
this.loadChart_01 = false;
var root_info = null;
var res_useage = null;
var res_cost = null;
var facList = null;
var filtered_res = null;
var apiParameters = {
blocId: 'BL0001',
readObjId: this.energyCd,
locKind: '',
upEccId: '',
};
var sendParam_chart_data = {
blocId: 'BL0001',
eccId: [],
eccNm: [],
fromObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
lockKind: '',
readObjId: this.energyCd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
upEccId: '',
};
var check_flag = true;
// 공정/설비 트리리스트 중 에너지원에 따른 최상위 정보 가져오기
try {
root_info = await this.postApiReturn({
apiKey: 'selectFtnPlcListTree',
resKey: 'ftnPlcTreeDatas',
sendParam: {
blocId: 'BL0001',
roiId: this.energyCd,
eqpmYn: 1,
// search:this.searchWord
},
});
filtered_res = root_info.filter(item => item.upEccId == 'ROOT');
apiParameters['locKind'] = filtered_res[0].locKind;
apiParameters['upEccId'] = filtered_res[0].eccId;
sendParam_chart_data['lockKind'] = filtered_res[0].locKind;
} catch (error) {
root_info = [];
filtered_res = [];
}
// 위의 정보로 해당 검침개소 정보 가져오기
try {
facList = await this.postApiReturn({
apiKey: 'selectEnergyUseReadDnPlc',
resKey: 'energyUseReadDnPlc',
sendParam: apiParameters,
});
for (var i in facList) {
sendParam_chart_data['eccId'].push(facList[i]['eccId']);
sendParam_chart_data['eccNm'].push(facList[i]['eccNm']);
}
// sendParam_chart_data['eccId'].push(facList[0]['eccId']);
// sendParam_chart_data['eccNm'].push(facList[0]['eccNm']);
sendParam_chart_data['upEccId'] = facList[0]['upEccId'];
} catch (error) {
check_flag = false;
}
// 위의 정보로 검침개소 시간별 사용량 가져오기
var final_chart_data = [];
if (check_flag) {
try {
res_useage = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM 안했을 경우 사용)
// var sum_data = {};
// for (var i in res_useage){
// res_useage[i]['type'] = 'use'
// for (var key in res_useage[i]){
// if(key.includes('qty')){
// if(sum_data[key] == undefined){
// sum_data[key] = res_useage[i][key]
// }else{
// sum_data[key] += res_useage[i][key]
// }
// }
// }
// // final_chart_data.push(res_useage[i])
// }
// final_chart_data.push({'type' : 'use', ...sum_data})
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM을 했을 경우 사용)
res_useage[0]['type'] = 'use';
final_chart_data.push(res_useage[0]);
} catch (error) {
res_useage = [];
}
try {
res_cost = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourCostAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
res_cost[0]['type'] = 'cost';
final_chart_data.push(res_cost[0]);
} catch (error) {
res_cost = [];
}
} else {
res_useage = [];
res_cost = [];
}
// 전주 평균 누적 사용량
let res_week_read = [];
res_week_read = await this.postApiReturn({
apiKey: 'selectEnergyUseReadLastWeekAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
if (res_week_read.length != 0) {
res_week_read[0]['type'] = 'week';
final_chart_data.push(res_week_read[0]);
}
// char data 넣기
this.$nextTick(() => {
this.setChartData(final_chart_data);
});
},
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 enrgUseRsltWidgetData = {
isFind: false,
enrgUsageChart: 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;
}
.v-radio > label {
font-size: 0.8rem;
}
.v-list-item {
min-height: 30px;
line-height: 1;
}
.v-list-item__content > * {
line-height: 1;
}
.v-select__widget > .v-input__control > .v-input__slot {
min-width: 60%;
}
.wrapper {
padding: 5px 10px 0px 10px !important;
border-bottom: thin solid rgba(255, 255, 255, 0.12);
}
</style>

View File

@ -0,0 +1,282 @@
<template>
<div class="l-layout">
<v-row ref="rowParent">
<v-col :cols="12">
<v-card class="pa-5 widget-card">
<div class="d-flex align-center justify-space-between">
<v-card-title class="pa-0">그리드</v-card-title>
<v-btn :ripple="false" @click="btnAction('popWidget')">화면</v-btn>
</div>
<div class="d-flex align-center justify-space-between mt-8">
<div class="mr-5" :style="{ width: '240px', height: '170px' }">
<component
:ref="gridName"
:is="loadGrid ? 'Grid' : null"
:parentPrgmId="parentPrgmId"
:gridName="gridName"
/>
</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 Grid from '~/components/common/Grid';
import Chart from '~/components/common/Chart';
export default {
props: {
parentPrgmId: {
type: String,
require: true,
},
},
components: {
DateUtility,
Grid,
Chart,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId];
},
isDarkMode: 'isDarkMode',
}),
},
watch: {},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
gridWidget: { gridWidgetData },
});
// console.log("2.vue::beforeCreate");
},
created() {
this.search();
},
mounted() {},
data() {
return {
loadGrid: false,
gridName: 'rowGrid',
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
}),
gridInit() {
const gridHeight = this.$refs.gridParent.offsetHeight - 36;
const myOptions = {
scrollX: false,
};
this.setGridOption({
gridKey: this.gridName,
// value: myOptions
value: Object.assign(Utility.defaultGridOption(gridHeight), myOptions),
});
this.setGridColumn({
gridKey: this.gridName,
value: myColumns,
});
// this.getRowGridData();
this.loadGrid = true;
},
async search() {
await this.getRowGridData();
await this.setPageData({
isFind: false,
});
},
async getUseWithPeak() {
this.loadChart_01 = false;
const res = await this.postApiReturn({
apiKey: 'selectUseWithPeak',
resKey: 'peakData',
sendParam: {},
});
res.forEach((item, idx) => {
this.chargedPower = Utility.setFormatInt(item.peakVal);
this.nowPeakVal = Utility.setFormatInt(item.curPeakVal);
});
this.$nextTick(() => {
this.setChart01Data(res);
});
},
//차트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%',
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: 'PeakWidget',
});
break;
}
},
},
};
const gridWidgetData = {
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>

View File

@ -0,0 +1,382 @@
<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-select
ref="selectEnergy"
v-model="selectValue"
:items="this.energyList"
item-text="enrgNm"
item-value="cd"
solo
outlined
:hide-details="true"
append-icon="mdi-chevron-down"
class="v-select__custom mr-2"
></v-select>
<component
ref="MainReadReptReadObjMultiPop"
:is="'MainReadReptReadObjMultiPop'"
:parentPrgmId="parentPrgmId"
:eqpmYn="0"
:popTitle="'검침대상 목록'"
:widgetId="this.widgetId"
@chDialogViewmainReadReptWidget="dialogViewChange"
/>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-icon
class="mr-1"
size="25"
v-bind="attrs"
v-on="on"
@click="readObjDialog"
>mdi-tooltip-plus</v-icon
>
</template>
<span>품질</span>
</v-tooltip>
<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="px-2 pt-3">
<v-banner single-line :style="{ paddingRight: '10px' }">
<v-row justify="space-between" align="center" no-gutters>
<v-col cols="auto" align="center">
<p class="body-2 mb-0">No</p>
</v-col>
<v-col cols="4" align="center">
검침개소
</v-col>
<v-col cols="2" align="center">
<p class="body-2 mb-0">kW</p>
</v-col>
<v-col cols="2" align="center">
상태
</v-col>
<v-col
cols="2"
align="center"
v-for="(item, index) in readObjIdList"
:key="item.readPlcId"
:class="{
'v-banner--last': index === readObjIdList.length - 1,
}"
>
{{ item.readObjNm }}
</v-col>
</v-row>
</v-banner>
<div
class="v-virtual-scroll-wrapper"
:style="{ paddingRight: '5px' }"
>
<v-banner
single-line
v-for="(item, index) in mainReadPlcData"
:key="item.readPlcId"
:class="{
'v-banner--last': index === mainReadPlcData.length - 1,
}"
>
<v-row justify="space-between" align="center" no-gutters>
<v-col cols="auto">
<p class="body-2 mb-0">{{ item.rowNum }}</p>
</v-col>
<v-col cols="4">
<div
class="d-flex align-center"
style="white-space: normal"
>
<p class="body-2 mb-0 ml-2">{{ item.readPlcNm }}</p>
</div>
</v-col>
<v-col cols="2" align="center">
<p class="body-2 mb-0">
{{
String(Math.floor(item.instantVal)).replace(
/\B(?=(\d{3})+(?!\d))/g,
',',
)
}}
</p>
</v-col>
<v-col cols="2" align="center">
<v-icon
:color="
isDarkMode
? tableDataGetDarkColorByState(item.stat)
: tableDataGetLightColorByState(item.stat)
"
size="8"
class="mr-1"
>mdi-circle</v-icon
>
<span class="body-2">{{ item.stat }}</span>
</v-col>
<v-col
cols="2"
align="center"
v-for="(item2, index) in readObjIdList"
:key="item2.readPlcId"
:class="{
'v-banner--last': index === readObjIdList.length - 1,
}"
>
<span class="body-2">{{ item[item2.readObjId] }}</span>
</v-col>
</v-row>
</v-banner>
</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';
import MainReadReptReadObjMultiPop from '~/components/common/modal/MainReadReptReadObjMultiPop';
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,
MainReadReptReadObjMultiPop,
},
computed: {
...mapState({
searchParam(state) {
return state.pageData[this.parentPrgmId][this.widgetId][
this.widgetId + 'Data'
];
},
isDarkMode: 'isDarkMode',
}),
selectValue: {
get() {
return this.energyCd;
},
set(value) {
this.energyCd = value;
},
},
},
watch: {
energyCd() {
this.getMainReadPlcStat();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
mainReadReptWidget: { mainReadReptWidgetData },
});
},
async created() {
this.energyList = await this.postApiReturn({
apiKey: 'selectEnergy',
resKey: 'energyData',
sendParam: {
useFg: 1,
},
});
this.energyCd = this.energyList[0].cd;
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
blocNm: '',
energyCd: '',
energyList: [],
mainReadPlcData: [],
widgetId: 'mainReadReptWidget',
dialogView: false,
readObjIdList: [],
readPlcIdList: [],
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
dialogViewChange() {
this.getMainReadPlcStat();
},
async search() {
this.setBlocNm();
await this.getMainReadPlcStat();
},
async getMainReadPlcStat() {
if (
this.$store.state.pageData[this.parentPrgmId].mainReadReptWidget
.mainReadReptWidgetData.readObjList.length > 0
) {
this.readObjIdList = this.$store.state.pageData[
this.parentPrgmId
].mainReadReptWidget.mainReadReptWidgetData.readObjList.map(item => {
return { readObjId: item.readObjId, readObjNm: item.readObjNm };
});
}
if (
this.$store.state.pageData[this.parentPrgmId].mainReadReptWidget
.mainReadReptWidgetData.plcKindList.length > 0
) {
this.readPlcIdList = this.$store.state.pageData[
this.parentPrgmId
].mainReadReptWidget.mainReadReptWidgetData.plcKindList.map(item => {
return item.readPlcId;
});
}
this.mainReadPlcData = await this.postApiReturn({
apiKey: 'selectMainReadPlcStat',
resKey: 'mainReadPlcData',
sendParam: {
readObjIdList: this.readObjIdList,
readPlcIdList: this.readPlcIdList,
},
});
// this.mainReadPlcData = [
// {
// "rowNum" : 1,
// "comId" : "CDR00",
// "readPlcId" : "RPC000002",
// "readPlcNm" : "[전력] LP-1_A동메인",
// "readObjNm" : "Heartbit",
// "readObjId" : "ROI000040",
// "instantVal" : 11239.0,
// "volt" : 228.9,
// "ampr" : 55.1,
// "ROI000001" : 93613.1,
// "ROI000005" : 229.7,
// "ROI000006" : 81.8,
// "ROI000008" : 1,
// "stat" : "가동중"
// }
// ]
},
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;
}
},
tableDataGetDarkColorByState: state => {
return {
가동중: '#01ae6a',
미사용: '#ffb046',
비정상: '#f6637b',
}[state];
},
tableDataGetLightColorByState: state => {
return {
가동중: '#3cc380',
미사용: '#ffb13b',
비정상: '#f98694',
}[state];
},
readObjDialog() {
this.$store.state.pageData[
this.parentPrgmId
].mainReadReptWidget.mainReadReptWidgetData.enrgDiv = this.$refs[
'selectEnergy'
].selectedItems[0].enrgDiv;
this.$refs['MainReadReptReadObjMultiPop'].dialog = true;
},
},
};
const mainReadReptWidgetData = {
readObjModalData: {},
isMulti: true,
blocId: 0,
blocMstrList: [],
readObjList: [],
energyCd: '',
energyList: [],
readObj: {},
enrgDiv: '',
plcKindList: [],
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>

View File

@ -0,0 +1,361 @@
<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="mt-1" align="right">
현재 피크 : {{ nowPeakVal }}kW ({{ peakRto }}%) / 요금적용전력 :
{{ chargedPower }}kW
</div>
<div class="d-flex align-center justify-space-between">
<div :style="{ width: '100%', height: '200px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'PeakTrndWidget'"
:widgetData="'PeakTrndWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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,
PeakTrndWidget: { PeakTrndWidgetData },
});
},
async created() {
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
blocNm: '',
//차트
chart_01: 'peakUsage',
loadChart_01: false,
//바인딩
rdbElecQual: 'Kw',
chargedPower: 0,
nowPeakVal: 0,
peakRto: 0,
dtToday: Utility.setFormatDate(new Date(), 'YYYY/MM/DD HH'),
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
setBlocNm() {
this.blocNm = this.$store.state.userInfo.blocNm;
if (this.blocNm != '') {
this.blocNm = '[' + this.blocNm + ']';
}
},
async search() {
this.setBlocNm();
await this.getPeakUsage();
},
async getPeakUsage() {
this.loadChart_01 = false;
let markAreaData = [];
let markColor = {
MAX: 'rgba(238, 102, 102, 0.1)',
MID: 'rgba(250, 200, 88, 0.1)',
MIN: 'rgba(145, 204, 117, 0.1)',
};
// 부하시간 가져오기
let res3 = [];
res3 = await this.postApiReturn({
apiKey: 'selectPeakKine',
resKey: 'peakData',
sendParam: {
readObjId: 'ROI000001',
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
},
});
markAreaData = res3.map(item => [
{
name: item.commCdNm,
xAxis:
parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')) == 23
? 0
: parseInt(item.strtTm.split(':')[0].replace(/(^0+)/, '')),
itemStyle: {
color: markColor[item.peakKine],
},
label: {
distance: [0],
fontSize: 9,
fontWeight: 'lighter',
color: '#fff',
},
},
{
xAxis: parseInt(item.endTm.split(':')[0].replace(/(^0+)/, '')),
},
]);
//전력 조회
let res = await this.postApiReturn({
apiKey: 'selectPeakTrnd',
resKey: 'peakTrndData',
sendParam: {
blocId: this.$store.state.userInfo.blocId,
readObjId: 'ROI000001',
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
},
});
this.$nextTick(() => {
this.setChart01Data(res, markAreaData);
});
// 상단에 표시할 요금전용전력, 현재피크
this.sendParamData = {
readObjId: 'ROI000001',
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
cmCycle: 'CYC_HOUR',
blocId: this.$store.state.userInfo.blocId,
};
this.getPeakPowTitle();
},
async getPeakPowTitle() {
if (this.sendParamData != undefined) {
let res3 = [];
res3 = await this.postApiReturn({
apiKey: 'selectPeakPowAndChargedPower',
resKey: 'peakData',
// sendParam: {dateType: this.pageData.cmCycle, date: this.pageData.dtToday}
sendParam: this.sendParamData,
});
let res4 = [];
res4 = await this.postApiReturn({
apiKey: 'selectUseWithPeak',
resKey: 'peakData',
sendParam: {},
});
res3.forEach(item => {
this.chargedPower =
item.peakVal == 0 ? 0 : Utility.setFormatInt(item.peakVal);
});
res4.forEach((item, idx) => {
this.nowPeakVal =
item.curPeakVal == 0 ? 0 : Utility.setFormatInt(item.curPeakVal);
this.peakRto =
item.peakRto == 0 ? 0 : Utility.setFormatDecimal(item.peakRto, 0);
});
}
},
//차트Setting
async setChart01Data(data, markAreaData) {
this.loadChart_01 = false;
this.$store.state.pageData[
this.parentPrgmId
].PeakTrndWidget.PeakTrndWidgetData.series = [];
if (!data.length) {
return;
}
let xAxisData = [];
let legendData = [];
// chart color 집합
let colorPalette = {
PLCPEAK: '#D73964',
PLCMAX: 'rgba(252,151,175,0.7)',
};
let seriesDataList = [];
let myKey = Object.keys(data[0]);
myKey = myKey.filter(v => {
return v.search('qty') != -1;
});
myKey.sort();
for (var i = 0; i < 24; i++) {
xAxisData.push(i + '시');
}
seriesDataList = data.map(item => ({
name: item.plcNm,
type: item.plcCd == 'PLCMAX' ? 'bar' : 'line',
color:
item.plcCd == 'PLCPEAK'
? colorPalette[item.plcCd]
: item.plcCd == 'PLCMAX'
? colorPalette[item.plcCd]
: colorPalette[item.readObjId],
symbol: item.plcCd == 'PLCPEAK' ? 'none' : 'circle',
data: myKey.map(key => item[key] || 0),
yAxisIndex:
item.readObjId == 'ROI000013' || item.readObjId == 'ROI000014'
? 1
: 0,
markArea: item.plcCd == 'PLCMAX' ? { data: markAreaData } : 'none',
}));
var chartOption = {
series: seriesDataList,
grid: {
left: '1%',
right: '2%',
top: '15%',
bottom: '15%',
containLabel: true,
},
legend: {
bottom: 'bottom',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
},
yAxis: {
type: 'value',
name: 'kWh',
splitLine: {
show: false,
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'PeakTrndWidget',
widgetData: 'PeakTrndWidgetData',
chartKey: 'peakUsage',
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 PeakTrndWidgetData = {
peakUsage: Utility.defaultChartOption(true),
sendParamData: { readObjId: '' },
};
</script>
<style lang="scss">
.v-avatar {
border-radius: 21px;
font-size: 1.75rem;
}
.v-virtual-scroll-wrapper {
overflow-y: auto;
max-height: 210px;
}
</style>

View File

@ -0,0 +1,524 @@
<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>

View File

@ -0,0 +1,646 @@
<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 text-right">
<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="row wrapper">
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseQty }}
<span class="font-weight-regular custom-text-2"
>kWh</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비({{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseQty
}}</strong>
<span class="caption mr-1">kWh</span>
<v-icon
small
:color="
isDarkMode
? isUseQtyStat
? '#f6637b'
: '#01ae6a'
: isUseQtyStat
? '#ff76bb'
: '#00c875'
"
>{{ useQtyStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
<div class="col-6">
<div class="px-5 pb-1">
<div class="text-center">
<strong class="custom-title-2-5"
>{{ dayUseCost }}
<span class="font-weight-regular custom-text-2"
>천원</span
></strong
>
<div class="d-flex align-center justify-center">
<span class="body-2 text-color--non-activate"
>전주 대비(0-{{ currHour }})</span
>
<div
class="d-flex align-baseline ml-2"
:style="{
color: isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875',
}"
>
<strong class="mr-1 custom-text-1">{{
compareUseCost
}}</strong>
<span class="caption mr-1">천원</span>
<v-icon
small
:color="
isDarkMode
? isUseCostStat
? '#f6637b'
: '#01ae6a'
: isUseCostStat
? '#ff76bb'
: '#00c875'
"
>{{ useCostStat }}</v-icon
>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="d-flex align-center justify-space-between mt-2">
<div :style="{ width: '100%', height: '160px' }">
<component
class="w100 h100"
:is="loadChart_01 ? 'Chart' : null"
:parentPrgmId="parentPrgmId"
:widgetId="'enrgUseRsltWidget'"
:widgetData="'enrgUseRsltWidgetData'"
:chartName="chart_01"
ref="chart_01"
/>
</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: {
// rdbEnrgUsage(){
// this.getEnrgUsage();
// },
energyCd() {
this.getEnrgUsage();
this.getChartData();
},
},
beforeCreate() {
this.$store.commit('setWidgetPageData', {
prgmId: this.$route.query.prgmId,
enrgUseRsltWidget: { enrgUseRsltWidgetData },
});
},
async created() {
this.energyList = await this.postApiReturn({
apiKey: 'selectEnergy',
resKey: 'energyData',
sendParam: {
useFg: 1,
},
});
this.energyList.filter(item => {
if (item.readObjCd == 'STEAM') {
//스팀
this.energyCd = item.cd;
this.unit = item.unit;
}
});
this.search();
this.timer = setInterval(this.search, this.widgetReflashMm);
},
beforeDestroy() {
window.clearTimeout(this.timer);
},
mounted() {},
data() {
return {
// blocNm:'',
//바인딩
energyCd: '',
energyList: [],
unit: '',
currHour: Utility.setFormatDate(new Date(), 'H') + '시 기준',
isUseQtyStat: true,
isUseCostStat: true,
dayUseQty: 0,
compareUseQty: 0,
useQtyStat: null,
dayUseCost: 0,
compareUseCost: 0,
useCostStat: null,
// 차트
chart_01: 'enrgUsageChart',
loadChart_01: false,
};
},
methods: {
...mapMutations({
setPageData: 'setPageData',
setWidgetChartOption: 'setWidgetChartOption',
openDashboardWidget: 'openDashboardWidget',
setWidgetChartYaxisData: 'setWidgetChartYaxisData',
}),
...mapActions({
postApi: 'modules/list/postApi',
postApiReturn: 'modules/list/postApiReturn',
getEnergyList: 'modules/search/getEnergyList',
}),
async search() {
// this.setBlocNm();
await this.getEnrgUsage();
await this.getChartData();
},
async getEnrgUsage() {
const res = await this.postApiReturn({
apiKey: 'selectUseCostDay',
resKey: 'dayUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
const res2 = await this.postApiReturn({
apiKey: 'selectUseCostPast',
resKey: 'pastUseCostData',
sendParam: {
readObjId: this.energyCd,
},
});
res.forEach((item, idx) => {
this.dayUseQty = Utility.setFormatInt(item.qty);
this.dayUseCost = Utility.setFormatInt(item.cost);
});
let dayUseQty,
dayUseQtyAvg,
dayUseCost,
dayUseCostAvg,
dayUseMaxQty,
dayUseMaxCost = 0;
if (res.length > 0) {
dayUseQty = res[0].qty;
dayUseCost = res[0].cost;
}
if (res2.length > 0) {
dayUseQtyAvg = res2[0].qtyAvg;
dayUseCostAvg = res2[0].costAvg;
dayUseMaxQty = res2[0].maxQty;
dayUseMaxCost = res2[0].maxCost;
}
this.compareUseQty = Utility.setFormatInt(dayUseQty - dayUseQtyAvg);
this.compareUseCost = Utility.setFormatInt(dayUseCost - dayUseCostAvg);
this.useQtyStat =
dayUseQty > dayUseQtyAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.useCostStat =
dayUseCost > dayUseCostAvg ? 'mdi-arrow-up' : 'mdi-arrow-down';
this.isUseQtyStat = this.useQtyStat == 'mdi-arrow-up' ? true : false;
this.isUseCostStat = this.useCostStat == 'mdi-arrow-up' ? true : false;
},
setChartData(data) {
let xAxisData = [];
let seriesData = [];
let legendData = [];
let arrDarkColors = ['rgba(1, 174, 106, 0.7)', 'rgba(67, 133, 227, 0.7)'];
let arrLightColors = [
'rgba(207, 116, 229, 0.7)',
'rgba(106, 155, 244, 0.7)',
];
const arrColors = this.isDarkMode ? arrDarkColors : arrLightColors;
// chart x축 data
var qtyNumber, qtyStr;
for (var i = 0; i < 24; i++) {
qtyNumber = i.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
xAxisData.push(i + '시');
}
// chart_data 중 누적 사용량과 누적 금액 구분
for (var i = 0; i < data.length; i++) {
var tempObj = { data: [] };
tempObj['type'] = 'line';
tempObj['lineStyle'] = { width: 2 };
tempObj['smooth'] = true;
tempObj['showSymbol'] = false;
tempObj['color'] = arrColors[i];
if (data[i]['type'] == 'use') {
tempObj['name'] = '누적 사용량';
legendData.push('누적 사용량');
tempObj['areaStyle'] = {
opacity: 0.5,
color: arrColors[i],
};
tempObj['yAxisIndex'] = 0;
} else if (data[i]['type'] == 'cost') {
tempObj['name'] = '누적 금액';
legendData.push('누적 금액');
tempObj['yAxisIndex'] = 1;
} else if (data[i]['type'] == 'week') {
tempObj['name'] = '전주 평균 누적 사용량';
legendData.push('전주 평균 누적 사용량');
tempObj['yAxisIndex'] = 0;
}
// 0~23시 까지의 데이터 seriesData 넣기
for (var j = 0; j < 24; j++) {
qtyNumber = j.toString().padStart(2, '0');
qtyStr = 'qty' + qtyNumber;
if (data[i].hasOwnProperty(qtyStr)) {
// tempObj['data'].push(Utility.setFormatIntDecimal(parseFloat(data[i][qtyStr]), 2).replace(',',''));
tempObj['data'].push(parseFloat(data[i][qtyStr]));
} else {
tempObj['data'].push(0);
}
}
seriesData.push(tempObj);
}
const yAxisData = [
{
type: 'value',
name: this.unit,
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
{
type: 'value',
name: '원',
splitLine: {
show: false,
},
nameTextStyle: {
fontSize: 12,
fontWeight: 'bold',
},
axisLabel: {
color: '#767D83',
fontSize: 9,
formatter: '{value}',
},
},
];
var chartOption = {
series: seriesData,
grid: {
left: '1%',
right: '2%',
top: '20%',
bottom: '15%',
containLabel: true,
},
legend: {
data: legendData,
bottom: 'bottom',
icon: 'bar',
},
xAxis: {
type: 'category',
//boundaryGap: false,
splitLine: false,
data: xAxisData,
axisLabel: {
fontSize: 9,
},
},
// yAxis: [
// {
// type: 'value',
// name: this.unit,
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// },
// {
// type: 'value',
// name: '원',
// splitLine: {
// show: false
// },
// nameTextStyle: {
// fontSize: 12,
// fontWeight:'bold'
// },
// axisLabel:{
// color: "#767D83",
// fontSize: 9,
// formatter: '{value}'
// }
// }
// ],
tooltip: {
trigger: 'axis',
},
};
this.setWidgetChartOption({
prgmId: this.$route.query.prgmId,
widgetKey: 'enrgUseRsltWidget',
widgetData: 'enrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: chartOption,
});
this.setWidgetChartYaxisData({
prgmId: this.$route.query.prgmId,
widgetKey: 'enrgUseRsltWidget',
widgetData: 'enrgUseRsltWidgetData',
chartKey: 'enrgUsageChart',
value: yAxisData,
});
this.loadChart_01 = true;
},
async getChartData() {
this.loadChart_01 = false;
var root_info = null;
var res_useage = null;
var res_cost = null;
var facList = null;
var filtered_res = null;
var apiParameters = {
blocId: 'BL0001',
readObjId: this.energyCd,
locKind: '',
upEccId: '',
};
var sendParam_chart_data = {
blocId: 'BL0001',
eccId: [],
eccNm: [],
fromObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
lockKind: '',
readObjId: this.energyCd,
toObjDt: Utility.setFormatDate(new Date(), 'YYYYMMDD'),
upEccId: '',
};
var check_flag = true;
// 공정/설비 트리리스트 중 에너지원에 따른 최상위 정보 가져오기
try {
root_info = await this.postApiReturn({
apiKey: 'selectFtnPlcListTree',
resKey: 'ftnPlcTreeDatas',
sendParam: {
blocId: 'BL0001',
roiId: this.energyCd,
eqpmYn: 1,
// search:this.searchWord
},
});
filtered_res = root_info.filter(item => item.upEccId == 'ROOT');
apiParameters['locKind'] = filtered_res[0].locKind;
apiParameters['upEccId'] = filtered_res[0].eccId;
sendParam_chart_data['lockKind'] = filtered_res[0].locKind;
} catch (error) {
root_info = [];
filtered_res = [];
}
// 위의 정보로 해당 검침개소 정보 가져오기
try {
facList = await this.postApiReturn({
apiKey: 'selectEnergyUseReadDnPlc',
resKey: 'energyUseReadDnPlc',
sendParam: apiParameters,
});
for (var i in facList) {
sendParam_chart_data['eccId'].push(facList[i]['eccId']);
sendParam_chart_data['eccNm'].push(facList[i]['eccNm']);
}
// sendParam_chart_data['eccId'].push(facList[0]['eccId']);
// sendParam_chart_data['eccNm'].push(facList[0]['eccNm']);
sendParam_chart_data['upEccId'] = facList[0]['upEccId'];
} catch (error) {
check_flag = false;
}
// 위의 정보로 검침개소 시간별 사용량 가져오기
var final_chart_data = [];
if (check_flag) {
try {
res_useage = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM 안했을 경우 사용)
// var sum_data = {};
// for (var i in res_useage){
// res_useage[i]['type'] = 'use'
// for (var key in res_useage[i]){
// if(key.includes('qty')){
// if(sum_data[key] == undefined){
// sum_data[key] = res_useage[i][key]
// }else{
// sum_data[key] += res_useage[i][key]
// }
// }
// }
// // final_chart_data.push(res_useage[i])
// }
// final_chart_data.push({'type' : 'use', ...sum_data})
// root 하위 개소들의 사용량을 sum 함(쿼리에서 SUM을 했을 경우 사용)
res_useage[0]['type'] = 'use';
final_chart_data.push(res_useage[0]);
} catch (error) {
res_useage = [];
}
try {
res_cost = await this.postApiReturn({
apiKey: 'selectEnergyUseReadHourCostAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
res_cost[0]['type'] = 'cost';
final_chart_data.push(res_cost[0]);
} catch (error) {
res_cost = [];
}
} else {
res_useage = [];
res_cost = [];
}
// 전주 평균 누적 사용량
let res_week_read = [];
res_week_read = await this.postApiReturn({
apiKey: 'selectEnergyUseReadLastWeekAddup',
resKey: 'energyUseRead',
sendParam: sendParam_chart_data,
});
if (res_week_read.length != 0) {
res_week_read[0]['type'] = 'week';
final_chart_data.push(res_week_read[0]);
}
// char data 넣기
this.$nextTick(() => {
this.setChartData(final_chart_data);
});
},
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 enrgUseRsltWidgetData = {
isFind: false,
enrgUsageChart: 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;
}
.v-radio > label {
font-size: 0.8rem;
}
.v-list-item {
min-height: 30px;
line-height: 1;
}
.v-list-item__content > * {
line-height: 1;
}
.v-select__widget > .v-input__control > .v-input__slot {
min-width: 60%;
}
.wrapper {
padding: 5px 10px 0px 10px !important;
border-bottom: thin solid rgba(255, 255, 255, 0.12);
}
</style>