chore: Typescript: Rewrite Site (#21612)

Co-authored-by: Michael Geers <michael@geers.tv>
This commit is contained in:
Maschga 2025-06-06 12:14:56 +02:00 • committed by GitHub
parent e89e7fcc7f
commit a4aa09932c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 112 additions and 37 deletions

View file

@ -31,6 +31,9 @@ GridAndPV.args = {
chargePower: 1000,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 1000,
@ -40,6 +43,9 @@ GridAndPV.args = {
chargePower: 1000,
connected: true,
index: 1,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 2200,
@ -49,6 +55,9 @@ GridAndPV.args = {
chargePower: 2200,
connected: true,
index: 2,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
tariffGrid: 0.25,
@ -101,6 +110,9 @@ BatteryCharging.args = {
chargePower: 1400,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
batteryPower: -1500,
@ -135,6 +147,9 @@ BatteryThresholds.args = {
chargePower: 5000,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 2500,
@ -144,6 +159,9 @@ BatteryThresholds.args = {
chargePower: 2500,
connected: true,
index: 1,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
batteryPower: -700,
@ -167,6 +185,9 @@ PVThresholds.args = {
chargePower: 5000,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 1600,
@ -176,6 +197,9 @@ PVThresholds.args = {
chargePower: 1600,
connected: true,
index: 1,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
batteryPower: 800,
@ -199,6 +223,9 @@ GridOnly.args = {
chargePower: 5500,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 0,
@ -208,6 +235,9 @@ GridOnly.args = {
chargePower: 0,
connected: false,
index: 1,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 0,
@ -217,6 +247,9 @@ GridOnly.args = {
chargePower: 0,
connected: false,
index: 2,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 0,
@ -226,6 +259,9 @@ GridOnly.args = {
chargePower: 0,
connected: false,
index: 3,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
batteryPower: 0,
@ -263,6 +299,9 @@ CO2.args = {
chargePower: 1000,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 1000,
@ -272,6 +311,9 @@ CO2.args = {
chargePower: 1000,
connected: true,
index: 1,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
{
power: 2200,
@ -281,6 +323,9 @@ CO2.args = {
chargePower: 2200,
connected: true,
index: 2,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
tariffGrid: 0.25,
@ -306,6 +351,9 @@ UnknownInput.args = {
chargePower: 1000,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
};
@ -336,6 +384,9 @@ UnknownOutput.args = {
chargePower: 1700,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
};
@ -355,6 +406,9 @@ UnknownOutputLessThan10Percent.args = {
chargePower: 1800,
connected: true,
index: 0,
vehicleName: "",
vehicleSoc: 50,
chargerFeatureHeating: false,
},
],
};

View file

@ -24,6 +24,7 @@ function loadpoint(opts = {}) {
title: "Garage",
power: 2100,
index: 0,
chargerFeatureHeating: false,
};
return { ...base, ...opts };
}

View file

@ -66,7 +66,7 @@
</div>
</template>
<script>
<script lang="ts">
import "@h2d2/shopicons/es/regular/arrowup";
import Navigation from "../Top/Navigation.vue";
import Notifications from "../Top/Notifications.vue";
@ -76,8 +76,19 @@ import Footer from "../Footer/Footer.vue";
import formatter from "@/mixins/formatter";
import collector from "@/mixins/collector";
import WelcomeIcons from "./WelcomeIcons.vue";
import { defineComponent, type PropType } from "vue";
import type {
Auth,
Battery,
CURRENCY,
Forecast,
LoadpointCompact,
Notification,
Sponsor,
} from "@/types/evcc";
import type { Grid } from "./types";
export default {
export default defineComponent({
name: "Site",
components: {
Loadpoints,
@ -89,25 +100,25 @@ export default {
},
mixins: [formatter, collector],
props: {
loadpoints: Array,
loadpoints: { type: Array as PropType<LoadpointCompact[]>, default: () => [] },
selectedLoadpointIndex: Number,
notifications: Array,
notifications: { type: Array as PropType<Notification[]>, default: () => [] },
offline: Boolean,
// details
gridConfigured: Boolean,
grid: Object,
grid: Object as PropType<Grid>,
homePower: Number,
pvPower: Number,
pv: Array,
pv: { type: Array, default: () => [] },
batteryPower: Number,
batterySoc: Number,
batteryDischargeControl: Boolean,
batteryGridChargeLimit: { type: Number, default: null },
batteryGridChargeActive: Boolean,
batteryMode: String,
battery: Array,
battery: { type: Array as PropType<Battery[]>, default: () => [] },
gridCurrents: Array,
prioritySoc: Number,
bufferSoc: Number,
@ -115,9 +126,9 @@ export default {
siteTitle: String,
vehicles: Object,
auth: Object,
auth: { type: Object as PropType<Auth>, default: () => ({ vehicles: {} }) },
currency: String,
currency: { type: String as PropType<CURRENCY>, required: true },
statistics: Object,
tariffFeedIn: Number,
tariffGrid: Number,
@ -132,10 +143,10 @@ export default {
hasUpdater: Boolean,
uploadMessage: String,
uploadProgress: Number,
sponsor: { type: Object, default: () => ({}) },
sponsor: { type: Object as PropType<Sponsor>, default: () => ({}) },
smartCostType: String,
fatal: Object,
forecast: Object, // as PropType<Forecast>,
forecast: Object as PropType<Forecast>,
},
computed: {
batteryConfigured() {
@ -173,8 +184,7 @@ export default {
return Object.entries(vehicles).map(([name, vehicle]) => ({ name, ...vehicle }));
},
topNavigation() {
const vehicleLogins = this.auth ? this.auth.vehicles : {};
return { vehicleLogins, ...this.collectProps(Navigation) };
return { vehicleLogins: this.auth.vehicles, ...this.collectProps(Navigation) };
},
showParkingLot() {
// work in progess
@ -205,14 +215,14 @@ export default {
},
},
methods: {
selectedLoadpointChanged(index) {
selectedLoadpointChanged(index: number) {
this.$router.push({ query: { lp: index + 1 } });
},
vehicleTitle(vehicleName) {
vehicleTitle(vehicleName: string) {
return this.vehicles?.[vehicleName]?.title;
},
},
};
});
</script>
<style scoped>
.site {
@ -223,9 +233,6 @@ export default {
flex-grow: 1;
z-index: 1;
}
.fatal {
}
.configure-button:not(:active):not(:hover),
.welcome-icons {
animation: colorTransition 10s infinite alternate;

View file

@ -12,7 +12,7 @@
</div>
</template>
<script>
<script lang="ts">
import "@h2d2/shopicons/es/regular/batterythreequarters";
import "@h2d2/shopicons/es/regular/cablecharge";
import "@h2d2/shopicons/es/regular/car3";
@ -29,9 +29,10 @@ import "@h2d2/shopicons/es/regular/clock";
import BatteryBoost from "../MaterialIcon/BatteryBoost.vue";
import SunUp from "../MaterialIcon/SunUp.vue";
import DynamicPrice from "../MaterialIcon/DynamicPrice.vue";
import { markRaw } from "vue";
import { defineComponent, markRaw } from "vue";
import type { Timeout } from "@/types/evcc";
export default {
export default defineComponent({
data() {
return {
leftIconIndex: 2,
@ -56,7 +57,7 @@ export default {
markRaw(SunUp),
markRaw(DynamicPrice),
],
interval: null,
interval: null as Timeout,
};
},
computed: {
@ -74,10 +75,12 @@ export default {
this.interval = setInterval(this.rotateIcons, 3000);
},
unmounted() {
clearInterval(this.interval);
if (this.interval) {
clearInterval(this.interval);
}
},
methods: {
getRandomIcon(excludeIndices) {
getRandomIcon(excludeIndices: number[]) {
const availableIndices = Array.from(Array(this.icons.length).keys()).filter(
(i) => !excludeIndices.includes(i)
);
@ -100,7 +103,7 @@ export default {
this.updatePosition = (this.updatePosition + Math.ceil(Math.random() * 2)) % 3;
},
},
};
});
</script>
<style scoped>

3
assets/js/components/Site/types.d.ts vendored Normal file
View file

@ -0,0 +1,3 @@
export interface Grid {
power?: number;
}

View file

@ -1,6 +1,6 @@
import type { Notification } from "@/types/evcc";
import Notifications from "./Notifications.vue";
import type { Meta, StoryFn } from "@storybook/vue3";
import type { Notification } from "./types";
const timeAgo = (hours = 0, minutes = 0, seconds = 0) => {
const date = new Date();

View file

@ -90,8 +90,7 @@
import "@h2d2/shopicons/es/regular/exclamationtriangle";
import formatter from "@/mixins/formatter";
import { defineComponent, type PropType } from "vue";
import type { Notification } from "./types";
import type { Timeout } from "@/types/evcc";
import type { Notification, Timeout } from "@/types/evcc";
export default defineComponent({
name: "Notifications",

View file

@ -1,11 +1,3 @@
export interface Notification {
message: string;
time: Date;
level: string;
lp: number;
count: number;
}
export interface Provider {
title: string;
loggedIn: boolean;

View file

@ -4,6 +4,10 @@ import type { ForecastSlot, SolarDetails } from "../components/Forecast/types";
declare global {
interface Window {
app: any;
evcc: {
version: string;
commit: string;
};
}
}
@ -38,6 +42,10 @@ export interface LoadpointCompact {
chargePower: number;
connected: boolean;
index: number;
vehicleName: string;
chargerIcon?: string;
vehicleSoc: number;
chargerFeatureHeating: boolean;
}
export enum CURRENCY {
@ -66,6 +74,14 @@ export interface Sponsor {
expiresSoon: boolean;
}
export interface Notification {
message: string;
time: Date;
level: string;
lp: number;
count: number;
}
export interface Battery {
power: number;
soc: number;