forked from jappel/leistungsbilanz-ts
Add optional cable-sizing module
Per-circuit cross-section recommendation as a separate module attached to the circuit list. It never writes project data itself: "Übernehmen" applies cable type, cross-section and length through the regular circuit.update command, so revisions and Undo/Redo stay intact. - Pure domain module (src/cable-sizing) with IEC 60364-5-52:2009 Annex B tables for PVC and XLPE, copper and aluminium, methods A1, A2, B1, B2, C, D1, D2 and E. Every value was cross-checked against public reproductions; where sources differ the lower value is used (docs/cable-sizing-module.md). - Temperature and grouping between table values round to the safer value; values outside the tables return no result instead of a factor of 1. Ground methods use B.52.18 (D2) and B.52.19 A (D1). - Overload protection: circuit-breakers In <= Iz; gG fuses additionally I2 <= 1.45 Iz with I2 = 1.6/1.9/2.1 In. - Inputs prefilled from the circuit: power, phase (group or device rows), project voltage, power-weighted cos phi, length and protective device. - Opened from a "Leitungsberechnung" button in the row actions, not from a grid cell, so cable cells keep the spreadsheet behavior. - Stateless API under /api/cable-sizing; no database table or migration. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d95f0bf5c0
commit
49488f4e1b
17 changed files with 1999 additions and 4 deletions
|
|
@ -5,6 +5,7 @@ import {
|
|||
ArrowDown,
|
||||
ArrowDown01,
|
||||
ArrowUp,
|
||||
Calculator,
|
||||
Check,
|
||||
Columns3,
|
||||
FilterX,
|
||||
|
|
@ -160,6 +161,7 @@ import type {
|
|||
import { DistributionBoardComponentModal } from "./distribution-board-component-modal";
|
||||
import { CircuitGroupModal } from "./circuit-group-modal";
|
||||
import { CircuitProtectionModal } from "./circuit-protection-modal";
|
||||
import { CableSizingModal } from "./cable-sizing-modal";
|
||||
import {
|
||||
circuitGroupCategoryLabels,
|
||||
type CircuitGroupCategory,
|
||||
|
|
@ -319,6 +321,8 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
useState<CircuitGroupEditorIntent | null>(null);
|
||||
const [protectionEditorCircuit, setProtectionEditorCircuit] =
|
||||
useState<CircuitTreeCircuitDto | null>(null);
|
||||
const [cableSizingEditorCircuit, setCableSizingEditorCircuit] =
|
||||
useState<CircuitTreeCircuitDto | null>(null);
|
||||
const [projectDevices, setProjectDevices] = useState<ProjectDeviceDto[]>([]);
|
||||
const [isProjectDeviceDrawerOpen, setIsProjectDeviceDrawerOpen] =
|
||||
useState(false);
|
||||
|
|
@ -1439,6 +1443,31 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
});
|
||||
}
|
||||
|
||||
async function handleApplyCableSizing(patch: {
|
||||
cableCrossSection: string;
|
||||
cableType?: string;
|
||||
cableLength?: number;
|
||||
}) {
|
||||
const circuit = cableSizingEditorCircuit;
|
||||
if (!circuit) {
|
||||
return;
|
||||
}
|
||||
await runCommand({
|
||||
label: "Leitungsberechnung übernehmen",
|
||||
redo: async () => {
|
||||
const result = await updateCircuitById(
|
||||
projectId,
|
||||
getExpectedProjectRevision(),
|
||||
circuit.id,
|
||||
patch
|
||||
);
|
||||
applyProjectCommandResult(result);
|
||||
setCableSizingEditorCircuit(null);
|
||||
return null;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function handleRedo() {
|
||||
if (historyBusy || isSaving || !historyState || historyState.redoDepth === 0) {
|
||||
return;
|
||||
|
|
@ -3185,6 +3214,21 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
onSave={handleSaveCircuitProtection}
|
||||
/>
|
||||
) : null}
|
||||
{cableSizingEditorCircuit ? (
|
||||
<CableSizingModal
|
||||
circuit={cableSizingEditorCircuit}
|
||||
circuitCategory={
|
||||
data.sections.find(
|
||||
(section) => section.id === cableSizingEditorCircuit.sectionId
|
||||
)?.category
|
||||
}
|
||||
isSaving={isSaving}
|
||||
onApply={handleApplyCableSizing}
|
||||
onClose={() => setCableSizingEditorCircuit(null)}
|
||||
singlePhaseVoltageV={data.singlePhaseVoltageV}
|
||||
threePhaseVoltageV={data.threePhaseVoltageV}
|
||||
/>
|
||||
) : null}
|
||||
<div className="editor-toolbar">
|
||||
<IconButton
|
||||
disabled={!historyState || historyState.undoDepth === 0 || historyBusy || isSaving}
|
||||
|
|
@ -4530,6 +4574,14 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||
>
|
||||
{row.circuit && row.rowType !== "deviceRow" ? (
|
||||
<>
|
||||
<IconButton
|
||||
disabled={isSaving}
|
||||
icon={Calculator}
|
||||
label="Leitungsberechnung"
|
||||
onClick={() => setCableSizingEditorCircuit(row.circuit!)}
|
||||
tabIndex={-1}
|
||||
title="Leitungsberechnung: Querschnitt ermitteln oder Kabel eintragen"
|
||||
/>
|
||||
<IconButton
|
||||
disabled={isSaving}
|
||||
icon={ListPlus}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue