Fix: Elektro-Input Remount, Bestellungen Ladeschleife durch kalkulator3d API-Format

This commit is contained in:
2026-05-31 14:41:21 +02:00
parent 9955fc77b7
commit 70fac26709
2 changed files with 58 additions and 47 deletions

View File

@@ -47,7 +47,7 @@ function BestellungDetail({ id, toast, onBack }) {
const [form, setForm] = useState({ name:'', bemerkung:'', custom_price:'', status:'warteliste' }); const [form, setForm] = useState({ name:'', bemerkung:'', custom_price:'', status:'warteliste' });
useEffect(() => { useEffect(() => {
api('/tools/kalkulator3d').then(setArchiv).catch(()=>{}); api('/tools/kalkulator3d').then(d => setArchiv(d.own || d || [])).catch(()=>{});
if (id) { if (id) {
api(`/tools/bestellungen/${id}`) api(`/tools/bestellungen/${id}`)
.then(o => { setOrder(o); setForm({ name:o.name, bemerkung:o.bemerkung, custom_price:o.custom_price??'', status:o.status }); }) .then(o => { setOrder(o); setForm({ name:o.name, bemerkung:o.bemerkung, custom_price:o.custom_price??'', status:o.status }); })

View File

@@ -270,27 +270,22 @@ function CronBuilder() {
} }
// ── Tool-Definitionen ───────────────────────────────────────────────────────── // ── Tool-Definitionen ─────────────────────────────────────────────────────────
// ── Elektro-Rechner ─────────────────────────────────────────────────────────── // ── Elektro-Hilfskomponenten (AUSSERHALB damit keine Remounts) ────────────────
function ElektroRechner({ mobile }) { function ElektroInp({ vals, setVals, k, label, unit, placeholder }) {
// Eingabe-State für alle Formeln return (
const [vals, setVals] = useState({});
const set = (k, v) => setVals(p => ({ ...p, [k]: v }));
const n = k => { const v = parseFloat(vals[k]); return isNaN(v) ? null : v; };
const fmt = (v, unit, digits=3) => v == null ? '—' : `${parseFloat(v.toPrecision(digits))} ${unit}`;
// Strompreis für Kostenrechner
const [preis, setPreis] = useState('0.30');
const Inp = ({ k, label, unit, placeholder }) => (
<div style={{ flex:1, minWidth:100 }}> <div style={{ flex:1, minWidth:100 }}>
<div style={{ color:'rgba(255,255,255,0.35)', fontFamily:'monospace', fontSize:9, marginBottom:3 }}>{label} [{unit}]</div> <div style={{ color:'rgba(255,255,255,0.35)', fontFamily:'monospace', fontSize:9, marginBottom:3 }}>
<input type="number" value={vals[k]||''} onChange={e=>set(k,e.target.value)} {label} [{unit}]
</div>
<input type="number" value={vals[k]||''} onChange={e=>setVals(p=>({...p,[k]:e.target.value}))}
placeholder={placeholder||''} placeholder={placeholder||''}
style={{ ...S.inp, fontSize:13, padding:'7px 9px', width:'100%', boxSizing:'border-box' }}/> style={{ ...S.inp, fontSize:13, padding:'7px 9px', width:'100%', boxSizing:'border-box' }}/>
</div> </div>
); );
}
const Result = ({ label, value, highlight }) => ( function ElektroResult({ label, value, highlight }) {
return (
<div style={{ display:'flex', justifyContent:'space-between', alignItems:'center', <div style={{ display:'flex', justifyContent:'space-between', alignItems:'center',
padding:'8px 12px', marginBottom:5, borderRadius:8, padding:'8px 12px', marginBottom:5, borderRadius:8,
background: highlight ? 'rgba(78,205,196,0.1)' : 'rgba(255,255,255,0.03)', background: highlight ? 'rgba(78,205,196,0.1)' : 'rgba(255,255,255,0.03)',
@@ -300,13 +295,29 @@ function ElektroRechner({ mobile }) {
fontSize:14, fontWeight:700 }}>{value}</span> fontSize:14, fontWeight:700 }}>{value}</span>
</div> </div>
); );
}
const Section = ({ title, children }) => ( function ElektroSection({ title, children }) {
return (
<div style={{ marginBottom:20 }}> <div style={{ marginBottom:20 }}>
<div style={{ ...S.head, marginBottom:10, color:'#4ecdc4' }}>{title}</div> <div style={{ ...S.head, marginBottom:10, color:'#4ecdc4' }}>{title}</div>
{children} {children}
</div> </div>
); );
}
// ── Elektro-Rechner ───────────────────────────────────────────────────────────
function ElektroRechner({ mobile }) {
const [vals, setVals] = useState({});
const [preis, setPreis] = useState('0.30');
const n = k => { const v = parseFloat(vals[k]); return isNaN(v) ? null : v; };
const fmt = (v, unit, digits=3) => v == null ? '—' : `${parseFloat(v.toPrecision(digits))} ${unit}`;
// Shorthand mit gebundenen props
const Inp = (props) => <ElektroInp vals={vals} setVals={setVals} {...props}/>;
const Res = (props) => <ElektroResult {...props}/>;
const Sec = (props) => <ElektroSection {...props}/>;
const cols = mobile ? '1fr' : '1fr 1fr'; const cols = mobile ? '1fr' : '1fr 1fr';
@@ -368,19 +379,19 @@ function ElektroRechner({ mobile }) {
<div style={{ display:'grid', gridTemplateColumns:cols, gap:20 }}> <div style={{ display:'grid', gridTemplateColumns:cols, gap:20 }}>
<div> <div>
{/* Ohmsches Gesetz */} {/* Ohmsches Gesetz */}
<Section title="⚡ Ohmsches Gesetz U = R · I"> <Sec title="⚡ Ohmsches Gesetz U = R · I">
<div style={{ display:'flex', gap:8, marginBottom:10, flexWrap:'wrap' }}> <div style={{ display:'flex', gap:8, marginBottom:10, flexWrap:'wrap' }}>
<Inp k="u1" label="Spannung" unit="V" placeholder="230"/> <Inp k="u1" label="Spannung" unit="V" placeholder="230"/>
<Inp k="i1" label="Strom" unit="A" placeholder="2"/> <Inp k="i1" label="Strom" unit="A" placeholder="2"/>
<Inp k="r1" label="Widerstand" unit="Ω" placeholder="115"/> <Inp k="r1" label="Widerstand" unit="Ω" placeholder="115"/>
</div> </div>
<Result label="U Spannung" value={fmt(ohmRes.U,'V')} highlight={!U1&&ohmRes.U!=null}/> <Res label="U Spannung" value={fmt(ohmRes.U,'V')} highlight={!U1&&ohmRes.U!=null}/>
<Result label="I Strom" value={fmt(ohmRes.I,'A')} highlight={!I1&&ohmRes.I!=null}/> <Res label="I Strom" value={fmt(ohmRes.I,'A')} highlight={!I1&&ohmRes.I!=null}/>
<Result label="R Widerstand" value={fmt(ohmRes.R,'Ω')} highlight={!R1&&ohmRes.R!=null}/> <Res label="R Widerstand" value={fmt(ohmRes.R,'Ω')} highlight={!R1&&ohmRes.R!=null}/>
</Section> </Sec>
{/* Leistung */} {/* Leistung */}
<Section title="🔋 Leistung P = U · I"> <Sec title="🔋 Leistung P = U · I">
<div style={{ display:'flex', gap:8, marginBottom:10, flexWrap:'wrap' }}> <div style={{ display:'flex', gap:8, marginBottom:10, flexWrap:'wrap' }}>
<Inp k="u2" label="Spannung" unit="V"/> <Inp k="u2" label="Spannung" unit="V"/>
<Inp k="i2" label="Strom" unit="A"/> <Inp k="i2" label="Strom" unit="A"/>
@@ -388,27 +399,27 @@ function ElektroRechner({ mobile }) {
<Inp k="r2" label="Widerstand" unit="Ω"/> <Inp k="r2" label="Widerstand" unit="Ω"/>
</div> </div>
{leistRes ? <> {leistRes ? <>
<Result label="P Leistung" value={fmt(leistRes.P,'W')} highlight={!P2}/> <Res label="P Leistung" value={fmt(leistRes.P,'W')} highlight={!P2}/>
<Result label="U Spannung" value={fmt(leistRes.U,'V')} highlight={!U2}/> <Res label="U Spannung" value={fmt(leistRes.U,'V')} highlight={!U2}/>
<Result label="I Strom" value={fmt(leistRes.I,'A')} highlight={!I2}/> <Res label="I Strom" value={fmt(leistRes.I,'A')} highlight={!I2}/>
<Result label="R Widerstand" value={fmt(leistRes.R,'Ω')} highlight={!R2}/> <Res label="R Widerstand" value={fmt(leistRes.R,'Ω')} highlight={!R2}/>
</> : <div style={{color:'rgba(255,255,255,0.2)',fontFamily:'monospace',fontSize:11}}>Mindestens 2 Werte eingeben</div>} </> : <div style={{color:'rgba(255,255,255,0.2)',fontFamily:'monospace',fontSize:11}}>Mindestens 2 Werte eingeben</div>}
</Section> </Sec>
{/* Wirkungsgrad */} {/* Wirkungsgrad */}
<Section title="🔄 Wirkungsgrad η = P_ab / P_zu"> <Sec title="🔄 Wirkungsgrad η = P_ab / P_zu">
<div style={{ display:'flex', gap:8, marginBottom:10 }}> <div style={{ display:'flex', gap:8, marginBottom:10 }}>
<Inp k="pa" label="Abgabe-Leistung" unit="W" placeholder="800"/> <Inp k="pa" label="Abgabe-Leistung" unit="W" placeholder="800"/>
<Inp k="pe" label="Aufnahme-Leistung" unit="W" placeholder="1000"/> <Inp k="pe" label="Aufnahme-Leistung" unit="W" placeholder="1000"/>
</div> </div>
<Result label= Wirkungsgrad" value={eta!=null ? `${eta.toFixed(1)} %` : '—'} highlight={eta!=null}/> <Res label= Wirkungsgrad" value={eta!=null ? `${eta.toFixed(1)} %` : '—'} highlight={eta!=null}/>
<Result label="Verlustleistung" value={fmt(verlust,'W')}/> <Res label="Verlustleistung" value={fmt(verlust,'W')}/>
</Section> </Sec>
</div> </div>
<div> <div>
{/* Stromkosten */} {/* Stromkosten */}
<Section title="💶 Stromkosten"> <Sec title="💶 Stromkosten">
<div style={{ display:'flex', gap:8, marginBottom:10, flexWrap:'wrap' }}> <div style={{ display:'flex', gap:8, marginBottom:10, flexWrap:'wrap' }}>
<Inp k="pw" label="Leistung" unit="W" placeholder="100"/> <Inp k="pw" label="Leistung" unit="W" placeholder="100"/>
<Inp k="std" label="Stunden/Tag" unit="h" placeholder="5"/> <Inp k="std" label="Stunden/Tag" unit="h" placeholder="5"/>
@@ -422,41 +433,41 @@ function ElektroRechner({ mobile }) {
step="0.01" min="0" step="0.01" min="0"
style={{ ...S.inp, fontSize:13, padding:'7px 9px', width:'100%', boxSizing:'border-box' }}/> style={{ ...S.inp, fontSize:13, padding:'7px 9px', width:'100%', boxSizing:'border-box' }}/>
</div> </div>
<Result label="kWh/Tag" value={kwhTag!=null ? `${kwhTag.toFixed(3)} kWh` : '—'}/> <Res label="kWh/Tag" value={kwhTag!=null ? `${kwhTag.toFixed(3)} kWh` : '—'}/>
<Result label="Kosten/Tag" value={kostenTag!=null ? `${kostenTag.toFixed(3)}` : '—'}/> <Res label="Kosten/Tag" value={kostenTag!=null ? `${kostenTag.toFixed(3)}` : '—'}/>
<Result label="kWh/Monat" value={kwhMonat!=null ? `${kwhMonat.toFixed(2)} kWh` : '—'}/> <Res label="kWh/Monat" value={kwhMonat!=null ? `${kwhMonat.toFixed(2)} kWh` : '—'}/>
<Result label="Kosten/Monat" value={kostenMonat!=null ? `${kostenMonat.toFixed(2)}`: '—'} highlight={kostenMonat!=null}/> <Res label="Kosten/Monat" value={kostenMonat!=null ? `${kostenMonat.toFixed(2)}`: '—'} highlight={kostenMonat!=null}/>
<Result label="kWh/Jahr" value={kwhJahr!=null ? `${kwhJahr.toFixed(1)} kWh` : '—'}/> <Res label="kWh/Jahr" value={kwhJahr!=null ? `${kwhJahr.toFixed(1)} kWh` : '—'}/>
<Result label="Kosten/Jahr" value={kostenJahr!=null ? `${kostenJahr.toFixed(2)}` : '—'} highlight={kostenJahr!=null}/> <Res label="Kosten/Jahr" value={kostenJahr!=null ? `${kostenJahr.toFixed(2)}` : '—'} highlight={kostenJahr!=null}/>
</Section> </Sec>
{/* Widerstände */} {/* Widerstände */}
<Section title="🔗 Widerstandsschaltung"> <Sec title="🔗 Widerstandsschaltung">
<div style={{ marginBottom:8 }}> <div style={{ marginBottom:8 }}>
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, marginBottom:5 }}>SERIE (R = R1+R2+)</div> <div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, marginBottom:5 }}>SERIE (R = R1+R2+)</div>
<div style={{ display:'flex', gap:6, flexWrap:'wrap', marginBottom:8 }}> <div style={{ display:'flex', gap:6, flexWrap:'wrap', marginBottom:8 }}>
{['rs1','rs2','rs3','rs4'].map(k=><Inp key={k} k={k} label={`R${k.slice(2)}`} unit="Ω"/>)} {['rs1','rs2','rs3','rs4'].map(k=><Inp key={k} k={k} label={`R${k.slice(2)}`} unit="Ω"/>)}
</div> </div>
<Result label="Gesamtwiderstand (Serie)" value={r_ser.length>=2 ? fmt(R_ser,'Ω') : '—'} highlight={r_ser.length>=2}/> <Res label="Gesamtwiderstand (Serie)" value={r_ser.length>=2 ? fmt(R_ser,'Ω') : '—'} highlight={r_ser.length>=2}/>
</div> </div>
<div> <div>
<div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, marginBottom:5 }}>PARALLEL (1/R = 1/R1+1/R2+)</div> <div style={{ color:'rgba(255,255,255,0.3)', fontFamily:'monospace', fontSize:9, marginBottom:5 }}>PARALLEL (1/R = 1/R1+1/R2+)</div>
<div style={{ display:'flex', gap:6, flexWrap:'wrap', marginBottom:8 }}> <div style={{ display:'flex', gap:6, flexWrap:'wrap', marginBottom:8 }}>
{['rp1','rp2','rp3','rp4'].map(k=><Inp key={k} k={k} label={`R${k.slice(2)}`} unit="Ω"/>)} {['rp1','rp2','rp3','rp4'].map(k=><Inp key={k} k={k} label={`R${k.slice(2)}`} unit="Ω"/>)}
</div> </div>
<Result label="Gesamtwiderstand (Parallel)" value={r_par.length>=2 ? fmt(R_par,'Ω') : '—'} highlight={r_par.length>=2}/> <Res label="Gesamtwiderstand (Parallel)" value={r_par.length>=2 ? fmt(R_par,'Ω') : '—'} highlight={r_par.length>=2}/>
</div> </div>
</Section> </Sec>
{/* Kondensator */} {/* Kondensator */}
<Section title="⚡ Kondensator I = C · (ΔU/Δt)"> <Sec title="⚡ Kondensator I = C · (ΔU/Δt)">
<div style={{ display:'flex', gap:8, flexWrap:'wrap', marginBottom:10 }}> <div style={{ display:'flex', gap:8, flexWrap:'wrap', marginBottom:10 }}>
<Inp k="cap" label="Kapazität" unit="F" placeholder="0.001"/> <Inp k="cap" label="Kapazität" unit="F" placeholder="0.001"/>
<Inp k="uc" label="Spannung" unit="V" placeholder="230"/> <Inp k="uc" label="Spannung" unit="V" placeholder="230"/>
<Inp k="tc" label="Zeit Δt" unit="s" placeholder="0.02"/> <Inp k="tc" label="Zeit Δt" unit="s" placeholder="0.02"/>
</div> </div>
<Result label="I Ladestrom" value={fmt(Ic,'A')} highlight={Ic!=null}/> <Res label="I Ladestrom" value={fmt(Ic,'A')} highlight={Ic!=null}/>
</Section> </Sec>
</div> </div>
</div> </div>