mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 11:59:35 +01:00
2094 lines
148 KiB
HTML
2094 lines
148 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de" class="h-full">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Effigenix ERP – Prototyp</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
|
||
<script>
|
||
tailwind.config = {
|
||
theme: {
|
||
extend: {
|
||
fontFamily: {
|
||
sans: ['Poppins', 'sans-serif'],
|
||
mono: ['JetBrains Mono', 'monospace'],
|
||
},
|
||
colors: {
|
||
brand: {
|
||
50: '#fdf6f0', 100: '#fae8d8', 200: '#f4cfaf',
|
||
300: '#ecb07f', 400: '#e18b4e', 500: '#c06b3a',
|
||
600: '#a8562e', 700: '#8c4426', 800: '#733822',
|
||
900: '#5f2f1e', 950: '#331710',
|
||
},
|
||
warm: {
|
||
50: '#faf8f4', 100: '#f4f1eb', 200: '#ede7dd',
|
||
300: '#ded9d1', 400: '#c5bfb5', 500: '#979089',
|
||
600: '#6d6459', 700: '#574c3e', 800: '#453d32',
|
||
900: '#2e2820', 950: '#1a1611',
|
||
},
|
||
success: { 50:'#f0f7f1', 100:'#d9edd9', 200:'#b4dbb6', 300:'#84c288', 400:'#5aaa60', 500:'#3d8f44', 600:'#2e7234', 700:'#265b2b', 800:'#214a25', 900:'#1c3d1f' },
|
||
warning: { 50:'#fdf9ec', 100:'#faf0c9', 200:'#f5dd8f', 300:'#efc64e', 400:'#e8ae25', 500:'#d49518', 600:'#ab7013', 700:'#825013', 800:'#6c4117', 900:'#5b3618' },
|
||
danger: { 50:'#fdf3f3', 100:'#fce4e4', 200:'#facece', 300:'#f5abab', 400:'#ec7a7a', 500:'#df5050', 600:'#c43a3a', 700:'#a42d2d', 800:'#882929', 900:'#712828' },
|
||
info: { 50:'#f0f7fb', 100:'#ddedf6', 200:'#c3dfef', 300:'#99cae3', 400:'#69aed4', 500:'#4993c3', 600:'#3879a8', 700:'#2e6189', 800:'#2a5272', 900:'#27455f' },
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
<style>
|
||
:root {
|
||
--primary: oklch(0.6171 0.1375 39.0427);
|
||
--primary-fg: #fff;
|
||
--bg: oklch(0.9818 0.0054 95.0986);
|
||
--fg: oklch(0.3438 0.0269 95.7226);
|
||
--sidebar-bg: oklch(0.9445 0.0110 96.50);
|
||
--border: oklch(0.8847 0.0069 97.3627);
|
||
--muted: oklch(0.6059 0.0075 97.4233);
|
||
--radius: 0.75rem;
|
||
}
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
body { background: var(--bg); color: var(--fg); }
|
||
|
||
/* ── Scrollbar (main content) ── */
|
||
main::-webkit-scrollbar { width: 6px; height: 6px; }
|
||
main::-webkit-scrollbar-track { background: transparent; }
|
||
main::-webkit-scrollbar-thumb { background: #c5bfb5; border-radius: 3px; }
|
||
main::-webkit-scrollbar-thumb:hover { background: #979089; }
|
||
|
||
/* ── Sidebar: hide scrollbar but keep scroll ── */
|
||
#sidebar { scrollbar-width: none; -ms-overflow-style: none; }
|
||
#sidebar::-webkit-scrollbar { display: none; }
|
||
|
||
/* ── Content Inset (elevated over sidebar, like Shadcn SidebarInset) ── */
|
||
.content-inset {
|
||
background: var(--bg);
|
||
border-top-left-radius: 0.875rem;
|
||
border-bottom-left-radius: 0.875rem;
|
||
box-shadow: -2px 0 20px rgba(0,0,0,0.07), -1px 0 4px rgba(0,0,0,0.03);
|
||
position: relative;
|
||
z-index: 1;
|
||
margin-top: 4px;
|
||
margin-bottom: 4px;
|
||
overflow: hidden;
|
||
}
|
||
.content-inset header { border-top-left-radius: inherit; }
|
||
|
||
/* ── Sidebar ── */
|
||
.sidebar-item { transition: all 0.15s ease; border-left: 3px solid transparent; margin-right: 4px; }
|
||
.sidebar-item:hover { background: rgba(192,107,58,0.06); }
|
||
.sidebar-item.active { background: rgba(192,107,58,0.1); color: #c06b3a; font-weight: 500; border-left-color: #c06b3a; border-radius: 0.5rem; }
|
||
.sidebar-group-btn { transition: color 0.15s; }
|
||
.sidebar-group-btn:hover { color: #574c3e; }
|
||
.sidebar-group-content { overflow: hidden; transition: max-height 0.25s cubic-bezier(0.4,0,0.2,1); }
|
||
.sidebar-group.collapsed .sidebar-group-content { max-height: 0 !important; }
|
||
.sidebar-group .chevron { transition: transform 0.25s cubic-bezier(0.4,0,0.2,1); }
|
||
.sidebar-group.collapsed .chevron { transform: rotate(-90deg); }
|
||
|
||
/* ── Pages ── */
|
||
.page { display: none; }
|
||
.page.active { display: block; animation: fadeIn 0.25s cubic-bezier(0.4,0,0.2,1); }
|
||
@keyframes fadeIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
|
||
|
||
/* ── Badges ── */
|
||
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 10px; border-radius: 9999px; font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.01em; white-space: nowrap; }
|
||
.badge-active { background: #d9edd9; color: #265b2b; }
|
||
.badge-draft { background: #faf0c9; color: #825013; }
|
||
.badge-archived { background: #ede7dd; color: #6d6459; }
|
||
.badge-blocked { background: #fce4e4; color: #a42d2d; }
|
||
.badge-planned { background: #ddedf6; color: #2e6189; }
|
||
.badge-inprogress { background: #c3dfef; color: #2a5272; }
|
||
.badge-completed { background: #d9edd9; color: #265b2b; }
|
||
.badge-cancelled { background: #fce4e4; color: #a42d2d; }
|
||
.badge-locked { background: #fce4e4; color: #a42d2d; }
|
||
.badge-inactive { background: #ede7dd; color: #6d6459; }
|
||
.badge-open { background: #ddedf6; color: #2e6189; }
|
||
.badge-counting { background: #faf0c9; color: #825013; }
|
||
.badge-released { background: #c3dfef; color: #2a5272; }
|
||
.badge-urgent { background: #fce4e4; color: #a42d2d; }
|
||
.badge-high { background: #faf0c9; color: #825013; }
|
||
.badge-normal { background: #ddedf6; color: #2e6189; }
|
||
.badge-low { background: #ede7dd; color: #6d6459; }
|
||
|
||
/* ── Buttons ── */
|
||
.btn { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.5rem 1rem; border-radius: var(--radius); font-size: 0.875rem; font-weight: 500; cursor: pointer; transition: all 0.2s cubic-bezier(0.4,0,0.2,1); border: none; user-select: none; }
|
||
.btn:active { transform: scale(0.97); }
|
||
.btn-primary { background: var(--primary); color: var(--primary-fg); box-shadow: 0 1px 3px rgba(192,107,58,0.3); }
|
||
.btn-primary:hover { box-shadow: 0 4px 12px rgba(192,107,58,0.35); filter: brightness(1.05); }
|
||
.btn-secondary { background: #ede7dd; color: #574c3e; }
|
||
.btn-secondary:hover { background: #ded9d1; }
|
||
.btn-outline { background: #fff; border: 1px solid var(--border); color: var(--fg); }
|
||
.btn-outline:hover { background: #faf8f4; border-color: #c5bfb5; }
|
||
.btn-ghost { background: transparent; color: var(--fg); }
|
||
.btn-ghost:hover { background: rgba(0,0,0,0.04); }
|
||
.btn-danger { background: #df5050; color: #fff; box-shadow: 0 1px 3px rgba(223,80,80,0.3); }
|
||
.btn-danger:hover { box-shadow: 0 4px 12px rgba(223,80,80,0.35); filter: brightness(1.05); }
|
||
.btn-sm { padding: 0.375rem 0.75rem; font-size: 0.8125rem; }
|
||
.btn-icon { padding: 0.5rem; }
|
||
.btn:disabled { opacity: 0.5; cursor: not-allowed; pointer-events: none; }
|
||
|
||
/* ── Cards ── */
|
||
.card { background: #fff; border: 1px solid var(--border); border-radius: var(--radius); box-shadow: 0 1px 2px rgba(0,0,0,0.04); }
|
||
|
||
/* ── Inputs ── */
|
||
.input { display: block; width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--border); border-radius: calc(var(--radius) - 2px); font-size: 0.875rem; font-family: inherit; background: #fff; transition: all 0.2s cubic-bezier(0.4,0,0.2,1); color: inherit; }
|
||
.input:hover { border-color: #c5bfb5; }
|
||
.input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(192,107,58,0.12); }
|
||
.input::placeholder { color: #c5bfb5; }
|
||
.select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236d6459' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 0.75rem center; padding-right: 2.5rem; cursor: pointer; }
|
||
textarea.input { resize: vertical; min-height: 2.5rem; }
|
||
label { cursor: pointer; }
|
||
|
||
/* ── Tables ── */
|
||
table { width: 100%; border-collapse: collapse; }
|
||
table th { text-align: left; padding: 0.625rem 1rem; font-size: 0.6875rem; font-weight: 700; color: #979089; text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 2px solid var(--border); background: #faf8f4; position: sticky; top: 0; z-index: 1; }
|
||
table td { padding: 0.6875rem 1rem; border-bottom: 1px solid rgba(222,217,209,0.4); font-size: 0.875rem; }
|
||
table tbody tr { cursor: pointer; transition: background 0.15s; }
|
||
table tbody tr:hover { background: rgba(192,107,58,0.04); }
|
||
table tbody tr:nth-child(even) { background: rgba(250,248,244,0.5); }
|
||
table tbody tr:nth-child(even):hover { background: rgba(192,107,58,0.06); }
|
||
|
||
/* ── KPI Cards ── */
|
||
.kpi-card { transition: transform 0.2s cubic-bezier(0.4,0,0.2,1), box-shadow 0.2s cubic-bezier(0.4,0,0.2,1); }
|
||
.kpi-card:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); }
|
||
|
||
/* ── Tabs ── */
|
||
.tab { padding: 0.625rem 1.25rem; font-size: 0.875rem; font-weight: 500; color: #979089; border-bottom: 2px solid transparent; cursor: pointer; transition: all 0.2s; background: none; border-top: none; border-left: none; border-right: none; }
|
||
.tab:hover { color: #574c3e; background: rgba(0,0,0,0.02); }
|
||
.tab.active { color: #c06b3a; border-bottom-color: #c06b3a; }
|
||
.tab-content { display: none; }
|
||
.tab-content.active { display: block; }
|
||
|
||
/* ── Misc ── */
|
||
.coming-soon-overlay { background: repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(192,107,58,0.03) 10px, rgba(192,107,58,0.03) 20px); }
|
||
.progress-bar { height: 8px; border-radius: 4px; background: #ede7dd; overflow: hidden; }
|
||
.progress-fill { height: 100%; border-radius: 4px; transition: width 0.6s cubic-bezier(0.4,0,0.2,1); }
|
||
.chart-bar { display: flex; align-items: end; gap: 8px; height: 140px; padding-bottom: 4px; }
|
||
.chart-bar div { flex: 1; border-radius: 6px 6px 0 0; transition: height 0.6s cubic-bezier(0.4,0,0.2,1); min-width: 24px; position: relative; }
|
||
.chart-bar div:hover { filter: brightness(1.08); }
|
||
.modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.4); backdrop-filter: blur(4px); z-index: 50; display: flex; align-items: center; justify-content: center; }
|
||
.modal-overlay.hidden { display: none; }
|
||
.modal { background: #fff; border-radius: var(--radius); max-width: 480px; width: 90%; max-height: 85vh; overflow-y: auto; box-shadow: 0 24px 48px rgba(0,0,0,0.15); }
|
||
.avatar { width: 2rem; height: 2rem; border-radius: 9999px; display: flex; align-items: center; justify-content: center; font-size: 0.75rem; font-weight: 600; }
|
||
|
||
/* ── Toast ── */
|
||
@keyframes slideInRight { from { opacity: 0; transform: translateX(24px); } to { opacity: 1; transform: translateX(0); } }
|
||
.toast { position: fixed; bottom: 1.5rem; right: 1.5rem; z-index: 100; padding: 0.75rem 1.25rem; border-radius: var(--radius); color: #fff; font-size: 0.875rem; font-weight: 500; box-shadow: 0 8px 24px rgba(0,0,0,0.15); animation: slideInRight 0.3s cubic-bezier(0.4,0,0.2,1); }
|
||
|
||
/* ── Detail Layout ── */
|
||
.detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 1.25rem; }
|
||
.detail-item label { display: block; font-size: 0.6875rem; font-weight: 700; color: #979089; text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 0.25rem; }
|
||
.detail-item span { font-size: 0.9375rem; color: #453d32; }
|
||
|
||
/* ── Recipe Preview Panel ── */
|
||
.recipe-preview { transition: opacity 0.3s, transform 0.3s; }
|
||
.recipe-preview.hidden-preview { opacity: 0; transform: translateX(12px); pointer-events: none; }
|
||
.recipe-preview .step-line { position: relative; padding-left: 2rem; }
|
||
.recipe-preview .step-line::before { content: ''; position: absolute; left: 0.6875rem; top: 1.75rem; bottom: -0.75rem; width: 2px; background: #ede7dd; }
|
||
.recipe-preview .step-line:last-child::before { display: none; }
|
||
|
||
/* ── Focus visible ── */
|
||
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
|
||
.btn:focus-visible, .input:focus-visible { outline: none; }
|
||
</style>
|
||
</head>
|
||
<body class="h-full font-sans antialiased">
|
||
|
||
<!-- ═══════════════ LOGIN SCREEN ═══════════════ -->
|
||
<div id="login-screen" class="min-h-screen flex items-center justify-center relative overflow-hidden" style="background: linear-gradient(135deg, #faf8f4 0%, #f4e8d8 50%, #ede7dd 100%)">
|
||
<div class="absolute inset-0 opacity-[0.03]" style="background-image: url('data:image/svg+xml,%3Csvg width="60" height="60" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg"%3E%3Cg fill="none" fill-rule="evenodd"%3E%3Cg fill="%23c06b3a" fill-opacity="1"%3E%3Cpath d="M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z"/%3E%3C/g%3E%3C/g%3E%3C/svg%3E');"></div>
|
||
<div class="card p-8 w-full max-w-md relative" style="box-shadow: 0 20px 60px rgba(0,0,0,0.08), 0 1px 3px rgba(0,0,0,0.06);">
|
||
<div class="text-center mb-8">
|
||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl mb-5 shadow-lg" style="background: linear-gradient(135deg, #c06b3a, #a8562e)">
|
||
<i data-lucide="beef" class="w-8 h-8 text-white"></i>
|
||
</div>
|
||
<h1 class="text-2xl font-semibold text-warm-800 tracking-tight">Effigenix ERP</h1>
|
||
<p class="text-warm-500 text-sm mt-1">Fleischerei-Management-System</p>
|
||
</div>
|
||
<div class="space-y-4">
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Benutzername</label>
|
||
<div class="relative">
|
||
<i data-lucide="user" class="w-4 h-4 text-warm-400 absolute left-3 top-1/2 -translate-y-1/2"></i>
|
||
<input type="text" class="input pl-9" placeholder="admin" value="admin">
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Passwort</label>
|
||
<div class="relative">
|
||
<i data-lucide="lock" class="w-4 h-4 text-warm-400 absolute left-3 top-1/2 -translate-y-1/2"></i>
|
||
<input type="password" class="input pl-9" placeholder="••••••••" value="password">
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center justify-between text-sm">
|
||
<label class="flex items-center gap-2 text-warm-600 cursor-pointer">
|
||
<input type="checkbox" class="w-4 h-4 rounded accent-brand-500" checked> Angemeldet bleiben
|
||
</label>
|
||
<a class="text-brand-500 hover:text-brand-600 font-medium cursor-pointer">Passwort vergessen?</a>
|
||
</div>
|
||
<button onclick="login()" class="btn btn-primary w-full justify-center py-2.5 text-base mt-1">
|
||
<i data-lucide="log-in" class="w-4 h-4"></i> Anmelden
|
||
</button>
|
||
</div>
|
||
<p class="text-center text-warm-400 text-xs mt-8">© 2026 Effigenix · v2.0.0</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ APP SHELL ═══════════════ -->
|
||
<div id="app-shell" class="hidden h-full flex">
|
||
|
||
<!-- ─── SIDEBAR ─── -->
|
||
<aside id="sidebar" class="w-64 h-full flex flex-col shrink-0 overflow-y-auto" style="background: var(--sidebar-bg)">
|
||
<!-- Logo -->
|
||
<div class="h-14 px-4 flex items-center gap-3 shrink-0">
|
||
<div class="w-8 h-8 rounded-lg flex items-center justify-center shrink-0 shadow-sm" style="background: linear-gradient(135deg, #c06b3a, #a8562e)">
|
||
<i data-lucide="beef" class="w-4.5 h-4.5 text-white"></i>
|
||
</div>
|
||
<div class="min-w-0">
|
||
<div class="font-semibold text-warm-800 text-sm leading-tight tracking-tight">Effigenix ERP</div>
|
||
<div class="text-warm-500 text-xs">Metzgerei Huber</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Nav -->
|
||
<nav class="flex-1 p-3 space-y-1 text-sm">
|
||
<!-- Dashboard -->
|
||
<a class="sidebar-item active flex items-center gap-2.5 px-3 py-2 rounded-lg text-warm-700" data-page="dashboard" onclick="navigate('dashboard')">
|
||
<i data-lucide="layout-dashboard" class="w-4 h-4"></i> Dashboard
|
||
</a>
|
||
|
||
<!-- Stammdaten -->
|
||
<div class="sidebar-group mt-3">
|
||
<button class="sidebar-group-btn flex items-center justify-between w-full px-3 py-2 rounded-lg text-warm-500 text-xs font-semibold uppercase tracking-wider" onclick="toggleGroup(this)">
|
||
<span class="flex items-center gap-2"><i data-lucide="database" class="w-3.5 h-3.5"></i> Stammdaten</span>
|
||
<i data-lucide="chevron-down" class="w-3.5 h-3.5 chevron"></i>
|
||
</button>
|
||
<div class="sidebar-group-content ml-2 space-y-0.5 mt-0.5" style="max-height:500px">
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="articles" onclick="navigate('articles')">
|
||
<i data-lucide="package" class="w-4 h-4"></i> Artikel
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="categories" onclick="navigate('categories')">
|
||
<i data-lucide="tags" class="w-4 h-4"></i> Kategorien
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="suppliers" onclick="navigate('suppliers')">
|
||
<i data-lucide="truck" class="w-4 h-4"></i> Lieferanten
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="customers" onclick="navigate('customers')">
|
||
<i data-lucide="users" class="w-4 h-4"></i> Kunden
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Lagerverwaltung -->
|
||
<div class="sidebar-group mt-1">
|
||
<button class="sidebar-group-btn flex items-center justify-between w-full px-3 py-2 rounded-lg text-warm-500 text-xs font-semibold uppercase tracking-wider" onclick="toggleGroup(this)">
|
||
<span class="flex items-center gap-2"><i data-lucide="warehouse" class="w-3.5 h-3.5"></i> Lagerverwaltung</span>
|
||
<i data-lucide="chevron-down" class="w-3.5 h-3.5 chevron"></i>
|
||
</button>
|
||
<div class="sidebar-group-content ml-2 space-y-0.5 mt-0.5" style="max-height:500px">
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="locations" onclick="navigate('locations')">
|
||
<i data-lucide="map-pin" class="w-4 h-4"></i> Lagerorte
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="stocks" onclick="navigate('stocks')">
|
||
<i data-lucide="boxes" class="w-4 h-4"></i> Bestände
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="movements" onclick="navigate('movements')">
|
||
<i data-lucide="arrow-left-right" class="w-4 h-4"></i> Warenbewegungen
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="counts" onclick="navigate('counts')">
|
||
<i data-lucide="clipboard-check" class="w-4 h-4"></i> Inventur
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Produktion -->
|
||
<div class="sidebar-group mt-1">
|
||
<button class="sidebar-group-btn flex items-center justify-between w-full px-3 py-2 rounded-lg text-warm-500 text-xs font-semibold uppercase tracking-wider" onclick="toggleGroup(this)">
|
||
<span class="flex items-center gap-2"><i data-lucide="factory" class="w-3.5 h-3.5"></i> Produktion</span>
|
||
<i data-lucide="chevron-down" class="w-3.5 h-3.5 chevron"></i>
|
||
</button>
|
||
<div class="sidebar-group-content ml-2 space-y-0.5 mt-0.5" style="max-height:500px">
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="recipes" onclick="navigate('recipes')">
|
||
<i data-lucide="book-open" class="w-4 h-4"></i> Rezepte
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="batches" onclick="navigate('batches')">
|
||
<i data-lucide="flask-conical" class="w-4 h-4"></i> Chargen
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="prod-orders" onclick="navigate('prod-orders')">
|
||
<i data-lucide="clipboard-list" class="w-4 h-4"></i> Aufträge
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Qualität -->
|
||
<div class="sidebar-group mt-1">
|
||
<button class="sidebar-group-btn flex items-center justify-between w-full px-3 py-2 rounded-lg text-warm-500 text-xs font-semibold uppercase tracking-wider" onclick="toggleGroup(this)">
|
||
<span class="flex items-center gap-2"><i data-lucide="shield-check" class="w-3.5 h-3.5"></i> Qualität</span>
|
||
<i data-lucide="chevron-down" class="w-3.5 h-3.5 chevron"></i>
|
||
</button>
|
||
<div class="sidebar-group-content ml-2 space-y-0.5 mt-0.5" style="max-height:500px">
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="quality" onclick="navigate('quality')">
|
||
<i data-lucide="thermometer" class="w-4 h-4"></i> HACCP & Hygiene
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Einkauf, Verkauf, Etiketten, Filialen -->
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-2 rounded-lg text-warm-600 mt-1" data-page="procurement" onclick="navigate('procurement')">
|
||
<i data-lucide="shopping-cart" class="w-4 h-4"></i> Einkauf
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-2 rounded-lg text-warm-600" data-page="sales" onclick="navigate('sales')">
|
||
<i data-lucide="receipt" class="w-4 h-4"></i> Verkauf
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-2 rounded-lg text-warm-600" data-page="labeling" onclick="navigate('labeling')">
|
||
<i data-lucide="tag" class="w-4 h-4"></i> Etikettierung
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-2 rounded-lg text-warm-600" data-page="branches" onclick="navigate('branches')">
|
||
<i data-lucide="store" class="w-4 h-4"></i> Filialen
|
||
</a>
|
||
|
||
<!-- Verwaltung -->
|
||
<div class="sidebar-group mt-3">
|
||
<button class="sidebar-group-btn flex items-center justify-between w-full px-3 py-2 rounded-lg text-warm-500 text-xs font-semibold uppercase tracking-wider" onclick="toggleGroup(this)">
|
||
<span class="flex items-center gap-2"><i data-lucide="settings" class="w-3.5 h-3.5"></i> Verwaltung</span>
|
||
<i data-lucide="chevron-down" class="w-3.5 h-3.5 chevron"></i>
|
||
</button>
|
||
<div class="sidebar-group-content ml-2 space-y-0.5 mt-0.5" style="max-height:500px">
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="users" onclick="navigate('users')">
|
||
<i data-lucide="user-cog" class="w-4 h-4"></i> Benutzer
|
||
</a>
|
||
<a class="sidebar-item flex items-center gap-2.5 px-3 py-1.5 rounded-lg text-warm-600" data-page="roles" onclick="navigate('roles')">
|
||
<i data-lucide="shield" class="w-4 h-4"></i> Rollen
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- User -->
|
||
<div class="p-3 mt-auto">
|
||
<div class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-warm-200/60 cursor-pointer transition">
|
||
<div class="avatar bg-brand-100 text-brand-700">MH</div>
|
||
<div class="min-w-0 flex-1">
|
||
<div class="text-sm font-medium text-warm-800 truncate">Max Huber</div>
|
||
<div class="text-xs text-warm-500">Administrator</div>
|
||
</div>
|
||
<i data-lucide="log-out" class="w-4 h-4 text-warm-400 hover:text-danger-500 cursor-pointer" onclick="logout()"></i>
|
||
</div>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- ─── MAIN CONTENT (elevated inset) ─── -->
|
||
<div class="content-inset flex-1 flex flex-col min-w-0 h-full">
|
||
<!-- Header -->
|
||
<header class="h-14 flex items-center justify-between px-6 border-b shrink-0 bg-white/60 backdrop-blur-sm" style="border-color: var(--border)">
|
||
<div class="flex items-center gap-3">
|
||
<button onclick="toggleSidebar()" class="btn-icon btn-ghost rounded-lg p-1.5 -ml-1.5 lg:hidden">
|
||
<i data-lucide="panel-left" class="w-5 h-5 text-warm-500"></i>
|
||
</button>
|
||
<nav id="breadcrumb" class="flex items-center gap-1.5 text-sm text-warm-500">
|
||
<span class="text-warm-800 font-medium">Dashboard</span>
|
||
</nav>
|
||
</div>
|
||
<div class="flex items-center gap-3">
|
||
<div class="relative group">
|
||
<i data-lucide="search" class="w-4 h-4 text-warm-400 absolute left-3 top-1/2 -translate-y-1/2 transition-colors group-focus-within:text-brand-500"></i>
|
||
<input type="text" class="input text-sm py-1.5 pl-9 pr-12 w-60 bg-warm-50 border-transparent hover:border-warm-300 focus:bg-white focus:border-brand-400" placeholder="Suchen…">
|
||
<kbd class="absolute right-2.5 top-1/2 -translate-y-1/2 text-[10px] font-mono text-warm-400 bg-warm-100 px-1.5 py-0.5 rounded border border-warm-200">⌘K</kbd>
|
||
</div>
|
||
<div class="w-px h-6 bg-warm-200"></div>
|
||
<button class="btn-icon btn-ghost rounded-lg p-2 relative" title="Benachrichtigungen">
|
||
<i data-lucide="bell" class="w-4.5 h-4.5 text-warm-500"></i>
|
||
<span class="absolute top-1.5 right-1.5 w-2 h-2 bg-danger-500 rounded-full ring-2 ring-white"></span>
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Content Area -->
|
||
<main class="flex-1 overflow-y-auto p-6">
|
||
|
||
<!-- ═══════════════ DASHBOARD ═══════════════ -->
|
||
<div id="page-dashboard" class="page active">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<h1 class="text-2xl font-semibold text-warm-800">Guten Morgen, Max</h1>
|
||
<p class="text-warm-500 text-sm mt-0.5">Mittwoch, 19. März 2026 · Metzgerei Huber, Hauptbetrieb</p>
|
||
</div>
|
||
<button class="btn btn-primary" onclick="navigate('prod-order-create')">
|
||
<i data-lucide="plus" class="w-4 h-4"></i> Neuer Auftrag
|
||
</button>
|
||
</div>
|
||
|
||
<!-- KPI Cards -->
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
|
||
<div class="card kpi-card p-5">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<span class="text-warm-500 text-sm font-medium">Heutige Produktion</span>
|
||
<div class="w-9 h-9 rounded-lg bg-brand-50 flex items-center justify-center"><i data-lucide="factory" class="w-4.5 h-4.5 text-brand-500"></i></div>
|
||
</div>
|
||
<div class="text-2xl font-semibold text-warm-800">847 kg</div>
|
||
<div class="flex items-center gap-1 mt-1 text-xs"><span class="text-success-600">+12%</span><span class="text-warm-400">vs. letzte Woche</span></div>
|
||
</div>
|
||
<div class="card kpi-card p-5">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<span class="text-warm-500 text-sm font-medium">Offene Aufträge</span>
|
||
<div class="w-9 h-9 rounded-lg bg-info-50 flex items-center justify-center"><i data-lucide="clipboard-list" class="w-4.5 h-4.5 text-info-500"></i></div>
|
||
</div>
|
||
<div class="text-2xl font-semibold text-warm-800">14</div>
|
||
<div class="flex items-center gap-1 mt-1 text-xs"><span class="text-warning-600">3 dringend</span><span class="text-warm-400">· 5 in Arbeit</span></div>
|
||
</div>
|
||
<div class="card kpi-card p-5">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<span class="text-warm-500 text-sm font-medium">Bestandswarnungen</span>
|
||
<div class="w-9 h-9 rounded-lg bg-warning-50 flex items-center justify-center"><i data-lucide="alert-triangle" class="w-4.5 h-4.5 text-warning-500"></i></div>
|
||
</div>
|
||
<div class="text-2xl font-semibold text-warm-800">6</div>
|
||
<div class="flex items-center gap-1 mt-1 text-xs"><span class="text-danger-500">2 unter Minimum</span><span class="text-warm-400">· 4 ablaufend</span></div>
|
||
</div>
|
||
<div class="card kpi-card p-5">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<span class="text-warm-500 text-sm font-medium">Chargen heute</span>
|
||
<div class="w-9 h-9 rounded-lg bg-success-50 flex items-center justify-center"><i data-lucide="flask-conical" class="w-4.5 h-4.5 text-success-500"></i></div>
|
||
</div>
|
||
<div class="text-2xl font-semibold text-warm-800">8</div>
|
||
<div class="flex items-center gap-1 mt-1 text-xs"><span class="text-success-600">5 abgeschlossen</span><span class="text-warm-400">· 3 laufend</span></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
<!-- Produktionsübersicht -->
|
||
<div class="card p-5 lg:col-span-2">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<h2 class="font-semibold text-warm-800">Produktionsübersicht (KW 12)</h2>
|
||
<select class="input select text-sm py-1 w-auto">
|
||
<option>Diese Woche</option><option>Letzte Woche</option><option>Dieser Monat</option>
|
||
</select>
|
||
</div>
|
||
<div class="chart-bar px-2 mb-2">
|
||
<div class="group relative" style="height:85%;background:linear-gradient(180deg,#c06b3a,#a8562e);opacity:0.75">
|
||
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-[10px] font-semibold text-warm-500 opacity-0 group-hover:opacity-100 transition">720</span>
|
||
</div>
|
||
<div class="group relative" style="height:92%;background:linear-gradient(180deg,#c06b3a,#a8562e);opacity:0.85">
|
||
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-[10px] font-semibold text-warm-500 opacity-0 group-hover:opacity-100 transition">780</span>
|
||
</div>
|
||
<div class="group relative" style="height:100%;background:linear-gradient(180deg,#c06b3a,#a8562e)">
|
||
<span class="absolute -top-5 left-1/2 -translate-x-1/2 text-[10px] font-semibold text-brand-600">847</span>
|
||
</div>
|
||
<div style="height:4px;background:#ede7dd;border-radius:2px;align-self:end"></div>
|
||
<div style="height:4px;background:#ede7dd;border-radius:2px;align-self:end"></div>
|
||
</div>
|
||
<div class="flex justify-between px-2 text-xs text-warm-400">
|
||
<span>Mo</span><span>Di</span><span class="font-semibold text-brand-600">Mi</span><span class="text-warm-300">Do</span><span class="text-warm-300">Fr</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Schnellaktionen & Ablaufende Chargen -->
|
||
<div class="space-y-4">
|
||
<div class="card p-5">
|
||
<h2 class="font-semibold text-warm-800 mb-3">Schnellaktionen</h2>
|
||
<div class="space-y-2">
|
||
<button class="btn btn-outline w-full justify-start text-sm" onclick="navigate('prod-order-create')">
|
||
<i data-lucide="plus-circle" class="w-4 h-4 text-brand-500"></i> Produktionsauftrag anlegen
|
||
</button>
|
||
<button class="btn btn-outline w-full justify-start text-sm" onclick="navigate('movement-record')">
|
||
<i data-lucide="arrow-left-right" class="w-4 h-4 text-info-500"></i> Warenbewegung erfassen
|
||
</button>
|
||
<button class="btn btn-outline w-full justify-start text-sm" onclick="navigate('count-create')">
|
||
<i data-lucide="clipboard-check" class="w-4 h-4 text-warning-500"></i> Inventur starten
|
||
</button>
|
||
<button class="btn btn-outline w-full justify-start text-sm" onclick="navigate('article-create')">
|
||
<i data-lucide="package" class="w-4 h-4 text-success-500"></i> Artikel anlegen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h2 class="font-semibold text-warm-800 mb-3">Ablaufende Chargen</h2>
|
||
<div class="space-y-3">
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<div class="text-sm font-medium text-warm-700">P-2026-03-15-002</div>
|
||
<div class="text-xs text-warm-500">Wiener Würstchen</div>
|
||
</div>
|
||
<span class="badge badge-blocked text-xs">morgen</span>
|
||
</div>
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<div class="text-sm font-medium text-warm-700">P-2026-03-14-005</div>
|
||
<div class="text-xs text-warm-500">Leberkäse</div>
|
||
</div>
|
||
<span class="badge badge-draft text-xs">3 Tage</span>
|
||
</div>
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<div class="text-sm font-medium text-warm-700">P-2026-03-12-001</div>
|
||
<div class="text-xs text-warm-500">Fleischwurst</div>
|
||
</div>
|
||
<span class="badge badge-draft text-xs">5 Tage</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Letzte Aktivitäten -->
|
||
<div class="card p-5 mt-6">
|
||
<h2 class="font-semibold text-warm-800 mb-4">Letzte Aktivitäten</h2>
|
||
<div class="space-y-3">
|
||
<div class="flex items-start gap-3">
|
||
<div class="w-8 h-8 rounded-full bg-success-100 flex items-center justify-center shrink-0 mt-0.5"><i data-lucide="check-circle-2" class="w-4 h-4 text-success-600"></i></div>
|
||
<div>
|
||
<div class="text-sm text-warm-700"><span class="font-medium">Charge P-2026-03-19-003</span> abgeschlossen – Bratwurst, 120 kg</div>
|
||
<div class="text-xs text-warm-400">vor 23 min · Lisa Meier</div>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-start gap-3">
|
||
<div class="w-8 h-8 rounded-full bg-info-100 flex items-center justify-center shrink-0 mt-0.5"><i data-lucide="play-circle" class="w-4 h-4 text-info-600"></i></div>
|
||
<div>
|
||
<div class="text-sm text-warm-700"><span class="font-medium">Auftrag PA-2026-0047</span> in Produktion gestartet</div>
|
||
<div class="text-xs text-warm-400">vor 1 Std · Stefan Koch</div>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-start gap-3">
|
||
<div class="w-8 h-8 rounded-full bg-warning-100 flex items-center justify-center shrink-0 mt-0.5"><i data-lucide="alert-triangle" class="w-4 h-4 text-warning-600"></i></div>
|
||
<div>
|
||
<div class="text-sm text-warm-700"><span class="font-medium">Nitritpökelsalz</span> – Bestand unter Mindestmenge (12 kg verbleibend)</div>
|
||
<div class="text-xs text-warm-400">vor 2 Std · System</div>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-start gap-3">
|
||
<div class="w-8 h-8 rounded-full bg-brand-100 flex items-center justify-center shrink-0 mt-0.5"><i data-lucide="package-plus" class="w-4 h-4 text-brand-600"></i></div>
|
||
<div>
|
||
<div class="text-sm text-warm-700"><span class="font-medium">Wareneingang</span> – 500 kg Schweinefleisch S1 von Fleischgroßhandel Müller</div>
|
||
<div class="text-xs text-warm-400">vor 3 Std · Thomas Schmidt</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ ARTIKEL LISTE ═══════════════ -->
|
||
<div id="page-articles" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<h1 class="text-xl font-semibold text-warm-800">Artikel</h1>
|
||
<p class="text-warm-500 text-sm">126 Artikel im System</p>
|
||
</div>
|
||
<button class="btn btn-primary" onclick="navigate('article-create')">
|
||
<i data-lucide="plus" class="w-4 h-4"></i> Artikel anlegen
|
||
</button>
|
||
</div>
|
||
<!-- Filter -->
|
||
<div class="card mb-4">
|
||
<div class="p-4 flex flex-wrap items-center gap-3">
|
||
<div class="relative flex-1 min-w-[200px]">
|
||
<input type="text" class="input pl-9 text-sm" placeholder="Artikel suchen…">
|
||
<i data-lucide="search" class="w-4 h-4 text-warm-400 absolute left-3 top-1/2 -translate-y-1/2"></i>
|
||
</div>
|
||
<select class="input select text-sm py-2 w-auto">
|
||
<option>Alle Kategorien</option><option>Wurstwaren</option><option>Frischfleisch</option><option>Gewürze & Zutaten</option><option>Verpackungsmaterial</option>
|
||
</select>
|
||
<select class="input select text-sm py-2 w-auto">
|
||
<option>Alle Status</option><option>Aktiv</option><option>Inaktiv</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<!-- Table -->
|
||
<div class="card overflow-hidden">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Art.-Nr.</th><th>Bezeichnung</th><th>Kategorie</th><th>VE</th><th>Status</th><th class="text-right">Lieferanten</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-001</td><td class="font-medium text-warm-800">Wiener Würstchen</td><td>Wurstwaren</td><td>kg, Stk</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">2</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-002</td><td class="font-medium text-warm-800">Leberkäse Bayerisch</td><td>Wurstwaren</td><td>kg</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">1</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-003</td><td class="font-medium text-warm-800">Bratwurst grob</td><td>Wurstwaren</td><td>kg, Stk</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">1</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-010</td><td class="font-medium text-warm-800">Schweinefleisch S1</td><td>Frischfleisch</td><td>kg</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">3</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-011</td><td class="font-medium text-warm-800">Rindfleisch R2</td><td>Frischfleisch</td><td>kg</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">2</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-020</td><td class="font-medium text-warm-800">Nitritpökelsalz</td><td>Gewürze & Zutaten</td><td>kg</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">1</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-021</td><td class="font-medium text-warm-800">Gewürzmischung Bratwurst</td><td>Gewürze & Zutaten</td><td>kg</td><td><span class="badge badge-active">Aktiv</span></td><td class="text-right">1</td></tr>
|
||
<tr onclick="navigate('article-detail')"><td class="font-mono text-sm">ART-030</td><td class="font-medium text-warm-800">Naturdarm 28/30</td><td>Verpackungsmaterial</td><td>Bund</td><td><span class="badge badge-inactive">Inaktiv</span></td><td class="text-right">1</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div class="px-4 py-3 flex items-center justify-between border-t text-sm text-warm-500" style="border-color:var(--border)">
|
||
<span>1–8 von 126</span>
|
||
<div class="flex items-center gap-1">
|
||
<button class="btn btn-ghost btn-sm" disabled>«</button>
|
||
<button class="btn btn-ghost btn-sm" disabled>‹</button>
|
||
<button class="btn btn-sm" style="background:var(--primary);color:#fff">1</button>
|
||
<button class="btn btn-ghost btn-sm">2</button>
|
||
<button class="btn btn-ghost btn-sm">3</button>
|
||
<button class="btn btn-ghost btn-sm">…</button>
|
||
<button class="btn btn-ghost btn-sm">16</button>
|
||
<button class="btn btn-ghost btn-sm">›</button>
|
||
<button class="btn btn-ghost btn-sm">»</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ ARTIKEL DETAIL ═══════════════ -->
|
||
<div id="page-article-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3">
|
||
<h1 class="text-xl font-semibold text-warm-800">Wiener Würstchen</h1>
|
||
<span class="badge badge-active">Aktiv</span>
|
||
</div>
|
||
<p class="text-warm-500 text-sm mt-0.5">ART-001 · Wurstwaren</p>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="pencil" class="w-3.5 h-3.5"></i> Bearbeiten</button>
|
||
<button class="btn btn-outline btn-sm text-danger-600"><i data-lucide="archive" class="w-3.5 h-3.5"></i> Deaktivieren</button>
|
||
</div>
|
||
</div>
|
||
<!-- Tabs -->
|
||
<div class="flex gap-0 border-b mb-6" style="border-color:var(--border)">
|
||
<button class="tab active" onclick="switchTab(this,'article-tab','article-info')">Übersicht</button>
|
||
<button class="tab" onclick="switchTab(this,'article-tab','article-units')">Verkaufseinheiten</button>
|
||
<button class="tab" onclick="switchTab(this,'article-tab','article-suppliers')">Lieferanten</button>
|
||
<button class="tab" onclick="switchTab(this,'article-tab','article-stock')">Bestand</button>
|
||
</div>
|
||
<!-- Tab: Übersicht -->
|
||
<div id="article-info" class="tab-content article-tab active">
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Allgemeine Informationen</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Artikelnummer</label><span class="font-mono">ART-001</span></div>
|
||
<div class="detail-item"><label>Bezeichnung</label><span>Wiener Würstchen</span></div>
|
||
<div class="detail-item"><label>Kategorie</label><span>Wurstwaren</span></div>
|
||
<div class="detail-item"><label>Status</label><span class="badge badge-active">Aktiv</span></div>
|
||
<div class="detail-item"><label>Erstellt am</label><span>12.01.2026</span></div>
|
||
<div class="detail-item"><label>Letzte Änderung</label><span>15.03.2026</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Bestandsübersicht</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Gesamtbestand</label><span class="text-lg font-semibold">342 kg</span></div>
|
||
<div class="detail-item"><label>Verfügbar</label><span class="text-lg font-semibold text-success-600">298 kg</span></div>
|
||
<div class="detail-item"><label>Reserviert</label><span class="text-lg font-semibold text-info-600">44 kg</span></div>
|
||
<div class="detail-item"><label>Mindestbestand</label><span>50 kg</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Tab: VEs -->
|
||
<div id="article-units" class="tab-content article-tab">
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex items-center justify-between">
|
||
<h3 class="font-semibold text-warm-800">Verkaufseinheiten</h3>
|
||
<button class="btn btn-primary btn-sm"><i data-lucide="plus" class="w-3.5 h-3.5"></i> VE hinzufügen</button>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Einheit</th><th>Faktor</th><th>Preismodell</th><th>Preis</th><th></th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Kilogramm (kg)</td><td>1.000</td><td>Fixpreis</td><td class="font-mono">8,90 €/kg</td><td class="text-right"><button class="btn btn-ghost btn-sm btn-icon"><i data-lucide="pencil" class="w-3.5 h-3.5"></i></button></td></tr>
|
||
<tr><td>Stück (Stk)</td><td>0.080</td><td>Fixpreis</td><td class="font-mono">0,89 €/Stk</td><td class="text-right"><button class="btn btn-ghost btn-sm btn-icon"><i data-lucide="pencil" class="w-3.5 h-3.5"></i></button></td></tr>
|
||
<tr><td>Packung (5er)</td><td>0.400</td><td>Fixpreis</td><td class="font-mono">3,99 €/Pkg</td><td class="text-right"><button class="btn btn-ghost btn-sm btn-icon"><i data-lucide="pencil" class="w-3.5 h-3.5"></i></button></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<!-- Tab: Lieferanten -->
|
||
<div id="article-suppliers" class="tab-content article-tab">
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex items-center justify-between">
|
||
<h3 class="font-semibold text-warm-800">Zugeordnete Lieferanten</h3>
|
||
<button class="btn btn-primary btn-sm"><i data-lucide="plus" class="w-3.5 h-3.5"></i> Lieferant zuordnen</button>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Lieferant</th><th>Bewertung</th><th>Zertifikate</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Fleischgroßhandel Müller</td><td>⭐⭐⭐⭐⭐</td><td>IFS, Bio-DE</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Süddeutsche Viehhandel GmbH</td><td>⭐⭐⭐⭐</td><td>QS</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<!-- Tab: Bestand -->
|
||
<div id="article-stock" class="tab-content article-tab">
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4"><h3 class="font-semibold text-warm-800">Bestandsverteilung nach Lagerort</h3></div>
|
||
<table>
|
||
<thead><tr><th>Lagerort</th><th>Chargen</th><th>Verfügbar</th><th>Reserviert</th><th>MHD (nächstes)</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('stock-detail')"><td>Kühlhaus 1</td><td>3</td><td class="font-mono">218 kg</td><td class="font-mono">30 kg</td><td>22.03.2026</td><td><span class="badge badge-active">OK</span></td></tr>
|
||
<tr onclick="navigate('stock-detail')"><td>Kühlhaus 2</td><td>2</td><td class="font-mono">80 kg</td><td class="font-mono">14 kg</td><td>25.03.2026</td><td><span class="badge badge-active">OK</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ ARTIKEL ANLEGEN ═══════════════ -->
|
||
<div id="page-article-create" class="page">
|
||
<div class="mb-6">
|
||
<h1 class="text-xl font-semibold text-warm-800">Artikel anlegen</h1>
|
||
<p class="text-warm-500 text-sm">Neuen Artikel im System erfassen</p>
|
||
</div>
|
||
<div class="card p-6 max-w-2xl">
|
||
<div class="space-y-5">
|
||
<div class="grid grid-cols-2 gap-4">
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Artikelnummer *</label><input class="input" placeholder="z.B. ART-040"></div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Bezeichnung *</label><input class="input" placeholder="z.B. Kalbsleberwurst fein"></div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Kategorie *</label>
|
||
<select class="input select"><option value="">Bitte wählen…</option><option>Wurstwaren</option><option>Frischfleisch</option><option>Gewürze & Zutaten</option><option>Verpackungsmaterial</option></select>
|
||
</div>
|
||
<hr class="border-warm-200">
|
||
<h3 class="font-semibold text-warm-800">Erste Verkaufseinheit</h3>
|
||
<div class="grid grid-cols-3 gap-4">
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Einheit *</label>
|
||
<select class="input select"><option>Kilogramm (kg)</option><option>Stück (Stk)</option><option>Liter (l)</option><option>Bund</option></select>
|
||
</div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Preismodell</label>
|
||
<select class="input select"><option>Fixpreis</option><option>Staffelpreis</option></select>
|
||
</div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Preis (€) *</label><input class="input" type="number" step="0.01" placeholder="0,00"></div>
|
||
</div>
|
||
<div class="flex justify-end gap-3 pt-4">
|
||
<button class="btn btn-outline" onclick="navigate('articles')">Abbrechen</button>
|
||
<button class="btn btn-primary" onclick="showToast('Artikel wurde angelegt','success');navigate('articles')">
|
||
<i data-lucide="check" class="w-4 h-4"></i> Artikel anlegen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ KATEGORIEN ═══════════════ -->
|
||
<div id="page-categories" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Kategorien</h1><p class="text-warm-500 text-sm">Produktkategorien verwalten</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Kategorie anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<table>
|
||
<thead><tr><th>Bezeichnung</th><th>Beschreibung</th><th>Artikel</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr><td class="font-medium text-warm-800">Wurstwaren</td><td>Brüh-, Koch- und Rohwurst</td><td>42</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr><td class="font-medium text-warm-800">Frischfleisch</td><td>Rind, Schwein, Kalb, Geflügel</td><td>35</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr><td class="font-medium text-warm-800">Gewürze & Zutaten</td><td>Gewürzmischungen, Salze, Zusatzstoffe</td><td>28</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr><td class="font-medium text-warm-800">Verpackungsmaterial</td><td>Därme, Folien, Etiketten</td><td>15</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr><td class="font-medium text-warm-800">Feinkost</td><td>Salate, Fertiggerichte, Beilagen</td><td>6</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ LIEFERANTEN LISTE ═══════════════ -->
|
||
<div id="page-suppliers" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Lieferanten</h1><p class="text-warm-500 text-sm">18 Lieferanten im System</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Lieferant anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4"><input type="text" class="input text-sm max-w-sm" placeholder="Lieferant suchen…"></div>
|
||
<table>
|
||
<thead><tr><th>Name</th><th>Ort</th><th>Telefon</th><th>Bewertung</th><th>Zertifikate</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Fleischgroßhandel Müller GmbH</td><td>München</td><td class="font-mono text-sm">089 / 123 456 0</td><td>⭐⭐⭐⭐⭐</td><td>IFS, Bio-DE, QS</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Gewürzhaus Schmidt KG</td><td>Nürnberg</td><td class="font-mono text-sm">0911 / 234 567</td><td>⭐⭐⭐⭐</td><td>IFS</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Naturdarme Weber e.K.</td><td>Stuttgart</td><td class="font-mono text-sm">0711 / 345 678</td><td>⭐⭐⭐⭐</td><td>–</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Süddeutsche Viehhandel GmbH</td><td>Augsburg</td><td class="font-mono text-sm">0821 / 456 789</td><td>⭐⭐⭐⭐</td><td>QS, Bio-DE</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('supplier-detail')"><td class="font-medium text-warm-800">Verpackung Direkt AG</td><td>Regensburg</td><td class="font-mono text-sm">0941 / 567 890</td><td>⭐⭐⭐</td><td>–</td><td><span class="badge badge-inactive">Inaktiv</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ LIEFERANT DETAIL ═══════════════ -->
|
||
<div id="page-supplier-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Fleischgroßhandel Müller GmbH</h1><span class="badge badge-active">Aktiv</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Lieferant seit 15.06.2024 · Bewertung: ⭐⭐⭐⭐⭐</p>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="pencil" class="w-3.5 h-3.5"></i> Bearbeiten</button>
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="star" class="w-3.5 h-3.5"></i> Bewerten</button>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Kontaktdaten</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Telefon</label><span>089 / 123 456 0</span></div>
|
||
<div class="detail-item"><label>E-Mail</label><span>info@fleisch-mueller.de</span></div>
|
||
<div class="detail-item"><label>Ansprechpartner</label><span>Karl Müller</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Adresse</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Straße</label><span>Industriestr. 45</span></div>
|
||
<div class="detail-item"><label>PLZ / Ort</label><span>80939 München</span></div>
|
||
<div class="detail-item"><label>Land</label><span>Deutschland</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Zahlungsbedingungen</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Zahlungsziel</label><span>30 Tage</span></div>
|
||
<div class="detail-item"><label>Bedingung</label><span>2% Skonto bei Zahlung innerhalb 10 Tagen</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Zertifikate</h3>
|
||
<div class="space-y-2">
|
||
<div class="flex items-center justify-between p-2 bg-warm-50 rounded-lg"><div class="flex items-center gap-2"><i data-lucide="award" class="w-4 h-4 text-success-500"></i><span class="text-sm font-medium">IFS Food v8</span></div><span class="text-xs text-warm-500">gültig bis 30.09.2026</span></div>
|
||
<div class="flex items-center justify-between p-2 bg-warm-50 rounded-lg"><div class="flex items-center gap-2"><i data-lucide="award" class="w-4 h-4 text-success-500"></i><span class="text-sm font-medium">Bio-DE-ÖKO-001</span></div><span class="text-xs text-warm-500">gültig bis 31.12.2026</span></div>
|
||
<div class="flex items-center justify-between p-2 bg-warm-50 rounded-lg"><div class="flex items-center gap-2"><i data-lucide="award" class="w-4 h-4 text-success-500"></i><span class="text-sm font-medium">QS-Prüfzeichen</span></div><span class="text-xs text-warm-500">gültig bis 15.06.2027</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ KUNDEN LISTE ═══════════════ -->
|
||
<div id="page-customers" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Kunden</h1><p class="text-warm-500 text-sm">34 Kunden im System</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Kunde anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex gap-3">
|
||
<input type="text" class="input text-sm max-w-sm" placeholder="Kunde suchen…">
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Typen</option><option>B2B</option><option>B2C</option></select>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Name</th><th>Typ</th><th>Ort</th><th>Telefon</th><th>Rahmenvertrag</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('customer-detail')"><td class="font-medium text-warm-800">Gasthof Zur Linde</td><td><span class="badge badge-planned">B2B</span></td><td>Rosenheim</td><td class="font-mono text-sm">08031 / 12 34 56</td><td><i data-lucide="check" class="w-4 h-4 text-success-500"></i></td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('customer-detail')"><td class="font-medium text-warm-800">REWE Markt Huber</td><td><span class="badge badge-planned">B2B</span></td><td>München</td><td class="font-mono text-sm">089 / 98 76 54</td><td><i data-lucide="check" class="w-4 h-4 text-success-500"></i></td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('customer-detail')"><td class="font-medium text-warm-800">Kantine Stadtwerke AG</td><td><span class="badge badge-planned">B2B</span></td><td>München</td><td class="font-mono text-sm">089 / 11 22 33</td><td><i data-lucide="minus" class="w-4 h-4 text-warm-300"></i></td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('customer-detail')"><td class="font-medium text-warm-800">Maria Gruber</td><td><span class="badge badge-archived">B2C</span></td><td>Kolbermoor</td><td class="font-mono text-sm">08031 / 44 55 66</td><td><i data-lucide="minus" class="w-4 h-4 text-warm-300"></i></td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('customer-detail')"><td class="font-medium text-warm-800">Hotel Alpenblick</td><td><span class="badge badge-planned">B2B</span></td><td>Garmisch</td><td class="font-mono text-sm">08821 / 77 88 99</td><td><i data-lucide="check" class="w-4 h-4 text-success-500"></i></td><td><span class="badge badge-inactive">Inaktiv</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ KUNDE DETAIL ═══════════════ -->
|
||
<div id="page-customer-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Gasthof Zur Linde</h1><span class="badge badge-planned">B2B</span><span class="badge badge-active">Aktiv</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Kunde seit 01.03.2025</p>
|
||
</div>
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="pencil" class="w-3.5 h-3.5"></i> Bearbeiten</button>
|
||
</div>
|
||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Kontakt</h3>
|
||
<div class="space-y-3">
|
||
<div class="detail-item"><label>Telefon</label><span>08031 / 12 34 56</span></div>
|
||
<div class="detail-item"><label>E-Mail</label><span>kueche@linde-rosenheim.de</span></div>
|
||
<div class="detail-item"><label>Ansprechpartner</label><span>Johann Linde</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Rechnungsadresse</h3>
|
||
<div class="text-sm text-warm-700 space-y-0.5">
|
||
<div>Gasthof Zur Linde</div><div>Lindenstraße 12</div><div>83022 Rosenheim</div><div>Deutschland</div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Lieferadressen</h3>
|
||
<div class="space-y-3">
|
||
<div class="p-2 bg-warm-50 rounded-lg"><div class="text-sm font-medium">Haupteingang</div><div class="text-xs text-warm-500">Lindenstraße 12, 83022 Rosenheim</div></div>
|
||
<div class="p-2 bg-warm-50 rounded-lg"><div class="text-sm font-medium">Kücheneingang</div><div class="text-xs text-warm-500">Hinterstr. 3, 83022 Rosenheim</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5 mt-6">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<h3 class="font-semibold text-warm-800">Rahmenvertrag</h3>
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="pencil" class="w-3.5 h-3.5"></i> Bearbeiten</button>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Artikel</th><th>Menge / Woche</th><th>Preismodell</th><th>Preis</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Wiener Würstchen</td><td>20 kg</td><td>Staffelpreis</td><td class="font-mono">7,90 €/kg</td></tr>
|
||
<tr><td>Leberkäse Bayerisch</td><td>15 kg</td><td>Fixpreis</td><td class="font-mono">9,50 €/kg</td></tr>
|
||
<tr><td>Bratwurst grob</td><td>10 kg</td><td>Fixpreis</td><td class="font-mono">8,20 €/kg</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ LAGERORTE ═══════════════ -->
|
||
<div id="page-locations" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Lagerorte</h1><p class="text-warm-500 text-sm">Alle Lagerstandorte und Kühlräume</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Lagerort anlegen</button>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
<div class="card p-5 cursor-pointer hover:shadow-md transition">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center gap-2"><i data-lucide="thermometer-snowflake" class="w-5 h-5 text-info-500"></i><h3 class="font-semibold text-warm-800">Kühlhaus 1</h3></div>
|
||
<span class="badge badge-active">Aktiv</span>
|
||
</div>
|
||
<div class="text-sm text-warm-500 space-y-1">
|
||
<div>Typ: <span class="text-warm-700">Kühlraum</span></div>
|
||
<div>Temperatur: <span class="text-warm-700">2–4 °C</span></div>
|
||
<div>Belegte Artikel: <span class="text-warm-700">12</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5 cursor-pointer hover:shadow-md transition">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center gap-2"><i data-lucide="thermometer-snowflake" class="w-5 h-5 text-info-500"></i><h3 class="font-semibold text-warm-800">Kühlhaus 2</h3></div>
|
||
<span class="badge badge-active">Aktiv</span>
|
||
</div>
|
||
<div class="text-sm text-warm-500 space-y-1">
|
||
<div>Typ: <span class="text-warm-700">Kühlraum</span></div>
|
||
<div>Temperatur: <span class="text-warm-700">0–2 °C</span></div>
|
||
<div>Belegte Artikel: <span class="text-warm-700">8</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5 cursor-pointer hover:shadow-md transition">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center gap-2"><i data-lucide="snowflake" class="w-5 h-5 text-info-700"></i><h3 class="font-semibold text-warm-800">Tiefkühler A</h3></div>
|
||
<span class="badge badge-active">Aktiv</span>
|
||
</div>
|
||
<div class="text-sm text-warm-500 space-y-1">
|
||
<div>Typ: <span class="text-warm-700">Tiefkühlung</span></div>
|
||
<div>Temperatur: <span class="text-warm-700">-18 bis -22 °C</span></div>
|
||
<div>Belegte Artikel: <span class="text-warm-700">6</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5 cursor-pointer hover:shadow-md transition">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center gap-2"><i data-lucide="box" class="w-5 h-5 text-warm-500"></i><h3 class="font-semibold text-warm-800">Trockenwarenlager</h3></div>
|
||
<span class="badge badge-active">Aktiv</span>
|
||
</div>
|
||
<div class="text-sm text-warm-500 space-y-1">
|
||
<div>Typ: <span class="text-warm-700">Trockenlager</span></div>
|
||
<div>Temperatur: <span class="text-warm-700">15–20 °C</span></div>
|
||
<div>Belegte Artikel: <span class="text-warm-700">18</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5 cursor-pointer hover:shadow-md transition">
|
||
<div class="flex items-center justify-between mb-3">
|
||
<div class="flex items-center gap-2"><i data-lucide="archive" class="w-5 h-5 text-warm-500"></i><h3 class="font-semibold text-warm-800">Regal Ladentheke</h3></div>
|
||
<span class="badge badge-active">Aktiv</span>
|
||
</div>
|
||
<div class="text-sm text-warm-500 space-y-1">
|
||
<div>Typ: <span class="text-warm-700">Regal</span></div>
|
||
<div>Temperatur: <span class="text-warm-700">4–7 °C (Kühlung)</span></div>
|
||
<div>Belegte Artikel: <span class="text-warm-700">22</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ BESTÄNDE LISTE ═══════════════ -->
|
||
<div id="page-stocks" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Bestände</h1><p class="text-warm-500 text-sm">Lagerbestände und Chargenverwaltung</p></div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="alert-triangle" class="w-3.5 h-3.5 text-warning-500"></i> Unter Minimum (2)</button>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Bestand anlegen</button>
|
||
</div>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex flex-wrap gap-3">
|
||
<input type="text" class="input text-sm max-w-xs" placeholder="Artikel suchen…">
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Lagerorte</option><option>Kühlhaus 1</option><option>Kühlhaus 2</option><option>Tiefkühler A</option><option>Trockenwarenlager</option></select>
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Status</option><option>Verfügbar</option><option>Bald ablaufend</option><option>Gesperrt</option></select>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Artikel</th><th>Lagerort</th><th>Verfügbar</th><th>Reserviert</th><th>Chargen</th><th>MHD (nächstes)</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('stock-detail')"><td class="font-medium text-warm-800">Wiener Würstchen</td><td>Kühlhaus 1</td><td class="font-mono">218 kg</td><td class="font-mono">30 kg</td><td>3</td><td>22.03.2026</td><td><span class="badge badge-active">OK</span></td></tr>
|
||
<tr onclick="navigate('stock-detail')"><td class="font-medium text-warm-800">Schweinefleisch S1</td><td>Kühlhaus 1</td><td class="font-mono">145 kg</td><td class="font-mono">50 kg</td><td>2</td><td>21.03.2026</td><td><span class="badge badge-draft">Bald ablaufend</span></td></tr>
|
||
<tr onclick="navigate('stock-detail')"><td class="font-medium text-warm-800">Leberkäse Bayerisch</td><td>Kühlhaus 2</td><td class="font-mono">87 kg</td><td class="font-mono">0 kg</td><td>2</td><td>24.03.2026</td><td><span class="badge badge-active">OK</span></td></tr>
|
||
<tr onclick="navigate('stock-detail')"><td class="font-medium text-warm-800">Nitritpökelsalz</td><td>Trockenwarenlager</td><td class="font-mono text-danger-600 font-semibold">12 kg</td><td class="font-mono">0 kg</td><td>1</td><td>15.12.2027</td><td><span class="badge badge-blocked">Unter Min.</span></td></tr>
|
||
<tr onclick="navigate('stock-detail')"><td class="font-medium text-warm-800">Bratwurst grob</td><td>Kühlhaus 1</td><td class="font-mono">65 kg</td><td class="font-mono">20 kg</td><td>1</td><td>23.03.2026</td><td><span class="badge badge-active">OK</span></td></tr>
|
||
<tr onclick="navigate('stock-detail')"><td class="font-medium text-warm-800">Rindfleisch R2</td><td>Tiefkühler A</td><td class="font-mono">230 kg</td><td class="font-mono">0 kg</td><td>4</td><td>15.06.2026</td><td><span class="badge badge-active">OK</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ BESTAND DETAIL ═══════════════ -->
|
||
<div id="page-stock-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Wiener Würstchen – Kühlhaus 1</h1><span class="badge badge-active">OK</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">3 Chargen · 218 kg verfügbar · 30 kg reserviert</p>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="plus" class="w-3.5 h-3.5"></i> Charge hinzufügen</button>
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="bookmark" class="w-3.5 h-3.5"></i> Reservieren</button>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-4 gap-4 mb-6">
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Gesamt</div><div class="text-xl font-semibold text-warm-800 mt-1">248 kg</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Verfügbar</div><div class="text-xl font-semibold text-success-600 mt-1">218 kg</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Reserviert</div><div class="text-xl font-semibold text-info-600 mt-1">30 kg</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Mindestbestand</div><div class="text-xl font-semibold text-warm-800 mt-1">50 kg</div></div>
|
||
</div>
|
||
<!-- Chargen -->
|
||
<div class="card overflow-hidden mb-6">
|
||
<div class="p-4"><h3 class="font-semibold text-warm-800">Chargen (FEFO-Sortierung)</h3></div>
|
||
<table>
|
||
<thead><tr><th>Charge</th><th>Menge</th><th>Allokiert</th><th>Verfügbar</th><th>MHD</th><th>Status</th><th></th></tr></thead>
|
||
<tbody>
|
||
<tr><td class="font-mono text-sm">P-2026-03-15-002</td><td class="font-mono">80 kg</td><td class="font-mono">20 kg</td><td class="font-mono">60 kg</td><td class="text-danger-600 font-medium">22.03.2026</td><td><span class="badge badge-draft">Bald ablaufend</span></td>
|
||
<td class="text-right"><button class="btn btn-ghost btn-sm btn-icon" title="Sperren"><i data-lucide="lock" class="w-3.5 h-3.5"></i></button></td></tr>
|
||
<tr><td class="font-mono text-sm">P-2026-03-17-001</td><td class="font-mono">100 kg</td><td class="font-mono">10 kg</td><td class="font-mono">90 kg</td><td>26.03.2026</td><td><span class="badge badge-active">Verfügbar</span></td>
|
||
<td class="text-right"><button class="btn btn-ghost btn-sm btn-icon" title="Sperren"><i data-lucide="lock" class="w-3.5 h-3.5"></i></button></td></tr>
|
||
<tr><td class="font-mono text-sm">P-2026-03-19-003</td><td class="font-mono">68 kg</td><td class="font-mono">0 kg</td><td class="font-mono">68 kg</td><td>28.03.2026</td><td><span class="badge badge-active">Verfügbar</span></td>
|
||
<td class="text-right"><button class="btn btn-ghost btn-sm btn-icon" title="Sperren"><i data-lucide="lock" class="w-3.5 h-3.5"></i></button></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<!-- Reservierungen -->
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4"><h3 class="font-semibold text-warm-800">Aktive Reservierungen</h3></div>
|
||
<table>
|
||
<thead><tr><th>Reservierung</th><th>Menge</th><th>Reserviert am</th><th>Referenz</th><th></th></tr></thead>
|
||
<tbody>
|
||
<tr><td class="font-mono text-sm">RES-0012</td><td class="font-mono">30 kg</td><td>19.03.2026, 08:15</td><td>PA-2026-0047</td>
|
||
<td class="text-right"><button class="btn btn-sm btn-primary">Bestätigen</button><button class="btn btn-sm btn-ghost ml-1">Freigeben</button></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ WARENBEWEGUNGEN ═══════════════ -->
|
||
<div id="page-movements" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Warenbewegungen</h1><p class="text-warm-500 text-sm">Alle Ein- und Ausgänge</p></div>
|
||
<button class="btn btn-primary" onclick="navigate('movement-record')"><i data-lucide="plus" class="w-4 h-4"></i> Bewegung erfassen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex gap-3">
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Typen</option><option>Eingang</option><option>Ausgang</option><option>Korrektur</option><option>Retoure</option></select>
|
||
<input type="date" class="input text-sm w-auto" value="2026-03-19">
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Datum</th><th>Typ</th><th>Artikel</th><th>Menge</th><th>Charge</th><th>Referenz</th><th>Benutzer</th></tr></thead>
|
||
<tbody>
|
||
<tr><td class="text-sm">19.03. 10:32</td><td><span class="badge badge-completed">Eingang</span></td><td>Schweinefleisch S1</td><td class="font-mono">500 kg</td><td class="font-mono text-sm">P-2026-03-19-005</td><td>LF-Müller-2026-0312</td><td>Thomas Schmidt</td></tr>
|
||
<tr><td class="text-sm">19.03. 09:15</td><td><span class="badge badge-cancelled">Ausgang</span></td><td>Wiener Würstchen</td><td class="font-mono">30 kg</td><td class="font-mono text-sm">P-2026-03-15-002</td><td>PA-2026-0047</td><td>Lisa Meier</td></tr>
|
||
<tr><td class="text-sm">19.03. 08:00</td><td><span class="badge badge-draft">Korrektur</span></td><td>Gewürzmischung BW</td><td class="font-mono">-2 kg</td><td class="font-mono text-sm">–</td><td>INV-2026-0008</td><td>Stefan Koch</td></tr>
|
||
<tr><td class="text-sm">18.03. 16:45</td><td><span class="badge badge-completed">Eingang</span></td><td>Naturdarm 28/30</td><td class="font-mono">50 Bund</td><td class="font-mono text-sm">–</td><td>LF-Weber-2026-0089</td><td>Thomas Schmidt</td></tr>
|
||
<tr><td class="text-sm">18.03. 14:20</td><td><span class="badge badge-cancelled">Ausgang</span></td><td>Bratwurst grob</td><td class="font-mono">45 kg</td><td class="font-mono text-sm">P-2026-03-17-001</td><td>VK-2026-0234</td><td>Lisa Meier</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ BEWEGUNG ERFASSEN ═══════════════ -->
|
||
<div id="page-movement-record" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Warenbewegung erfassen</h1><p class="text-warm-500 text-sm">Warenein- oder -ausgang buchen</p></div>
|
||
<div class="card p-6 max-w-2xl">
|
||
<div class="space-y-5">
|
||
<div class="grid grid-cols-2 gap-4">
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Bewegungstyp *</label>
|
||
<select class="input select"><option>Eingang</option><option>Ausgang</option><option>Korrektur</option><option>Retoure</option></select></div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Datum *</label><input type="date" class="input" value="2026-03-19"></div>
|
||
</div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Artikel *</label>
|
||
<select class="input select"><option>Bitte wählen…</option><option>ART-001 – Wiener Würstchen</option><option>ART-010 – Schweinefleisch S1</option><option>ART-020 – Nitritpökelsalz</option></select></div>
|
||
<div class="grid grid-cols-2 gap-4">
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Menge *</label><input class="input" type="number" placeholder="0"></div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Einheit</label><input class="input" value="kg" readonly></div>
|
||
</div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Referenz</label><input class="input" placeholder="z.B. Lieferschein-Nr., Auftragsnr."></div>
|
||
<div class="flex justify-end gap-3 pt-4">
|
||
<button class="btn btn-outline" onclick="navigate('movements')">Abbrechen</button>
|
||
<button class="btn btn-primary" onclick="showToast('Warenbewegung gebucht','success');navigate('movements')"><i data-lucide="check" class="w-4 h-4"></i> Buchen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ INVENTUR LISTE ═══════════════ -->
|
||
<div id="page-counts" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Inventur</h1><p class="text-warm-500 text-sm">Bestandszählungen und Ausgleichsbuchungen</p></div>
|
||
<button class="btn btn-primary" onclick="navigate('count-create')"><i data-lucide="plus" class="w-4 h-4"></i> Inventur anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<table>
|
||
<thead><tr><th>Nr.</th><th>Lagerort</th><th>Datum</th><th>Angelegt von</th><th>Abgeschlossen von</th><th>Positionen</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('count-detail')"><td class="font-mono">INV-0009</td><td>Kühlhaus 1</td><td>19.03.2026</td><td>Stefan Koch</td><td>–</td><td>0 / 12</td><td><span class="badge badge-open">Offen</span></td></tr>
|
||
<tr onclick="navigate('count-detail')"><td class="font-mono">INV-0008</td><td>Trockenwarenlager</td><td>18.03.2026</td><td>Stefan Koch</td><td>Lisa Meier</td><td>18 / 18</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('count-detail')"><td class="font-mono">INV-0007</td><td>Kühlhaus 2</td><td>15.03.2026</td><td>Max Huber</td><td>Stefan Koch</td><td>8 / 8</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('count-detail')"><td class="font-mono">INV-0006</td><td>Tiefkühler A</td><td>12.03.2026</td><td>Lisa Meier</td><td>Max Huber</td><td>6 / 6</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ INVENTUR DETAIL ═══════════════ -->
|
||
<div id="page-count-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Inventur INV-0009</h1><span class="badge badge-open">Offen</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Kühlhaus 1 · 19.03.2026 · Angelegt von Stefan Koch</p>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-secondary"><i data-lucide="play" class="w-4 h-4"></i> Zählung starten</button>
|
||
<button class="btn btn-primary" disabled><i data-lucide="check-check" class="w-4 h-4"></i> Abschließen</button>
|
||
</div>
|
||
</div>
|
||
<div class="card p-4 bg-info-50 border-info-200 mb-6">
|
||
<div class="flex items-center gap-2 text-info-700 text-sm"><i data-lucide="info" class="w-4 h-4"></i> Vier-Augen-Prinzip: Die Inventur muss von einer anderen Person abgeschlossen werden als der, die sie angelegt hat.</div>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4"><h3 class="font-semibold text-warm-800">Zählpositionen</h3></div>
|
||
<table>
|
||
<thead><tr><th>Artikel</th><th>Soll-Bestand</th><th>Gezählt</th><th>Differenz</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>Wiener Würstchen</td><td class="font-mono">248 kg</td><td><input class="input w-24 inline text-right font-mono" placeholder="–"></td><td class="font-mono">–</td><td><span class="badge badge-archived">Offen</span></td></tr>
|
||
<tr><td>Schweinefleisch S1</td><td class="font-mono">195 kg</td><td><input class="input w-24 inline text-right font-mono" placeholder="–"></td><td class="font-mono">–</td><td><span class="badge badge-archived">Offen</span></td></tr>
|
||
<tr><td>Bratwurst grob</td><td class="font-mono">85 kg</td><td><input class="input w-24 inline text-right font-mono" placeholder="–"></td><td class="font-mono">–</td><td><span class="badge badge-archived">Offen</span></td></tr>
|
||
<tr><td>Fleischwurst</td><td class="font-mono">42 kg</td><td><input class="input w-24 inline text-right font-mono" placeholder="–"></td><td class="font-mono">–</td><td><span class="badge badge-archived">Offen</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ INVENTUR ANLEGEN ═══════════════ -->
|
||
<div id="page-count-create" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Inventur anlegen</h1></div>
|
||
<div class="card p-6 max-w-lg">
|
||
<div class="space-y-5">
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Lagerort *</label>
|
||
<select class="input select"><option>Bitte wählen…</option><option>Kühlhaus 1</option><option>Kühlhaus 2</option><option>Tiefkühler A</option><option>Trockenwarenlager</option></select></div>
|
||
<div><label class="block text-sm font-medium text-warm-700 mb-1.5">Datum *</label><input type="date" class="input" value="2026-03-19"></div>
|
||
<div class="flex justify-end gap-3 pt-4">
|
||
<button class="btn btn-outline" onclick="navigate('counts')">Abbrechen</button>
|
||
<button class="btn btn-primary" onclick="showToast('Inventur angelegt','success');navigate('counts')"><i data-lucide="check" class="w-4 h-4"></i> Anlegen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ REZEPTE LISTE ═══════════════ -->
|
||
<div id="page-recipes" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Rezepte</h1><p class="text-warm-500 text-sm">Rezepturen und Produktionsspezifikationen</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Rezept anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex gap-3">
|
||
<input type="text" class="input text-sm max-w-sm" placeholder="Rezept suchen…">
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Typen</option><option>Fertigprodukt</option><option>Halbfertigprodukt</option><option>Rohstoff</option></select>
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Status</option><option>Entwurf</option><option>Aktiv</option><option>Archiviert</option></select>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Rezept</th><th>Typ</th><th>Version</th><th>Ausbeute</th><th>MHD (Tage)</th><th>Zutaten</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('recipe-detail')"><td class="font-medium text-warm-800">Wiener Würstchen</td><td>Fertigprodukt</td><td class="font-mono">v3</td><td>92%</td><td>10</td><td>6</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('recipe-detail')"><td class="font-medium text-warm-800">Leberkäse Bayerisch</td><td>Fertigprodukt</td><td class="font-mono">v2</td><td>95%</td><td>7</td><td>5</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('recipe-detail')"><td class="font-medium text-warm-800">Bratwurst grob</td><td>Fertigprodukt</td><td class="font-mono">v4</td><td>90%</td><td>8</td><td>7</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('recipe-detail')"><td class="font-medium text-warm-800">Fleischwurst</td><td>Fertigprodukt</td><td class="font-mono">v1</td><td>88%</td><td>14</td><td>5</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('recipe-detail')"><td class="font-medium text-warm-800">Brät Grundmasse</td><td>Halbfertigprodukt</td><td class="font-mono">v2</td><td>96%</td><td>3</td><td>4</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('recipe-detail')"><td class="font-medium text-warm-800">Weißwurst (neu)</td><td>Fertigprodukt</td><td class="font-mono">v1</td><td>91%</td><td>5</td><td>8</td><td><span class="badge badge-draft">Entwurf</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ REZEPT DETAIL ═══════════════ -->
|
||
<div id="page-recipe-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Wiener Würstchen</h1><span class="badge badge-active">Aktiv</span><span class="text-sm text-warm-500">v3</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Fertigprodukt · Ausbeute 92% · MHD 10 Tage · Ausgabeartikel: ART-001</p>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="archive" class="w-3.5 h-3.5"></i> Archivieren</button>
|
||
</div>
|
||
</div>
|
||
<!-- Tabs -->
|
||
<div class="flex gap-0 border-b mb-6" style="border-color:var(--border)">
|
||
<button class="tab active" onclick="switchTab(this,'recipe-tab','recipe-ingredients')">Zutaten</button>
|
||
<button class="tab" onclick="switchTab(this,'recipe-tab','recipe-steps')">Produktionsschritte</button>
|
||
<button class="tab" onclick="switchTab(this,'recipe-tab','recipe-batches')">Prod.-Historie</button>
|
||
</div>
|
||
<!-- Zutaten -->
|
||
<div id="recipe-ingredients" class="tab-content recipe-tab active">
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex items-center justify-between">
|
||
<h3 class="font-semibold text-warm-800">Zutaten (für 100 kg Ausgabe)</h3>
|
||
<button class="btn btn-primary btn-sm" disabled><i data-lucide="plus" class="w-3.5 h-3.5"></i> Zutat hinzufügen</button>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>#</th><th>Artikel</th><th>Menge</th><th>Anteil</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>1</td><td class="font-medium text-warm-800">Schweinefleisch S1</td><td class="font-mono">45 kg</td><td>
|
||
<div class="flex items-center gap-2"><div class="progress-bar w-20"><div class="progress-fill bg-brand-400" style="width:45%"></div></div><span class="text-xs text-warm-500">45%</span></div></td></tr>
|
||
<tr><td>2</td><td class="font-medium text-warm-800">Eis / Wasser</td><td class="font-mono">25 kg</td><td>
|
||
<div class="flex items-center gap-2"><div class="progress-bar w-20"><div class="progress-fill bg-info-400" style="width:25%"></div></div><span class="text-xs text-warm-500">25%</span></div></td></tr>
|
||
<tr><td>3</td><td class="font-medium text-warm-800">Schweinefett (Speck)</td><td class="font-mono">20 kg</td><td>
|
||
<div class="flex items-center gap-2"><div class="progress-bar w-20"><div class="progress-fill bg-warning-400" style="width:20%"></div></div><span class="text-xs text-warm-500">20%</span></div></td></tr>
|
||
<tr><td>4</td><td class="font-medium text-warm-800">Nitritpökelsalz</td><td class="font-mono">1.8 kg</td><td>
|
||
<div class="flex items-center gap-2"><div class="progress-bar w-20"><div class="progress-fill bg-warm-400" style="width:2%"></div></div><span class="text-xs text-warm-500">1.8%</span></div></td></tr>
|
||
<tr><td>5</td><td class="font-medium text-warm-800">Gewürzmischung Wiener</td><td class="font-mono">0.8 kg</td><td>
|
||
<div class="flex items-center gap-2"><div class="progress-bar w-20"><div class="progress-fill bg-warm-400" style="width:1%"></div></div><span class="text-xs text-warm-500">0.8%</span></div></td></tr>
|
||
<tr><td>6</td><td class="font-medium text-warm-800">Naturdarm 28/30</td><td class="font-mono">15 Bund</td><td>–</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<!-- Schritte -->
|
||
<div id="recipe-steps" class="tab-content recipe-tab">
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex items-center justify-between">
|
||
<h3 class="font-semibold text-warm-800">Produktionsschritte</h3>
|
||
<button class="btn btn-primary btn-sm" disabled><i data-lucide="plus" class="w-3.5 h-3.5"></i> Schritt hinzufügen</button>
|
||
</div>
|
||
<div class="p-4 space-y-4">
|
||
<div class="flex gap-4 items-start">
|
||
<div class="w-8 h-8 rounded-full bg-brand-100 text-brand-700 flex items-center justify-center font-semibold text-sm shrink-0">1</div>
|
||
<div><div class="font-medium text-warm-800">Fleisch wolfen</div><div class="text-sm text-warm-500 mt-0.5">Schweinefleisch und Speck durch 3mm-Scheibe wolfen · ca. 15 min</div></div>
|
||
</div>
|
||
<div class="flex gap-4 items-start">
|
||
<div class="w-8 h-8 rounded-full bg-brand-100 text-brand-700 flex items-center justify-center font-semibold text-sm shrink-0">2</div>
|
||
<div><div class="font-medium text-warm-800">Kuttern</div><div class="text-sm text-warm-500 mt-0.5">Gewolftes mit Eis und Gewürzen im Kutter emulgieren, Kerntemperatur max. 12 °C · ca. 20 min</div></div>
|
||
</div>
|
||
<div class="flex gap-4 items-start">
|
||
<div class="w-8 h-8 rounded-full bg-brand-100 text-brand-700 flex items-center justify-center font-semibold text-sm shrink-0">3</div>
|
||
<div><div class="font-medium text-warm-800">Füllen</div><div class="text-sm text-warm-500 mt-0.5">Brät in Naturdarm 28/30 füllen und abdrehen (ca. 80g/Stück) · ca. 30 min</div></div>
|
||
</div>
|
||
<div class="flex gap-4 items-start">
|
||
<div class="w-8 h-8 rounded-full bg-brand-100 text-brand-700 flex items-center justify-center font-semibold text-sm shrink-0">4</div>
|
||
<div><div class="font-medium text-warm-800">Brühen</div><div class="text-sm text-warm-500 mt-0.5">Bei 75 °C brühen bis Kerntemperatur 72 °C erreicht · ca. 25 min</div></div>
|
||
</div>
|
||
<div class="flex gap-4 items-start">
|
||
<div class="w-8 h-8 rounded-full bg-brand-100 text-brand-700 flex items-center justify-center font-semibold text-sm shrink-0">5</div>
|
||
<div><div class="font-medium text-warm-800">Abkühlen</div><div class="text-sm text-warm-500 mt-0.5">In Eiswasser auf < 7 °C abkühlen · ca. 20 min</div></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- Historie -->
|
||
<div id="recipe-batches" class="tab-content recipe-tab">
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4"><h3 class="font-semibold text-warm-800">Letzte Produktionschargen</h3></div>
|
||
<table>
|
||
<thead><tr><th>Charge</th><th>Datum</th><th>Soll</th><th>Ist</th><th>Ausschuss</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono">P-2026-03-19-003</td><td>19.03.2026</td><td class="font-mono">120 kg</td><td class="font-mono">118 kg</td><td class="font-mono">2.4 kg</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono">P-2026-03-17-001</td><td>17.03.2026</td><td class="font-mono">100 kg</td><td class="font-mono">97 kg</td><td class="font-mono">3.1 kg</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono">P-2026-03-15-002</td><td>15.03.2026</td><td class="font-mono">80 kg</td><td class="font-mono">78 kg</td><td class="font-mono">2.0 kg</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ CHARGEN LISTE ═══════════════ -->
|
||
<div id="page-batches" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Chargen</h1><p class="text-warm-500 text-sm">Produktionschargen und Rückverfolgbarkeit</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Charge planen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex gap-3">
|
||
<input type="text" class="input text-sm max-w-sm" placeholder="Chargennummer suchen…">
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Status</option><option>Geplant</option><option>In Produktion</option><option>Abgeschlossen</option><option>Storniert</option></select>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Charge</th><th>Rezept</th><th>Soll</th><th>Ist</th><th>Prod.-Datum</th><th>MHD</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono font-medium">P-2026-03-19-004</td><td>Leberkäse Bayerisch</td><td class="font-mono">80 kg</td><td class="font-mono">–</td><td>19.03.2026</td><td>–</td><td><span class="badge badge-inprogress">In Produktion</span></td></tr>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono font-medium">P-2026-03-19-003</td><td>Wiener Würstchen</td><td class="font-mono">120 kg</td><td class="font-mono">118 kg</td><td>19.03.2026</td><td>29.03.2026</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono font-medium">P-2026-03-19-002</td><td>Bratwurst grob</td><td class="font-mono">100 kg</td><td class="font-mono">96 kg</td><td>19.03.2026</td><td>27.03.2026</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono font-medium">P-2026-03-19-001</td><td>Brät Grundmasse</td><td class="font-mono">200 kg</td><td class="font-mono">195 kg</td><td>19.03.2026</td><td>22.03.2026</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('batch-detail')"><td class="font-mono font-medium">P-2026-03-20-001</td><td>Fleischwurst</td><td class="font-mono">60 kg</td><td class="font-mono">–</td><td>20.03.2026</td><td>–</td><td><span class="badge badge-planned">Geplant</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ CHARGE DETAIL ═══════════════ -->
|
||
<div id="page-batch-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Charge P-2026-03-19-003</h1><span class="badge badge-completed">Abgeschlossen</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Wiener Würstchen · 19.03.2026 · MHD 29.03.2026</p>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-outline btn-sm" onclick="navigate('batch-trace')"><i data-lucide="git-branch" class="w-3.5 h-3.5"></i> Rückverfolgung</button>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-5 gap-4 mb-6">
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Soll-Menge</div><div class="text-lg font-semibold text-warm-800 mt-1">120 kg</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Ist-Menge</div><div class="text-lg font-semibold text-success-600 mt-1">118 kg</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Ausschuss</div><div class="text-lg font-semibold text-danger-600 mt-1">2.4 kg</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Ausbeute</div><div class="text-lg font-semibold text-warm-800 mt-1">98.3%</div></div>
|
||
<div class="card p-4 text-center"><div class="text-xs text-warm-500 font-medium uppercase">Rezept-Ausbeute</div><div class="text-lg font-semibold text-warm-500 mt-1">92%</div></div>
|
||
</div>
|
||
<!-- Verbrauchte Chargen -->
|
||
<div class="card overflow-hidden mb-6">
|
||
<div class="p-4"><h3 class="font-semibold text-warm-800">Verbrauchte Eingangsmaterialien (Genealogie)</h3></div>
|
||
<table>
|
||
<thead><tr><th>Eingangscharge</th><th>Artikel</th><th>Menge</th><th>Herkunft</th></tr></thead>
|
||
<tbody>
|
||
<tr><td class="font-mono text-sm">WE-2026-03-18-001</td><td>Schweinefleisch S1</td><td class="font-mono">54 kg</td><td>Fleischgroßhandel Müller</td></tr>
|
||
<tr><td class="font-mono text-sm">WE-2026-03-17-003</td><td>Schweinefett (Speck)</td><td class="font-mono">24 kg</td><td>Fleischgroßhandel Müller</td></tr>
|
||
<tr><td class="font-mono text-sm">–</td><td>Eis / Wasser</td><td class="font-mono">30 kg</td><td>Eigenproduktion</td></tr>
|
||
<tr><td class="font-mono text-sm">WE-2026-03-10-012</td><td>Nitritpökelsalz</td><td class="font-mono">2.2 kg</td><td>Gewürzhaus Schmidt</td></tr>
|
||
<tr><td class="font-mono text-sm">WE-2026-03-10-013</td><td>Gewürzmischung Wiener</td><td class="font-mono">1.0 kg</td><td>Gewürzhaus Schmidt</td></tr>
|
||
<tr><td class="font-mono text-sm">WE-2026-03-15-008</td><td>Naturdarm 28/30</td><td class="font-mono">18 Bund</td><td>Naturdarme Weber</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-3">Bemerkungen</h3>
|
||
<p class="text-sm text-warm-600">Brühtemperatur 74°C erreicht, Kerntemperatur 72°C nach 23 min. Charge planmäßig abgeschlossen. Leichter Mehrverbrauch bei Naturdarm (+3 Bund) aufgrund von Darmrissen.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ PRODUKTIONSAUFTRÄGE LISTE ═══════════════ -->
|
||
<div id="page-prod-orders" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Produktionsaufträge</h1><p class="text-warm-500 text-sm">Planung und Steuerung</p></div>
|
||
<button class="btn btn-primary" onclick="navigate('prod-order-create')"><i data-lucide="plus" class="w-4 h-4"></i> Auftrag anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<div class="p-4 flex gap-3">
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Status</option><option>Geplant</option><option>Freigegeben</option><option>In Bearbeitung</option><option>Abgeschlossen</option><option>Storniert</option></select>
|
||
<select class="input select text-sm py-2 w-auto"><option>Alle Prioritäten</option><option>Dringend</option><option>Hoch</option><option>Normal</option><option>Niedrig</option></select>
|
||
</div>
|
||
<table>
|
||
<thead><tr><th>Auftrag</th><th>Rezept</th><th>Menge</th><th>Geplant für</th><th>Priorität</th><th>Charge</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('prod-order-detail')"><td class="font-mono font-medium">PA-2026-0049</td><td>Fleischwurst</td><td class="font-mono">60 kg</td><td>20.03.2026</td><td><span class="badge badge-urgent">Dringend</span></td><td>–</td><td><span class="badge badge-released">Freigegeben</span></td></tr>
|
||
<tr onclick="navigate('prod-order-detail')"><td class="font-mono font-medium">PA-2026-0048</td><td>Leberkäse Bayerisch</td><td class="font-mono">80 kg</td><td>19.03.2026</td><td><span class="badge badge-high">Hoch</span></td><td class="font-mono text-sm">P-2026-03-19-004</td><td><span class="badge badge-inprogress">In Bearbeitung</span></td></tr>
|
||
<tr onclick="navigate('prod-order-detail')"><td class="font-mono font-medium">PA-2026-0047</td><td>Wiener Würstchen</td><td class="font-mono">120 kg</td><td>19.03.2026</td><td><span class="badge badge-normal">Normal</span></td><td class="font-mono text-sm">P-2026-03-19-003</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('prod-order-detail')"><td class="font-mono font-medium">PA-2026-0046</td><td>Bratwurst grob</td><td class="font-mono">100 kg</td><td>19.03.2026</td><td><span class="badge badge-normal">Normal</span></td><td class="font-mono text-sm">P-2026-03-19-002</td><td><span class="badge badge-completed">Abgeschlossen</span></td></tr>
|
||
<tr onclick="navigate('prod-order-detail')"><td class="font-mono font-medium">PA-2026-0050</td><td>Weißwurst</td><td class="font-mono">40 kg</td><td>21.03.2026</td><td><span class="badge badge-low">Niedrig</span></td><td>–</td><td><span class="badge badge-planned">Geplant</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ PRODUKTIONSAUFTRAG DETAIL ═══════════════ -->
|
||
<div id="page-prod-order-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Auftrag PA-2026-0048</h1><span class="badge badge-inprogress">In Bearbeitung</span><span class="badge badge-high">Hoch</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Leberkäse Bayerisch · 80 kg · Geplant für 19.03.2026</p>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-primary"><i data-lucide="check-check" class="w-4 h-4"></i> Abschließen</button>
|
||
<button class="btn btn-outline btn-sm text-danger-600"><i data-lucide="x-circle" class="w-3.5 h-3.5"></i> Stornieren</button>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Auftragsdaten</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Auftragsnr.</label><span class="font-mono">PA-2026-0048</span></div>
|
||
<div class="detail-item"><label>Rezept</label><span>Leberkäse Bayerisch (v2)</span></div>
|
||
<div class="detail-item"><label>Soll-Menge</label><span>80 kg</span></div>
|
||
<div class="detail-item"><label>Geplant für</label><span>19.03.2026</span></div>
|
||
<div class="detail-item"><label>Priorität</label><span class="badge badge-high">Hoch</span></div>
|
||
<div class="detail-item"><label>Status</label><span class="badge badge-inprogress">In Bearbeitung</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Zugeordnete Charge</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Chargennr.</label><span class="font-mono cursor-pointer text-brand-600" onclick="navigate('batch-detail')">P-2026-03-19-004</span></div>
|
||
<div class="detail-item"><label>Chargen-Status</label><span class="badge badge-inprogress">In Produktion</span></div>
|
||
<div class="detail-item"><label>Gestartet</label><span>19.03.2026, 09:30</span></div>
|
||
<div class="detail-item"><label>Ist-Menge</label><span>–</span></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-3">Notizen</h3>
|
||
<p class="text-sm text-warm-600">Bestellung von REWE Markt Huber – Lieferung am 20.03. bis 08:00 Uhr. Achtung: Käse-Anteil wie vereinbart auf 15% erhöht.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ AUFTRAG ANLEGEN ═══════════════ -->
|
||
<div id="page-prod-order-create" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Produktionsauftrag anlegen</h1><p class="text-warm-500 text-sm">Neuen Produktionsauftrag planen</p></div>
|
||
|
||
<!--
|
||
Grid layout (Desktop):
|
||
┌────────────┬─────────────────────────────────┐
|
||
│ │ Rezept Info │
|
||
│ Formular ├────────────────┬────────────────┤
|
||
│ (row-span) │ Zutaten │ Schritte │
|
||
└────────────┴────────────────┴────────────────┘
|
||
-->
|
||
<div class="grid gap-6" style="grid-template-columns: 1fr 1fr 1fr; grid-template-rows: auto 1fr;">
|
||
|
||
<!-- Form: spans both rows, column 1 -->
|
||
<div class="card p-6 flex flex-col" style="grid-row: 1 / 3; grid-column: 1;">
|
||
<div class="space-y-5 flex-1">
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Rezept *</label>
|
||
<select id="recipe-select" class="input select" onchange="updateRecipePreview(this.value)">
|
||
<option value="">Bitte wählen…</option>
|
||
<option value="wiener">Wiener Würstchen (v3, Aktiv)</option>
|
||
<option value="leberkaese">Leberkäse Bayerisch (v2, Aktiv)</option>
|
||
<option value="bratwurst">Bratwurst grob (v4, Aktiv)</option>
|
||
<option value="fleischwurst">Fleischwurst (v1, Aktiv)</option>
|
||
<option value="braet">Brät Grundmasse (v2, Aktiv)</option>
|
||
</select>
|
||
</div>
|
||
<div class="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Menge (kg) *</label>
|
||
<input id="order-qty" class="input" type="number" placeholder="0" oninput="updateIngredientCalc()">
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Geplant für *</label>
|
||
<input type="date" class="input" value="2026-03-20">
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Priorität</label>
|
||
<div class="flex gap-2">
|
||
<label class="flex-1 cursor-pointer">
|
||
<input type="radio" name="priority" value="low" class="sr-only peer">
|
||
<div class="text-center py-2 px-3 rounded-lg border text-sm font-medium transition-all peer-checked:border-brand-400 peer-checked:bg-brand-50 peer-checked:text-brand-700 border-warm-200 text-warm-500 hover:border-warm-300">Niedrig</div>
|
||
</label>
|
||
<label class="flex-1 cursor-pointer">
|
||
<input type="radio" name="priority" value="normal" class="sr-only peer" checked>
|
||
<div class="text-center py-2 px-3 rounded-lg border text-sm font-medium transition-all peer-checked:border-brand-400 peer-checked:bg-brand-50 peer-checked:text-brand-700 border-warm-200 text-warm-500 hover:border-warm-300">Normal</div>
|
||
</label>
|
||
<label class="flex-1 cursor-pointer">
|
||
<input type="radio" name="priority" value="high" class="sr-only peer">
|
||
<div class="text-center py-2 px-3 rounded-lg border text-sm font-medium transition-all peer-checked:border-warning-400 peer-checked:bg-warning-50 peer-checked:text-warning-700 border-warm-200 text-warm-500 hover:border-warm-300">Hoch</div>
|
||
</label>
|
||
<label class="flex-1 cursor-pointer">
|
||
<input type="radio" name="priority" value="urgent" class="sr-only peer">
|
||
<div class="text-center py-2 px-3 rounded-lg border text-sm font-medium transition-all peer-checked:border-danger-400 peer-checked:bg-danger-50 peer-checked:text-danger-700 border-warm-200 text-warm-500 hover:border-warm-300">Dringend</div>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label class="block text-sm font-medium text-warm-700 mb-1.5">Notizen</label>
|
||
<textarea class="input" rows="3" placeholder="Optionale Hinweise zum Auftrag…"></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="flex justify-end gap-3 pt-5 mt-5 border-t border-warm-100">
|
||
<button class="btn btn-outline" onclick="navigate('prod-orders')">Abbrechen</button>
|
||
<button class="btn btn-primary" onclick="showToast('Produktionsauftrag angelegt','success');navigate('prod-orders')">
|
||
<i data-lucide="check" class="w-4 h-4"></i> Auftrag anlegen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Recipe Info: row 1, columns 2-3 -->
|
||
<div id="recipe-preview-panel" class="recipe-preview" style="grid-row: 1; grid-column: 2 / 4;">
|
||
<!-- Empty state -->
|
||
<div id="recipe-empty" class="card h-full flex flex-col items-center justify-center p-8 text-center">
|
||
<div class="inline-flex items-center justify-center w-14 h-14 rounded-xl bg-warm-100 mb-4"><i data-lucide="book-open" class="w-7 h-7 text-warm-400"></i></div>
|
||
<p class="text-warm-500 text-sm">Wählen Sie ein Rezept aus, um Details,<br>Zutaten und Arbeitsschritte zu sehen.</p>
|
||
</div>
|
||
<!-- Filled state -->
|
||
<div id="recipe-details" class="hidden card h-full p-5">
|
||
<div class="flex items-center justify-between mb-4">
|
||
<div>
|
||
<h3 id="rp-name" class="font-semibold text-warm-800 text-lg">Wiener Würstchen</h3>
|
||
<p class="text-xs text-warm-500 mt-0.5"><span id="rp-type">Fertigprodukt</span> · Version <span id="rp-version">3</span></p>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<span class="badge badge-active">Aktiv</span>
|
||
<button class="btn btn-ghost btn-sm btn-icon text-brand-600" onclick="navigate('recipe-detail')" title="Rezept öffnen"><i data-lucide="external-link" class="w-4 h-4"></i></button>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-3 gap-3">
|
||
<div class="text-center p-2.5 bg-warm-50 rounded-lg">
|
||
<div class="text-[11px] text-warm-500 font-semibold uppercase tracking-wider">Ausbeute</div>
|
||
<div id="rp-yield" class="text-base font-semibold text-warm-800 mt-0.5">92%</div>
|
||
</div>
|
||
<div class="text-center p-2.5 bg-warm-50 rounded-lg">
|
||
<div class="text-[11px] text-warm-500 font-semibold uppercase tracking-wider">MHD</div>
|
||
<div id="rp-shelf" class="text-base font-semibold text-warm-800 mt-0.5">10 Tage</div>
|
||
</div>
|
||
<div class="text-center p-2.5 bg-warm-50 rounded-lg">
|
||
<div class="text-[11px] text-warm-500 font-semibold uppercase tracking-wider">Zutaten</div>
|
||
<div id="rp-count" class="text-base font-semibold text-warm-800 mt-0.5">6</div>
|
||
</div>
|
||
</div>
|
||
<span id="rp-calc-label" class="text-xs text-warm-500 hidden block mt-3">Mengen berechnet für <span id="rp-calc-qty" class="font-semibold text-brand-600">0</span> kg</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ingredients: row 2, column 2 -->
|
||
<div id="recipe-col-ingredients" class="hidden card overflow-hidden" style="grid-row: 2; grid-column: 2;">
|
||
<div class="px-4 py-3 border-b flex items-center justify-between" style="border-color: var(--border)">
|
||
<h4 class="text-sm font-semibold text-warm-800"><i data-lucide="list" class="w-4 h-4 inline -mt-0.5 mr-1 text-warm-400"></i> Zutaten</h4>
|
||
<span id="rp-calc-label2" class="text-xs text-warm-500 hidden">für <span id="rp-calc-qty2" class="font-semibold text-brand-600">100</span> kg</span>
|
||
</div>
|
||
<div id="rp-ingredients" class="divide-y divide-warm-100">
|
||
<!-- filled by JS -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Steps: row 2, column 3 -->
|
||
<div id="recipe-col-steps" class="hidden card overflow-hidden" style="grid-row: 2; grid-column: 3;">
|
||
<div class="px-4 py-3 border-b" style="border-color: var(--border)">
|
||
<h4 class="text-sm font-semibold text-warm-800"><i data-lucide="list-ordered" class="w-4 h-4 inline -mt-0.5 mr-1 text-warm-400"></i> Produktionsschritte</h4>
|
||
</div>
|
||
<div id="rp-steps" class="p-4 space-y-3">
|
||
<!-- filled by JS -->
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ BENUTZER LISTE ═══════════════ -->
|
||
<div id="page-users" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Benutzer</h1><p class="text-warm-500 text-sm">Benutzerverwaltung und Zugriffsrechte</p></div>
|
||
<button class="btn btn-primary"><i data-lucide="plus" class="w-4 h-4"></i> Benutzer anlegen</button>
|
||
</div>
|
||
<div class="card overflow-hidden">
|
||
<table>
|
||
<thead><tr><th>Name</th><th>E-Mail</th><th>Rolle</th><th>Filiale</th><th>Letzter Login</th><th>Status</th></tr></thead>
|
||
<tbody>
|
||
<tr onclick="navigate('user-detail')"><td><div class="flex items-center gap-2"><div class="avatar bg-brand-100 text-brand-700">MH</div><span class="font-medium text-warm-800">Max Huber</span></div></td><td class="text-sm">m.huber@metzgerei-huber.de</td><td>Administrator</td><td>Hauptbetrieb</td><td class="text-sm">19.03.2026 07:45</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('user-detail')"><td><div class="flex items-center gap-2"><div class="avatar bg-info-100 text-info-700">LM</div><span class="font-medium text-warm-800">Lisa Meier</span></div></td><td class="text-sm">l.meier@metzgerei-huber.de</td><td>Produktion</td><td>Hauptbetrieb</td><td class="text-sm">19.03.2026 06:30</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('user-detail')"><td><div class="flex items-center gap-2"><div class="avatar bg-success-100 text-success-700">SK</div><span class="font-medium text-warm-800">Stefan Koch</span></div></td><td class="text-sm">s.koch@metzgerei-huber.de</td><td>Lager</td><td>Hauptbetrieb</td><td class="text-sm">19.03.2026 06:00</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('user-detail')"><td><div class="flex items-center gap-2"><div class="avatar bg-warning-100 text-warning-700">TS</div><span class="font-medium text-warm-800">Thomas Schmidt</span></div></td><td class="text-sm">t.schmidt@metzgerei-huber.de</td><td>Einkauf</td><td>Hauptbetrieb</td><td class="text-sm">18.03.2026 15:00</td><td><span class="badge badge-active">Aktiv</span></td></tr>
|
||
<tr onclick="navigate('user-detail')"><td><div class="flex items-center gap-2"><div class="avatar bg-warm-200 text-warm-600">AW</div><span class="font-medium text-warm-800">Anna Weber</span></div></td><td class="text-sm">a.weber@metzgerei-huber.de</td><td>Verkauf</td><td>Filiale Süd</td><td class="text-sm">17.03.2026 12:30</td><td><span class="badge badge-locked">Gesperrt</span></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ BENUTZER DETAIL ═══════════════ -->
|
||
<div id="page-user-detail" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div>
|
||
<div class="flex items-center gap-3"><h1 class="text-xl font-semibold text-warm-800">Lisa Meier</h1><span class="badge badge-active">Aktiv</span></div>
|
||
<p class="text-warm-500 text-sm mt-0.5">Rolle: Produktion · Hauptbetrieb · Letzter Login: 19.03.2026 06:30</p>
|
||
</div>
|
||
<div class="flex gap-2">
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="pencil" class="w-3.5 h-3.5"></i> Bearbeiten</button>
|
||
<button class="btn btn-outline btn-sm"><i data-lucide="key" class="w-3.5 h-3.5"></i> Passwort ändern</button>
|
||
<button class="btn btn-outline btn-sm text-danger-600"><i data-lucide="lock" class="w-3.5 h-3.5"></i> Sperren</button>
|
||
</div>
|
||
</div>
|
||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Benutzerdaten</h3>
|
||
<div class="detail-grid">
|
||
<div class="detail-item"><label>Benutzername</label><span>l.meier</span></div>
|
||
<div class="detail-item"><label>E-Mail</label><span>l.meier@metzgerei-huber.de</span></div>
|
||
<div class="detail-item"><label>Filiale</label><span>Hauptbetrieb</span></div>
|
||
<div class="detail-item"><label>Erstellt am</label><span>15.01.2025</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<h3 class="font-semibold text-warm-800 mb-4">Rolle & Berechtigungen</h3>
|
||
<div class="mb-3"><span class="badge badge-planned text-sm">Produktion</span></div>
|
||
<div class="flex flex-wrap gap-1.5">
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">RECIPE_READ</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">RECIPE_WRITE</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">BATCH_READ</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">BATCH_WRITE</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">BATCH_COMPLETE</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">PRODUCTION_ORDER_READ</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">PRODUCTION_ORDER_WRITE</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">STOCK_READ</span>
|
||
<span class="text-xs bg-warm-100 text-warm-600 px-2 py-1 rounded">STOCK_MOVEMENT_WRITE</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ ROLLEN ═══════════════ -->
|
||
<div id="page-roles" class="page">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<div><h1 class="text-xl font-semibold text-warm-800">Rollen</h1><p class="text-warm-500 text-sm">Rollen und Berechtigungsprofile</p></div>
|
||
</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
<div class="card p-5">
|
||
<div class="flex items-center justify-between mb-3"><h3 class="font-semibold text-warm-800">Administrator</h3><span class="text-xs text-warm-500">1 Benutzer</span></div>
|
||
<p class="text-sm text-warm-500 mb-3">Vollzugriff auf alle Module und Verwaltungsfunktionen</p>
|
||
<div class="text-xs text-warm-400">Alle Berechtigungen (47)</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<div class="flex items-center justify-between mb-3"><h3 class="font-semibold text-warm-800">Produktion</h3><span class="text-xs text-warm-500">1 Benutzer</span></div>
|
||
<p class="text-sm text-warm-500 mb-3">Rezepte, Chargen und Produktionsaufträge verwalten</p>
|
||
<div class="text-xs text-warm-400">9 Berechtigungen</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<div class="flex items-center justify-between mb-3"><h3 class="font-semibold text-warm-800">Lager</h3><span class="text-xs text-warm-500">1 Benutzer</span></div>
|
||
<p class="text-sm text-warm-500 mb-3">Bestände, Warenbewegungen und Inventur verwalten</p>
|
||
<div class="text-xs text-warm-400">6 Berechtigungen</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<div class="flex items-center justify-between mb-3"><h3 class="font-semibold text-warm-800">Einkauf</h3><span class="text-xs text-warm-500">1 Benutzer</span></div>
|
||
<p class="text-sm text-warm-500 mb-3">Lieferanten, Bestellungen und Wareneingänge</p>
|
||
<div class="text-xs text-warm-400">8 Berechtigungen</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<div class="flex items-center justify-between mb-3"><h3 class="font-semibold text-warm-800">Verkauf</h3><span class="text-xs text-warm-500">1 Benutzer</span></div>
|
||
<p class="text-sm text-warm-500 mb-3">Kunden, Bestellungen und Rechnungen</p>
|
||
<div class="text-xs text-warm-400">9 Berechtigungen</div>
|
||
</div>
|
||
<div class="card p-5">
|
||
<div class="flex items-center justify-between mb-3"><h3 class="font-semibold text-warm-800">Qualitätsmanagement</h3><span class="text-xs text-warm-500">0 Benutzer</span></div>
|
||
<p class="text-sm text-warm-500 mb-3">HACCP, Temperaturprotokolle, Reinigungspläne</p>
|
||
<div class="text-xs text-warm-400">8 Berechtigungen</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ RÜCKVERFOLGUNG ═══════════════ -->
|
||
<div id="page-batch-trace" class="page">
|
||
<div class="mb-6">
|
||
<h1 class="text-xl font-semibold text-warm-800">Rückverfolgung – P-2026-03-19-003</h1>
|
||
<p class="text-warm-500 text-sm">Wiener Würstchen · Vollständige Herkunftskette</p>
|
||
</div>
|
||
<div class="card p-6">
|
||
<div class="flex items-center gap-2 mb-6">
|
||
<button class="btn btn-sm btn-primary">Rückwärts (Herkunft)</button>
|
||
<button class="btn btn-sm btn-outline">Vorwärts (Verwendung)</button>
|
||
</div>
|
||
<!-- Trace Visualization -->
|
||
<div class="space-y-4">
|
||
<div class="flex items-center gap-4">
|
||
<div class="w-48 shrink-0 text-right text-sm text-warm-500">Fertigprodukt</div>
|
||
<div class="card p-3 flex-1 border-brand-300 bg-brand-50">
|
||
<div class="font-mono text-sm font-medium text-brand-700">P-2026-03-19-003</div>
|
||
<div class="text-sm text-warm-600">Wiener Würstchen · 118 kg · MHD 29.03.2026</div>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-4 ml-48 pl-4"><i data-lucide="arrow-up" class="w-4 h-4 text-warm-300"></i></div>
|
||
<div class="flex items-center gap-4">
|
||
<div class="w-48 shrink-0 text-right text-sm text-warm-500">Eingangsmaterial</div>
|
||
<div class="space-y-2 flex-1">
|
||
<div class="card p-3 border-info-200 bg-info-50">
|
||
<div class="font-mono text-sm font-medium text-info-700">WE-2026-03-18-001</div>
|
||
<div class="text-sm text-warm-600">Schweinefleisch S1 · 54 kg · Fleischgroßhandel Müller</div>
|
||
</div>
|
||
<div class="card p-3 border-info-200 bg-info-50">
|
||
<div class="font-mono text-sm font-medium text-info-700">WE-2026-03-17-003</div>
|
||
<div class="text-sm text-warm-600">Schweinefett · 24 kg · Fleischgroßhandel Müller</div>
|
||
</div>
|
||
<div class="card p-3 border-info-200 bg-info-50">
|
||
<div class="font-mono text-sm font-medium text-info-700">WE-2026-03-10-012</div>
|
||
<div class="text-sm text-warm-600">Nitritpökelsalz · 2.2 kg · Gewürzhaus Schmidt</div>
|
||
</div>
|
||
<div class="card p-3 border-info-200 bg-info-50">
|
||
<div class="font-mono text-sm font-medium text-info-700">WE-2026-03-10-013</div>
|
||
<div class="text-sm text-warm-600">Gewürzmischung Wiener · 1.0 kg · Gewürzhaus Schmidt</div>
|
||
</div>
|
||
<div class="card p-3 border-info-200 bg-info-50">
|
||
<div class="font-mono text-sm font-medium text-info-700">WE-2026-03-15-008</div>
|
||
<div class="text-sm text-warm-600">Naturdarm 28/30 · 18 Bund · Naturdarme Weber</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ PLACEHOLDER PAGES ═══════════════ -->
|
||
<div id="page-quality" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Qualitätsmanagement</h1><p class="text-warm-500 text-sm">HACCP, Hygiene und Prüfungen</p></div>
|
||
<div class="card p-12 text-center coming-soon-overlay">
|
||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-warm-100 mb-4"><i data-lucide="shield-check" class="w-8 h-8 text-warm-400"></i></div>
|
||
<h2 class="text-lg font-semibold text-warm-700 mb-2">In Entwicklung</h2>
|
||
<p class="text-warm-500 max-w-md mx-auto">Das Qualitätsmanagement-Modul wird Temperaturprotokolle, Reinigungspläne, Wareneingangskontrollen, Probenentnahme und HACCP-Reports umfassen.</p>
|
||
<div class="flex flex-wrap justify-center gap-2 mt-6">
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Temperaturprotokolle</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Reinigungspläne</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Wareneingangskontrollen</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Probenentnahme</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">HACCP-Reports</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Schulungsnachweise</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Wartungsprotokolle</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="page-procurement" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Einkauf</h1><p class="text-warm-500 text-sm">Bestellwesen und Wareneingang</p></div>
|
||
<div class="card p-12 text-center coming-soon-overlay">
|
||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-warm-100 mb-4"><i data-lucide="shopping-cart" class="w-8 h-8 text-warm-400"></i></div>
|
||
<h2 class="text-lg font-semibold text-warm-700 mb-2">In Entwicklung</h2>
|
||
<p class="text-warm-500 max-w-md mx-auto">Das Einkaufsmodul umfasst Bestellungen, Wareneingangsprüfungen, Lieferantenangebote und automatische Bestellvorschläge basierend auf Mindestbeständen.</p>
|
||
<div class="flex flex-wrap justify-center gap-2 mt-6">
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Bestellungen</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Wareneingang</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Angebotsvergleich</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Bestellvorschläge</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="page-sales" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Verkauf</h1><p class="text-warm-500 text-sm">Aufträge, Rechnungen und Lieferscheine</p></div>
|
||
<div class="card p-12 text-center coming-soon-overlay">
|
||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-warm-100 mb-4"><i data-lucide="receipt" class="w-8 h-8 text-warm-400"></i></div>
|
||
<h2 class="text-lg font-semibold text-warm-700 mb-2">In Entwicklung</h2>
|
||
<p class="text-warm-500 max-w-md mx-auto">Das Verkaufsmodul umfasst Kundenaufträge, Rechnungsstellung, Lieferscheine und die Integration mit Rahmenverträgen.</p>
|
||
<div class="flex flex-wrap justify-center gap-2 mt-6">
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Kundenaufträge</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Rechnungen</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Lieferscheine</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Rahmenverträge</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="page-labeling" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Etikettierung</h1><p class="text-warm-500 text-sm">Etiketten-Design und Druck</p></div>
|
||
<div class="card p-12 text-center coming-soon-overlay">
|
||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-warm-100 mb-4"><i data-lucide="tag" class="w-8 h-8 text-warm-400"></i></div>
|
||
<h2 class="text-lg font-semibold text-warm-700 mb-2">In Entwicklung</h2>
|
||
<p class="text-warm-500 max-w-md mx-auto">Etikettierung mit automatischer Übernahme von Chargeninformationen, MHD, Zutatenverzeichnis und Nährwertangaben.</p>
|
||
<div class="flex flex-wrap justify-center gap-2 mt-6">
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Etikettenvorlagen</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Chargendaten</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Nährwertangaben</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Druckanbindung</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="page-branches" class="page">
|
||
<div class="mb-6"><h1 class="text-xl font-semibold text-warm-800">Filialen</h1><p class="text-warm-500 text-sm">Filialverwaltung und Transfers</p></div>
|
||
<div class="card p-12 text-center coming-soon-overlay">
|
||
<div class="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-warm-100 mb-4"><i data-lucide="store" class="w-8 h-8 text-warm-400"></i></div>
|
||
<h2 class="text-lg font-semibold text-warm-700 mb-2">In Entwicklung</h2>
|
||
<p class="text-warm-500 max-w-md mx-auto">Verwaltung mehrerer Filialen mit eigenem Bestand, filialübergreifende Transfers und zentraler Produktionsplanung.</p>
|
||
<div class="flex flex-wrap justify-center gap-2 mt-6">
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Filialstammdaten</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Bestandsübersicht</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Transfers</span>
|
||
<span class="text-xs bg-warm-100 text-warm-500 px-3 py-1.5 rounded-full">Zentrale Planung</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ═══════════════ TOAST ═══════════════ -->
|
||
<div id="toast" class="toast hidden"></div>
|
||
|
||
<!-- ═══════════════ JAVASCRIPT ═══════════════ -->
|
||
<script>
|
||
// ─── Init ───
|
||
document.addEventListener('DOMContentLoaded', () => { lucide.createIcons(); });
|
||
|
||
// ─── Navigation ───
|
||
const breadcrumbs = {
|
||
'dashboard': [{ label: 'Dashboard' }],
|
||
'articles': [{ label: 'Stammdaten' }, { label: 'Artikel' }],
|
||
'article-detail': [{ label: 'Stammdaten' }, { label: 'Artikel', page: 'articles' }, { label: 'Wiener Würstchen' }],
|
||
'article-create': [{ label: 'Stammdaten' }, { label: 'Artikel', page: 'articles' }, { label: 'Anlegen' }],
|
||
'categories': [{ label: 'Stammdaten' }, { label: 'Kategorien' }],
|
||
'suppliers': [{ label: 'Stammdaten' }, { label: 'Lieferanten' }],
|
||
'supplier-detail': [{ label: 'Stammdaten' }, { label: 'Lieferanten', page: 'suppliers' }, { label: 'Fleischgroßhandel Müller' }],
|
||
'customers': [{ label: 'Stammdaten' }, { label: 'Kunden' }],
|
||
'customer-detail': [{ label: 'Stammdaten' }, { label: 'Kunden', page: 'customers' }, { label: 'Gasthof Zur Linde' }],
|
||
'locations': [{ label: 'Lagerverwaltung' }, { label: 'Lagerorte' }],
|
||
'stocks': [{ label: 'Lagerverwaltung' }, { label: 'Bestände' }],
|
||
'stock-detail': [{ label: 'Lagerverwaltung' }, { label: 'Bestände', page: 'stocks' }, { label: 'Wiener Würstchen – Kühlhaus 1' }],
|
||
'movements': [{ label: 'Lagerverwaltung' }, { label: 'Warenbewegungen' }],
|
||
'movement-record': [{ label: 'Lagerverwaltung' }, { label: 'Warenbewegungen', page: 'movements' }, { label: 'Erfassen' }],
|
||
'counts': [{ label: 'Lagerverwaltung' }, { label: 'Inventur' }],
|
||
'count-detail': [{ label: 'Lagerverwaltung' }, { label: 'Inventur', page: 'counts' }, { label: 'INV-0009' }],
|
||
'count-create': [{ label: 'Lagerverwaltung' }, { label: 'Inventur', page: 'counts' }, { label: 'Anlegen' }],
|
||
'recipes': [{ label: 'Produktion' }, { label: 'Rezepte' }],
|
||
'recipe-detail': [{ label: 'Produktion' }, { label: 'Rezepte', page: 'recipes' }, { label: 'Wiener Würstchen' }],
|
||
'batches': [{ label: 'Produktion' }, { label: 'Chargen' }],
|
||
'batch-detail': [{ label: 'Produktion' }, { label: 'Chargen', page: 'batches' }, { label: 'P-2026-03-19-003' }],
|
||
'batch-trace': [{ label: 'Produktion' }, { label: 'Chargen', page: 'batches' }, { label: 'P-2026-03-19-003', page: 'batch-detail' }, { label: 'Rückverfolgung' }],
|
||
'prod-orders': [{ label: 'Produktion' }, { label: 'Aufträge' }],
|
||
'prod-order-detail': [{ label: 'Produktion' }, { label: 'Aufträge', page: 'prod-orders' }, { label: 'PA-2026-0048' }],
|
||
'prod-order-create': [{ label: 'Produktion' }, { label: 'Aufträge', page: 'prod-orders' }, { label: 'Anlegen' }],
|
||
'users': [{ label: 'Verwaltung' }, { label: 'Benutzer' }],
|
||
'user-detail': [{ label: 'Verwaltung' }, { label: 'Benutzer', page: 'users' }, { label: 'Lisa Meier' }],
|
||
'roles': [{ label: 'Verwaltung' }, { label: 'Rollen' }],
|
||
'quality': [{ label: 'Qualitätsmanagement' }],
|
||
'procurement': [{ label: 'Einkauf' }],
|
||
'sales': [{ label: 'Verkauf' }],
|
||
'labeling': [{ label: 'Etikettierung' }],
|
||
'branches': [{ label: 'Filialen' }],
|
||
};
|
||
|
||
let currentPage = 'dashboard';
|
||
|
||
function navigate(page) {
|
||
// Hide all pages
|
||
document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
|
||
// Show target
|
||
const target = document.getElementById('page-' + page);
|
||
if (target) target.classList.add('active');
|
||
|
||
// Update sidebar
|
||
document.querySelectorAll('.sidebar-item').forEach(n => n.classList.remove('active'));
|
||
const sidebarItem = document.querySelector(`.sidebar-item[data-page="${page}"]`);
|
||
// Try parent pages for detail/create views
|
||
if (!sidebarItem) {
|
||
const parentMap = {
|
||
'article-detail':'articles','article-create':'articles',
|
||
'supplier-detail':'suppliers','customer-detail':'customers',
|
||
'stock-detail':'stocks','movement-record':'movements',
|
||
'count-detail':'counts','count-create':'counts',
|
||
'recipe-detail':'recipes','batch-detail':'batches','batch-trace':'batches',
|
||
'prod-order-detail':'prod-orders','prod-order-create':'prod-orders',
|
||
'user-detail':'users'
|
||
};
|
||
const parent = parentMap[page];
|
||
if (parent) document.querySelector(`.sidebar-item[data-page="${parent}"]`)?.classList.add('active');
|
||
} else {
|
||
sidebarItem.classList.add('active');
|
||
}
|
||
|
||
// Update breadcrumb
|
||
const bc = breadcrumbs[page] || [{ label: page }];
|
||
const bcEl = document.getElementById('breadcrumb');
|
||
bcEl.innerHTML = bc.map((item, i) => {
|
||
const isLast = i === bc.length - 1;
|
||
const sep = i > 0 ? '<i data-lucide="chevron-right" class="w-3.5 h-3.5 text-warm-300"></i>' : '';
|
||
if (isLast) return `${sep}<span class="text-warm-800 font-medium">${item.label}</span>`;
|
||
if (item.page) return `${sep}<a class="hover:text-brand-500 cursor-pointer" onclick="navigate('${item.page}')">${item.label}</a>`;
|
||
return `${sep}<span>${item.label}</span>`;
|
||
}).join('');
|
||
lucide.createIcons();
|
||
|
||
currentPage = page;
|
||
window.scrollTo(0, 0);
|
||
document.querySelector('main')?.scrollTo(0, 0);
|
||
}
|
||
|
||
// ─── Login / Logout ───
|
||
function login() {
|
||
document.getElementById('login-screen').classList.add('hidden');
|
||
document.getElementById('app-shell').classList.remove('hidden');
|
||
lucide.createIcons();
|
||
}
|
||
function logout() {
|
||
document.getElementById('app-shell').classList.add('hidden');
|
||
document.getElementById('login-screen').classList.remove('hidden');
|
||
}
|
||
|
||
// ─── Sidebar ───
|
||
function toggleGroup(btn) {
|
||
btn.closest('.sidebar-group').classList.toggle('collapsed');
|
||
}
|
||
function toggleSidebar() {
|
||
const sb = document.getElementById('sidebar');
|
||
sb.classList.toggle('hidden');
|
||
}
|
||
|
||
// ─── Tabs ───
|
||
function switchTab(tabBtn, groupClass, contentId) {
|
||
// Deactivate siblings
|
||
tabBtn.parentElement.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||
tabBtn.classList.add('active');
|
||
// Hide all tab contents in group
|
||
document.querySelectorAll('.tab-content.' + groupClass).forEach(c => c.classList.remove('active'));
|
||
document.getElementById(contentId)?.classList.add('active');
|
||
}
|
||
|
||
// ─── Toast ───
|
||
function showToast(msg, type) {
|
||
const toast = document.getElementById('toast');
|
||
toast.textContent = msg;
|
||
toast.className = 'toast';
|
||
toast.classList.add(type === 'success' ? 'bg-success-600' : type === 'error' ? 'bg-danger-600' : 'bg-info-600');
|
||
setTimeout(() => toast.classList.add('hidden'), 3000);
|
||
}
|
||
|
||
// ─── Recipe Preview (Produktionsauftrag anlegen) ───
|
||
const recipeData = {
|
||
wiener: {
|
||
name: 'Wiener Würstchen', type: 'Fertigprodukt', version: 3, yield: 92, shelf: 10,
|
||
ingredients: [
|
||
{ name: 'Schweinefleisch S1', qty: 45, unit: 'kg', pct: 45, color: 'bg-brand-400' },
|
||
{ name: 'Eis / Wasser', qty: 25, unit: 'kg', pct: 25, color: 'bg-info-400' },
|
||
{ name: 'Schweinefett (Speck)', qty: 20, unit: 'kg', pct: 20, color: 'bg-warning-400' },
|
||
{ name: 'Nitritpökelsalz', qty: 1.8, unit: 'kg', pct: 1.8, color: 'bg-warm-400' },
|
||
{ name: 'Gewürzmischung Wiener', qty: 0.8, unit: 'kg', pct: 0.8, color: 'bg-warm-400' },
|
||
{ name: 'Naturdarm 28/30', qty: 15, unit: 'Bund', pct: null, color: 'bg-warm-300' },
|
||
],
|
||
steps: [
|
||
{ title: 'Fleisch wolfen', desc: '3mm-Scheibe', time: '15 min' },
|
||
{ title: 'Kuttern', desc: 'Emulgieren, Kerntemp. max. 12 °C', time: '20 min' },
|
||
{ title: 'Füllen', desc: 'Naturdarm 28/30, ca. 80g/Stk.', time: '30 min' },
|
||
{ title: 'Brühen', desc: '75 °C bis Kerntemp. 72 °C', time: '25 min' },
|
||
{ title: 'Abkühlen', desc: 'Eiswasser, Ziel < 7 °C', time: '20 min' },
|
||
]
|
||
},
|
||
leberkaese: {
|
||
name: 'Leberkäse Bayerisch', type: 'Fertigprodukt', version: 2, yield: 95, shelf: 7,
|
||
ingredients: [
|
||
{ name: 'Schweinefleisch S1', qty: 40, unit: 'kg', pct: 40, color: 'bg-brand-400' },
|
||
{ name: 'Rindfleisch R2', qty: 20, unit: 'kg', pct: 20, color: 'bg-danger-300' },
|
||
{ name: 'Schweinefett (Speck)', qty: 25, unit: 'kg', pct: 25, color: 'bg-warning-400' },
|
||
{ name: 'Eis / Wasser', qty: 12, unit: 'kg', pct: 12, color: 'bg-info-400' },
|
||
{ name: 'Leberkäse-Gewürz', qty: 1.8, unit: 'kg', pct: 1.8, color: 'bg-warm-400' },
|
||
],
|
||
steps: [
|
||
{ title: 'Fleisch wolfen', desc: '5mm-Scheibe', time: '15 min' },
|
||
{ title: 'Kuttern', desc: 'Fein kuttern, Kerntemp. max. 14 °C', time: '25 min' },
|
||
{ title: 'In Formen füllen', desc: 'Kastenformen einfetten', time: '15 min' },
|
||
{ title: 'Backen', desc: '180 °C, Kerntemp. 69 °C', time: '90 min' },
|
||
]
|
||
},
|
||
bratwurst: {
|
||
name: 'Bratwurst grob', type: 'Fertigprodukt', version: 4, yield: 90, shelf: 8,
|
||
ingredients: [
|
||
{ name: 'Schweinefleisch S1', qty: 50, unit: 'kg', pct: 50, color: 'bg-brand-400' },
|
||
{ name: 'Schweinefett (Speck)', qty: 25, unit: 'kg', pct: 25, color: 'bg-warning-400' },
|
||
{ name: 'Eis / Wasser', qty: 15, unit: 'kg', pct: 15, color: 'bg-info-400' },
|
||
{ name: 'Bratwurst-Gewürz', qty: 2.0, unit: 'kg', pct: 2.0, color: 'bg-warm-400' },
|
||
{ name: 'Nitritpökelsalz', qty: 1.8, unit: 'kg', pct: 1.8, color: 'bg-warm-400' },
|
||
{ name: 'Zwiebeln, geröstet', qty: 3.0, unit: 'kg', pct: 3.0, color: 'bg-success-300' },
|
||
{ name: 'Schweinedarm 32/34', qty: 12, unit: 'Bund', pct: null, color: 'bg-warm-300' },
|
||
],
|
||
steps: [
|
||
{ title: 'Fleisch wolfen', desc: '6mm-Scheibe (grob)', time: '12 min' },
|
||
{ title: 'Mischen', desc: 'Gewürze und Eis untermischen', time: '10 min' },
|
||
{ title: 'Füllen & Abdrehen', desc: 'Schweinedarm, ca. 100g/Stk.', time: '35 min' },
|
||
{ title: 'Abkühlen', desc: 'Kühlhaus, Ziel < 4 °C', time: '60 min' },
|
||
]
|
||
},
|
||
fleischwurst: {
|
||
name: 'Fleischwurst', type: 'Fertigprodukt', version: 1, yield: 88, shelf: 14,
|
||
ingredients: [
|
||
{ name: 'Schweinefleisch S1', qty: 50, unit: 'kg', pct: 50, color: 'bg-brand-400' },
|
||
{ name: 'Schweinefett (Speck)', qty: 20, unit: 'kg', pct: 20, color: 'bg-warning-400' },
|
||
{ name: 'Eis / Wasser', qty: 22, unit: 'kg', pct: 22, color: 'bg-info-400' },
|
||
{ name: 'Nitritpökelsalz', qty: 1.8, unit: 'kg', pct: 1.8, color: 'bg-warm-400' },
|
||
{ name: 'Fleischwurst-Gewürz', qty: 1.0, unit: 'kg', pct: 1.0, color: 'bg-warm-400' },
|
||
],
|
||
steps: [
|
||
{ title: 'Fleisch wolfen', desc: '3mm-Scheibe', time: '15 min' },
|
||
{ title: 'Kuttern', desc: 'Fein emulgieren, Kerntemp. max. 12 °C', time: '20 min' },
|
||
{ title: 'Füllen', desc: 'Kunstdarm 60mm', time: '20 min' },
|
||
{ title: 'Brühen', desc: '78 °C bis Kerntemp. 72 °C', time: '60 min' },
|
||
{ title: 'Kalt abschrecken', desc: 'Eiswasser', time: '30 min' },
|
||
]
|
||
},
|
||
braet: {
|
||
name: 'Brät Grundmasse', type: 'Halbfertigprodukt', version: 2, yield: 96, shelf: 3,
|
||
ingredients: [
|
||
{ name: 'Schweinefleisch S1', qty: 55, unit: 'kg', pct: 55, color: 'bg-brand-400' },
|
||
{ name: 'Schweinefett (Speck)', qty: 20, unit: 'kg', pct: 20, color: 'bg-warning-400' },
|
||
{ name: 'Eis / Wasser', qty: 23, unit: 'kg', pct: 23, color: 'bg-info-400' },
|
||
{ name: 'Nitritpökelsalz', qty: 1.8, unit: 'kg', pct: 1.8, color: 'bg-warm-400' },
|
||
],
|
||
steps: [
|
||
{ title: 'Fleisch wolfen', desc: '3mm-Scheibe', time: '15 min' },
|
||
{ title: 'Kuttern', desc: 'Fein emulgieren, Kerntemp. max. 10 °C', time: '25 min' },
|
||
{ title: 'Kühlen', desc: 'Sofort in Kühlhaus lagern', time: '–' },
|
||
]
|
||
}
|
||
};
|
||
|
||
function updateRecipePreview(recipeKey) {
|
||
const empty = document.getElementById('recipe-empty');
|
||
const details = document.getElementById('recipe-details');
|
||
const colIng = document.getElementById('recipe-col-ingredients');
|
||
const colSteps = document.getElementById('recipe-col-steps');
|
||
|
||
if (!recipeKey) {
|
||
empty.classList.remove('hidden');
|
||
details.classList.add('hidden');
|
||
colIng.classList.add('hidden');
|
||
colSteps.classList.add('hidden');
|
||
return;
|
||
}
|
||
|
||
const r = recipeData[recipeKey];
|
||
if (!r) return;
|
||
|
||
// Fill header card
|
||
document.getElementById('rp-name').textContent = r.name;
|
||
document.getElementById('rp-type').textContent = r.type;
|
||
document.getElementById('rp-version').textContent = r.version;
|
||
document.getElementById('rp-yield').textContent = r.yield + '%';
|
||
document.getElementById('rp-shelf').textContent = r.shelf + ' Tage';
|
||
document.getElementById('rp-count').textContent = r.ingredients.length;
|
||
|
||
// Fill ingredients (bottom row, left)
|
||
const ingEl = document.getElementById('rp-ingredients');
|
||
ingEl.innerHTML = r.ingredients.map(ing => `
|
||
<div class="flex items-center gap-3 px-4 py-2.5">
|
||
<div class="w-1.5 h-6 rounded-full ${ing.color} shrink-0"></div>
|
||
<div class="flex-1 min-w-0">
|
||
<div class="text-sm text-warm-800 font-medium truncate">${ing.name}</div>
|
||
${ing.pct ? `<div class="text-xs text-warm-400">${ing.pct}%</div>` : ''}
|
||
</div>
|
||
<div class="text-sm font-mono text-warm-600 shrink-0"><span class="ing-qty">${ing.qty}</span> ${ing.unit}</div>
|
||
</div>
|
||
`).join('');
|
||
|
||
// Fill steps (bottom row, right)
|
||
const stepsEl = document.getElementById('rp-steps');
|
||
stepsEl.innerHTML = r.steps.map((s, i) => `
|
||
<div class="step-line flex gap-3 items-start">
|
||
<div class="w-6 h-6 rounded-full bg-brand-100 text-brand-700 flex items-center justify-center text-xs font-bold shrink-0">${i+1}</div>
|
||
<div class="flex-1 min-w-0 pb-1">
|
||
<div class="text-sm font-medium text-warm-800">${s.title}</div>
|
||
<div class="text-xs text-warm-500">${s.desc} · ${s.time}</div>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
|
||
empty.classList.add('hidden');
|
||
details.classList.remove('hidden');
|
||
colIng.classList.remove('hidden');
|
||
colSteps.classList.remove('hidden');
|
||
|
||
updateIngredientCalc();
|
||
lucide.createIcons();
|
||
}
|
||
|
||
function updateIngredientCalc() {
|
||
const qty = parseFloat(document.getElementById('order-qty')?.value) || 0;
|
||
const sel = document.getElementById('recipe-select')?.value;
|
||
const label = document.getElementById('rp-calc-label');
|
||
const qtyLabel = document.getElementById('rp-calc-qty');
|
||
const label2 = document.getElementById('rp-calc-label2');
|
||
const qtyLabel2 = document.getElementById('rp-calc-qty2');
|
||
|
||
if (!sel || qty <= 0) {
|
||
label?.classList.add('hidden');
|
||
label2?.classList.add('hidden');
|
||
return;
|
||
}
|
||
|
||
const r = recipeData[sel];
|
||
if (!r) return;
|
||
|
||
label?.classList.remove('hidden');
|
||
label2?.classList.remove('hidden');
|
||
if (qtyLabel) qtyLabel.textContent = qty;
|
||
if (qtyLabel2) qtyLabel2.textContent = qty;
|
||
|
||
// Update quantities relative to 100kg base
|
||
const factor = qty / 100;
|
||
document.querySelectorAll('#rp-ingredients .ing-qty').forEach((el, i) => {
|
||
if (i < r.ingredients.length) {
|
||
const calcQty = (r.ingredients[i].qty * factor).toFixed(1).replace(/\.0$/, '');
|
||
el.textContent = calcQty;
|
||
}
|
||
});
|
||
}
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|