Remove legacy consumer UI

This commit is contained in:
2026-07-23 19:23:53 +02:00
parent d7ce135ac8
commit 04c299e3f2
11 changed files with 14 additions and 2491 deletions
@@ -10,4 +10,4 @@
- No full norm-compliant voltage-drop and protection-dimensioning calculation flow yet.
- Sorting is view-only until users explicitly apply sorted order.
- Cross-section circuit drag-reorder is intentionally blocked.
- Legacy consumer and circuit-first paths coexist; migration is transitional and still requires operational discipline.
- The legacy consumer UI has been removed after complete migration; its server endpoints and retained database records are still pending final cleanup.
+3 -2
View File
@@ -46,7 +46,8 @@ Run in this order for local database workflows:
The migration command finishes with a cutover verification across the complete
database. It exits with an error while any legacy consumer lacks a migration
mapping, including consumers that cannot be migrated because they have no circuit
list assignment. Do not remove or disable the legacy path until this check passes.
list assignment. The legacy multi-list UI was removed only after this check passed;
old `/projects/:projectId/circuit-lists` bookmarks redirect to the project page.
## Validation Checks
@@ -77,6 +78,6 @@ Actions:
Do not delete legacy consumers yet.
- legacy endpoints/views remain enabled only until the cutover verification passes
- legacy write endpoints remain temporarily available for the next server cutover step
- migration trace tables reference old/new mapping
- keeping legacy rows allows comparison and rollback validation during transition
@@ -24,9 +24,6 @@ export default function CircuitTreeEditPage() {
<Link href={`/projects/${params.projectId}`} className="btn btn-outline-secondary btn-sm">
Zum Projekt
</Link>
<Link href={`/projects/${params.projectId}/circuit-lists`} className="btn btn-outline-secondary btn-sm">
Bisherige Listenansicht
</Link>
</div>
</div>
<CircuitTreeEditor projectId={params.projectId} circuitListId={params.circuitListId} />
@@ -25,10 +25,10 @@ export default function CircuitTreePreviewPage() {
Editor öffnen
</Link>
<Link
href={`/projects/${projectId}/circuit-lists`}
href={`/projects/${projectId}`}
className="btn btn-outline-secondary btn-sm"
>
Zurück zur bisherigen Listenansicht
Zum Projekt
</Link>
</div>
File diff suppressed because it is too large Load Diff
-11
View File
@@ -607,12 +607,6 @@ export default function ProjectDetailPage() {
Keine Stromkreisliste vorhanden
</span>
)}
<Link
className="btn btn-sm btn-outline-secondary"
href={`/projects/${projectId}/circuit-lists?boardId=${board.id}`}
>
Bisherige Ansicht
</Link>
</div>
</td>
</tr>
@@ -1124,11 +1118,6 @@ export default function ProjectDetailPage() {
) : null}
</section>
<div className="mt-4">
<Link className="btn btn-primary" href={`/projects/${projectId}/circuit-lists`}>
3 parallele Stromkreislisten öffnen
</Link>
</div>
</main>
);
}
-4
View File
@@ -1,4 +0,0 @@
# Components Placeholder
Reusable UI components for project, distribution board, and consumer tables.
@@ -1,666 +0,0 @@
"use client";
import { Activity, FolderPlus, Pencil, Plus, RefreshCw, Save, Trash2, X, Zap } from "lucide-react";
import { FormEvent, useEffect, useMemo, useState } from "react";
import {
createConsumer,
createDistributionBoard,
createProject,
deleteConsumer,
listConsumers,
listDistributionBoards,
listProjects,
updateConsumer,
} from "../utils/api";
import type {
ConsumerWithCalculatedValues,
CreateConsumerInput,
DistributionBoardDto,
ProjectDto,
UpdateConsumerInput,
} from "../types";
const initialConsumerForm = {
name: "",
category: "",
quantity: "1",
installedPowerPerUnitKw: "0.1",
demandFactor: "1",
voltageV: "230",
phaseCount: "1",
powerFactor: "1",
note: "",
};
interface EditConsumerForm {
name: string;
category: string;
distributionBoardId: string;
quantity: string;
installedPowerPerUnitKw: string;
demandFactor: string;
voltageV: string;
phaseCount: "1" | "3";
powerFactor: string;
note: string;
}
type ConsumerForm = typeof initialConsumerForm;
function toOptionalNumber(value: string) {
if (value.trim() === "") {
return undefined;
}
return Number(value);
}
function formatNumber(value: number | undefined, digits = 2) {
if (value === undefined || Number.isNaN(value)) {
return "-";
}
return new Intl.NumberFormat("de-DE", {
maximumFractionDigits: digits,
minimumFractionDigits: digits,
}).format(value);
}
function createEditForm(consumer: ConsumerWithCalculatedValues): EditConsumerForm {
return {
name: consumer.name,
category: consumer.category ?? "",
distributionBoardId: consumer.distributionBoardId ?? "",
quantity: String(consumer.quantity),
installedPowerPerUnitKw: String(consumer.installedPowerPerUnitKw),
demandFactor: String(consumer.demandFactor),
voltageV: consumer.voltageV !== undefined ? String(consumer.voltageV) : "",
phaseCount: consumer.phaseCount === 3 ? "3" : "1",
powerFactor: consumer.powerFactor !== undefined ? String(consumer.powerFactor) : "",
note: consumer.note ?? "",
};
}
export function PowerBalanceWorkspace() {
const [projects, setProjects] = useState<ProjectDto[]>([]);
const [selectedProjectId, setSelectedProjectId] = useState("");
const [distributionBoards, setDistributionBoards] = useState<DistributionBoardDto[]>([]);
const [selectedBoardId, setSelectedBoardId] = useState("");
const [consumers, setConsumers] = useState<ConsumerWithCalculatedValues[]>([]);
const [projectName, setProjectName] = useState("");
const [boardName, setBoardName] = useState("");
const [consumerForm, setConsumerForm] = useState<ConsumerForm>(initialConsumerForm);
const [editingConsumerId, setEditingConsumerId] = useState<string | null>(null);
const [editConsumerForm, setEditConsumerForm] = useState<EditConsumerForm | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState<string | null>(null);
const selectedProject = projects.find((project) => project.id === selectedProjectId);
const selectedBoard = distributionBoards.find((board) => board.id === selectedBoardId);
const boardNames = new Map(distributionBoards.map((board) => [board.id, board.name]));
const visibleConsumers = selectedBoardId
? consumers.filter((consumer) => consumer.distributionBoardId === selectedBoardId)
: consumers;
const totals = useMemo(
() =>
visibleConsumers.reduce(
(sum, consumer) => ({
installedPowerKw: sum.installedPowerKw + consumer.installedPowerKw,
demandPowerKw: sum.demandPowerKw + consumer.demandPowerKw,
}),
{ installedPowerKw: 0, demandPowerKw: 0 }
),
[visibleConsumers]
);
const totalsByBoard = useMemo(() => {
const bucket = new Map<string, { consumerCount: number; installedPowerKw: number; demandPowerKw: number }>();
for (const board of distributionBoards) {
bucket.set(board.id, { consumerCount: 0, installedPowerKw: 0, demandPowerKw: 0 });
}
bucket.set("__unassigned__", { consumerCount: 0, installedPowerKw: 0, demandPowerKw: 0 });
for (const consumer of consumers) {
const key = consumer.distributionBoardId ?? "__unassigned__";
const entry = bucket.get(key);
if (!entry) {
continue;
}
entry.consumerCount += 1;
entry.installedPowerKw += consumer.installedPowerKw;
entry.demandPowerKw += consumer.demandPowerKw;
}
return [
...distributionBoards.map((board) => ({
key: board.id,
boardName: board.name,
...bucket.get(board.id)!,
})),
{
key: "__unassigned__",
boardName: "Ohne Verteilung",
...bucket.get("__unassigned__")!,
},
].filter((item) => item.consumerCount > 0);
}, [consumers, distributionBoards]);
const projectTotals = useMemo(
() =>
consumers.reduce(
(sum, consumer) => ({
consumerCount: sum.consumerCount + 1,
installedPowerKw: sum.installedPowerKw + consumer.installedPowerKw,
demandPowerKw: sum.demandPowerKw + consumer.demandPowerKw,
}),
{ consumerCount: 0, installedPowerKw: 0, demandPowerKw: 0 }
),
[consumers]
);
async function refreshProjects() {
setError(null);
const loadedProjects = await listProjects();
setProjects(loadedProjects);
setSelectedProjectId((current) => current || loadedProjects[0]?.id || "");
}
async function refreshConsumers(projectId: string) {
if (!projectId) {
setConsumers([]);
return;
}
setError(null);
setConsumers(await listConsumers(projectId));
}
async function refreshDistributionBoards(projectId: string) {
if (!projectId) {
setDistributionBoards([]);
setSelectedBoardId("");
return;
}
setError(null);
const boards = await listDistributionBoards(projectId);
setDistributionBoards(boards);
setSelectedBoardId((current) => (boards.some((board) => board.id === current) ? current : boards[0]?.id || ""));
}
useEffect(() => {
refreshProjects()
.catch((err: unknown) => setError(err instanceof Error ? err.message : "Projekte konnten nicht geladen werden."))
.finally(() => setIsLoading(false));
}, []);
useEffect(() => {
setEditingConsumerId(null);
setEditConsumerForm(null);
refreshDistributionBoards(selectedProjectId).catch((err: unknown) =>
setError(err instanceof Error ? err.message : "Verteilungen konnten nicht geladen werden.")
);
refreshConsumers(selectedProjectId).catch((err: unknown) =>
setError(err instanceof Error ? err.message : "Verbraucher konnten nicht geladen werden.")
);
}, [selectedProjectId]);
async function handleCreateProject(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const name = projectName.trim();
if (!name) {
return;
}
setIsSaving(true);
setError(null);
try {
const project = await createProject(name);
setProjects((current) => [...current, project]);
setSelectedProjectId(project.id);
setProjectName("");
} catch (err) {
setError(err instanceof Error ? err.message : "Projekt konnte nicht angelegt werden.");
} finally {
setIsSaving(false);
}
}
async function handleCreateDistributionBoard(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const name = boardName.trim();
if (!selectedProjectId || !name) {
return;
}
setIsSaving(true);
setError(null);
try {
const board = await createDistributionBoard(selectedProjectId, name);
setDistributionBoards((current) => [...current, board]);
setSelectedBoardId(board.id);
setBoardName("");
} catch (err) {
setError(err instanceof Error ? err.message : "Verteilung konnte nicht angelegt werden.");
} finally {
setIsSaving(false);
}
}
async function handleCreateConsumer(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
if (!selectedProjectId || !consumerForm.name.trim()) {
return;
}
const input: CreateConsumerInput = {
projectId: selectedProjectId,
distributionBoardId: selectedBoardId || undefined,
name: consumerForm.name.trim(),
category: consumerForm.category.trim() || undefined,
quantity: Number(consumerForm.quantity),
installedPowerPerUnitKw: Number(consumerForm.installedPowerPerUnitKw),
demandFactor: Number(consumerForm.demandFactor),
voltageV: toOptionalNumber(consumerForm.voltageV),
phaseCount: consumerForm.phaseCount === "3" ? 3 : 1,
powerFactor: toOptionalNumber(consumerForm.powerFactor),
note: consumerForm.note.trim() || undefined,
};
setIsSaving(true);
setError(null);
try {
const created = await createConsumer(input);
setConsumers((current) => [...current, created]);
setConsumerForm(initialConsumerForm);
} catch (err) {
setError(err instanceof Error ? err.message : "Verbraucher konnte nicht angelegt werden.");
} finally {
setIsSaving(false);
}
}
async function handleSaveConsumer(consumerId: string) {
if (!selectedProjectId || !editConsumerForm) {
return;
}
const input: UpdateConsumerInput = {
projectId: selectedProjectId,
distributionBoardId: editConsumerForm.distributionBoardId || undefined,
name: editConsumerForm.name.trim(),
category: editConsumerForm.category.trim() || undefined,
quantity: Number(editConsumerForm.quantity),
installedPowerPerUnitKw: Number(editConsumerForm.installedPowerPerUnitKw),
demandFactor: Number(editConsumerForm.demandFactor),
voltageV: toOptionalNumber(editConsumerForm.voltageV),
phaseCount: editConsumerForm.phaseCount === "3" ? 3 : 1,
powerFactor: toOptionalNumber(editConsumerForm.powerFactor),
note: editConsumerForm.note.trim() || undefined,
};
setIsSaving(true);
setError(null);
try {
const updated = await updateConsumer(consumerId, input);
setConsumers((current) => current.map((item) => (item.id === consumerId ? updated : item)));
setEditingConsumerId(null);
setEditConsumerForm(null);
} catch (err) {
setError(err instanceof Error ? err.message : "Verbraucher konnte nicht gespeichert werden.");
} finally {
setIsSaving(false);
}
}
async function handleDeleteConsumer(consumerId: string) {
setIsSaving(true);
setError(null);
try {
await deleteConsumer(consumerId);
setConsumers((current) => current.filter((item) => item.id !== consumerId));
if (editingConsumerId === consumerId) {
setEditingConsumerId(null);
setEditConsumerForm(null);
}
} catch (err) {
setError(err instanceof Error ? err.message : "Verbraucher konnte nicht gelöscht werden.");
} finally {
setIsSaving(false);
}
}
function startEditConsumer(consumer: ConsumerWithCalculatedValues) {
setEditingConsumerId(consumer.id);
setEditConsumerForm(createEditForm(consumer));
}
function cancelEditConsumer() {
setEditingConsumerId(null);
setEditConsumerForm(null);
}
function updateConsumerForm(field: keyof ConsumerForm, value: string) {
setConsumerForm((current) => ({ ...current, [field]: value }));
}
function updateEditConsumerForm(field: keyof EditConsumerForm, value: string) {
setEditConsumerForm((current) => (current ? { ...current, [field]: value } : current));
}
return (
<main className="workspace">
<header className="topbar">
<div>
<p className="eyebrow">TGA / ELT Planung</p>
<h1>Leistungsbilanz</h1>
</div>
<button className="iconButton" type="button" onClick={() => refreshConsumers(selectedProjectId)} title="Aktualisieren">
<RefreshCw size={18} />
</button>
</header>
{error ? <p className="alert">{error}</p> : null}
<section className="toolbarBand">
<form className="projectForm" onSubmit={handleCreateProject}>
<label>
Projekt
<select value={selectedProjectId} onChange={(event) => setSelectedProjectId(event.target.value)}>
<option value="">Kein Projekt</option>
{projects.map((project) => (
<option key={project.id} value={project.id}>
{project.name}
</option>
))}
</select>
</label>
<label>
Neues Projekt
<input value={projectName} onChange={(event) => setProjectName(event.target.value)} placeholder="z. B. BV Neubau" />
</label>
<button className="primaryButton" type="submit" disabled={isSaving}>
<FolderPlus size={17} />
Anlegen
</button>
</form>
<form className="boardForm" onSubmit={handleCreateDistributionBoard}>
<label>
Verteilung
<select value={selectedBoardId} onChange={(event) => setSelectedBoardId(event.target.value)}>
<option value="">Alle Verteilungen</option>
{distributionBoards.map((board) => (
<option key={board.id} value={board.id}>
{board.name}
</option>
))}
</select>
</label>
<label>
Neue Verteilung
<input value={boardName} onChange={(event) => setBoardName(event.target.value)} placeholder="z. B. UV-01" />
</label>
<button className="primaryButton" type="submit" disabled={!selectedProjectId || isSaving}>
<Plus size={17} />
Anlegen
</button>
</form>
<div className="summaryStrip" aria-label="Summen">
<div>
<span>Verbraucher</span>
<strong>{visibleConsumers.length}</strong>
</div>
<div>
<span>Installierte Leistung</span>
<strong>{formatNumber(totals.installedPowerKw)} kW</strong>
</div>
<div>
<span>Berechnete Leistung</span>
<strong>{formatNumber(totals.demandPowerKw)} kW</strong>
</div>
</div>
</section>
<section className="entryBand">
<form className="consumerForm" onSubmit={handleCreateConsumer}>
<label>
Verbraucher
<input value={consumerForm.name} onChange={(event) => updateConsumerForm("name", event.target.value)} placeholder="z. B. Steckdosen Büro" />
</label>
<label>
Kategorie
<input value={consumerForm.category} onChange={(event) => updateConsumerForm("category", event.target.value)} placeholder="Allgemein" />
</label>
<label>
Anzahl
<input min="0" type="number" value={consumerForm.quantity} onChange={(event) => updateConsumerForm("quantity", event.target.value)} />
</label>
<label>
Leistung je Stück [kW]
<input min="0" step="0.01" type="number" value={consumerForm.installedPowerPerUnitKw} onChange={(event) => updateConsumerForm("installedPowerPerUnitKw", event.target.value)} />
</label>
<label>
Gleichzeitigkeitsfaktor
<input min="0" max="1" step="0.01" type="number" value={consumerForm.demandFactor} onChange={(event) => updateConsumerForm("demandFactor", event.target.value)} />
</label>
<label>
Spannung [V]
<input min="1" type="number" value={consumerForm.voltageV} onChange={(event) => updateConsumerForm("voltageV", event.target.value)} />
</label>
<label>
Phasen
<select value={consumerForm.phaseCount} onChange={(event) => updateConsumerForm("phaseCount", event.target.value)}>
<option value="1">1-phasig</option>
<option value="3">3-phasig</option>
</select>
</label>
<label>
cos phi
<input min="0" max="1" step="0.01" type="number" value={consumerForm.powerFactor} onChange={(event) => updateConsumerForm("powerFactor", event.target.value)} />
</label>
<label className="wideField">
Bemerkung
<input value={consumerForm.note} onChange={(event) => updateConsumerForm("note", event.target.value)} />
</label>
<button className="primaryButton" type="submit" disabled={!selectedProjectId || isSaving}>
<Plus size={17} />
Hinzufügen
</button>
</form>
</section>
<section className="tableBand">
<div className="tableHeader">
<div>
<p className="eyebrow">Aktuelles Projekt</p>
<h2>{selectedProject?.name || "Noch kein Projekt ausgewählt"}</h2>
<p className="subline">{selectedBoard ? `Verteilung: ${selectedBoard.name}` : "Alle Verteilungen"}</p>
</div>
<div className="statusPill">
<Activity size={16} />
{isLoading ? "Lädt" : "Bereit"}
</div>
</div>
<div className="boardTotals">
<h3>Summen nach Verteilung</h3>
<div className="tableScroll">
<table>
<thead>
<tr>
<th>Verteilung</th>
<th>Verbraucher</th>
<th>Installierte Leistung [kW]</th>
<th>Berechnete Leistung [kW]</th>
</tr>
</thead>
<tbody>
{totalsByBoard.map((item) => (
<tr key={item.key}>
<td>{item.boardName}</td>
<td>{item.consumerCount}</td>
<td>{formatNumber(item.installedPowerKw)}</td>
<td>{formatNumber(item.demandPowerKw)}</td>
</tr>
))}
{!totalsByBoard.length ? (
<tr>
<td colSpan={4} className="emptyState">
Noch keine Verbraucher für eine Summenbildung vorhanden.
</td>
</tr>
) : null}
<tr className="totalRow">
<td>Projekt gesamt</td>
<td>{projectTotals.consumerCount}</td>
<td>{formatNumber(projectTotals.installedPowerKw)}</td>
<td>{formatNumber(projectTotals.demandPowerKw)}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="tableScroll">
<table>
<thead>
<tr>
<th>Verbraucher</th>
<th>Verteilung</th>
<th>Kategorie</th>
<th>Anzahl</th>
<th>Leistung je Stück [kW]</th>
<th>Installierte Leistung [kW]</th>
<th>GZF</th>
<th>Berechnete Leistung [kW]</th>
<th>Strom [A]</th>
<th>Bemerkung</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{visibleConsumers.map((consumer) => {
const isEditing = editingConsumerId === consumer.id && editConsumerForm;
return (
<tr key={consumer.id}>
<td className="nameCell">
<Zap size={15} />
{isEditing ? (
<input value={editConsumerForm.name} onChange={(event) => updateEditConsumerForm("name", event.target.value)} />
) : (
consumer.name
)}
</td>
<td>
{isEditing ? (
<select
value={editConsumerForm.distributionBoardId}
onChange={(event) => updateEditConsumerForm("distributionBoardId", event.target.value)}
>
<option value="">-</option>
{distributionBoards.map((board) => (
<option key={board.id} value={board.id}>
{board.name}
</option>
))}
</select>
) : consumer.distributionBoardId ? (
boardNames.get(consumer.distributionBoardId) || "-"
) : (
"-"
)}
</td>
<td>
{isEditing ? (
<input value={editConsumerForm.category} onChange={(event) => updateEditConsumerForm("category", event.target.value)} />
) : (
consumer.category || "-"
)}
</td>
<td>
{isEditing ? (
<input min="0" type="number" value={editConsumerForm.quantity} onChange={(event) => updateEditConsumerForm("quantity", event.target.value)} />
) : (
consumer.quantity
)}
</td>
<td>
{isEditing ? (
<input
min="0"
step="0.01"
type="number"
value={editConsumerForm.installedPowerPerUnitKw}
onChange={(event) => updateEditConsumerForm("installedPowerPerUnitKw", event.target.value)}
/>
) : (
formatNumber(consumer.installedPowerPerUnitKw)
)}
</td>
<td>{formatNumber(consumer.installedPowerKw)}</td>
<td>
{isEditing ? (
<input min="0" max="1" step="0.01" type="number" value={editConsumerForm.demandFactor} onChange={(event) => updateEditConsumerForm("demandFactor", event.target.value)} />
) : (
formatNumber(consumer.demandFactor)
)}
</td>
<td>{formatNumber(consumer.demandPowerKw)}</td>
<td>
{isEditing ? (
<div className="rowField">
<input min="1" type="number" value={editConsumerForm.voltageV} onChange={(event) => updateEditConsumerForm("voltageV", event.target.value)} />
<select value={editConsumerForm.phaseCount} onChange={(event) => updateEditConsumerForm("phaseCount", event.target.value)}>
<option value="1">1</option>
<option value="3">3</option>
</select>
<input min="0" max="1" step="0.01" type="number" value={editConsumerForm.powerFactor} onChange={(event) => updateEditConsumerForm("powerFactor", event.target.value)} />
</div>
) : (
formatNumber(consumer.currentA)
)}
</td>
<td>
{isEditing ? (
<input value={editConsumerForm.note} onChange={(event) => updateEditConsumerForm("note", event.target.value)} />
) : (
consumer.note || "-"
)}
</td>
<td>
<div className="rowActions">
{isEditing ? (
<>
<button className="iconButton small" type="button" title="Speichern" onClick={() => handleSaveConsumer(consumer.id)} disabled={isSaving}>
<Save size={14} />
</button>
<button className="iconButton small muted" type="button" title="Abbrechen" onClick={cancelEditConsumer}>
<X size={14} />
</button>
</>
) : (
<button className="iconButton small" type="button" title="Bearbeiten" onClick={() => startEditConsumer(consumer)}>
<Pencil size={14} />
</button>
)}
<button className="iconButton small danger" type="button" title="Löschen" onClick={() => handleDeleteConsumer(consumer.id)} disabled={isSaving}>
<Trash2 size={14} />
</button>
</div>
</td>
</tr>
);
})}
{!visibleConsumers.length ? (
<tr>
<td colSpan={11} className="emptyState">
Lege eine Verteilung an oder erfasse den ersten Verbraucher.
</td>
</tr>
) : null}
</tbody>
</table>
</div>
</section>
</main>
);
}
-77
View File
@@ -5,45 +5,6 @@ export interface ProjectDto {
threePhaseVoltageV: number;
}
export interface ConsumerWithCalculatedValues {
id: string;
projectId: string;
distributionBoardId?: string | null;
circuitListId?: string | null;
projectDeviceId?: string | null;
isLinkedToDevice?: boolean;
roomId?: string | null;
roomNumber?: string;
roomName?: string;
floorId?: string;
floorName?: string;
circuitNumber?: string;
description?: string;
name: string;
category?: string;
deviceType?: string;
phaseType?: string;
tradeOrCostGroup?: string;
group?: string;
protectionType?: string;
protectionRatedCurrent?: number;
protectionCharacteristic?: string;
cableType?: string;
cableCrossSection?: string;
comment?: string;
quantity: number;
installedPowerPerUnitKw: number;
demandFactor: number;
voltageV?: number;
phaseCount?: 1 | 3;
powerFactor?: number;
note?: string;
installedPowerKw: number;
demandPowerKw: number;
effectiveVoltageV?: number;
currentA?: number;
}
export interface DistributionBoardDto {
id: string;
projectId: string;
@@ -101,47 +62,9 @@ export interface ProjectDeviceDto {
totalPower: number;
cosPhi: number | null;
remark: string | null;
// Legacy aliases retained until the old Consumer editor is removed.
installedPowerPerUnitKw: number;
demandFactor: number;
voltageV: number | null;
phaseCount: 1 | 3 | null;
powerFactor: number | null;
note: string | null;
}
export interface CreateConsumerInput {
projectId: string;
distributionBoardId?: string;
circuitListId?: string;
projectDeviceId?: string;
isLinkedToDevice?: boolean;
roomId?: string;
circuitNumber?: string;
description?: string;
name: string;
category?: string;
deviceType?: string;
phaseType?: string;
tradeOrCostGroup?: string;
group?: string;
protectionType?: string;
protectionRatedCurrent?: number;
protectionCharacteristic?: string;
cableType?: string;
cableCrossSection?: string;
comment?: string;
quantity: number;
installedPowerPerUnitKw: number;
demandFactor: number;
voltageV?: number;
phaseCount?: 1 | 3;
powerFactor?: number;
note?: string;
}
export interface UpdateConsumerInput extends CreateConsumerInput {}
export interface CreateFloorInput {
name: string;
}
-25
View File
@@ -3,8 +3,6 @@ import type {
CreateFloorInput,
CreateProjectDeviceInput,
CreateRoomInput,
ConsumerWithCalculatedValues,
CreateConsumerInput,
CreateGlobalDeviceInput,
DistributionBoardDto,
FloorDto,
@@ -16,7 +14,6 @@ import type {
ProjectDeviceSyncResultDto,
ProjectDto,
RoomDto,
UpdateConsumerInput,
CircuitTreeResponseDto,
CircuitTreeCircuitDto,
CircuitTreeDeviceRowDto,
@@ -229,28 +226,6 @@ export function createRoom(projectId: string, input: CreateRoomInput) {
});
}
export function listConsumers(projectId: string) {
return request<ConsumerWithCalculatedValues[]>(`/api/consumers/projects/${projectId}`);
}
export function createConsumer(input: CreateConsumerInput) {
return request<ConsumerWithCalculatedValues>("/api/consumers", {
method: "POST",
body: JSON.stringify(input),
});
}
export function updateConsumer(consumerId: string, input: UpdateConsumerInput) {
return request<ConsumerWithCalculatedValues>(`/api/consumers/${consumerId}`, {
method: "PUT",
body: JSON.stringify(input),
});
}
export function deleteConsumer(consumerId: string) {
return request<void>(`/api/consumers/${consumerId}`, { method: "DELETE" });
}
export function listGlobalDevices() {
return request<GlobalDeviceDto[]>("/api/global-devices");
}
-39
View File
@@ -1,39 +0,0 @@
export interface ProjectDto {
id: string;
name: string;
}
export interface DistributionBoardDto {
id: string;
projectId: string;
name: string;
}
export interface ConsumerDto {
id: string;
projectId: string;
distributionBoardId: string | null;
circuitListId: string | null;
roomId: string | null;
circuitNumber: string | null;
description: string | null;
name: string;
category: string | null;
deviceType: string | null;
phaseType: string | null;
tradeOrCostGroup: string | null;
group: string | null;
protectionType: string | null;
protectionRatedCurrent: number | null;
protectionCharacteristic: string | null;
cableType: string | null;
cableCrossSection: string | null;
comment: string | null;
quantity: number;
installedPowerPerUnitKw: number;
demandFactor: number;
voltageV: number | null;
phaseCount: 1 | 3 | null;
powerFactor: number | null;
note: string | null;
}