UI: darker dark mode, card layout, battery card polish (#31515)
This commit is contained in:
parent
82a3f643a6
commit
5e25ed4b02
19 changed files with 232 additions and 193 deletions
|
|
@ -83,6 +83,7 @@
|
|||
|
||||
--bs-danger: var(--evcc-red);
|
||||
--bs-danger-rgb: var(--evcc-red-rgb);
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.05);
|
||||
|
||||
--bs-form-invalid-border-color: var(--bs-danger);
|
||||
|
||||
|
|
@ -112,7 +113,7 @@
|
|||
--evcc-export: var(--evcc-yellow);
|
||||
--evcc-export-contrast: var(--evcc-yellow);
|
||||
--evcc-background: var(--bs-gray-deep);
|
||||
--evcc-box: var(--bs-gray-dark);
|
||||
--evcc-box: var(--bs-gray-darker);
|
||||
--evcc-box-border: var(--bs-gray-darker);
|
||||
--evcc-default-text: var(--bs-white);
|
||||
--evcc-gray: var(--bs-gray-light);
|
||||
|
|
@ -121,7 +122,7 @@
|
|||
--evcc-accent3: var(--evcc-darker-green);
|
||||
--bs-primary: var(--evcc-dark-green);
|
||||
--bs-primary-dim: color-mix(in srgb, var(--bs-primary) 70%, transparent);
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.175);
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.08);
|
||||
--bs-code-color: var(--evcc-dark-green);
|
||||
--evcc-backdrop: #000000aa; /* black + transparent */
|
||||
--tab-bar-background: var(--evcc-box);
|
||||
|
|
@ -442,6 +443,7 @@ a:hover {
|
|||
border-radius: 1rem;
|
||||
padding: 1.25rem;
|
||||
background-color: var(--evcc-box);
|
||||
border: 1px solid var(--bs-border-color-translucent);
|
||||
color: var(--evcc-default-text);
|
||||
}
|
||||
|
||||
|
|
@ -742,9 +744,18 @@ html.app .modal-dialog {
|
|||
border-radius: 1rem;
|
||||
color: var(--evcc-default-text);
|
||||
background: var(--evcc-box);
|
||||
border: 1px solid var(--bs-border-color-translucent);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
/* pull boxes into the container padding so box content aligns with the page header */
|
||||
@media (min-width: 576px) {
|
||||
.box-pull-out {
|
||||
margin-left: -1.5rem;
|
||||
margin-right: -1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.round-box--error {
|
||||
box-shadow: 0 0 0.5rem var(--bs-danger);
|
||||
border: 1px solid var(--bs-danger);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div v-if="batteryAvailable" data-testid="battery-experimental">
|
||||
<BatteryStatusCards class="mb-4" :battery="state.battery" />
|
||||
<BatteryStatusCards class="mb-4 box-pull-out" :battery="state.battery" />
|
||||
|
||||
<BatteryHistoryCard
|
||||
class="mb-4"
|
||||
class="mb-4 box-pull-out"
|
||||
:batteries="chartBatteries"
|
||||
:now="now"
|
||||
:kwh-available="kWhAvailable"
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
/>
|
||||
|
||||
<BatteryConfigCard
|
||||
class="mb-4"
|
||||
class="mb-4 box-pull-out"
|
||||
:buffer-soc="state.bufferSoc"
|
||||
:priority-soc="state.prioritySoc"
|
||||
:buffer-start-soc="state.bufferStartSoc"
|
||||
|
|
@ -19,7 +19,11 @@
|
|||
:battery="state.battery"
|
||||
/>
|
||||
|
||||
<Card v-if="gridChargeVisible" :title="$t('batterySettings.gridChargeTab')">
|
||||
<Card
|
||||
v-if="gridChargeVisible"
|
||||
class="box-pull-out"
|
||||
:title="$t('batterySettings.gridChargeTab')"
|
||||
>
|
||||
<SmartCostLimit v-bind="smartCostLimitProps" />
|
||||
</Card>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<template>
|
||||
<div v-if="showSplit" class="cards cards--split gap-3">
|
||||
<div v-if="showSplit" class="cards cards--split gap-4">
|
||||
<BatteryStatusCard v-bind="cards[0]" />
|
||||
<Card :title="$t('battery.optimizer.title')" data-testid="battery-optimizer-card">
|
||||
<OptimizerInfo :suggestion="suggestion" :forecast="batteryForecast" />
|
||||
</Card>
|
||||
</div>
|
||||
<div v-else class="cards gap-3">
|
||||
<div v-else class="cards gap-4">
|
||||
<BatteryStatusCard v-for="card in cards" :key="card.id" v-bind="card" />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<section class="evcc-card p-3 p-sm-4" :class="{ 'evcc-card--edge': edgeToEdge }">
|
||||
<section class="evcc-card round-box p-3 p-sm-4" :class="{ 'evcc-card--edge': edgeToEdge }">
|
||||
<div
|
||||
v-if="hasHeader"
|
||||
class="evcc-card-header d-flex align-items-center gap-3 flex-wrap mb-3"
|
||||
|
|
@ -57,11 +57,6 @@ export default defineComponent({
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.evcc-card {
|
||||
background: var(--evcc-box);
|
||||
border: 1px solid var(--bs-border-color-translucent);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
.evcc-card-subtitle {
|
||||
color: var(--evcc-gray);
|
||||
}
|
||||
|
|
@ -69,9 +64,10 @@ export default defineComponent({
|
|||
.evcc-card--edge {
|
||||
margin-left: -1.5rem;
|
||||
margin-right: -1.5rem;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-width: 1px 0;
|
||||
border-radius: 0;
|
||||
padding-left: 1.5rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ export default defineComponent({
|
|||
border-radius: 2rem;
|
||||
color: var(--evcc-default-text);
|
||||
background: var(--evcc-box);
|
||||
border: 1px solid var(--bs-border-color-translucent);
|
||||
}
|
||||
|
||||
.details > div {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="mb-4">
|
||||
<div>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="mb-5">
|
||||
<div>
|
||||
<div class="chart-container my-3">
|
||||
<Chart
|
||||
ref="chartRef"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<button
|
||||
class="btn btn-link position-absolute text-primary rounded"
|
||||
class="btn btn-link position-absolute text-primary"
|
||||
:style="buttonStyle"
|
||||
:title="copied ? 'Copied!' : 'Copy to clipboard'"
|
||||
@click="handleCopy"
|
||||
|
|
@ -47,7 +47,6 @@ export default defineComponent({
|
|||
top: this.top,
|
||||
right: this.right,
|
||||
padding: this.padding,
|
||||
backgroundColor: "var(--evcc-box)",
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -251,8 +251,9 @@ export default defineComponent({
|
|||
padding: 0.75rem 0;
|
||||
border-top: 1px solid var(--evcc-gray-25);
|
||||
}
|
||||
.field:last-child {
|
||||
border-bottom: 1px solid var(--evcc-gray-25);
|
||||
/* card provides the outer boundary */
|
||||
.field:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
.field-head {
|
||||
display: flex;
|
||||
|
|
@ -279,6 +280,14 @@ export default defineComponent({
|
|||
text-underline-offset: 3px;
|
||||
}
|
||||
|
||||
/* small: slightly reduced value size, rows are tighter */
|
||||
@media (max-width: 767.98px) {
|
||||
.field-value .large,
|
||||
.field-value .fs-4 {
|
||||
font-size: 1.125rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* md and up: each field a vertical stack (label, value, caption); columns via Bootstrap grid */
|
||||
@media (min-width: 768px) {
|
||||
.field {
|
||||
|
|
@ -289,9 +298,6 @@ export default defineComponent({
|
|||
padding: 0.75rem 1.5rem;
|
||||
border: none;
|
||||
}
|
||||
.field:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
/* promote label + caption so value can sit between them via order */
|
||||
.field-head {
|
||||
display: contents;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="mb-5">
|
||||
<div>
|
||||
<div class="chart-container my-3">
|
||||
<Chart
|
||||
ref="chartRef"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="mb-5">
|
||||
<div>
|
||||
<div v-for="(_battery, index) in evopt.res.batteries" :key="index" class="mb-3">
|
||||
<div class="mb-2" style="font-size: 0.875rem; font-weight: bold">
|
||||
{{ getBatteryTitle(index) }}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="mb-4">
|
||||
<div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<template>
|
||||
<h3 class="fw-normal mb-4">{{ $t("sessions.overview") }}</h3>
|
||||
|
||||
<div v-if="sessions.length === 0" data-testid="sessions-nodata" class="mb-5">
|
||||
<div v-if="sessions.length === 0" data-testid="sessions-nodata">
|
||||
<p>{{ $t("sessions.noData") }}</p>
|
||||
</div>
|
||||
<div v-else class="mb-5 table-outer">
|
||||
<div v-else class="table-outer">
|
||||
<table class="table text-nowrap">
|
||||
<thead class="sticky-top">
|
||||
<tr data-testid="sessions-head">
|
||||
|
|
@ -479,7 +477,7 @@ export default defineComponent({
|
|||
}
|
||||
.table thead,
|
||||
.table tfoot {
|
||||
background: var(--evcc-background);
|
||||
background: var(--evcc-box);
|
||||
}
|
||||
.table tfoot th {
|
||||
border-top-width: 2px;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<label :for="formId" class="col-sm-4 col-form-label pt-0 pt-sm-2">
|
||||
{{ limitLabel }}
|
||||
</label>
|
||||
<div class="col-sm-8 col-lg-4 pe-0">
|
||||
<div class="col-sm-8 col-lg-4 pe-lg-0">
|
||||
<div class="input-group input-group-sm mb-1 mb-lg-0">
|
||||
<div class="input-group-text">
|
||||
<div class="form-check form-switch m-0">
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.general") }}</h2>
|
||||
<GeneralConfig
|
||||
class="box-pull-out"
|
||||
:experimental="experimental"
|
||||
:sponsor-error="hasClassError('sponsorship')"
|
||||
@site-changed="siteChanged"
|
||||
|
|
@ -23,7 +24,7 @@
|
|||
|
||||
<WelcomeBanner v-if="setupRequired" />
|
||||
<h2 class="my-4">{{ $t("config.section.loadpoints") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<DeviceCard
|
||||
v-for="loadpoint in loadpoints"
|
||||
:id="`loadpoint_${loadpoint.name}`"
|
||||
|
|
@ -55,7 +56,7 @@
|
|||
</div>
|
||||
|
||||
<h2 class="my-4">{{ $t("config.section.vehicles") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<DeviceCard
|
||||
v-for="vehicle in vehicles"
|
||||
:id="`vehicle_${vehicle.name}`"
|
||||
|
|
@ -82,7 +83,7 @@
|
|||
</div>
|
||||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.consumers") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<MeterCard
|
||||
v-for="meter in consumerMeters"
|
||||
:key="meter.name"
|
||||
|
|
@ -109,7 +110,7 @@
|
|||
</div>
|
||||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.grid") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<MeterCard
|
||||
v-if="gridMeter"
|
||||
:meter="gridMeter"
|
||||
|
|
@ -127,7 +128,7 @@
|
|||
/>
|
||||
</div>
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.meter") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<MeterCard
|
||||
v-for="meter in pvMeters"
|
||||
:key="meter.name"
|
||||
|
|
@ -154,7 +155,7 @@
|
|||
</div>
|
||||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.additionalMeter") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<MeterCard
|
||||
v-for="meter in extMeters"
|
||||
:key="meter.name"
|
||||
|
|
@ -172,7 +173,7 @@
|
|||
</div>
|
||||
|
||||
<h2 id="tariffs" class="my-4 mt-5">{{ $t("config.tariff.title") }}</h2>
|
||||
<div v-if="!!tariffsYamlSource" class="p-0 config-list">
|
||||
<div v-if="!!tariffsYamlSource" class="p-0 config-list box-pull-out">
|
||||
<DeviceCard
|
||||
:title="$t('config.tariff.title')"
|
||||
:editable="tariffsYamlSource === 'db'"
|
||||
|
|
@ -191,7 +192,7 @@
|
|||
</template>
|
||||
</DeviceCard>
|
||||
</div>
|
||||
<div v-else class="p-0 config-list">
|
||||
<div v-else class="p-0 config-list box-pull-out">
|
||||
<TariffCard
|
||||
v-if="gridTariff"
|
||||
:tariff="gridTariff"
|
||||
|
|
@ -252,7 +253,7 @@
|
|||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.integrations") }}</h2>
|
||||
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<AuthProvidersCard
|
||||
:providers="authProviders"
|
||||
data-testid="auth-providers"
|
||||
|
|
@ -374,7 +375,7 @@
|
|||
</div>
|
||||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.services") }}</h2>
|
||||
<div class="p-0 config-list">
|
||||
<div class="p-0 config-list box-pull-out">
|
||||
<DeviceCard
|
||||
:title="$t('config.ocpp.title')"
|
||||
editable
|
||||
|
|
@ -416,7 +417,10 @@
|
|||
<hr class="my-5" />
|
||||
|
||||
<h2 class="my-4 mt-5">{{ $t("config.section.system") }}</h2>
|
||||
<div data-testid="config-system" class="round-box p-4 d-flex gap-4 flex-wrap">
|
||||
<div
|
||||
data-testid="config-system"
|
||||
class="round-box box-pull-out p-4 d-flex gap-4 flex-wrap"
|
||||
>
|
||||
<router-link to="/log" class="btn btn-outline-secondary">
|
||||
{{ $t("config.system.logs") }}
|
||||
</router-link>
|
||||
|
|
|
|||
|
|
@ -42,13 +42,14 @@
|
|||
</div>
|
||||
<div v-else class="row">
|
||||
<main class="col-12 d-flex flex-column">
|
||||
<section v-if="forecast.solar" class="mb-5">
|
||||
<div class="d-flex align-items-baseline my-4">
|
||||
<h3 class="fw-normal mb-0">{{ $t("forecast.type.solar") }}</h3>
|
||||
<div
|
||||
v-if="showSolarAdjust"
|
||||
class="form-check form-switch ms-auto mb-0 text-nowrap"
|
||||
>
|
||||
<Card
|
||||
v-if="forecast.solar"
|
||||
:title="$t('forecast.type.solar')"
|
||||
edge-to-edge
|
||||
class="box-pull-out mb-4"
|
||||
>
|
||||
<template v-if="showSolarAdjust" #actions>
|
||||
<div class="form-check form-switch mb-0 text-nowrap">
|
||||
<input
|
||||
id="solarForecastAdjust"
|
||||
:checked="solarAdjusted"
|
||||
|
|
@ -62,7 +63,7 @@
|
|||
<span class="d-none d-md-inline">{{ solarAdjustTextMedium }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="chart-edge">
|
||||
<SolarChart
|
||||
:solar="solar"
|
||||
|
|
@ -74,16 +75,17 @@
|
|||
/>
|
||||
</div>
|
||||
<SolarDetails :solar="solar" />
|
||||
</section>
|
||||
</Card>
|
||||
|
||||
<section
|
||||
<Card
|
||||
v-if="forecast.grid"
|
||||
class="mb-5"
|
||||
:title="$t('forecast.type.price')"
|
||||
edge-to-edge
|
||||
class="box-pull-out mb-4"
|
||||
:style="isGridStatic ? { order: 1 } : undefined"
|
||||
>
|
||||
<div class="d-flex align-items-baseline my-4">
|
||||
<h3 class="fw-normal mb-0">{{ $t("forecast.type.price") }}</h3>
|
||||
<div class="form-check form-switch ms-auto mb-0 text-nowrap">
|
||||
<template #actions>
|
||||
<div class="form-check form-switch mb-0 text-nowrap">
|
||||
<input
|
||||
id="priceZoom"
|
||||
:checked="priceZoom"
|
||||
|
|
@ -96,7 +98,7 @@
|
|||
{{ $t("forecast.priceZoom") }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="chart-edge">
|
||||
<PriceChart
|
||||
:grid="forecast.grid"
|
||||
|
|
@ -116,10 +118,14 @@
|
|||
:show-feedin="showFeedin"
|
||||
@toggle-feedin="toggleFeedin"
|
||||
/>
|
||||
</section>
|
||||
</Card>
|
||||
|
||||
<section v-if="forecast.co2" class="mb-5">
|
||||
<h3 class="fw-normal my-4">{{ $t("forecast.type.co2") }}</h3>
|
||||
<Card
|
||||
v-if="forecast.co2"
|
||||
:title="$t('forecast.type.co2')"
|
||||
edge-to-edge
|
||||
class="box-pull-out mb-4"
|
||||
>
|
||||
<div class="chart-edge">
|
||||
<Co2Chart
|
||||
:co2="forecast.co2"
|
||||
|
|
@ -130,7 +136,7 @@
|
|||
/>
|
||||
</div>
|
||||
<Co2Details :co2="forecast.co2" />
|
||||
</section>
|
||||
</Card>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -141,6 +147,7 @@ import "@h2d2/shopicons/es/regular/sun";
|
|||
import "@h2d2/shopicons/es/regular/eco1";
|
||||
import { defineComponent } from "vue";
|
||||
import Header from "../components/Top/Header.vue";
|
||||
import Card from "../components/Helper/Card.vue";
|
||||
import DynamicPriceIcon from "../components/MaterialIcon/DynamicPrice.vue";
|
||||
import SolarChart from "../components/Forecast/SolarChart.vue";
|
||||
import SolarDetails from "../components/Forecast/SolarDetails.vue";
|
||||
|
|
@ -160,6 +167,7 @@ export default defineComponent({
|
|||
name: "Forecast",
|
||||
components: {
|
||||
TopHeader: Header,
|
||||
Card,
|
||||
DynamicPriceIcon,
|
||||
SolarChart,
|
||||
SolarDetails,
|
||||
|
|
@ -295,9 +303,17 @@ export default defineComponent({
|
|||
max-width: 480px;
|
||||
}
|
||||
@media (max-width: 575.98px) {
|
||||
/* cancel the card's padding for full-bleed charts */
|
||||
.chart-edge {
|
||||
margin-left: -1.5rem;
|
||||
margin-right: -1.5rem;
|
||||
}
|
||||
}
|
||||
@media (min-width: 576px) {
|
||||
/* compensate the card border so the chart width fits without scrolling on wide screens */
|
||||
.chart-edge {
|
||||
margin-left: -1px;
|
||||
margin-right: -1px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
<div
|
||||
v-for="i in 3"
|
||||
:key="i"
|
||||
class="history-tile history-tile-skeleton mb-4"
|
||||
class="history-tile history-tile-skeleton box-pull-out mb-4"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
</div>
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
:title="$t(`main.history.group.${group}`)"
|
||||
:subtitle="groupTotalLabel(group)"
|
||||
edge-to-edge
|
||||
class="mb-4"
|
||||
class="box-pull-out mb-4"
|
||||
:data-testid="`history-section-${group}`"
|
||||
>
|
||||
<GroupChart
|
||||
|
|
|
|||
|
|
@ -1,25 +1,24 @@
|
|||
<template>
|
||||
<div class="container px-4 safe-area-inset">
|
||||
<TopHeader title="Optimize Debug 🧪" />
|
||||
<OptimizeHeader
|
||||
class="mt-4 mb-5"
|
||||
:updated="evopt?.updated"
|
||||
:status="evopt?.res?.status"
|
||||
:net-cost="netCost"
|
||||
:horizon-hours="horizonHours"
|
||||
:currency="currency"
|
||||
:charging-strategies="chargingStrategies"
|
||||
:selected-strategy="optimizerChargingStrategy"
|
||||
:pending="pending"
|
||||
@optimize="optimizeNow"
|
||||
@change-strategy="changeChargingStrategy"
|
||||
/>
|
||||
<Card edge-to-edge class="box-pull-out mt-4 mb-4">
|
||||
<OptimizeHeader
|
||||
:updated="evopt?.updated"
|
||||
:status="evopt?.res?.status"
|
||||
:net-cost="netCost"
|
||||
:horizon-hours="horizonHours"
|
||||
:currency="currency"
|
||||
:charging-strategies="chargingStrategies"
|
||||
:selected-strategy="optimizerChargingStrategy"
|
||||
:pending="pending"
|
||||
@optimize="optimizeNow"
|
||||
@change-strategy="changeChargingStrategy"
|
||||
/>
|
||||
</Card>
|
||||
<div class="row">
|
||||
<main class="col-12">
|
||||
<div v-if="evopt">
|
||||
<!-- Optimizer Plan -->
|
||||
<section class="mb-5">
|
||||
<h3 class="fw-normal mb-4">Result: Charging Plan</h3>
|
||||
<Card title="Result: Charging Plan" edge-to-edge class="box-pull-out mb-4">
|
||||
<ChargeChart
|
||||
:evopt="evopt"
|
||||
:battery-details="evopt.details.batteryDetails"
|
||||
|
|
@ -28,8 +27,9 @@
|
|||
:battery-colors="batteryColors"
|
||||
:device-colors="deviceColors"
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<h3 class="fw-normal mb-4">Result: SoC Projection</h3>
|
||||
<Card title="Result: SoC Projection" edge-to-edge class="box-pull-out mb-4">
|
||||
<SocChart
|
||||
:evopt="evopt"
|
||||
:battery-details="evopt.details.batteryDetails"
|
||||
|
|
@ -37,42 +37,30 @@
|
|||
:currency="currency"
|
||||
:battery-colors="batteryColors"
|
||||
/>
|
||||
</section>
|
||||
</Card>
|
||||
|
||||
<!-- Input Parameters -->
|
||||
<section class="mb-5">
|
||||
<h3 class="fw-normal mb-4">Input: Grid Prices</h3>
|
||||
<Card title="Input: Grid Prices" edge-to-edge class="box-pull-out mb-4">
|
||||
<PriceChart
|
||||
:evopt="evopt"
|
||||
:timestamp="evopt.details.timestamp[0]"
|
||||
:currency="currency"
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<h3
|
||||
class="fw-normal d-flex gap-3 flex-wrap d-flex align-items-baseline overflow-hidden mb-4"
|
||||
>
|
||||
<span class="d-block no-wrap text-truncate"> Input: Battery </span>
|
||||
<small class="d-block no-wrap text-truncate">
|
||||
{{ fmtPercentage((evopt.req.eta_c || 1) * 100, 1) }} charge
|
||||
efficiency ・
|
||||
{{ fmtPercentage((evopt.req.eta_d || 1) * 100, 1) }} discharge
|
||||
efficiency
|
||||
</small>
|
||||
</h3>
|
||||
|
||||
<Card
|
||||
title="Input: Battery"
|
||||
:subtitle="batteryEfficiencySubtitle"
|
||||
edge-to-edge
|
||||
class="box-pull-out mb-4"
|
||||
>
|
||||
<BatteryConfigurationTable
|
||||
:batteries="evopt.req.batteries"
|
||||
:battery-details="evopt.details.batteryDetails"
|
||||
:currency="currency"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<hr class="my-5" />
|
||||
|
||||
<!-- Debugging -->
|
||||
<section class="mb-5">
|
||||
<h3 class="fw-normal mb-4">Time Series</h3>
|
||||
</Card>
|
||||
|
||||
<Card title="Time Series" edge-to-edge class="box-pull-out mb-4">
|
||||
<TimeSeriesDataTable
|
||||
:evopt="evopt"
|
||||
:battery-details="evopt.details.batteryDetails"
|
||||
|
|
@ -81,33 +69,33 @@
|
|||
:battery-colors="batteryColors"
|
||||
:dimmed-battery-colors="dimmedBatteryColors"
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<h3 class="fw-normal mb-4">Raw Data</h3>
|
||||
|
||||
<Card title="Raw Data" edge-to-edge class="box-pull-out mb-4">
|
||||
<div class="mb-4">
|
||||
<p class="mb-2">Request:</p>
|
||||
<div class="position-relative">
|
||||
<pre
|
||||
class="p-3 rounded border overflow-auto"
|
||||
style="background-color: var(--evcc-box)"
|
||||
class="p-3 overflow-auto"
|
||||
style="background-color: var(--evcc-gray-10)"
|
||||
>{{ formattedRequest }}</pre
|
||||
>
|
||||
<CopyButton :content="formattedRequest" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<div>
|
||||
<p class="mb-2">Response:</p>
|
||||
<div class="position-relative">
|
||||
<pre
|
||||
class="p-3 rounded border overflow-auto"
|
||||
style="background-color: var(--evcc-box)"
|
||||
class="p-3 overflow-auto"
|
||||
style="background-color: var(--evcc-gray-10)"
|
||||
>{{ formattedResponse }}</pre
|
||||
>
|
||||
<CopyButton :content="formattedResponse" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Card>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p>nothing to see here</p>
|
||||
|
|
@ -120,6 +108,7 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent } from "vue";
|
||||
import Header from "../components/Top/Header.vue";
|
||||
import Card from "../components/Helper/Card.vue";
|
||||
import OptimizeHeader from "../components/Optimize/OptimizeHeader.vue";
|
||||
import BatteryConfigurationTable from "../components/Optimize/BatteryConfigurationTable.vue";
|
||||
import SocChart from "../components/Optimize/SocChart.vue";
|
||||
|
|
@ -138,6 +127,7 @@ export default defineComponent({
|
|||
name: "Optimize",
|
||||
components: {
|
||||
TopHeader: Header,
|
||||
Card,
|
||||
OptimizeHeader,
|
||||
BatteryConfigurationTable,
|
||||
SocChart,
|
||||
|
|
@ -176,6 +166,11 @@ export default defineComponent({
|
|||
if (!dt?.length) return 0;
|
||||
return Math.round(dt.reduce((sum, s) => sum + s, 0) / 3600);
|
||||
},
|
||||
batteryEfficiencySubtitle(): string {
|
||||
const etaC = this.fmtPercentage((this.evopt?.req.eta_c || 1) * 100, 1);
|
||||
const etaD = this.fmtPercentage((this.evopt?.req.eta_d || 1) * 100, 1);
|
||||
return `${etaC} charge efficiency ・ ${etaD} discharge efficiency`;
|
||||
},
|
||||
deviceColors() {
|
||||
return deviceColorMap(store.state.deviceColors);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -65,91 +65,98 @@
|
|||
</IconSelectGroup>
|
||||
</div>
|
||||
|
||||
<h3
|
||||
class="fw-normal my-0 d-flex gap-3 flex-wrap d-flex align-items-baseline overflow-hidden"
|
||||
<Card
|
||||
:title="historyTitle"
|
||||
:subtitle="historySubTitle"
|
||||
edge-to-edge
|
||||
class="box-pull-out mb-4"
|
||||
>
|
||||
<span v-if="historyTitle" class="d-block no-wrap text-truncate">
|
||||
{{ historyTitle }}
|
||||
</span>
|
||||
<small class="d-block no-wrap text-truncate">{{ historySubTitle }}</small>
|
||||
</h3>
|
||||
<EnergyHistoryChart
|
||||
v-if="activeType === types.SOLAR"
|
||||
class="mb-5"
|
||||
:sessions="currentSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroup"
|
||||
:period="period"
|
||||
/>
|
||||
<CostHistoryChart
|
||||
v-else
|
||||
class="mb-5"
|
||||
:sessions="currentTypeSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroup"
|
||||
:cost-type="activeType"
|
||||
:currency="currency"
|
||||
:period="period"
|
||||
/>
|
||||
<div v-if="showExtraCharts" class="row align-items-start">
|
||||
<div class="col-12 col-lg-6 mb-5">
|
||||
<h3 class="fw-normal my-4">{{ firstExtraTitle }}</h3>
|
||||
<div v-if="activeType === types.SOLAR">
|
||||
<SolarYearChart
|
||||
v-if="showSolarYearChart"
|
||||
:period="period"
|
||||
:sessions="currentSessions"
|
||||
/>
|
||||
<SolarGroupedChart
|
||||
v-else
|
||||
:sessions="currentSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
/>
|
||||
<EnergyHistoryChart
|
||||
v-if="activeType === types.SOLAR"
|
||||
:sessions="currentSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroup"
|
||||
:period="period"
|
||||
/>
|
||||
<CostHistoryChart
|
||||
v-else
|
||||
:sessions="currentTypeSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroup"
|
||||
:cost-type="activeType"
|
||||
:currency="currency"
|
||||
:period="period"
|
||||
/>
|
||||
</Card>
|
||||
<div v-if="showExtraCharts" class="box-pull-out">
|
||||
<div class="row align-items-start">
|
||||
<div class="col-12 col-lg-6 mb-4">
|
||||
<Card :title="firstExtraTitle" edge-to-edge>
|
||||
<div v-if="activeType === types.SOLAR">
|
||||
<SolarYearChart
|
||||
v-if="showSolarYearChart"
|
||||
:period="period"
|
||||
:sessions="currentSessions"
|
||||
/>
|
||||
<SolarGroupedChart
|
||||
v-else
|
||||
:sessions="currentSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
/>
|
||||
</div>
|
||||
<AvgCostGroupedChart
|
||||
v-else
|
||||
:sessions="currentTypeSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:suggested-max-price="suggestedMaxAvgCost"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
:cost-type="activeType"
|
||||
:currency="currency"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb-4">
|
||||
<Card :title="secondExtraTitle" edge-to-edge>
|
||||
<EnergyGroupedChart
|
||||
v-if="activeType === types.SOLAR"
|
||||
:sessions="currentSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
/>
|
||||
<CostGroupedChart
|
||||
v-else
|
||||
:sessions="currentTypeSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
:cost-type="activeType"
|
||||
:currency="currency"
|
||||
/>
|
||||
</Card>
|
||||
</div>
|
||||
<AvgCostGroupedChart
|
||||
v-else
|
||||
:sessions="currentTypeSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:suggested-max-price="suggestedMaxAvgCost"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
:cost-type="activeType"
|
||||
:currency="currency"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-12 col-lg-6 mb-5">
|
||||
<h3 class="fw-normal my-4">{{ secondExtraTitle }}</h3>
|
||||
<EnergyGroupedChart
|
||||
v-if="activeType === types.SOLAR"
|
||||
:sessions="currentSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
/>
|
||||
<CostGroupedChart
|
||||
v-else
|
||||
:sessions="currentTypeSessions"
|
||||
:color-mappings="colorMappings"
|
||||
:device-colors="deviceColors"
|
||||
:group-by="selectedGroupWithoutNone"
|
||||
:cost-type="activeType"
|
||||
:currency="currency"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<SessionTable
|
||||
<Card
|
||||
v-if="showTable"
|
||||
:sessions="currentSessions"
|
||||
:vehicleFilter="vehicleFilter"
|
||||
:loadpointFilter="loadpointFilter"
|
||||
:currency="currency"
|
||||
@show-session="showDetails"
|
||||
/>
|
||||
:title="$t('sessions.overview')"
|
||||
edge-to-edge
|
||||
class="box-pull-out mb-4"
|
||||
>
|
||||
<SessionTable
|
||||
:sessions="currentSessions"
|
||||
:vehicleFilter="vehicleFilter"
|
||||
:loadpointFilter="loadpointFilter"
|
||||
:currency="currency"
|
||||
@show-session="showDetails"
|
||||
/>
|
||||
</Card>
|
||||
<div class="d-flex gap-2 my-3">
|
||||
<a
|
||||
class="btn btn-outline-secondary"
|
||||
|
|
@ -201,6 +208,7 @@ import CostHistoryChart from "../components/Sessions/CostHistoryChart.vue";
|
|||
import CostGroupedChart from "../components/Sessions/CostGroupedChart.vue";
|
||||
import AvgCostGroupedChart from "../components/Sessions/AvgCostGroupedChart.vue";
|
||||
import Header from "../components/Top/Header.vue";
|
||||
import Card from "../components/Helper/Card.vue";
|
||||
import IconSelectGroup from "../components/Helper/IconSelectGroup.vue";
|
||||
import IconSelectItem from "../components/Helper/IconSelectItem.vue";
|
||||
import SelectGroup from "../components/Helper/SelectGroup.vue";
|
||||
|
|
@ -223,6 +231,7 @@ export default defineComponent({
|
|||
SessionDetailsModal,
|
||||
SessionTable,
|
||||
TopHeader: Header,
|
||||
Card,
|
||||
EnergyHistoryChart,
|
||||
EnergyGroupedChart,
|
||||
IconSelectGroup,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue