update sodistore home information tab based on weekly meeting's feedback
This commit is contained in:
parent
baaabbecd0
commit
0657a5fb82
|
|
@ -27,6 +27,13 @@ public class Installation : TreeNode
|
|||
public String Location { get; set; } = "";
|
||||
public String Region { get; set; } = "";
|
||||
public String Country { get; set; } = "";
|
||||
public String Street { get; set; } = "";
|
||||
public String PostCode { get; set; } = "";
|
||||
public String City { get; set; } = "";
|
||||
public String Canton { get; set; } = "";
|
||||
public String DistributionPartner { get; set; } = "";
|
||||
public String InverterFirmwareVersion { get; set; } = "";
|
||||
public String BatteryFirmwareVersion { get; set; } = "";
|
||||
public String VpnIp { get; set; } = "";
|
||||
public String InstallationName { get; set; } = "";
|
||||
|
||||
|
|
|
|||
|
|
@ -364,12 +364,15 @@ public static class ReportAggregationService
|
|||
var installationName = installation?.Name ?? $"Installation {installationId}";
|
||||
var monthName = new DateTime(year, month, 1).ToString("MMMM yyyy");
|
||||
|
||||
var weatherCity = !string.IsNullOrWhiteSpace(installation?.City) ? installation.City : installation?.Location;
|
||||
var weatherRegion = !string.IsNullOrWhiteSpace(installation?.Canton) ? installation.Canton : installation?.Region;
|
||||
|
||||
var aiInsight = await GenerateMonthlyAiInsightAsync(
|
||||
installationName, monthName, days.Count,
|
||||
totalPv, totalConsump, totalGridIn, totalGridOut,
|
||||
totalBattChg, totalBattDis, energySaved, savingsCHF,
|
||||
selfSufficiency, batteryEff, language,
|
||||
installation?.Location, installation?.Country, installation?.Region);
|
||||
weatherCity, installation?.Country, weatherRegion);
|
||||
|
||||
var monthlySummary = new MonthlyReportSummary
|
||||
{
|
||||
|
|
@ -591,6 +594,8 @@ public static class ReportAggregationService
|
|||
var installationName = installation?.Name
|
||||
?? $"Installation {report.InstallationId}";
|
||||
var monthName = new DateTime(report.Year, report.Month, 1).ToString("MMMM yyyy");
|
||||
var weatherCity = !string.IsNullOrWhiteSpace(installation?.City) ? installation.City : installation?.Location;
|
||||
var weatherRegion = !string.IsNullOrWhiteSpace(installation?.Canton) ? installation.Canton : installation?.Region;
|
||||
return GetOrGenerateInsightAsync("monthly", report.Id, language,
|
||||
() => GenerateMonthlyAiInsightAsync(
|
||||
installationName, monthName, report.WeekCount,
|
||||
|
|
@ -599,7 +604,7 @@ public static class ReportAggregationService
|
|||
report.TotalBatteryCharged, report.TotalBatteryDischarged,
|
||||
report.TotalEnergySaved, report.TotalSavingsCHF,
|
||||
report.SelfSufficiencyPercent, report.BatteryEfficiencyPercent, language,
|
||||
installation?.Location, installation?.Country, installation?.Region));
|
||||
weatherCity, installation?.Country, weatherRegion));
|
||||
}
|
||||
|
||||
/// <summary>Cached-or-generated AI insight for a stored YearlyReportSummary.</summary>
|
||||
|
|
|
|||
|
|
@ -179,9 +179,9 @@ public static class WeeklyReportService
|
|||
|
||||
// 4. Get installation location for weather forecast
|
||||
var installation = Db.GetInstallationById(installationId);
|
||||
var location = installation?.Location;
|
||||
var location = !string.IsNullOrWhiteSpace(installation?.City) ? installation.City : installation?.Location;
|
||||
var country = installation?.Country;
|
||||
var region = installation?.Region;
|
||||
var region = !string.IsNullOrWhiteSpace(installation?.Canton) ? installation.Canton : installation?.Region;
|
||||
Console.WriteLine($"[WeeklyReportService] Installation {installationId}: Location='{location}', Region='{region}', Country='{country}', HourlyRecords={currentHourlyData.Count}");
|
||||
|
||||
return await GenerateReportFromDataAsync(
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
const theme = useTheme();
|
||||
const intl = useIntl();
|
||||
const [formValues, setFormValues] = useState(props.values);
|
||||
const requiredFields = ['name', 'region', 'location', 'country'];
|
||||
const requiredFields = ['name'];
|
||||
const [openModalDeleteInstallation, setOpenModalDeleteInstallation] =
|
||||
useState(false);
|
||||
const [pendingPreset, setPendingPreset] = useState<string | null>(null);
|
||||
|
|
@ -95,7 +95,7 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
|
||||
const DeviceTypes = [
|
||||
{ id: 3, name: 'Growatt' },
|
||||
{ id: 4, name: 'Sinexcel' }
|
||||
{ id: 4, name: 'inesco 12K - WR Hybrid' }
|
||||
];
|
||||
|
||||
// Preset state — initializes from persisted installationModel, empty for legacy
|
||||
|
|
@ -533,27 +533,45 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="region" defaultMessage="Region" />}
|
||||
name="region"
|
||||
value={formValues.region}
|
||||
label={<FormattedMessage id="street" defaultMessage="Street" />}
|
||||
name="street"
|
||||
value={formValues.street || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
required={canEdit}
|
||||
error={canEdit && formValues.region === ''}
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="location" defaultMessage="Location" />}
|
||||
name="location"
|
||||
value={formValues.location}
|
||||
label={<FormattedMessage id="postCode" defaultMessage="Postcode" />}
|
||||
name="postCode"
|
||||
value={formValues.postCode || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="city" defaultMessage="City" />}
|
||||
name="city"
|
||||
value={formValues.city || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="canton" defaultMessage="Canton" />}
|
||||
name="canton"
|
||||
value={formValues.canton || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
required={canEdit}
|
||||
error={canEdit && formValues.location === ''}
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -561,12 +579,21 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
<TextField
|
||||
label={<FormattedMessage id="country" defaultMessage="Country" />}
|
||||
name="country"
|
||||
value={formValues.country}
|
||||
value={formValues.country || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="distributionPartner" defaultMessage="Distribution Partner" />}
|
||||
name="distributionPartner"
|
||||
value={formValues.distributionPartner || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
required={canEdit}
|
||||
error={canEdit && formValues.country === ''}
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -696,6 +723,18 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
<FormattedMessage id="installationSetup" defaultMessage="Installation Setup" />
|
||||
</Typography>
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="installationSerialNumber" defaultMessage="Installation Serial Number" />}
|
||||
name="serialNumber"
|
||||
value={formValues.serialNumber || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<FormControl sx={{ m: 1, width: '50ch' }}>
|
||||
<InputLabel
|
||||
|
|
@ -725,9 +764,21 @@ function InformationSodistorehome(props: InformationSodistorehomeProps) {
|
|||
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="installationSerialNumber" defaultMessage="Installation Serial Number" />}
|
||||
name="serialNumber"
|
||||
value={formValues.serialNumber}
|
||||
label={<FormattedMessage id="inverterFirmwareVersion" defaultMessage="Inverter Firmware Version" />}
|
||||
name="inverterFirmwareVersion"
|
||||
value={formValues.inverterFirmwareVersion || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
inputProps={{ readOnly: !canEdit }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="batteryFirmwareVersion" defaultMessage="Battery Firmware Version" />}
|
||||
name="batteryFirmwareVersion"
|
||||
value={formValues.batteryFirmwareVersion || ''}
|
||||
onChange={handleChange}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ function Log(props: LogProps) {
|
|||
onChange={e => { setDemoAlarm(e.target.value); setDemoResult(null); }}
|
||||
sx={{ minWidth: 260 }}
|
||||
>
|
||||
<ListSubheader>Sinexcel</ListSubheader>
|
||||
<ListSubheader>inesco 12K - WR Hybrid</ListSubheader>
|
||||
{DEMO_ALARMS.sinexcel.map(a => (
|
||||
<MenuItem key={a} value={a}>{a}</MenuItem>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -96,14 +96,14 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
<TableCell>
|
||||
<FormattedMessage id="name" defaultMessage="Name" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="location" defaultMessage="Location" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="installationSN" defaultMessage="Installation SN" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="region" defaultMessage="Region" />
|
||||
<FormattedMessage id="DeviceType" defaultMessage="Device Type" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="canton" defaultMessage="Canton" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="country" defaultMessage="Country" />
|
||||
|
|
@ -146,19 +146,6 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.location}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
|
|
@ -181,7 +168,20 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.region}
|
||||
{installation.device === 3 ? 'Growatt' : installation.device === 4 ? 'inesco 12K - WR Hybrid' : ''}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.canton || ''}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,18 +30,15 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
const [open, setOpen] = useState(true);
|
||||
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
|
||||
name: '',
|
||||
region: '',
|
||||
location: '',
|
||||
country: '',
|
||||
vpnIp: '',
|
||||
installationModel: '',
|
||||
externalEms: 'No',
|
||||
});
|
||||
const requiredFields = ['name', 'location', 'country', 'vpnIp', 'installationModel'];
|
||||
const requiredFields = ['name', 'vpnIp', 'installationModel'];
|
||||
|
||||
const DeviceTypes = [
|
||||
{ id: 3, name: 'Growatt' },
|
||||
{ id: 4, name: 'Sinexcel' }
|
||||
{ id: 4, name: 'inesco 12K - WR Hybrid' }
|
||||
];
|
||||
const installationContext = useContext(InstallationsContext);
|
||||
const { createInstallation, loading, setLoading, error, setError } =
|
||||
|
|
@ -127,42 +124,6 @@ function SodistorehomeInstallationForm(props: SodistorehomeInstallationFormPros)
|
|||
error={formValues.name === ''}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="region" defaultMessage="Region" />}
|
||||
name="region"
|
||||
value={formValues.region}
|
||||
onChange={handleChange}
|
||||
required
|
||||
error={formValues.region === ''}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label={
|
||||
<FormattedMessage id="location" defaultMessage="Location" />
|
||||
}
|
||||
name="location"
|
||||
value={formValues.location}
|
||||
onChange={handleChange}
|
||||
required
|
||||
error={formValues.location === ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label={
|
||||
<FormattedMessage id="country" defaultMessage="Country" />
|
||||
}
|
||||
name="country"
|
||||
value={formValues.country}
|
||||
onChange={handleChange}
|
||||
required
|
||||
error={formValues.country === ''}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label={<FormattedMessage id="VpnIp" defaultMessage="VpnIp" />}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ const deviceOptionsByProduct: Record<number, { value: number; label: string }[]>
|
|||
],
|
||||
2: [
|
||||
{ value: 3, label: 'Growatt' },
|
||||
{ value: 4, label: 'Sinexcel' }
|
||||
{ value: 4, label: 'inesco 12K - WR Hybrid' }
|
||||
]
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,13 @@ export interface I_Installation extends I_S3Credentials {
|
|||
location: string;
|
||||
region: string;
|
||||
country: string;
|
||||
street?: string;
|
||||
postCode?: string;
|
||||
city?: string;
|
||||
canton?: string;
|
||||
distributionPartner?: string;
|
||||
inverterFirmwareVersion?: string;
|
||||
batteryFirmwareVersion?: string;
|
||||
installationName: string;
|
||||
vpnIp: string;
|
||||
orderNumbers: string[] | string;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,13 @@
|
|||
"alarms": "Alarme",
|
||||
"applyChanges": "Änderungen speichern",
|
||||
"country": "Land",
|
||||
"street": "Strasse",
|
||||
"postCode": "PLZ",
|
||||
"city": "Ort",
|
||||
"canton": "Kanton",
|
||||
"distributionPartner": "Vertriebspartner",
|
||||
"inverterFirmwareVersion": "Wechselrichter-Firmware-Version",
|
||||
"batteryFirmwareVersion": "Batterie-Firmware-Version",
|
||||
"networkProvider": "Netzbetreiber",
|
||||
"createNewFolder": "Neuer Ordner",
|
||||
"createNewUser": "Neuer Benutzer",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@
|
|||
"allInstallations": "All installations",
|
||||
"applyChanges": "Apply changes",
|
||||
"country": "Country",
|
||||
"street": "Street",
|
||||
"postCode": "Postcode",
|
||||
"city": "City",
|
||||
"canton": "Canton",
|
||||
"distributionPartner": "Distribution Partner",
|
||||
"inverterFirmwareVersion": "Inverter Firmware Version",
|
||||
"batteryFirmwareVersion": "Battery Firmware Version",
|
||||
"networkProvider": "Network Provider",
|
||||
"customerName": "Customer name",
|
||||
"english": "English",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@
|
|||
"alarms": "Alarmes",
|
||||
"applyChanges": "Appliquer",
|
||||
"country": "Pays",
|
||||
"street": "Rue",
|
||||
"postCode": "Code postal",
|
||||
"city": "Ville",
|
||||
"canton": "Canton",
|
||||
"distributionPartner": "Partenaire de distribution",
|
||||
"inverterFirmwareVersion": "Version firmware onduleur",
|
||||
"batteryFirmwareVersion": "Version firmware batterie",
|
||||
"networkProvider": "Gestionnaire de réseau",
|
||||
"createNewFolder": "Nouveau dossier",
|
||||
"createNewUser": "Nouvel utilisateur",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,13 @@
|
|||
"allInstallations": "Tutte le installazioni",
|
||||
"applyChanges": "Applica modifiche",
|
||||
"country": "Paese",
|
||||
"street": "Via",
|
||||
"postCode": "CAP",
|
||||
"city": "Città",
|
||||
"canton": "Cantone",
|
||||
"distributionPartner": "Partner di distribuzione",
|
||||
"inverterFirmwareVersion": "Versione firmware inverter",
|
||||
"batteryFirmwareVersion": "Versione firmware batteria",
|
||||
"networkProvider": "Gestore di rete",
|
||||
"customerName": "Nome cliente",
|
||||
"english": "Inglese",
|
||||
|
|
|
|||
Loading…
Reference in New Issue