feat: MVP 3D-Druck Kostenkalkulator

- Single-Page HTML-App mit allen 18 Eingabefeldern
- 12 Berechnungen live (calc.js, reine Funktionen)
- LocalStorage-Persistenz, Mehrfach-Projekte via Sidebar
- Excel Im-/Export ueber SheetJS (vendored, MIT)
- Drag&Drop + File-Picker-Import
- Apple-Swiss-Styling, responsive
- Vorlagen-Excel mit 3 Reitern (Eingabe/Kalkulation/Angebot), Formeln referenzieren Eingabe
- openpyxl-Script fuer reproduzierbaren Template-Build
- 5 Test-Szenarien validiert

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 21:15:25 +02:00
commit 7507f768a3
12 changed files with 1308 additions and 0 deletions

64
assets/state.js Normal file
View File

@@ -0,0 +1,64 @@
/* LocalStorage State-Management + Mehrfach-Projekte */
/* global window */
const STORAGE_KEY = 'kalk3d_projects_v1';
const CURRENT_KEY = 'kalk3d_current_v1';
const FIELDS = [
'projectName', 'customer', 'materialType',
'materialCostPerKg', 'materialUsageG',
'printTimeH', 'machineRate', 'powerKwh', 'powerPrice',
'postMin', 'postRate',
'packagingCost', 'shippingCost', 'setupCost',
'scrapPct', 'marginPct', 'quantity', 'individualAdjustment',
'vatPct', 'notes',
];
const makeDefault = (name = 'Neues Projekt') => ({
id: 'p_' + Date.now() + '_' + Math.random().toString(36).slice(2, 7),
projectName: name,
customer: '',
materialType: 'PLA',
materialCostPerKg: 25,
materialUsageG: 0,
printTimeH: 0,
machineRate: 3,
powerKwh: 0.15,
powerPrice: 0.35,
postMin: 0,
postRate: 30,
packagingCost: 0,
shippingCost: 0,
setupCost: 0,
scrapPct: 5,
marginPct: 30,
quantity: 1,
individualAdjustment: 0,
vatPct: 19,
notes: '',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});
const load = () => {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return [];
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : [];
} catch (e) {
console.warn('State-Load-Fehler:', e);
return [];
}
};
const save = (projects) => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(projects));
};
const getCurrentId = () => localStorage.getItem(CURRENT_KEY);
const setCurrentId = (id) => localStorage.setItem(CURRENT_KEY, id);
window.Store = {
FIELDS, makeDefault, load, save, getCurrentId, setCurrentId, STORAGE_KEY, CURRENT_KEY,
};