webapp: Introduce Modal component
Less duplicated code
This commit is contained in:
parent
5d63f64411
commit
6b31a4d470
52
webapp/src/components/Modal.vue
Normal file
52
webapp/src/components/Modal.vue
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<div class="modal" :id="modalId" tabindex="-1">
|
||||||
|
<div class="modal-dialog" :class="[small ? '' : 'modal-lg']">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">{{ title }}</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" :aria-label="getCloseText"
|
||||||
|
@click="close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="text-center" v-if="loading">
|
||||||
|
<div class="spinner-border" role="status">
|
||||||
|
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<slot v-else>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<slot name="footer">
|
||||||
|
</slot>
|
||||||
|
<button type="button" class="btn btn-secondary" @click="close" data-bs-dismiss="modal">{{
|
||||||
|
getCloseText }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
'modalId': { type: String, required: true },
|
||||||
|
'title': { type: String, required: true },
|
||||||
|
'closeText': { type: String, required: false, default: '' },
|
||||||
|
'small': Boolean,
|
||||||
|
'loading': Boolean,
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
getCloseText() {
|
||||||
|
return this.closeText == '' ? this.$t('base.Close') : this.closeText;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@ -29,7 +29,8 @@
|
|||||||
"Save": "Speichern",
|
"Save": "Speichern",
|
||||||
"Refreshing": "Aktualisieren",
|
"Refreshing": "Aktualisieren",
|
||||||
"Pull": "Zum Aktualisieren nach unten ziehen",
|
"Pull": "Zum Aktualisieren nach unten ziehen",
|
||||||
"Release": "Loslassen zum Aktualisieren"
|
"Release": "Loslassen zum Aktualisieren",
|
||||||
|
"Close": "Schließen"
|
||||||
},
|
},
|
||||||
"localeswitcher": {
|
"localeswitcher": {
|
||||||
"Dark": "Dunkel",
|
"Dark": "Dunkel",
|
||||||
@ -116,7 +117,6 @@
|
|||||||
"UnreadMessages": "Ungelesene Meldungen",
|
"UnreadMessages": "Ungelesene Meldungen",
|
||||||
"Loading": "@:base.Loading",
|
"Loading": "@:base.Loading",
|
||||||
"EventLog": "Ereignisanzeige",
|
"EventLog": "Ereignisanzeige",
|
||||||
"Close": "Schließen",
|
|
||||||
"InverterInfo": "Wechselrichter-Informationen",
|
"InverterInfo": "Wechselrichter-Informationen",
|
||||||
"LimitSettings": "Limit-Einstellungen",
|
"LimitSettings": "Limit-Einstellungen",
|
||||||
"LastLimitSetStatus": "Letzter Übertragungsstatus:",
|
"LastLimitSetStatus": "Letzter Übertragungsstatus:",
|
||||||
|
|||||||
@ -29,7 +29,8 @@
|
|||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"Refreshing": "Refreshing",
|
"Refreshing": "Refreshing",
|
||||||
"Pull": "Pull down to refresh",
|
"Pull": "Pull down to refresh",
|
||||||
"Release": "Release to refresh"
|
"Release": "Release to refresh",
|
||||||
|
"Close": "Close"
|
||||||
},
|
},
|
||||||
"localeswitcher": {
|
"localeswitcher": {
|
||||||
"Dark": "Dark",
|
"Dark": "Dark",
|
||||||
@ -116,7 +117,6 @@
|
|||||||
"UnreadMessages": "unread messages",
|
"UnreadMessages": "unread messages",
|
||||||
"Loading": "@:base.Loading",
|
"Loading": "@:base.Loading",
|
||||||
"EventLog": "Event Log",
|
"EventLog": "Event Log",
|
||||||
"Close": "Close",
|
|
||||||
"InverterInfo": "Inverter Info",
|
"InverterInfo": "Inverter Info",
|
||||||
"LimitSettings": "Limit Settings",
|
"LimitSettings": "Limit Settings",
|
||||||
"LastLimitSetStatus": "Last Limit Set Status:",
|
"LastLimitSetStatus": "Last Limit Set Status:",
|
||||||
|
|||||||
@ -29,7 +29,8 @@
|
|||||||
"Save": "Sauvegarder",
|
"Save": "Sauvegarder",
|
||||||
"Refreshing": "Refreshing",
|
"Refreshing": "Refreshing",
|
||||||
"Pull": "Pull down to refresh",
|
"Pull": "Pull down to refresh",
|
||||||
"Release": "Release to refresh"
|
"Release": "Release to refresh",
|
||||||
|
"Close": "Fermer"
|
||||||
},
|
},
|
||||||
"localeswitcher": {
|
"localeswitcher": {
|
||||||
"Dark": "Sombre",
|
"Dark": "Sombre",
|
||||||
@ -116,7 +117,6 @@
|
|||||||
"UnreadMessages": "messages non lus",
|
"UnreadMessages": "messages non lus",
|
||||||
"Loading": "@:base.Loading",
|
"Loading": "@:base.Loading",
|
||||||
"EventLog": "Journal des événements",
|
"EventLog": "Journal des événements",
|
||||||
"Close": "Fermer",
|
|
||||||
"InverterInfo": "Informations sur l'onduleur",
|
"InverterInfo": "Informations sur l'onduleur",
|
||||||
"LimitSettings": "Paramètres de la limite",
|
"LimitSettings": "Paramètres de la limite",
|
||||||
"LastLimitSetStatus": "Statut de la dernière limite fixée",
|
"LastLimitSetStatus": "Statut de la dernière limite fixée",
|
||||||
|
|||||||
@ -88,32 +88,21 @@
|
|||||||
</CardElement>
|
</CardElement>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|
||||||
<div class="modal" id="factoryReset" tabindex="-1">
|
<Modal modalId="factoryReset" small :title="$t('configadmin.FactoryReset')" :closeText="$t('configadmin.Cancel')">
|
||||||
<div class="modal-dialog">
|
{{ $t('configadmin.ResetMsg') }}
|
||||||
<div class="modal-content">
|
<template #footer>
|
||||||
<div class="modal-header">
|
<button type="button" class="btn btn-danger" @click="onFactoryResetPerform">
|
||||||
<h5 class="modal-title">{{ $t('configadmin.FactoryReset') }}</h5>
|
{{ $t('configadmin.ResetConfirm') }}
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
</button>
|
||||||
</div>
|
</template>
|
||||||
<div class="modal-body">
|
</Modal>
|
||||||
{{ $t('configadmin.ResetMsg') }}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" @click="onFactoryResetCancel"
|
|
||||||
data-bs-dismiss="modal">{{ $t('configadmin.Cancel') }}</button>
|
|
||||||
<button type="button" class="btn btn-danger" @click="onFactoryResetPerform">
|
|
||||||
{{ $t('configadmin.ResetConfirm') }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import BasePage from '@/components/BasePage.vue';
|
import BasePage from '@/components/BasePage.vue';
|
||||||
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
||||||
import CardElement from '@/components/CardElement.vue';
|
import CardElement from '@/components/CardElement.vue';
|
||||||
|
import Modal from '@/components/Modal.vue';
|
||||||
import type { ConfigFileList } from '@/types/Config';
|
import type { ConfigFileList } from '@/types/Config';
|
||||||
import { authHeader, handleResponse } from '@/utils/authentication';
|
import { authHeader, handleResponse } from '@/utils/authentication';
|
||||||
import * as bootstrap from 'bootstrap';
|
import * as bootstrap from 'bootstrap';
|
||||||
@ -129,6 +118,7 @@ export default defineComponent({
|
|||||||
BasePage,
|
BasePage,
|
||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
CardElement,
|
CardElement,
|
||||||
|
Modal,
|
||||||
BIconArrowLeft,
|
BIconArrowLeft,
|
||||||
BIconCheckCircle,
|
BIconCheckCircle,
|
||||||
BIconExclamationCircleFill,
|
BIconExclamationCircleFill,
|
||||||
|
|||||||
@ -124,229 +124,122 @@
|
|||||||
</div>
|
</div>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|
||||||
<div class="modal" id="eventView" tabindex="-1">
|
<Modal modalId="eventView" :title="$t('home.EventLog')" :loading="eventLogLoading">
|
||||||
<div class="modal-dialog modal-lg">
|
<EventLog :eventLogList="eventLogList" />
|
||||||
<div class="modal-content">
|
</Modal>
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{{ $t('home.EventLog') }}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="text-center" v-if="eventLogLoading">
|
|
||||||
<div class="spinner-border" role="status">
|
|
||||||
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<EventLog v-if="!eventLogLoading" :eventLogList="eventLogList" />
|
<Modal modalId="devInfoView" :title="$t('home.InverterInfo')" :loading="devInfoLoading">
|
||||||
</div>
|
<DevInfo :devInfoList="devInfoList" />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<Modal modalId="gridProfileView" :title="$t('home.GridProfile')" :loading="gridProfileLoading">
|
||||||
<button type="button" class="btn btn-secondary" @click="onHideEventlog"
|
<GridProfile :gridProfileList="gridProfileList" :gridProfileRawList="gridProfileRawList" />
|
||||||
data-bs-dismiss="modal">{{ $t('home.Close') }}</button>
|
</Modal>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<Modal modalId="limitSettingView" :title="$t('home.LimitSettings')" :loading="limitSettingLoading">
|
||||||
|
<BootstrapAlert v-model="showAlertLimit" :variant="alertTypeLimit">
|
||||||
|
{{ alertMessageLimit }}
|
||||||
|
</BootstrapAlert>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="inputCurrentLimit" class="col-sm-3 col-form-label">{{ $t('home.CurrentLimit') }}
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control" id="inputCurrentLimit" aria-describedby="currentLimitType"
|
||||||
|
v-model="currentLimitRelative" disabled />
|
||||||
|
<span class="input-group-text" id="currentLimitType">%</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal" id="devInfoView" tabindex="-1">
|
<div class="col-sm-4" v-if="currentLimitList.max_power > 0">
|
||||||
<div class="modal-dialog modal-lg">
|
<div class="input-group">
|
||||||
<div class="modal-content">
|
<input type="text" class="form-control" id="inputCurrentLimitAbsolute"
|
||||||
<div class="modal-header">
|
aria-describedby="currentLimitTypeAbsolute" v-model="currentLimitAbsolute" disabled />
|
||||||
<h5 class="modal-title">{{ $t('home.InverterInfo') }}</h5>
|
<span class="input-group-text" id="currentLimitTypeAbsolute">W</span>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="text-center" v-if="devInfoLoading">
|
|
||||||
<div class="spinner-border" role="status">
|
|
||||||
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DevInfo v-if="!devInfoLoading" :devInfoList="devInfoList" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" @click="onHideDevInfo"
|
|
||||||
data-bs-dismiss="modal">{{ $t('home.Close') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal" id="gridProfileView" tabindex="-1">
|
<div class="row mb-3 align-items-center">
|
||||||
<div class="modal-dialog modal-lg">
|
<label for="inputLastLimitSet" class="col-sm-3 col-form-label">
|
||||||
<div class="modal-content">
|
{{ $t('home.LastLimitSetStatus') }}
|
||||||
<div class="modal-header">
|
</label>
|
||||||
<h5 class="modal-title">{{ $t('home.GridProfile') }}</h5>
|
<div class="col-sm-9">
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
<span class="badge" :class="{
|
||||||
</div>
|
'text-bg-danger': currentLimitList.limit_set_status == 'Failure',
|
||||||
<div class="modal-body">
|
'text-bg-warning': currentLimitList.limit_set_status == 'Pending',
|
||||||
<div class="text-center" v-if="gridProfileLoading">
|
'text-bg-success': currentLimitList.limit_set_status == 'Ok',
|
||||||
<div class="spinner-border" role="status">
|
'text-bg-secondary': currentLimitList.limit_set_status == 'Unknown',
|
||||||
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
}">
|
||||||
</div>
|
{{ $t('home.' + currentLimitList.limit_set_status) }}
|
||||||
</div>
|
</span>
|
||||||
|
|
||||||
<GridProfile v-if="!gridProfileLoading" :gridProfileList="gridProfileList" :gridProfileRawList="gridProfileRawList" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" @click="onHideGridProfile"
|
|
||||||
data-bs-dismiss="modal">{{ $t('home.Close') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal" id="limitSettingView" ref="limitSettingView" tabindex="-1">
|
<div class="row mb-3">
|
||||||
<div class="modal-dialog modal-lg">
|
<label for="inputTargetLimit" class="col-sm-3 col-form-label">{{ $t('home.SetLimit')
|
||||||
<div class="modal-content">
|
}}</label>
|
||||||
<form @submit="onSubmitLimit">
|
<div class="col-sm-9">
|
||||||
<div class="modal-header">
|
<div class="input-group">
|
||||||
<h5 class="modal-title">{{ $t('home.LimitSettings') }}</h5>
|
<input type="number" name="inputTargetLimit" class="form-control" id="inputTargetLimit"
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
:min="targetLimitMin" :max="targetLimitMax" v-model="targetLimitList.limit_value">
|
||||||
</div>
|
<button class="btn btn-primary dropdown-toggle" type="button" data-bs-toggle="dropdown"
|
||||||
<div class="modal-body">
|
aria-expanded="false">{{ targetLimitTypeText
|
||||||
|
}}</button>
|
||||||
<BootstrapAlert v-model="showAlertLimit" :variant="alertTypeLimit">
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
{{ alertMessageLimit }}
|
<li><a class="dropdown-item" @click="onSelectType(1)" href="#">{{
|
||||||
</BootstrapAlert>
|
$t('home.Relative') }}</a></li>
|
||||||
<div class="text-center" v-if="limitSettingLoading">
|
<li><a class="dropdown-item" @click="onSelectType(0)" href="#">{{
|
||||||
<div class="spinner-border" role="status">
|
$t('home.Absolute') }}</a></li>
|
||||||
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div v-if="targetLimitType == 0" class="alert alert-secondary mt-3" role="alert"
|
||||||
|
v-html="$t('home.LimitHint')"></div>
|
||||||
<template v-if="!limitSettingLoading">
|
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<label for="inputCurrentLimit" class="col-sm-3 col-form-label">{{ $t('home.CurrentLimit') }} </label>
|
|
||||||
<div class="col-sm-4">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" id="inputCurrentLimit"
|
|
||||||
aria-describedby="currentLimitType" v-model="currentLimitRelative"
|
|
||||||
disabled />
|
|
||||||
<span class="input-group-text" id="currentLimitType">%</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-sm-4" v-if="currentLimitList.max_power > 0">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" id="inputCurrentLimitAbsolute"
|
|
||||||
aria-describedby="currentLimitTypeAbsolute" v-model="currentLimitAbsolute"
|
|
||||||
disabled />
|
|
||||||
<span class="input-group-text" id="currentLimitTypeAbsolute">W</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mb-3 align-items-center">
|
|
||||||
<label for="inputLastLimitSet" class="col-sm-3 col-form-label">
|
|
||||||
{{ $t('home.LastLimitSetStatus') }}
|
|
||||||
</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<span class="badge" :class="{
|
|
||||||
'text-bg-danger': currentLimitList.limit_set_status == 'Failure',
|
|
||||||
'text-bg-warning': currentLimitList.limit_set_status == 'Pending',
|
|
||||||
'text-bg-success': currentLimitList.limit_set_status == 'Ok',
|
|
||||||
'text-bg-secondary': currentLimitList.limit_set_status == 'Unknown',
|
|
||||||
}">
|
|
||||||
{{ $t('home.' + currentLimitList.limit_set_status) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mb-3">
|
|
||||||
<label for="inputTargetLimit" class="col-sm-3 col-form-label">{{ $t('home.SetLimit') }}</label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" name="inputTargetLimit" class="form-control"
|
|
||||||
id="inputTargetLimit" :min="targetLimitMin" :max="targetLimitMax"
|
|
||||||
v-model="targetLimitList.limit_value">
|
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button"
|
|
||||||
data-bs-toggle="dropdown" aria-expanded="false">{{ targetLimitTypeText
|
|
||||||
}}</button>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
|
||||||
<li><a class="dropdown-item" @click="onSelectType(1)" href="#">{{ $t('home.Relative') }}</a></li>
|
|
||||||
<li><a class="dropdown-item" @click="onSelectType(0)" href="#">{{ $t('home.Absolute') }}</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div v-if="targetLimitType == 0" class="alert alert-secondary mt-3" role="alert" v-html="$t('home.LimitHint')"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-danger" @click="onSetLimitSettings(true)">{{ $t('home.SetPersistent') }}</button>
|
|
||||||
|
|
||||||
<button type="submit" class="btn btn-danger" @click="onSetLimitSettings(false)">{{ $t('home.SetNonPersistent') }}</button>
|
|
||||||
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ $t('home.Close') }}</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal" id="powerSettingView" ref="powerSettingView" tabindex="-1">
|
<template #footer>
|
||||||
<div class="modal-dialog modal-lg">
|
<button type="button" class="btn btn-danger" @click="onSetLimitSettings(true)">{{
|
||||||
<div class="modal-content">
|
$t('home.SetPersistent') }}</button>
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{{ $t('home.PowerSettings') }}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<BootstrapAlert v-model="showAlertPower" :variant="alertTypePower">
|
<button type="button" class="btn btn-danger" @click="onSetLimitSettings(false)">{{
|
||||||
{{ alertMessagePower }}
|
$t('home.SetNonPersistent') }}</button>
|
||||||
</BootstrapAlert>
|
</template>
|
||||||
<div class="text-center" v-if="powerSettingLoading">
|
</Modal>
|
||||||
<div class="spinner-border" role="status">
|
|
||||||
<span class="visually-hidden">{{ $t('home.Loading') }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template v-if="!powerSettingLoading">
|
<Modal modalId="powerSettingView" :title="$t('home.PowerSettings')" :loading="powerSettingLoading">
|
||||||
<div class="row mb-3 align-items-center">
|
<BootstrapAlert v-model="showAlertPower" :variant="alertTypePower">
|
||||||
<label for="inputLastPowerSet" class="col col-form-label">{{ $t('home.LastPowerSetStatus') }}</label>
|
{{ alertMessagePower }}
|
||||||
<div class="col">
|
</BootstrapAlert>
|
||||||
<span class="badge" :class="{
|
|
||||||
'text-bg-danger': successCommandPower == 'Failure',
|
|
||||||
'text-bg-warning': successCommandPower == 'Pending',
|
|
||||||
'text-bg-success': successCommandPower == 'Ok',
|
|
||||||
'text-bg-secondary': successCommandPower == 'Unknown',
|
|
||||||
}">
|
|
||||||
{{ $t('home.' + successCommandPower) }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-grid gap-2 col-6 mx-auto">
|
<div class="row mb-3 align-items-center">
|
||||||
<button type="button" class="btn btn-success" @click="onSetPowerSettings(true)">
|
<label for="inputLastPowerSet" class="col col-form-label">{{ $t('home.LastPowerSetStatus')
|
||||||
<BIconToggleOn class="fs-4" /> {{ $t('home.TurnOn') }}
|
}}</label>
|
||||||
</button>
|
<div class="col">
|
||||||
<button type="button" class="btn btn-danger" @click="onSetPowerSettings(false)">
|
<span class="badge" :class="{
|
||||||
<BIconToggleOff class="fs-4" /> {{ $t('home.TurnOff') }}
|
'text-bg-danger': successCommandPower == 'Failure',
|
||||||
</button>
|
'text-bg-warning': successCommandPower == 'Pending',
|
||||||
<button type="button" class="btn btn-warning" @click="onSetPowerSettings(true, true)">
|
'text-bg-success': successCommandPower == 'Ok',
|
||||||
<BIconArrowCounterclockwise class="fs-4" /> {{ $t('home.Restart') }}
|
'text-bg-secondary': successCommandPower == 'Unknown',
|
||||||
</button>
|
}">
|
||||||
</div>
|
{{ $t('home.' + successCommandPower) }}
|
||||||
</template>
|
</span>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{ $t('home.Close') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="d-grid gap-2 col-6 mx-auto">
|
||||||
|
<button type="button" class="btn btn-success" @click="onSetPowerSettings(true)">
|
||||||
|
<BIconToggleOn class="fs-4" /> {{ $t('home.TurnOn') }}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-danger" @click="onSetPowerSettings(false)">
|
||||||
|
<BIconToggleOff class="fs-4" /> {{ $t('home.TurnOff') }}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-warning" @click="onSetPowerSettings(true, true)">
|
||||||
|
<BIconArrowCounterclockwise class="fs-4" /> {{ $t('home.Restart') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -358,6 +251,7 @@ import GridProfile from '@/components/GridProfile.vue';
|
|||||||
import HintView from '@/components/HintView.vue';
|
import HintView from '@/components/HintView.vue';
|
||||||
import InverterChannelInfo from "@/components/InverterChannelInfo.vue";
|
import InverterChannelInfo from "@/components/InverterChannelInfo.vue";
|
||||||
import InverterTotalInfo from '@/components/InverterTotalInfo.vue';
|
import InverterTotalInfo from '@/components/InverterTotalInfo.vue';
|
||||||
|
import Modal from '@/components/Modal.vue';
|
||||||
import type { DevInfoStatus } from '@/types/DevInfoStatus';
|
import type { DevInfoStatus } from '@/types/DevInfoStatus';
|
||||||
import type { EventlogItems } from '@/types/EventlogStatus';
|
import type { EventlogItems } from '@/types/EventlogStatus';
|
||||||
import type { GridProfileStatus } from '@/types/GridProfileStatus';
|
import type { GridProfileStatus } from '@/types/GridProfileStatus';
|
||||||
@ -392,6 +286,7 @@ export default defineComponent({
|
|||||||
HintView,
|
HintView,
|
||||||
InverterChannelInfo,
|
InverterChannelInfo,
|
||||||
InverterTotalInfo,
|
InverterTotalInfo,
|
||||||
|
Modal,
|
||||||
BIconArrowCounterclockwise,
|
BIconArrowCounterclockwise,
|
||||||
BIconCheckCircleFill,
|
BIconCheckCircleFill,
|
||||||
BIconCpu,
|
BIconCpu,
|
||||||
@ -435,7 +330,6 @@ export default defineComponent({
|
|||||||
targetLimitMax: 100,
|
targetLimitMax: 100,
|
||||||
targetLimitTypeText: this.$t('home.Relative'),
|
targetLimitTypeText: this.$t('home.Relative'),
|
||||||
targetLimitType: 1,
|
targetLimitType: 1,
|
||||||
targetLimitPersistent: false,
|
|
||||||
|
|
||||||
alertMessageLimit: "",
|
alertMessageLimit: "",
|
||||||
alertTypeLimit: "info",
|
alertTypeLimit: "info",
|
||||||
@ -469,9 +363,6 @@ export default defineComponent({
|
|||||||
this.gridProfileView = new bootstrap.Modal('#gridProfileView');
|
this.gridProfileView = new bootstrap.Modal('#gridProfileView');
|
||||||
this.limitSettingView = new bootstrap.Modal('#limitSettingView');
|
this.limitSettingView = new bootstrap.Modal('#limitSettingView');
|
||||||
this.powerSettingView = new bootstrap.Modal('#powerSettingView');
|
this.powerSettingView = new bootstrap.Modal('#powerSettingView');
|
||||||
|
|
||||||
(this.$refs.limitSettingView as HTMLElement).addEventListener("hide.bs.modal", this.onHideLimitSettings);
|
|
||||||
(this.$refs.powerSettingView as HTMLElement).addEventListener("hide.bs.modal", this.onHidePowerSettings);
|
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.closeSocket();
|
this.closeSocket();
|
||||||
@ -509,14 +400,14 @@ export default defineComponent({
|
|||||||
'decimalTwoDigits');
|
'decimalTwoDigits');
|
||||||
},
|
},
|
||||||
inverterData(): Inverter[] {
|
inverterData(): Inverter[] {
|
||||||
return this.liveData.inverters.slice().sort((a : Inverter, b: Inverter) => {
|
return this.liveData.inverters.slice().sort((a: Inverter, b: Inverter) => {
|
||||||
return a.order - b.order;
|
return a.order - b.order;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
getInitialData(triggerLoading : boolean = true) {
|
getInitialData(triggerLoading: boolean = true) {
|
||||||
if (triggerLoading) {
|
if (triggerLoading) {
|
||||||
this.dataLoading = true;
|
this.dataLoading = true;
|
||||||
}
|
}
|
||||||
@ -568,7 +459,7 @@ export default defineComponent({
|
|||||||
self.isWebsocketConnected = true;
|
self.isWebsocketConnected = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.socket.onclose = function() {
|
this.socket.onclose = function () {
|
||||||
console.log("Connection to websocket closed...")
|
console.log("Connection to websocket closed...")
|
||||||
self.isWebsocketConnected = false;
|
self.isWebsocketConnected = false;
|
||||||
}
|
}
|
||||||
@ -605,9 +496,6 @@ export default defineComponent({
|
|||||||
this.heartInterval && clearTimeout(this.heartInterval);
|
this.heartInterval && clearTimeout(this.heartInterval);
|
||||||
this.isFirstFetchAfterConnect = true;
|
this.isFirstFetchAfterConnect = true;
|
||||||
},
|
},
|
||||||
onHideEventlog() {
|
|
||||||
this.eventLogView.hide();
|
|
||||||
},
|
|
||||||
onShowEventlog(serial: number) {
|
onShowEventlog(serial: number) {
|
||||||
this.eventLogLoading = true;
|
this.eventLogLoading = true;
|
||||||
fetch("/api/eventlog/status?inv=" + serial + "&locale=" + this.$i18n.locale, { headers: authHeader() })
|
fetch("/api/eventlog/status?inv=" + serial + "&locale=" + this.$i18n.locale, { headers: authHeader() })
|
||||||
@ -619,9 +507,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.eventLogView.show();
|
this.eventLogView.show();
|
||||||
},
|
},
|
||||||
onHideDevInfo() {
|
|
||||||
this.devInfoView.hide();
|
|
||||||
},
|
|
||||||
onShowDevInfo(serial: number) {
|
onShowDevInfo(serial: number) {
|
||||||
this.devInfoLoading = true;
|
this.devInfoLoading = true;
|
||||||
fetch("/api/devinfo/status?inv=" + serial, { headers: authHeader() })
|
fetch("/api/devinfo/status?inv=" + serial, { headers: authHeader() })
|
||||||
@ -634,9 +519,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.devInfoView.show();
|
this.devInfoView.show();
|
||||||
},
|
},
|
||||||
onHideGridProfile() {
|
|
||||||
this.devInfoView.hide();
|
|
||||||
},
|
|
||||||
onShowGridProfile(serial: number) {
|
onShowGridProfile(serial: number) {
|
||||||
this.gridProfileLoading = true;
|
this.gridProfileLoading = true;
|
||||||
fetch("/api/gridprofile/status?inv=" + serial, { headers: authHeader() })
|
fetch("/api/gridprofile/status?inv=" + serial, { headers: authHeader() })
|
||||||
@ -645,19 +527,17 @@ export default defineComponent({
|
|||||||
this.gridProfileList = data;
|
this.gridProfileList = data;
|
||||||
|
|
||||||
fetch("/api/gridprofile/rawdata?inv=" + serial, { headers: authHeader() })
|
fetch("/api/gridprofile/rawdata?inv=" + serial, { headers: authHeader() })
|
||||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.gridProfileRawList = data;
|
this.gridProfileRawList = data;
|
||||||
this.gridProfileLoading = false;
|
this.gridProfileLoading = false;
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gridProfileView.show();
|
this.gridProfileView.show();
|
||||||
},
|
},
|
||||||
onHideLimitSettings() {
|
|
||||||
this.showAlertLimit = false;
|
|
||||||
},
|
|
||||||
onShowLimitSettings(serial: number) {
|
onShowLimitSettings(serial: number) {
|
||||||
|
this.showAlertLimit = false;
|
||||||
this.targetLimitList.serial = 0;
|
this.targetLimitList.serial = 0;
|
||||||
this.targetLimitList.limit_value = 0;
|
this.targetLimitList.limit_value = 0;
|
||||||
this.targetLimitType = 1;
|
this.targetLimitType = 1;
|
||||||
@ -674,10 +554,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
this.limitSettingView.show();
|
this.limitSettingView.show();
|
||||||
},
|
},
|
||||||
onSubmitLimit(e: Event) {
|
onSetLimitSettings(setPersistent: boolean) {
|
||||||
e.preventDefault();
|
this.targetLimitList.limit_type = (setPersistent ? 256 : 0) + this.targetLimitType
|
||||||
|
|
||||||
this.targetLimitList.limit_type = (this.targetLimitPersistent ? 256 : 0) + this.targetLimitType
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("data", JSON.stringify(this.targetLimitList));
|
formData.append("data", JSON.stringify(this.targetLimitList));
|
||||||
|
|
||||||
@ -701,9 +579,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
onSetLimitSettings(setPersistent: boolean) {
|
|
||||||
this.targetLimitPersistent = setPersistent;
|
|
||||||
},
|
|
||||||
onSelectType(type: number) {
|
onSelectType(type: number) {
|
||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
this.targetLimitTypeText = this.$t('home.Relative');
|
this.targetLimitTypeText = this.$t('home.Relative');
|
||||||
@ -718,6 +593,8 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
onShowPowerSettings(serial: number) {
|
onShowPowerSettings(serial: number) {
|
||||||
|
this.showAlertPower = false;
|
||||||
|
this.powerSettingSerial = 0;
|
||||||
this.powerSettingLoading = true;
|
this.powerSettingLoading = true;
|
||||||
fetch("/api/power/status", { headers: authHeader() })
|
fetch("/api/power/status", { headers: authHeader() })
|
||||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||||
@ -729,11 +606,6 @@ export default defineComponent({
|
|||||||
this.powerSettingView.show();
|
this.powerSettingView.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
onHidePowerSettings() {
|
|
||||||
this.powerSettingSerial = 0;
|
|
||||||
this.showAlertPower = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
onSetPowerSettings(turnOn: boolean, restart = false) {
|
onSetPowerSettings(turnOn: boolean, restart = false) {
|
||||||
let data = {};
|
let data = {};
|
||||||
if (restart) {
|
if (restart) {
|
||||||
|
|||||||
@ -71,170 +71,135 @@
|
|||||||
</CardElement>
|
</CardElement>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|
||||||
<div class="modal" id="inverterEdit" tabindex="-1">
|
<Modal modalId="inverterEdit" :title="$t('inverteradmin.EditInverter')" :closeText="$t('inverteradmin.Cancel')">
|
||||||
<div class="modal-dialog modal-lg">
|
<nav>
|
||||||
<div class="modal-content">
|
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||||
<div class="modal-header">
|
<button class="nav-link active" id="nav-general-tab" data-bs-toggle="tab" data-bs-target="#nav-general"
|
||||||
<h5 class="modal-title">{{ $t('inverteradmin.EditInverter') }}</h5>
|
type="button" role="tab" aria-controls="nav-general" aria-selected="true">{{
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
$t('inverteradmin.General')
|
||||||
|
}}</button>
|
||||||
|
<button class="nav-link" id="nav-string-tab" data-bs-toggle="tab" data-bs-target="#nav-string" type="button"
|
||||||
|
role="tab" aria-controls="nav-string">{{ $t('inverteradmin.String') }}</button>
|
||||||
|
<button class="nav-link" id="nav-advanced-tab" data-bs-toggle="tab" data-bs-target="#nav-advanced"
|
||||||
|
type="button" role="tab" aria-controls="nav-advanced">{{ $t('inverteradmin.Advanced') }}</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<div class="tab-content" id="nav-tabContent">
|
||||||
|
<div class="tab-pane fade show active" id="nav-general" role="tabpanel" aria-labelledby="nav-general-tab"
|
||||||
|
tabindex="0">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="inverter-serial" class="col-form-label">
|
||||||
|
{{ $t('inverteradmin.InverterSerial') }}
|
||||||
|
</label>
|
||||||
|
<input v-model="selectedInverterData.serial" type="number" id="inverter-serial" class="form-control" />
|
||||||
|
<label for="inverter-name" class="col-form-label">{{ $t('inverteradmin.InverterName') }}
|
||||||
|
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.InverterNameHint')" />
|
||||||
|
</label>
|
||||||
|
<input v-model="selectedInverterData.name" type="text" id="inverter-name" class="form-control"
|
||||||
|
maxlength="31" />
|
||||||
|
|
||||||
|
<CardElement :text="$t('inverteradmin.InverterStatus')" addSpace>
|
||||||
|
<InputElement :label="$t('inverteradmin.PollEnable')" v-model="selectedInverterData.poll_enable"
|
||||||
|
type="checkbox" wide />
|
||||||
|
<InputElement :label="$t('inverteradmin.PollEnableNight')"
|
||||||
|
v-model="selectedInverterData.poll_enable_night" type="checkbox" wide />
|
||||||
|
<InputElement :label="$t('inverteradmin.CommandEnable')"
|
||||||
|
v-model="selectedInverterData.command_enable" type="checkbox" wide />
|
||||||
|
<InputElement :label="$t('inverteradmin.CommandEnableNight')"
|
||||||
|
v-model="selectedInverterData.command_enable_night" type="checkbox" wide />
|
||||||
|
<div class="alert alert-secondary mt-3" role="alert" v-html="$t('inverteradmin.StatusHint')">
|
||||||
|
</div>
|
||||||
|
</CardElement>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
</div>
|
||||||
<form>
|
|
||||||
<nav>
|
|
||||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
|
||||||
<button class="nav-link active" id="nav-general-tab" data-bs-toggle="tab" data-bs-target="#nav-general"
|
|
||||||
type="button" role="tab" aria-controls="nav-general" aria-selected="true">{{
|
|
||||||
$t('inverteradmin.General')
|
|
||||||
}}</button>
|
|
||||||
<button class="nav-link" id="nav-string-tab" data-bs-toggle="tab" data-bs-target="#nav-string"
|
|
||||||
type="button" role="tab" aria-controls="nav-string">{{ $t('inverteradmin.String') }}</button>
|
|
||||||
<button class="nav-link" id="nav-advanced-tab" data-bs-toggle="tab" data-bs-target="#nav-advanced"
|
|
||||||
type="button" role="tab" aria-controls="nav-advanced">{{ $t('inverteradmin.Advanced') }}</button>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="tab-content" id="nav-tabContent">
|
|
||||||
<div class="tab-pane fade show active" id="nav-general" role="tabpanel" aria-labelledby="nav-general-tab" tabindex="0">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="inverter-serial" class="col-form-label">
|
|
||||||
{{ $t('inverteradmin.InverterSerial') }}
|
|
||||||
</label>
|
|
||||||
<input v-model="selectedInverterData.serial" type="number" id="inverter-serial"
|
|
||||||
class="form-control" />
|
|
||||||
<label for="inverter-name" class="col-form-label">{{ $t('inverteradmin.InverterName') }}
|
|
||||||
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.InverterNameHint')" />
|
|
||||||
</label>
|
|
||||||
<input v-model="selectedInverterData.name" type="text" id="inverter-name"
|
|
||||||
class="form-control" maxlength="31" />
|
|
||||||
|
|
||||||
<CardElement :text="$t('inverteradmin.InverterStatus')" addSpace>
|
<div class="tab-pane fade show" id="nav-string" role="tabpanel" aria-labelledby="nav-string-tab" tabindex="0">
|
||||||
<InputElement :label="$t('inverteradmin.PollEnable')"
|
<div v-for="(ch, index) in selectedInverterData.channel" :key="`${index}`">
|
||||||
v-model="selectedInverterData.poll_enable"
|
<div class="row g-2">
|
||||||
type="checkbox" wide />
|
<div class="col-md">
|
||||||
<InputElement :label="$t('inverteradmin.PollEnableNight')"
|
<label :for="`inverter-name_${index}`" class="col-form-label">
|
||||||
v-model="selectedInverterData.poll_enable_night"
|
{{ $t('inverteradmin.StringName', { num: index + 1 }) }}
|
||||||
type="checkbox" wide/>
|
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.StringNameHint')" />
|
||||||
<InputElement :label="$t('inverteradmin.CommandEnable')"
|
</label>
|
||||||
v-model="selectedInverterData.command_enable"
|
<div class="d-flex mb-2">
|
||||||
type="checkbox" wide/>
|
<div class="input-group">
|
||||||
<InputElement :label="$t('inverteradmin.CommandEnableNight')"
|
<input type="text" class="form-control" :id="`inverter-name_${index}`" maxlength="31"
|
||||||
v-model="selectedInverterData.command_enable_night"
|
v-model="ch.name" />
|
||||||
type="checkbox" wide/>
|
|
||||||
<div class="alert alert-secondary mt-3" role="alert" v-html="$t('inverteradmin.StatusHint')"></div>
|
|
||||||
</CardElement>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-pane fade show" id="nav-string" role="tabpanel" aria-labelledby="nav-string-tab" tabindex="0">
|
|
||||||
<div v-for="(ch, index) in selectedInverterData.channel" :key="`${index}`">
|
|
||||||
<div class="row g-2">
|
|
||||||
<div class="col-md">
|
|
||||||
<label :for="`inverter-name_${index}`" class="col-form-label">
|
|
||||||
{{ $t('inverteradmin.StringName', { num: index + 1 }) }}
|
|
||||||
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.StringNameHint')" />
|
|
||||||
</label>
|
|
||||||
<div class="d-flex mb-2">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" :id="`inverter-name_${index}`"
|
|
||||||
maxlength="31" v-model="ch.name" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row g-2">
|
|
||||||
<div class="col">
|
|
||||||
<label :for="`inverter-max_${index}`" class="col-form-label">
|
|
||||||
{{ $t('inverteradmin.StringMaxPower', { num: index + 1 }) }}
|
|
||||||
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.StringMaxPowerHint')" />
|
|
||||||
</label>
|
|
||||||
<div class="d-flex mb-2">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" class="form-control" :id="`inverter-max_${index}`"
|
|
||||||
min="0" v-model="ch.max_power"
|
|
||||||
:aria-describedby="`inverter-maxDescription_${index} inverter-customizer`" />
|
|
||||||
<span class="input-group-text"
|
|
||||||
:id="`inverter-maxDescription_${index}`">W<sub>p</sub><sup>*</sup></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<label :for="`inverter-ytoffset_${index}`" class="col-form-label">
|
|
||||||
{{ $t('inverteradmin.StringYtOffset', { num: index + 1 }) }}
|
|
||||||
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.StringYtOffsetHint')" />
|
|
||||||
</label>
|
|
||||||
<div class="d-flex mb-2">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="number" class="form-control" :id="`inverter-ytoffset_${index}`"
|
|
||||||
min="0" v-model="ch.yield_total_offset"
|
|
||||||
:aria-describedby="`inverter-ytoffsetDescription_${index} inverter-customizer`" />
|
|
||||||
<span class="input-group-text"
|
|
||||||
:id="`inverter-ytoffsetDescription_${index}`">kWh</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div :id="`inverter-customizer`" class="form-text" v-html="$t('inverteradmin.InverterHint')">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tab-pane fade show" id="nav-advanced" role="tabpanel" aria-labelledby="nav-advanced-tab" tabindex="0">
|
|
||||||
<InputElement :label="$t('inverteradmin.ReachableThreshold')"
|
|
||||||
v-model="selectedInverterData.reachable_threshold"
|
|
||||||
type="number" min="1" max="100"
|
|
||||||
:tooltip="$t('inverteradmin.ReachableThresholdHint')" wide />
|
|
||||||
|
|
||||||
<InputElement :label="$t('inverteradmin.ZeroRuntime')"
|
|
||||||
v-model="selectedInverterData.zero_runtime"
|
|
||||||
type="checkbox"
|
|
||||||
:tooltip="$t('inverteradmin.ZeroRuntimeHint')" wide/>
|
|
||||||
|
|
||||||
<InputElement :label="$t('inverteradmin.ZeroDay')"
|
|
||||||
v-model="selectedInverterData.zero_day"
|
|
||||||
type="checkbox"
|
|
||||||
:tooltip="$t('inverteradmin.ZeroDayHint')" wide/>
|
|
||||||
|
|
||||||
<InputElement :label="$t('inverteradmin.YieldDayCorrection')"
|
|
||||||
v-model="selectedInverterData.yieldday_correction"
|
|
||||||
type="checkbox"
|
|
||||||
:tooltip="$t('inverteradmin.YieldDayCorrectionHint')" wide/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
<div class="row g-2">
|
||||||
|
<div class="col">
|
||||||
|
<label :for="`inverter-max_${index}`" class="col-form-label">
|
||||||
|
{{ $t('inverteradmin.StringMaxPower', { num: index + 1 }) }}
|
||||||
|
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.StringMaxPowerHint')" />
|
||||||
|
</label>
|
||||||
|
<div class="d-flex mb-2">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control" :id="`inverter-max_${index}`" min="0"
|
||||||
|
v-model="ch.max_power"
|
||||||
|
:aria-describedby="`inverter-maxDescription_${index} inverter-customizer`" />
|
||||||
|
<span class="input-group-text"
|
||||||
|
:id="`inverter-maxDescription_${index}`">W<sub>p</sub><sup>*</sup></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col">
|
||||||
|
<label :for="`inverter-ytoffset_${index}`" class="col-form-label">
|
||||||
|
{{ $t('inverteradmin.StringYtOffset', { num: index + 1 }) }}
|
||||||
|
<BIconInfoCircle v-tooltip :title="$t('inverteradmin.StringYtOffsetHint')" />
|
||||||
|
</label>
|
||||||
|
<div class="d-flex mb-2">
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control" :id="`inverter-ytoffset_${index}`" min="0"
|
||||||
|
v-model="ch.yield_total_offset"
|
||||||
|
:aria-describedby="`inverter-ytoffsetDescription_${index} inverter-customizer`" />
|
||||||
|
<span class="input-group-text" :id="`inverter-ytoffsetDescription_${index}`">kWh</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div :id="`inverter-customizer`" class="form-text" v-html="$t('inverteradmin.InverterHint')">
|
||||||
<button type="button" class="btn btn-secondary" @click="onCloseModal(modal)"
|
|
||||||
data-bs-dismiss="modal">{{ $t('inverteradmin.Cancel') }}</button>
|
|
||||||
<button type="button" class="btn btn-primary" @click="onEditSubmit">
|
|
||||||
{{ $t('inverteradmin.Save') }}</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal" id="inverterDelete" tabindex="-1">
|
<div class="tab-pane fade show" id="nav-advanced" role="tabpanel" aria-labelledby="nav-advanced-tab"
|
||||||
<div class="modal-dialog">
|
tabindex="0">
|
||||||
<div class="modal-content">
|
<InputElement :label="$t('inverteradmin.ReachableThreshold')"
|
||||||
<div class="modal-header">
|
v-model="selectedInverterData.reachable_threshold" type="number" min="1" max="100"
|
||||||
<h5 class="modal-title">{{ $t('inverteradmin.DeleteInverter') }}</h5>
|
:tooltip="$t('inverteradmin.ReachableThresholdHint')" wide />
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
<InputElement :label="$t('inverteradmin.ZeroRuntime')" v-model="selectedInverterData.zero_runtime"
|
||||||
<div class="modal-body">
|
type="checkbox" :tooltip="$t('inverteradmin.ZeroRuntimeHint')" wide />
|
||||||
{{ $t('inverteradmin.DeleteMsg', {
|
|
||||||
name: selectedInverterData.name,
|
<InputElement :label="$t('inverteradmin.ZeroDay')" v-model="selectedInverterData.zero_day" type="checkbox"
|
||||||
serial: selectedInverterData.serial
|
:tooltip="$t('inverteradmin.ZeroDayHint')" wide />
|
||||||
})
|
|
||||||
}}
|
<InputElement :label="$t('inverteradmin.YieldDayCorrection')"
|
||||||
</div>
|
v-model="selectedInverterData.yieldday_correction" type="checkbox"
|
||||||
<div class="modal-footer">
|
:tooltip="$t('inverteradmin.YieldDayCorrectionHint')" wide />
|
||||||
<button type="button" class="btn btn-secondary" @click="onCloseModal(modalDelete)"
|
|
||||||
data-bs-dismiss="modal">{{ $t('inverteradmin.Cancel') }}</button>
|
|
||||||
<button type="button" class="btn btn-danger" @click="onDelete">
|
|
||||||
{{ $t('inverteradmin.Delete') }}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<template #footer>
|
||||||
|
<button type="button" class="btn btn-primary" @click="onEditSubmit">
|
||||||
|
{{ $t('inverteradmin.Save') }}</button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal modalId="inverterDelete" small :title="$t('inverteradmin.DeleteInverter')"
|
||||||
|
:closeText="$t('inverteradmin.Cancel')">
|
||||||
|
{{ $t('inverteradmin.DeleteMsg', {
|
||||||
|
name: selectedInverterData.name,
|
||||||
|
serial: selectedInverterData.serial
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
<template #footer>
|
||||||
|
<button type="button" class="btn btn-danger" @click="onDelete">
|
||||||
|
{{ $t('inverteradmin.Delete') }}</button>
|
||||||
|
</template>
|
||||||
|
</Modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -242,6 +207,7 @@ import BasePage from '@/components/BasePage.vue';
|
|||||||
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
||||||
import CardElement from '@/components/CardElement.vue';
|
import CardElement from '@/components/CardElement.vue';
|
||||||
import InputElement from '@/components/InputElement.vue';
|
import InputElement from '@/components/InputElement.vue';
|
||||||
|
import Modal from '@/components/Modal.vue';
|
||||||
import Sortable from 'sortablejs';
|
import Sortable from 'sortablejs';
|
||||||
import { authHeader, handleResponse } from '@/utils/authentication';
|
import { authHeader, handleResponse } from '@/utils/authentication';
|
||||||
import * as bootstrap from 'bootstrap';
|
import * as bootstrap from 'bootstrap';
|
||||||
@ -291,6 +257,7 @@ export default defineComponent({
|
|||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
CardElement,
|
CardElement,
|
||||||
InputElement,
|
InputElement,
|
||||||
|
Modal,
|
||||||
BIconInfoCircle,
|
BIconInfoCircle,
|
||||||
BIconPencil,
|
BIconPencil,
|
||||||
BIconTrash,
|
BIconTrash,
|
||||||
@ -323,7 +290,7 @@ export default defineComponent({
|
|||||||
fetch("/api/inverter/list", { headers: authHeader() })
|
fetch("/api/inverter/list", { headers: authHeader() })
|
||||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
this.inverters = data.inverter.slice().sort((a : Inverter, b: Inverter) => {
|
this.inverters = data.inverter.slice().sort((a: Inverter, b: Inverter) => {
|
||||||
return a.order - b.order;
|
return a.order - b.order;
|
||||||
});
|
});
|
||||||
this.dataLoading = false;
|
this.dataLoading = false;
|
||||||
|
|||||||
@ -12,31 +12,20 @@
|
|||||||
</CardElement>
|
</CardElement>
|
||||||
</BasePage>
|
</BasePage>
|
||||||
|
|
||||||
<div class="modal" id="performReboot" tabindex="-1">
|
<Modal modalId="performReboot" small :title="$t('maintenancereboot.RebootOpenDTU')" :closeText="$t('maintenancereboot.Cancel')">
|
||||||
<div class="modal-dialog">
|
{{ $t('maintenancereboot.RebootQuestion') }}
|
||||||
<div class="modal-content">
|
<template #footer>
|
||||||
<div class="modal-header">
|
<button type="button" class="btn btn-danger" @click="onReboot">
|
||||||
<h5 class="modal-title">{{ $t('maintenancereboot.RebootOpenDTU') }}</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{{ $t('maintenancereboot.RebootQuestion') }}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" @click="onCloseModal(performReboot)"
|
|
||||||
data-bs-dismiss="modal">{{ $t('maintenancereboot.Cancel') }}</button>
|
|
||||||
<button type="button" class="btn btn-danger" @click="onReboot">
|
|
||||||
{{ $t('maintenancereboot.Reboot') }}</button>
|
{{ $t('maintenancereboot.Reboot') }}</button>
|
||||||
</div>
|
</template>
|
||||||
</div>
|
</Modal>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import BasePage from '@/components/BasePage.vue';
|
import BasePage from '@/components/BasePage.vue';
|
||||||
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
import BootstrapAlert from "@/components/BootstrapAlert.vue";
|
||||||
import CardElement from '@/components/CardElement.vue';
|
import CardElement from '@/components/CardElement.vue';
|
||||||
|
import Modal from '@/components/Modal.vue';
|
||||||
import { authHeader, handleResponse, isLoggedIn } from '@/utils/authentication';
|
import { authHeader, handleResponse, isLoggedIn } from '@/utils/authentication';
|
||||||
import * as bootstrap from 'bootstrap';
|
import * as bootstrap from 'bootstrap';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
@ -46,6 +35,7 @@ export default defineComponent({
|
|||||||
BasePage,
|
BasePage,
|
||||||
BootstrapAlert,
|
BootstrapAlert,
|
||||||
CardElement,
|
CardElement,
|
||||||
|
Modal,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user