webapp: Added gui to manage inverters

This commit is contained in:
Thomas Basler 2022-05-04 21:55:18 +02:00
parent ba0aa20211
commit 34e86437d2
6 changed files with 302 additions and 46 deletions

View File

@ -10,6 +10,7 @@
"dependencies": { "dependencies": {
"@popperjs/core": "^2.11.5", "@popperjs/core": "^2.11.5",
"bootstrap": "^5.1.3", "bootstrap": "^5.1.3",
"bootstrap-icons-vue": "^1.8.1",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-router": "^4.0.14" "vue-router": "^4.0.14"

View File

@ -0,0 +1,239 @@
<template>
<div class="container" role="main">
<div class="page-header">
<h1>Inverter Settings</h1>
</div>
<BootstrapAlert v-model="showAlert" dismissible :variant="alertType">
{{ this.alertMessage }}
</BootstrapAlert>
<div class="card">
<div class="card-header text-white bg-primary">Add a new Inverter</div>
<div class="card-body">
<form class="form-inline" v-on:submit.prevent="onSubmit">
<div class="form-group">
<label>Serial</label>
<input
v-model="inverterData.serial"
type="number"
class="form-control ml-sm-2 mr-sm-4 my-2"
required
/>
</div>
<div class="form-group">
<label>Name</label>
<input
v-model="inverterData.name"
type="text"
class="form-control ml-sm-2 mr-sm-4 my-2"
maxlength="31"
required
/>
</div>
<div class="ml-auto text-right">
<button type="submit" class="btn btn-primary my-2">Add</button>
</div>
</form>
</div>
</div>
<div class="card mt-5">
<div class="card-header text-white bg-primary">Inverter List</div>
<div class="card-body">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th scope="col">Serial</th>
<th>Name</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="inverter in sortedInverters" v-bind:key="inverter.id">
<template v-if="editId == inverter.id">
<td>
<input
v-model="editInverterData.serial"
type="number"
class="form-control"
/>
</td>
<td>
<input
v-model="editInverterData.name"
type="text"
class="form-control"
maxlength="31"
/>
</td>
<td>
<a href="#" class="icon">
<BIconCheck v-on:click="onEditSubmit(inverter.id)" />
</a>
<a href="#" class="icon">
<BIconX v-on:click="onCancel" />
</a>
</td>
</template>
<template v-else>
<td>
{{ inverter.serial }}
</td>
<td>
{{ inverter.name }}
</td>
<td>
<a href="#" class="icon">
<BIconTrash v-on:click="onDelete(inverter.id)" />
</a>
<a href="#" class="icon">
<BIconPencil v-on:click="onEdit(inverter)" />
</a>
</td>
</template>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
<script>
import BootstrapAlert from "@/components/partials/BootstrapAlert.vue";
export default {
components: {
BootstrapAlert,
},
data() {
return {
editId: "-1",
inverterData: {
id: "",
serial: "",
name: "",
},
editInverterData: {
id: "",
serial: "",
name: "",
},
inverters: [],
alertMessage: "",
alertType: "info",
showAlert: false,
};
},
created() {
this.getInverters();
},
computed: {
sortedInverters() {
return this.inverters.slice().sort((a, b) => {
return a.serial - b.serial;
});
},
},
methods: {
getInverters() {
fetch("/api/inverter/list")
.then((response) => response.json())
.then((data) => (this.inverters = data.inverter));
},
onSubmit() {
let formData = new FormData();
formData.append("data", JSON.stringify(this.inverterData));
fetch("/api/inverter/add", {
method: "POST",
body: formData,
})
.then(function (response) {
if (response.status != 200) {
throw response.status;
} else {
return response.json();
}
})
.then(
function (response) {
this.alertMessage = response.message;
this.alertType = response.type;
this.showAlert = true;
}.bind(this)
)
.then(this.getInverters());
this.inverterData.serial = "";
this.inverterData.name = "";
},
onDelete(id) {
let formData = new FormData();
formData.append("data", JSON.stringify({ id: id }));
fetch("/api/inverter/del", {
method: "POST",
body: formData,
})
.then(function (response) {
if (response.status != 200) {
throw response.status;
} else {
return response.json();
}
})
.then(
function (response) {
this.alertMessage = response.message;
this.alertType = response.type;
this.showAlert = true;
}.bind(this)
)
.then(this.getInverters());
},
onEdit(inverter) {
this.editId = inverter.id;
this.editInverterData.serial = inverter.serial;
this.editInverterData.name = inverter.name;
},
onCancel() {
this.editId = "-1";
this.editInverterData.serial = "";
this.editInverterData.name = "";
},
onEditSubmit(id) {
let formData = new FormData();
this.editInverterData.id = id;
formData.append("data", JSON.stringify(this.editInverterData));
fetch("/api/inverter/edit", {
method: "POST",
body: formData,
})
.then(function (response) {
if (response.status != 200) {
throw response.status;
} else {
return response.json();
}
})
.then(
function (response) {
this.alertMessage = response.message;
this.alertType = response.type;
this.showAlert = true;
}.bind(this)
)
.then(this.getInverters());
this.editId = "-1";
this.editInverterData.serial = "";
this.editInverterData.name = "";
},
},
};
</script>

View File

@ -45,6 +45,11 @@
>MqTT Settings</router-link >MqTT Settings</router-link
> >
</li> </li>
<li>
<router-link class="dropdown-item" to="/settings/inverter"
>Inverter Settings</router-link
>
</li>
</ul> </ul>
</li> </li>
<li class="nav-item dropdown"> <li class="nav-item dropdown">

View File

@ -1,8 +1,9 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import { BootstrapIconsPlugin } from 'bootstrap-icons-vue';
import "bootstrap/dist/css/bootstrap.min.css" import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap/dist/js/bootstrap.js" import "bootstrap/dist/js/bootstrap.js"
createApp(App).use(router).mount('#app') createApp(App).use(router).use(BootstrapIconsPlugin).mount('#app')

View File

@ -8,53 +8,58 @@ import NetworkAdminView from '@/components/NetworkAdminView'
import NtpAdminView from '@/components/NtpAdminView' import NtpAdminView from '@/components/NtpAdminView'
import MqttAdminView from '@/components/MqttAdminView' import MqttAdminView from '@/components/MqttAdminView'
import MqttInfoView from '@/components/MqttInfoView' import MqttInfoView from '@/components/MqttInfoView'
import InverterAdminView from '@/components/InverterAdminView'
const routes = [{ const routes = [{
path: '/', path: '/',
name: 'Home', name: 'Home',
component: HomeView component: HomeView
}, },
{ {
path: '/about', path: '/about',
name: 'About', name: 'About',
component: AboutView component: AboutView
}, },
{ {
path: '/info/network', path: '/info/network',
name: 'Network', name: 'Network',
component: NetworkInfoView component: NetworkInfoView
}, },
{ {
path: '/info/system', path: '/info/system',
name: 'System', name: 'System',
component: SystemInfoView component: SystemInfoView
}, },
{ {
path: '/info/ntp', path: '/info/ntp',
name: 'NTP', name: 'NTP',
component: NtpInfoView component: NtpInfoView
}, },
{ {
path: '/info/mqtt', path: '/info/mqtt',
name: 'MqTT', name: 'MqTT',
component: MqttInfoView component: MqttInfoView
}, },
{ {
path: '/settings/network', path: '/settings/network',
name: 'Network Settings', name: 'Network Settings',
component: NetworkAdminView component: NetworkAdminView
}, },
{ {
path: '/settings/ntp', path: '/settings/ntp',
name: 'NTP Settings', name: 'NTP Settings',
component: NtpAdminView component: NtpAdminView
}, },
{ {
path: '/settings/mqtt', path: '/settings/mqtt',
name: 'MqTT Settings', name: 'MqTT Settings',
component: MqttAdminView component: MqttAdminView
} },
]; {
path: '/settings/inverter',
name: 'Inverter Settings',
component: InverterAdminView
}];
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),

View File

@ -2077,6 +2077,11 @@ boolbase@^1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
bootstrap-icons-vue@^1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/bootstrap-icons-vue/-/bootstrap-icons-vue-1.8.1.tgz#ce4a0c1f6efe41dabcc1341f2cb191d307fbaf50"
integrity sha512-uItRULwQz0epETi9x/RBEqfjHmTAmkIIczpH1R6L9T6yyaaijk0826PzTWnWNm15tw66JT/8GNuXjB0HI5PHLw==
bootstrap@^5.1.3: bootstrap@^5.1.3:
version "5.1.3" version "5.1.3"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.3.tgz#ba081b0c130f810fa70900acbc1c6d3c28fa8f34"