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