- Header gets the same title/subtitle pair + primary "Neuer Benutzer" pill on the right that the other tabs use, with the person_add glyph. - Table shell now matches Übersicht/Provisionen: bordered white card, surface-container-high header band with label-caps column titles, zebra rows, hover highlight. - "Admin" column renders a verified_user icon for admins and a long dash otherwise instead of the previous green check. The username column shows a small primary "Sie" badge for the logged-in user. - Action column collapses to two icon-only buttons (edit / delete); delete is rendered with reduced opacity and disabled when it is the logged-in user's row. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2352 lines
119 KiB
HTML
2352 lines
119 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Provisions-Tracker</title>
|
||
|
||
<!-- Tailwind via CDN + Stitch design theme. Preflight is disabled so the
|
||
remaining legacy inline CSS keeps applying to screens we haven't
|
||
migrated yet. -->
|
||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||
<link href="https://fonts.googleapis.com" rel="preconnect">
|
||
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect">
|
||
<link href="https://fonts.googleapis.com/css2?family=Hanken+Grotesk:wght@400;600;700&family=JetBrains+Mono:wght@500&display=swap" rel="stylesheet">
|
||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
||
<script>
|
||
tailwind.config = {
|
||
corePlugins: { preflight: false },
|
||
theme: {
|
||
extend: {
|
||
colors: {
|
||
"primary": "#004ac6",
|
||
"primary-container": "#2563eb",
|
||
"primary-fixed": "#dbe1ff",
|
||
"primary-fixed-dim": "#b4c5ff",
|
||
"on-primary": "#ffffff",
|
||
"on-primary-container": "#eeefff",
|
||
"secondary": "#4e6073",
|
||
"secondary-container": "#cfe2f9",
|
||
"on-secondary": "#ffffff",
|
||
"tertiary": "#943700",
|
||
"tertiary-container": "#bc4800",
|
||
"on-tertiary": "#ffffff",
|
||
"error": "#ba1a1a",
|
||
"error-container": "#ffdad6",
|
||
"on-error": "#ffffff",
|
||
"on-error-container": "#93000a",
|
||
"background": "#f8f9ff",
|
||
"on-background": "#0b1c30",
|
||
"surface": "#f8f9ff",
|
||
"surface-bright": "#f8f9ff",
|
||
"surface-container-lowest": "#ffffff",
|
||
"surface-container-low": "#eff4ff",
|
||
"surface-container": "#e5eeff",
|
||
"surface-container-high": "#dce9ff",
|
||
"surface-container-highest": "#d3e4fe",
|
||
"surface-variant": "#d3e4fe",
|
||
"surface-dim": "#cbdbf5",
|
||
"on-surface": "#0b1c30",
|
||
"on-surface-variant": "#434655",
|
||
"inverse-surface": "#213145",
|
||
"inverse-on-surface": "#eaf1ff",
|
||
"outline": "#737686",
|
||
"outline-variant": "#c3c6d7"
|
||
},
|
||
spacing: {
|
||
"base": "4px", "xs": "4px", "sm": "8px", "md": "16px",
|
||
"lg": "24px", "xl": "32px", "gutter": "16px", "margin": "24px"
|
||
},
|
||
fontFamily: {
|
||
"body-md": ["Hanken Grotesk", "sans-serif"],
|
||
"body-sm": ["Hanken Grotesk", "sans-serif"],
|
||
"title-sm": ["Hanken Grotesk", "sans-serif"],
|
||
"headline-md": ["Hanken Grotesk", "sans-serif"],
|
||
"display-lg": ["Hanken Grotesk", "sans-serif"],
|
||
"label-caps": ["Hanken Grotesk", "sans-serif"],
|
||
"label-numeric": ["JetBrains Mono", "monospace"]
|
||
},
|
||
fontSize: {
|
||
"body-md": ["14px", { lineHeight: "20px", fontWeight: "400" }],
|
||
"body-sm": ["13px", { lineHeight: "18px", fontWeight: "400" }],
|
||
"title-sm": ["18px", { lineHeight: "24px", fontWeight: "600" }],
|
||
"headline-md": ["24px", { lineHeight: "32px", letterSpacing: "-0.01em", fontWeight: "600" }],
|
||
"display-lg": ["32px", { lineHeight: "40px", letterSpacing: "-0.02em", fontWeight: "700" }],
|
||
"label-caps": ["11px", { lineHeight: "16px", letterSpacing: "0.05em", fontWeight: "700" }],
|
||
"label-numeric": ["13px", { lineHeight: "16px", fontWeight: "500" }]
|
||
},
|
||
borderRadius: {
|
||
"DEFAULT": "0.25rem", "lg": "0.5rem", "xl": "0.75rem", "full": "9999px"
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
<style>
|
||
.material-symbols-outlined {
|
||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||
}
|
||
/* Tailwind preflight is disabled to keep legacy screens working,
|
||
but the border utilities expect Preflight's defaults. Restore
|
||
just the border slice: reset width to 0 and set a default
|
||
style+colour so Tailwind's `border` / `border-b` etc. work as
|
||
expected, while not turning every browser-default control
|
||
outline into a visible 2px border. Legacy CSS rules that set
|
||
shorthand `border: …` still win via their class specificity. */
|
||
*, ::before, ::after {
|
||
border-width: 0;
|
||
border-style: solid;
|
||
border-color: #c3c6d7;
|
||
}
|
||
</style>
|
||
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
line-height: 1.6;
|
||
color: #333;
|
||
background-color: #f4f4f4;
|
||
}
|
||
|
||
/* Layout primitives now use Tailwind in the markup; the legacy
|
||
.container/.tab-content keep working so non-migrated screens stay
|
||
styled. body padding-top reserves space for the fixed header. */
|
||
body {
|
||
padding-top: 56px;
|
||
}
|
||
.container {
|
||
max-width: 1440px;
|
||
margin: 0 auto;
|
||
padding: 24px;
|
||
}
|
||
.tab-content {
|
||
display: none;
|
||
}
|
||
.tab-content.active {
|
||
display: block;
|
||
}
|
||
|
||
/* Nav-tab states. The active tab gets a 2px underline anchored to
|
||
the bottom edge of the dark header via inset box-shadow. */
|
||
header .nav-tab {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 100%;
|
||
padding: 0 8px;
|
||
background: transparent;
|
||
border: none;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
font-size: 14px;
|
||
line-height: 20px;
|
||
color: #c3c6d7;
|
||
transition: color 0.15s, box-shadow 0.15s;
|
||
}
|
||
header .nav-tab:hover {
|
||
color: #eaf1ff;
|
||
}
|
||
header .nav-tab.active {
|
||
color: #eaf1ff;
|
||
box-shadow: inset 0 -2px 0 0 #b4c5ff;
|
||
}
|
||
|
||
/* Reset for icon-only buttons (table actions, modal close,
|
||
pdf zoom). The legacy global `button { background, padding,
|
||
color }` would otherwise turn them into solid blue blobs.
|
||
Tailwind utilities like `bg-primary` still win since they
|
||
share class specificity but come later in the cascade. */
|
||
table button,
|
||
.icon-btn {
|
||
background: transparent;
|
||
color: inherit;
|
||
padding: 0;
|
||
border: 0;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
font-size: inherit;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
font-weight: bold;
|
||
color: #2c3e50;
|
||
}
|
||
|
||
input, select, textarea {
|
||
width: 100%;
|
||
padding: 12px;
|
||
border: 2px solid #ddd;
|
||
border-radius: 6px;
|
||
font-size: 16px;
|
||
transition: border-color 0.3s;
|
||
}
|
||
|
||
input:focus, select:focus, textarea:focus {
|
||
outline: none;
|
||
border-color: #3498db;
|
||
}
|
||
|
||
.form-row {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 20px;
|
||
}
|
||
|
||
.form-row-thirds {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr 1fr;
|
||
gap: 20px;
|
||
}
|
||
|
||
button {
|
||
background: #3498db;
|
||
color: white;
|
||
padding: 12px 24px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
transition: background-color 0.3s;
|
||
}
|
||
|
||
button:hover {
|
||
background: #2980b9;
|
||
}
|
||
|
||
.btn-success {
|
||
background: #27ae60;
|
||
}
|
||
|
||
.btn-success:hover {
|
||
background: #229954;
|
||
}
|
||
|
||
.btn-danger {
|
||
background: #e74c3c;
|
||
}
|
||
|
||
.btn-danger:hover {
|
||
background: #c0392b;
|
||
}
|
||
|
||
.admin-section {
|
||
margin-bottom: 30px;
|
||
padding: 20px;
|
||
background: #f8f9fa;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.admin-section h3 {
|
||
margin-bottom: 15px;
|
||
color: #2c3e50;
|
||
}
|
||
|
||
/* New Admin Interface Styles: sidebar + content */
|
||
/* Admin layout — Stitch style sidebar + content pane */
|
||
.admin-layout {
|
||
display: grid;
|
||
grid-template-columns: 260px 1fr;
|
||
gap: 24px;
|
||
align-items: start;
|
||
}
|
||
|
||
.admin-sidebar {
|
||
background: #eff4ff;
|
||
padding: 16px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 8px;
|
||
position: sticky;
|
||
top: 76px;
|
||
}
|
||
|
||
.admin-sidebar h2 {
|
||
margin: 0 0 4px 0;
|
||
color: #0b1c30;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
padding: 0 8px;
|
||
}
|
||
.admin-sidebar .admin-sidebar-subtitle {
|
||
margin: 0 0 16px 0;
|
||
color: #434655;
|
||
font-size: 13px;
|
||
padding: 0 8px;
|
||
}
|
||
|
||
.admin-main {
|
||
min-width: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
|
||
.admin-categories {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
|
||
.admin-cat-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 8px 12px;
|
||
background: transparent;
|
||
border: none;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
transition: all 0.15s ease;
|
||
text-align: left;
|
||
font-family: inherit;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: #434655;
|
||
width: 100%;
|
||
}
|
||
.admin-cat-btn .material-symbols-outlined {
|
||
font-size: 20px;
|
||
color: #737686;
|
||
flex-shrink: 0;
|
||
}
|
||
.admin-cat-btn:hover {
|
||
background: #dce9ff;
|
||
color: #0b1c30;
|
||
}
|
||
.admin-cat-btn:hover .material-symbols-outlined {
|
||
color: #0b1c30;
|
||
}
|
||
.admin-cat-btn.active {
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
font-weight: 600;
|
||
}
|
||
.admin-cat-btn.active .material-symbols-outlined {
|
||
color: #ffffff;
|
||
font-variation-settings: 'FILL' 1;
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.admin-layout {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
.admin-sidebar {
|
||
position: static;
|
||
}
|
||
.admin-categories {
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
}
|
||
.admin-cat-btn {
|
||
width: auto;
|
||
}
|
||
}
|
||
|
||
/* Compact buttons for tables and action cells */
|
||
table button,
|
||
td button,
|
||
.btn-sm {
|
||
padding: 5px 10px !important;
|
||
font-size: 13px !important;
|
||
border-radius: 4px !important;
|
||
}
|
||
|
||
td.actions, .action-cell, table th:last-child, table td:last-child {
|
||
white-space: nowrap;
|
||
}
|
||
|
||
table button + button,
|
||
td button + button,
|
||
.btn-row button + button {
|
||
margin-left: 5px;
|
||
}
|
||
|
||
.admin-category {
|
||
display: none;
|
||
}
|
||
.admin-category.active {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
|
||
/* Each admin sub-page is now a column of bordered cards */
|
||
.admin-page {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24px;
|
||
}
|
||
|
||
.admin-header {
|
||
background: transparent;
|
||
padding: 0;
|
||
text-align: left;
|
||
color: inherit;
|
||
border-bottom: 1px solid #c3c6d7;
|
||
padding-bottom: 16px;
|
||
}
|
||
.admin-header h3 {
|
||
margin: 0 0 4px 0;
|
||
font-size: 24px;
|
||
font-weight: 600;
|
||
color: #0b1c30;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
.admin-header p {
|
||
margin: 0;
|
||
color: #434655;
|
||
font-size: 14px;
|
||
opacity: 1;
|
||
}
|
||
|
||
.admin-form-section,
|
||
.admin-content-section {
|
||
padding: 20px;
|
||
background: #ffffff;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 8px;
|
||
box-shadow: 0 2px 4px rgba(0,0,0,0.04);
|
||
}
|
||
.admin-form-section h4,
|
||
.admin-content-section h4 {
|
||
margin: 0 0 16px 0;
|
||
color: #0b1c30;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.form-row {
|
||
display: flex;
|
||
gap: 15px;
|
||
margin-bottom: 15px;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.form-row label {
|
||
min-width: 120px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.form-row input, .form-row select {
|
||
flex: 1;
|
||
min-width: 200px;
|
||
}
|
||
|
||
.form-row small {
|
||
flex-basis: 100%;
|
||
color: #6c757d;
|
||
font-size: 12px;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
/* Text readability improvements */
|
||
.text-muted {
|
||
color: #6c757d !important;
|
||
font-weight: 500;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.list-item {
|
||
color: #2c3e50 !important;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.list-item strong {
|
||
color: #2c3e50 !important;
|
||
font-weight: 700;
|
||
font-size: 16px;
|
||
}
|
||
|
||
.list-item small {
|
||
color: #495057 !important;
|
||
font-weight: 500;
|
||
font-size: 13px;
|
||
}
|
||
|
||
/* Admin text improvements */
|
||
.admin-card-content {
|
||
color: #2c3e50;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.admin-list p {
|
||
color: #495057 !important;
|
||
font-weight: 500;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.admin-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.admin-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 13px;
|
||
}
|
||
.admin-table thead {
|
||
background: #dce9ff;
|
||
border-bottom: 2px solid #c3c6d7;
|
||
}
|
||
.admin-table th {
|
||
padding: 10px 16px;
|
||
text-align: left;
|
||
font-family: 'Hanken Grotesk', sans-serif;
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
color: #434655;
|
||
}
|
||
.admin-table td {
|
||
padding: 8px 16px;
|
||
border-bottom: 1px solid rgba(195, 198, 215, 0.3);
|
||
color: #0b1c30;
|
||
}
|
||
.admin-table tbody tr:nth-child(even) {
|
||
background: rgba(239, 244, 255, 0.5);
|
||
}
|
||
.admin-table tbody tr:hover {
|
||
background: rgba(211, 228, 254, 0.3);
|
||
}
|
||
|
||
.table-container {
|
||
overflow-x: auto;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 8px;
|
||
background: #ffffff;
|
||
}
|
||
|
||
/* Admin table action buttons — Stitch-like text buttons.
|
||
Overrides the table-button reset for the admin tables. */
|
||
.admin-table button {
|
||
background: #ffffff;
|
||
color: #434655;
|
||
padding: 4px 10px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
transition: background 0.15s, color 0.15s, border-color 0.15s;
|
||
}
|
||
.admin-table button:hover {
|
||
background: #dce9ff;
|
||
color: #0b1c30;
|
||
border-color: #2563eb;
|
||
}
|
||
.admin-table button.btn-success,
|
||
.admin-table button.btn-primary {
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
border-color: #2563eb;
|
||
}
|
||
.admin-table button.btn-success:hover,
|
||
.admin-table button.btn-primary:hover {
|
||
background: #004ac6;
|
||
border-color: #004ac6;
|
||
}
|
||
.admin-table button.btn-danger {
|
||
background: #ffffff;
|
||
color: #ba1a1a;
|
||
border-color: #ffdad6;
|
||
}
|
||
.admin-table button.btn-danger:hover {
|
||
background: #ffdad6;
|
||
border-color: #ba1a1a;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; transform: translateY(20px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.admin-categories {
|
||
grid-template-columns: 1fr 1fr;
|
||
}
|
||
|
||
.form-row {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
}
|
||
|
||
.form-row label {
|
||
min-width: auto;
|
||
}
|
||
}
|
||
|
||
/* Compact admin form controls */
|
||
.admin-form-section input[type=text],
|
||
.admin-form-section input[type=number],
|
||
.admin-form-section input[type=date],
|
||
.admin-form-section select,
|
||
.admin-form-section textarea {
|
||
padding: 6px 10px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 6px;
|
||
font-size: 13px;
|
||
font-family: inherit;
|
||
background: #ffffff;
|
||
color: #0b1c30;
|
||
}
|
||
.admin-form-section input:focus,
|
||
.admin-form-section select:focus,
|
||
.admin-form-section textarea:focus {
|
||
outline: none;
|
||
border-color: #2563eb;
|
||
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
|
||
}
|
||
.admin-form-section label {
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
color: #434655;
|
||
min-width: 0;
|
||
}
|
||
/* Admin form buttons (primary + ghost) */
|
||
.admin-form-section .btn-success,
|
||
.admin-form-section .btn-primary,
|
||
.admin-form-section button.btn {
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
padding: 8px 16px;
|
||
border-radius: 8px;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
border: none;
|
||
cursor: pointer;
|
||
transition: background 0.15s;
|
||
}
|
||
.admin-form-section .btn-success:hover,
|
||
.admin-form-section .btn-primary:hover,
|
||
.admin-form-section button.btn:hover {
|
||
background: #004ac6;
|
||
}
|
||
|
||
.add-form {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.list-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
gap: 16px;
|
||
padding: 10px 14px;
|
||
background: #ffffff;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 6px;
|
||
font-size: 13px;
|
||
color: #0b1c30;
|
||
}
|
||
.list-item strong {
|
||
color: #0b1c30;
|
||
font-weight: 600;
|
||
}
|
||
.list-item small {
|
||
color: #434655;
|
||
font-size: 12px;
|
||
}
|
||
.list-item button {
|
||
background: #ffffff;
|
||
color: #434655;
|
||
padding: 4px 10px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
}
|
||
.list-item button:hover {
|
||
background: #dce9ff;
|
||
color: #0b1c30;
|
||
border-color: #2563eb;
|
||
}
|
||
.list-item button.btn-danger {
|
||
background: #ffffff;
|
||
color: #ba1a1a;
|
||
border-color: #ffdad6;
|
||
}
|
||
.list-item button.btn-danger:hover {
|
||
background: #ffdad6;
|
||
border-color: #ba1a1a;
|
||
}
|
||
.list-item button.btn-success {
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
border-color: #2563eb;
|
||
}
|
||
.list-item button.btn-success:hover {
|
||
background: #004ac6;
|
||
}
|
||
|
||
/* Provider cards used by MA-Prozentsätze / MA-Provisionen / Provisionsregeln */
|
||
.admin-card {
|
||
background: #ffffff;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
}
|
||
.admin-card-header {
|
||
padding: 12px 16px;
|
||
background: #eff4ff;
|
||
border-bottom: 1px solid #c3c6d7;
|
||
}
|
||
.admin-card-header h4 {
|
||
margin: 0;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: #0b1c30;
|
||
}
|
||
.admin-card-content {
|
||
padding: 12px 16px;
|
||
color: #0b1c30;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
.prozentsaetze-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
.tarif-provision-controls .form-row {
|
||
margin-bottom: 0;
|
||
align-items: center;
|
||
}
|
||
.tarif-provision-controls label {
|
||
color: #434655;
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
}
|
||
.tarif-provision-controls input[type=number] {
|
||
padding: 6px 10px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 6px;
|
||
font-size: 13px;
|
||
}
|
||
.tarif-provision-controls button.btn-success {
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
padding: 6px 12px;
|
||
border: none;
|
||
border-radius: 6px;
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
}
|
||
.tarif-provision-controls button.btn-success:hover {
|
||
background: #004ac6;
|
||
}
|
||
|
||
.table-container {
|
||
overflow-x: auto;
|
||
}
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
th, td {
|
||
text-align: left;
|
||
padding: 12px;
|
||
border-bottom: 1px solid #ddd;
|
||
}
|
||
|
||
th {
|
||
background: #34495e;
|
||
color: white;
|
||
}
|
||
|
||
tr:hover {
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.file-upload-area {
|
||
border: 2px dashed #bdc3c7;
|
||
border-radius: 6px;
|
||
padding: 40px;
|
||
text-align: center;
|
||
background: #f8f9fa;
|
||
transition: border-color 0.3s;
|
||
}
|
||
|
||
.file-upload-area:hover {
|
||
border-color: #3498db;
|
||
}
|
||
|
||
.file-upload-area.dragover {
|
||
border-color: #3498db;
|
||
background: #e3f2fd;
|
||
}
|
||
|
||
.message {
|
||
padding: 15px;
|
||
margin: 15px 0;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.message.success {
|
||
background: #d4edda;
|
||
color: #155724;
|
||
border: 1px solid #c3e6cb;
|
||
}
|
||
|
||
.message.error {
|
||
background: #f8d7da;
|
||
color: #721c24;
|
||
border: 1px solid #f5c6cb;
|
||
}
|
||
|
||
.documents-list {
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.document-item {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 10px;
|
||
margin-bottom: 5px;
|
||
background: #f8f9fa;
|
||
border-radius: 4px;
|
||
border: 1px solid #dee2e6;
|
||
}
|
||
|
||
.required {
|
||
color: #e74c3c;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.form-row, .form-row-thirds {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.nav-tabs {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.add-form {
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
|
||
/* Documents modal is now styled with Tailwind in the markup.
|
||
Only keep the document-item rule at line ~574 — that one is
|
||
still used by other places (file upload preview list). */
|
||
|
||
/* Shared app-modal scaffolding (Stitch style). Pair `display:none`
|
||
with `display:flex` in JS to toggle. */
|
||
.app-modal {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(0, 0, 0, 0.4);
|
||
z-index: 1000;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 24px;
|
||
}
|
||
.app-modal-card {
|
||
background: #ffffff;
|
||
border: 1px solid rgba(195, 198, 215, 0.3);
|
||
border-radius: 12px;
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);
|
||
width: 100%;
|
||
max-height: 85vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden;
|
||
}
|
||
.app-modal-header {
|
||
padding: 16px 24px;
|
||
border-bottom: 1px solid #c3c6d7;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
}
|
||
.app-modal-header h3 {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
color: #0b1c30;
|
||
}
|
||
.app-modal-body {
|
||
padding: 24px;
|
||
overflow-y: auto;
|
||
color: #0b1c30;
|
||
}
|
||
.app-modal-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
.app-modal-field {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
.app-modal-field > span {
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
color: #434655;
|
||
}
|
||
.app-modal-field input[type=text],
|
||
.app-modal-field input[type=number],
|
||
.app-modal-field input[type=password],
|
||
.app-modal-field input[type=date],
|
||
.app-modal-field select,
|
||
.app-modal-field textarea {
|
||
padding: 8px 12px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
font-family: inherit;
|
||
color: #0b1c30;
|
||
background: #ffffff;
|
||
width: 100%;
|
||
}
|
||
.app-modal-field input:focus,
|
||
.app-modal-field select:focus,
|
||
.app-modal-field textarea:focus {
|
||
outline: none;
|
||
border-color: #2563eb;
|
||
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
|
||
}
|
||
.app-modal-checkbox {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 14px;
|
||
color: #0b1c30;
|
||
cursor: pointer;
|
||
}
|
||
.app-modal-checkbox input[type=checkbox] {
|
||
width: 16px;
|
||
height: 16px;
|
||
accent-color: #2563eb;
|
||
cursor: pointer;
|
||
}
|
||
.app-modal-footer {
|
||
padding: 16px 24px;
|
||
border-top: 1px solid #c3c6d7;
|
||
background: rgba(239, 244, 255, 0.5);
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
gap: 8px;
|
||
}
|
||
.app-modal-btn-primary {
|
||
background: #2563eb;
|
||
color: #ffffff;
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||
}
|
||
.app-modal-btn-primary:hover {
|
||
background: #004ac6;
|
||
}
|
||
.app-modal-btn-secondary {
|
||
background: #ffffff;
|
||
color: #0b1c30;
|
||
padding: 8px 16px;
|
||
border: 1px solid #c3c6d7;
|
||
border-radius: 8px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
font-family: inherit;
|
||
}
|
||
.app-modal-btn-secondary:hover {
|
||
background: #eff4ff;
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
@keyframes slideIn {
|
||
from { transform: translateY(-50px); opacity: 0; }
|
||
to { transform: translateY(0); opacity: 1; }
|
||
}
|
||
|
||
/* PDF Viewer Styles */
|
||
/* PDF viewer modal now styled with Tailwind in the markup.
|
||
Only keep the canvas container neutral so the PDF page stands
|
||
out against the body background. */
|
||
.pdf-canvas-container {
|
||
text-align: center;
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
}
|
||
|
||
/* Enhanced Tarifoptionen Styling */
|
||
.tarifoption-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 8px 12px;
|
||
margin: 5px 0;
|
||
background: white;
|
||
border: 1px solid #dee2e6;
|
||
border-radius: 6px;
|
||
transition: all 0.2s ease;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.tarifoption-item:hover {
|
||
background: #e3f2fd;
|
||
border-color: #2196f3;
|
||
transform: translateX(2px);
|
||
}
|
||
|
||
.tarifoption-item input[type="checkbox"] {
|
||
width: 18px;
|
||
height: 18px;
|
||
margin: 0;
|
||
cursor: pointer;
|
||
accent-color: #3498db;
|
||
}
|
||
|
||
.tarifoption-label {
|
||
flex: 1;
|
||
font-weight: 500;
|
||
color: #2c3e50;
|
||
cursor: pointer;
|
||
user-select: none;
|
||
}
|
||
|
||
.tarifoption-price {
|
||
font-size: 12px;
|
||
color: #27ae60;
|
||
font-weight: 600;
|
||
background: #e8f5e8;
|
||
padding: 2px 8px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.tarifoption-price.negative {
|
||
color: #e74c3c;
|
||
background: #fde8e8;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body class="bg-background min-h-screen text-on-background" style="font-family: 'Hanken Grotesk', sans-serif;">
|
||
|
||
<!-- Stitch-style top nav: dark slate header with brand on the left,
|
||
tab navigation in the middle, user pill on the right. The nav-tab
|
||
class is kept as a JS hook; CSS is now Tailwind. -->
|
||
<header class="bg-inverse-surface border-b border-outline-variant fixed top-0 left-0 right-0 z-50 h-14">
|
||
<div class="flex justify-between items-center w-full px-lg h-full max-w-[1440px] mx-auto">
|
||
<div class="flex items-center gap-sm">
|
||
<span class="material-symbols-outlined text-inverse-on-surface">monitoring</span>
|
||
<span class="text-title-sm font-semibold text-inverse-on-surface">Provisions-Tracker</span>
|
||
</div>
|
||
<nav class="hidden md:flex items-stretch h-full">
|
||
<ul class="flex gap-lg h-full">
|
||
<li class="h-full flex"><button class="nav-tab active" onclick="showTab('schaltung')">Schaltung erfassen</button></li>
|
||
<li class="h-full flex"><button class="nav-tab" onclick="showTab('overview')">Übersicht</button></li>
|
||
<li class="h-full flex"><button class="nav-tab" onclick="showTab('provisionen')">Provisionen</button></li>
|
||
<li class="h-full flex"><button class="nav-tab" onclick="showTab('geloeschte')">Gelöschte Schaltungen</button></li>
|
||
<li class="h-full flex"><button class="nav-tab" onclick="showTab('admin')">Administration</button></li>
|
||
<li class="h-full flex admin-only" style="display:none"><button class="nav-tab" onclick="showTab('users')">Benutzer</button></li>
|
||
</ul>
|
||
</nav>
|
||
<div class="flex items-center gap-md">
|
||
<span id="headerUserName" class="text-body-sm text-inverse-on-surface/90 hidden lg:inline-block"></span>
|
||
<div class="h-6 w-px bg-outline-variant/30"></div>
|
||
<button id="headerLogoutBtn" class="text-body-md text-primary-fixed-dim hover:text-inverse-on-surface transition-colors flex items-center gap-xs">
|
||
<span class="material-symbols-outlined text-[18px]">logout</span>
|
||
Abmelden
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="container">
|
||
|
||
<!-- Schaltung erfassen Tab (2-step wizard) -->
|
||
<div id="schaltung" class="tab-content active">
|
||
|
||
<!-- Step 1: Anbieter wählen -->
|
||
<div id="wizardStep1" class="bg-surface-container-lowest border border-outline-variant rounded-lg p-lg shadow-[0_2px_4px_rgba(0,0,0,0.04)]">
|
||
<div class="mb-lg border-b border-outline-variant pb-md">
|
||
<h1 class="text-headline-md text-on-surface mb-xs">Neue Schaltung</h1>
|
||
<p class="text-body-sm text-on-surface-variant">Schritt 1 von 2: Anbieter wählen</p>
|
||
</div>
|
||
<div id="wizardAnbieterButtons" class="grid grid-cols-2 lg:grid-cols-3 gap-md"></div>
|
||
</div>
|
||
|
||
<!-- Step 2: VO + Tarif + Tarifoptionen + Kundendaten -->
|
||
<div id="wizardStep2" style="display:none;" class="bg-surface-container-lowest border border-outline-variant rounded-lg p-lg shadow-[0_2px_4px_rgba(0,0,0,0.04)]">
|
||
<div class="mb-lg border-b border-outline-variant pb-md flex justify-between items-start gap-md">
|
||
<div>
|
||
<h2 class="text-headline-md text-on-surface mb-xs">Neue Schaltung</h2>
|
||
<p class="text-body-sm text-on-surface-variant">Schritt 2 von 2: Vertragsdetails erfassen<span id="wizardAnbieterLabel" class="text-primary"></span></p>
|
||
</div>
|
||
<button type="button" onclick="wizardBackToStep1()" class="px-md py-sm rounded-lg border border-outline-variant bg-surface text-on-surface text-body-sm hover:bg-surface-container-low transition-colors flex items-center gap-xs">
|
||
<span class="material-symbols-outlined text-[18px]">arrow_back</span>
|
||
Anbieter ändern
|
||
</button>
|
||
</div>
|
||
|
||
<form id="schaltungForm">
|
||
<div class="flex flex-col xl:flex-row gap-lg">
|
||
<!-- Linke Spalte: Aktivierungsdaten -->
|
||
<div class="flex-1 flex flex-col gap-md">
|
||
<h3 class="text-title-sm text-on-surface border-b border-outline-variant pb-xs">Aktivierungsdaten</h3>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="wizardVo">VO-Auswahl <span class="text-primary">*</span></label>
|
||
<select id="wizardVo" required onchange="loadTarifeForWizard()"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
<option value="">VO wählen...</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="wizardTarif">Tarif <span class="text-primary">*</span></label>
|
||
<select id="wizardTarif" name="tarif_id" required onchange="loadTarifoptionenForWizard()"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
<option value="">Erst VO wählen...</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base" id="tarifoptionenSection" style="display:none;">
|
||
<label class="text-label-caps text-on-surface-variant">Tarifoptionen</label>
|
||
<div id="tarifoptionenList" class="grid grid-cols-1 gap-xs"></div>
|
||
<div id="noTarifoptionen" style="display:none;" class="text-body-sm text-on-surface-variant italic">Keine Tarifoptionen verfügbar</div>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-2 gap-md">
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="eingabeDatum">Erfassung <span class="text-primary">*</span></label>
|
||
<input type="date" id="eingabeDatum" name="eingabe_datum" required
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm font-label-numeric text-label-numeric text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="schaltungsDatum">Vertragsbeginn <span class="text-primary">*</span></label>
|
||
<input type="date" id="schaltungsDatum" name="schaltungs_datum" required
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm font-label-numeric text-label-numeric text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant">Erfasser</label>
|
||
<input type="text" id="wizardErfasser" readonly
|
||
class="w-full bg-surface-container-low border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface-variant outline-none">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Rechte Spalte: Vertragsdaten -->
|
||
<div class="flex-1 flex flex-col gap-md">
|
||
<h3 class="text-title-sm text-on-surface border-b border-outline-variant pb-xs">Vertragsdaten</h3>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="schaltungsId">Schaltungs-ID <span class="text-primary">*</span></label>
|
||
<input type="text" id="schaltungsId" name="schaltungs_id" required
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm font-label-numeric text-label-numeric text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="firma">Firma (optional)</label>
|
||
<input type="text" id="firma" name="firma"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
|
||
<div class="grid grid-cols-2 gap-md">
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="vorname">Vorname <span class="text-primary">*</span></label>
|
||
<input type="text" id="vorname" name="vorname" required
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="nachname">Nachname <span class="text-primary">*</span></label>
|
||
<input type="text" id="nachname" name="nachname" required
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="rufnummer">Rufnummer (optional)</label>
|
||
<input type="text" id="rufnummer" name="rufnummer"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm font-label-numeric text-label-numeric text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="hardware">Hardware (optional, 15 Zeichen)</label>
|
||
<input type="text" id="hardware" name="hardware" onchange="toggleHardwarePricing()"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm text-body-md text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
|
||
<div id="hardwarePricingFields" style="display:none;" class="grid grid-cols-2 gap-md">
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="hardwareEk">Hardware-EK</label>
|
||
<input type="number" id="hardwareEk" name="hardware_ek" step="0.01" min="0" placeholder="0.00"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm font-label-numeric text-label-numeric text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant" for="kundenverkaufspreis">Kundenverkaufspreis</label>
|
||
<input type="number" id="kundenverkaufspreis" name="kundenverkaufspreis_netto" step="0.01" min="0" placeholder="0.00"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded-lg h-10 px-sm font-label-numeric text-label-numeric text-on-surface focus:border-primary focus:ring-4 focus:ring-primary/20 outline-none">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="flex flex-col gap-base">
|
||
<label class="text-label-caps text-on-surface-variant">Dokumente hochladen</label>
|
||
<div class="file-upload-area border border-dashed border-outline-variant rounded-lg p-md flex flex-col items-center justify-center bg-surface-container-lowest hover:bg-surface-container-low transition-colors cursor-pointer" id="fileUploadArea">
|
||
<span class="material-symbols-outlined text-on-surface-variant text-[28px] mb-xs">upload_file</span>
|
||
<p class="text-body-sm text-on-surface-variant">Dateien hier ablegen oder klicken</p>
|
||
<input type="file" id="documentUpload" multiple accept=".pdf,.jpg,.jpeg,.png,.doc,.docx" style="display:none;">
|
||
</div>
|
||
<div id="uploadedFiles" class="flex flex-col gap-xs mt-xs"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<input type="hidden" id="anbieter" name="anbieter_id">
|
||
|
||
<div class="mt-xl pt-md border-t border-outline-variant flex justify-end">
|
||
<button type="submit" class="px-md py-sm rounded-lg bg-primary-container text-on-primary text-title-sm hover:bg-primary transition-colors flex items-center gap-xs shadow-sm">
|
||
<span class="material-symbols-outlined text-[18px]">save</span>
|
||
Schaltung speichern
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Übersicht Tab -->
|
||
<div id="overview" class="tab-content">
|
||
<div class="flex flex-col gap-lg">
|
||
|
||
<!-- Page header -->
|
||
<div class="flex justify-between items-end flex-wrap gap-md">
|
||
<div>
|
||
<h1 class="text-headline-md text-on-background mb-xs">Schaltungs-Übersicht</h1>
|
||
<p class="text-body-sm text-on-surface-variant">Verwaltung und Kontrolle aller erfassten Schaltungen.</p>
|
||
</div>
|
||
<button type="button" onclick="showTab('schaltung')" class="bg-primary-container text-on-primary hover:bg-primary transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-sm shadow-sm">
|
||
<span class="material-symbols-outlined text-[18px]">add</span>
|
||
Neue Schaltung
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Filter bar -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg p-md shadow-[0_2px_4px_rgba(0,0,0,0.04)] flex flex-wrap items-end gap-md">
|
||
<div class="flex flex-col gap-xs w-[180px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterAnbieterOverview">Anbieter</label>
|
||
<select id="filterAnbieterOverview" class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm text-body-sm text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
<option value="">Alle Anbieter</option>
|
||
</select>
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[180px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterTarifOverview">Tarif</label>
|
||
<select id="filterTarifOverview" class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm text-body-sm text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
<option value="">Alle Tarife</option>
|
||
</select>
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[160px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterSchaltungsIdOverview">Schaltungs-ID</label>
|
||
<input type="text" id="filterSchaltungsIdOverview" placeholder="ID1, ID2…"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-label-numeric text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[160px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterRufnummerOverview">Rufnummer</label>
|
||
<input type="text" id="filterRufnummerOverview" placeholder="Suche…"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-label-numeric text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[320px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase">Zeitraum</label>
|
||
<div class="flex items-center gap-sm">
|
||
<input type="date" id="filterDatumVonOverview"
|
||
class="flex-1 min-w-0 bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-[12px] text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
<span class="text-outline-variant shrink-0">–</span>
|
||
<input type="date" id="filterDatumBisOverview"
|
||
class="flex-1 min-w-0 bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-[12px] text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
</div>
|
||
</div>
|
||
<button type="button" onclick="clearFiltersOverview()"
|
||
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded px-md h-8 text-body-sm flex items-center gap-xs">
|
||
<span class="material-symbols-outlined text-[16px]">restart_alt</span>
|
||
Zurücksetzen
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Data table -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg shadow-[0_2px_4px_rgba(0,0,0,0.04)] overflow-hidden">
|
||
<div class="overflow-x-auto">
|
||
<table id="schaltungenTable" class="w-full text-left border-collapse">
|
||
<thead class="bg-surface-container-high border-b-2 border-outline-variant">
|
||
<tr>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-right w-[80px]">ID</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Daten</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Kunde / Firma</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Rufnummer</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Anbieter</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Tarif</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Hardware</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-center w-[80px]">Dokumente</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-center w-[80px]">Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="text-body-sm text-on-surface"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Provisionen Tab -->
|
||
<div id="provisionen" class="tab-content">
|
||
<div class="flex flex-col gap-lg">
|
||
|
||
<!-- Page header -->
|
||
<div class="flex justify-between items-end flex-wrap gap-md">
|
||
<div>
|
||
<h1 class="text-headline-md text-on-background mb-xs">Provisions-Übersicht</h1>
|
||
<p class="text-body-sm text-on-surface-variant">Auswertung der berechneten Shop- und Mitarbeiter-Provisionen.</p>
|
||
</div>
|
||
<button onclick="exportProvisionenToPdf()" class="bg-primary-container text-on-primary hover:bg-primary transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-sm shadow-sm">
|
||
<span class="material-symbols-outlined text-[18px]">download</span>
|
||
PDF-Export
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Filter bar -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg p-md shadow-[0_2px_4px_rgba(0,0,0,0.04)] flex flex-wrap items-end gap-md">
|
||
<div class="flex flex-col gap-xs w-[180px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterAnbieterProvisionen">Anbieter</label>
|
||
<select id="filterAnbieterProvisionen" class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm text-body-sm text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
<option value="">Alle Anbieter</option>
|
||
</select>
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[180px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterTarifProvisionen">Tarif</label>
|
||
<select id="filterTarifProvisionen" class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm text-body-sm text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
<option value="">Alle Tarife</option>
|
||
</select>
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[160px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterSchaltungsIdProvisionen">Schaltungs-ID</label>
|
||
<input type="text" id="filterSchaltungsIdProvisionen" placeholder="ID1, ID2…"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-label-numeric text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[160px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase" for="filterRufnummerProvisionen">Rufnummer</label>
|
||
<input type="text" id="filterRufnummerProvisionen" placeholder="Suche…"
|
||
class="w-full bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-label-numeric text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
</div>
|
||
<div class="flex flex-col gap-xs w-[320px]">
|
||
<label class="text-label-caps text-on-surface-variant uppercase">Zeitraum</label>
|
||
<div class="flex items-center gap-sm">
|
||
<input type="date" id="filterDatumVonProvisionen"
|
||
class="flex-1 min-w-0 bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-[12px] text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
<span class="text-outline-variant shrink-0">–</span>
|
||
<input type="date" id="filterDatumBisProvisionen"
|
||
class="flex-1 min-w-0 bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm font-label-numeric text-[12px] text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary">
|
||
</div>
|
||
</div>
|
||
<button type="button" onclick="clearFiltersProvisionen()"
|
||
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded px-md h-8 text-body-sm flex items-center gap-xs">
|
||
<span class="material-symbols-outlined text-[16px]">restart_alt</span>
|
||
Zurücksetzen
|
||
</button>
|
||
</div>
|
||
|
||
<!-- KPI cards -->
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-md">
|
||
<!-- Shop -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg p-md shadow-[0_2px_4px_rgba(0,0,0,0.04)] flex flex-col gap-sm relative overflow-hidden">
|
||
<div class="absolute right-0 top-0 w-16 h-16 bg-surface-container-low rounded-bl-full opacity-50 pointer-events-none"></div>
|
||
<h3 class="text-label-caps text-on-surface-variant uppercase tracking-widest flex items-center gap-xs">
|
||
<span class="material-symbols-outlined text-outline text-[14px]">storefront</span>
|
||
Shop-Provision gesamt
|
||
</h3>
|
||
<div class="flex justify-end items-baseline gap-xs">
|
||
<span id="totalShopProvision" class="font-label-numeric text-display-lg text-on-surface leading-none">0,00 €</span>
|
||
</div>
|
||
</div>
|
||
<!-- Mitarbeiter -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg p-md shadow-[0_2px_4px_rgba(0,0,0,0.04)] flex flex-col gap-sm relative overflow-hidden">
|
||
<div class="absolute right-0 top-0 w-16 h-16 bg-surface-container-low rounded-bl-full opacity-50 pointer-events-none"></div>
|
||
<h3 class="text-label-caps text-on-surface-variant uppercase tracking-widest flex items-center gap-xs">
|
||
<span class="material-symbols-outlined text-outline text-[14px]">badge</span>
|
||
Mitarbeiter-Provision gesamt
|
||
</h3>
|
||
<div class="flex justify-end items-baseline gap-xs">
|
||
<span id="totalMitarbeiterProvision" class="font-label-numeric text-display-lg text-on-surface leading-none">0,00 €</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Data table -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg shadow-[0_2px_4px_rgba(0,0,0,0.04)] overflow-hidden">
|
||
<div class="overflow-x-auto">
|
||
<table id="provisionenTable" class="w-full text-left border-collapse">
|
||
<thead class="bg-surface-container-high border-b-2 border-outline-variant">
|
||
<tr>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-right w-[80px]">ID</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase w-[110px]">Datum</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Kunde</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Anbieter</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Tarif</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-right w-[140px]">Shop-Prov.</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-right w-[140px]">MA-Prov.</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-center w-[60px]">Quelle</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="text-body-sm text-on-surface"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Gelöschte Schaltungen Tab -->
|
||
<div id="geloeschte" class="tab-content">
|
||
<div class="flex flex-col gap-lg">
|
||
|
||
<!-- Page header -->
|
||
<div class="flex justify-between items-end flex-wrap gap-md">
|
||
<div>
|
||
<h1 class="text-headline-md text-on-background mb-xs">Gelöschte Schaltungen</h1>
|
||
<p class="text-body-sm text-on-surface-variant">Archiv aller soft-gelöschten Schaltungen mit Löschgrund und Zeitstempel.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Data table -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg shadow-[0_2px_4px_rgba(0,0,0,0.04)] overflow-hidden">
|
||
<div class="overflow-x-auto">
|
||
<table id="geloeschteSchaltungenTable" class="w-full text-left border-collapse">
|
||
<thead class="bg-surface-container-high border-b-2 border-outline-variant">
|
||
<tr>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-right w-[80px]">ID</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Daten</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Kunde / Firma</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Rufnummer</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Anbieter</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Tarif</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Hardware</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Löschgrund</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase w-[140px]">Gelöscht am</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody class="text-body-sm text-on-surface"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Administration Tab -->
|
||
<div id="admin" class="tab-content">
|
||
<div class="admin-layout">
|
||
<!-- Sidebar -->
|
||
<aside class="admin-sidebar">
|
||
<h2>Administration</h2>
|
||
<p class="admin-sidebar-subtitle">Systemsteuerung</p>
|
||
<div class="admin-categories">
|
||
<button class="admin-cat-btn active" onclick="showAdminCategory('anbieter')">
|
||
<span class="material-symbols-outlined">corporate_fare</span>
|
||
<span>Anbieter</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('vos')">
|
||
<span class="material-symbols-outlined">badge</span>
|
||
<span>VOs</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('tarife')">
|
||
<span class="material-symbols-outlined">receipt_long</span>
|
||
<span>Tarife</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('tarifoptionen')">
|
||
<span class="material-symbols-outlined">tune</span>
|
||
<span>Tarifoptionen</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('mitarbeiter-prozentsaetze')">
|
||
<span class="material-symbols-outlined">percent</span>
|
||
<span>MA-Prozentsätze</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('mitarbeiter-provisionen')">
|
||
<span class="material-symbols-outlined">payments</span>
|
||
<span>MA-Provisionen</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('provisionsregeln')">
|
||
<span class="material-symbols-outlined">rule</span>
|
||
<span>Provisionsregeln</span>
|
||
</button>
|
||
<button class="admin-cat-btn" onclick="showAdminCategory('global-provisionsregeln')">
|
||
<span class="material-symbols-outlined">public</span>
|
||
<span>Globale Regeln</span>
|
||
</button>
|
||
</div>
|
||
</aside>
|
||
|
||
<!-- Content -->
|
||
<main class="admin-main">
|
||
|
||
<!-- Anbieter Management -->
|
||
<div id="admin-anbieter" class="admin-category active">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Anbieter verwalten</h3>
|
||
<p>Hier können Sie Telekommunikationsanbieter hinzufügen und verwalten.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<h4>Neuen Anbieter hinzufügen</h4>
|
||
<div class="add-form">
|
||
<input type="text" id="newAnbieter" placeholder="Name des Anbieters (z.B. Telekom, Vodafone)">
|
||
<button onclick="addAnbieter()" class="btn-success">Hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Bestehende Anbieter</h4>
|
||
<div class="table-container">
|
||
<table class="admin-table">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Anbieter-Name</th>
|
||
<th>Erstellt am</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="anbieterList">
|
||
<!-- Content loaded dynamically -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- VOs Management -->
|
||
<div id="admin-vos" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>VOs (Vertriebspartner-Nummern) verwalten</h3>
|
||
<p>Pro Anbieter können beliebig viele VOs angelegt werden. Jeder Tarif wird genau einer VO zugeordnet.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<h4>Neue VO hinzufügen</h4>
|
||
<div class="add-form">
|
||
<select id="voAnbieter" style="margin-right:8px;">
|
||
<option value="">Anbieter wählen...</option>
|
||
</select>
|
||
<input type="text" id="voNummer" placeholder="VO-Nummer (z.B. 27518900)" style="margin-right:8px;">
|
||
<input type="text" id="voBezeichnung" placeholder="Bezeichnung (z.B. Fachhandel)" style="margin-right:8px;">
|
||
<button onclick="addVo()" class="btn-success">Hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Bestehende VOs</h4>
|
||
<p style="color:#666; font-size:13px;">Die mit ★ markierte VO wird bei der Schaltungserfassung automatisch vorausgewählt.</p>
|
||
<div class="table-container">
|
||
<table class="admin-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Anbieter</th>
|
||
<th>Nummer</th>
|
||
<th>Bezeichnung</th>
|
||
<th>Aktiv</th>
|
||
<th>Standard</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="vosList"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tarife Management -->
|
||
<div id="admin-tarife" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Tarife verwalten</h3>
|
||
<p>Verwalten Sie Tarife und deren Provisionen für jeden Anbieter.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<h4>Neuen Tarif hinzufügen</h4>
|
||
<div class="tarif-form">
|
||
<div class="form-row">
|
||
<select id="tarifAnbieter" onchange="loadVosForTarifForm()">
|
||
<option value="">Anbieter wählen...</option>
|
||
</select>
|
||
<select id="tarifVo">
|
||
<option value="">VO wählen...</option>
|
||
</select>
|
||
<input type="text" id="newTarif" placeholder="Name des Tarifs">
|
||
</div>
|
||
<div class="form-row">
|
||
<label>Provision (€):</label>
|
||
<input type="number" id="tarifProvisionBetrag" placeholder="Betrag in Euro" step="0.01" min="0">
|
||
</div>
|
||
<div class="form-row">
|
||
<label>Beschreibung:</label>
|
||
<input type="text" id="tarifBeschreibung" placeholder="Beschreibung (optional)">
|
||
</div>
|
||
<button onclick="addTarif()" class="btn-success">Tarif hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Bestehende Tarife</h4>
|
||
<div class="table-container">
|
||
<table class="admin-table">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Anbieter</th>
|
||
<th>VO</th>
|
||
<th>Tarif-Name</th>
|
||
<th>Provision (€)</th>
|
||
<th>Beschreibung</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tarifeList">
|
||
<!-- Content loaded dynamically -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tarifoptionen Management -->
|
||
<div id="admin-tarifoptionen" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Tarifoptionen verwalten</h3>
|
||
<p>Verwalten Sie Zusatzoptionen und Aktionscodes für Tarife.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<div class="flex justify-between items-center">
|
||
<div>
|
||
<h4 style="margin:0;">Tarifoptionen verwalten</h4>
|
||
<p style="margin:4px 0 0 0; color:#434655; font-size:13px;">Erstellen und verwalten Sie Zusatzoptionen für Tarife</p>
|
||
</div>
|
||
<button onclick="openAddTarifoptionModal()"
|
||
class="bg-primary-container text-on-primary hover:bg-primary transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-xs shadow-sm">
|
||
<span class="material-symbols-outlined text-[18px]">add</span>
|
||
Neue Tarifoption
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<div class="flex justify-between items-center" style="margin-bottom:16px;">
|
||
<h4 style="margin:0;">Bestehende Tarifoptionen</h4>
|
||
<div class="flex items-center gap-sm">
|
||
<input type="text" id="tarifoptionSearch" placeholder="Nach Tarif oder Option suchen…"
|
||
oninput="filterTarifoptionenAdmin()"
|
||
class="bg-surface-container-lowest border border-outline-variant rounded h-8 px-sm text-body-sm text-on-surface focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary"
|
||
style="width:250px;">
|
||
<button onclick="clearTarifoptionSearch()"
|
||
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded h-8 px-md text-body-sm">
|
||
Zurücksetzen
|
||
</button>
|
||
<div id="tarifoptionSearchCounter" class="text-body-sm text-on-surface-variant" style="min-width:120px;"></div>
|
||
</div>
|
||
</div>
|
||
<div class="table-container">
|
||
<table class="admin-table">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Anbieter</th>
|
||
<th>Tarif</th>
|
||
<th>Option</th>
|
||
<th>Code</th>
|
||
<th>Provision (€)</th>
|
||
<th>Beschreibung</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="tarifoptionenAdminList">
|
||
<!-- Content loaded dynamically -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mitarbeiter Prozentsätze Management -->
|
||
<div id="admin-mitarbeiter-prozentsaetze" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Mitarbeiter-Provisionen</h3>
|
||
<p>Verwalten Sie die Prozentsätze für Mitarbeiter-Provisionen pro Anbieter.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<h4>Mitarbeiter-Prozentsatz festlegen</h4>
|
||
<div class="mitarbeiter-form">
|
||
<div class="form-row">
|
||
<select id="mitarbeiterAnbieter">
|
||
<option value="">Anbieter wählen...</option>
|
||
</select>
|
||
<input type="number" id="mitarbeiterProzentsatz" placeholder="Prozentsatz" step="0.01" min="0" max="100">
|
||
<span>%</span>
|
||
</div>
|
||
<div class="form-row">
|
||
<input type="date" id="mitarbeiterGueltigAb" placeholder="Gültig ab">
|
||
<input type="text" id="mitarbeiterBeschreibung" placeholder="Beschreibung (optional)">
|
||
</div>
|
||
<button onclick="addMitarbeiterProzentsatz()" class="btn-success">Prozentsatz festlegen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Aktuelle Mitarbeiter-Prozentsätze</h4>
|
||
<div id="mitarbeiterProzentsaetzeList" class="admin-list"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mitarbeiter Provisionen Management -->
|
||
<div id="admin-mitarbeiter-provisionen" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Mitarbeiter-Provisionen pro Tarif</h3>
|
||
<p>Legen Sie für jeden Tarif individuell die Mitarbeiter-Provision fest.</p>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Tarife und Mitarbeiter-Provisionen</h4>
|
||
<div id="tarifProvisionsList" class="admin-list"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Provisionsregeln Management -->
|
||
<div id="admin-provisionsregeln" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Provisionsregeln verwalten</h3>
|
||
<p>Verwalten Sie spezifische Provisionsregeln für Tarife.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<h4>Neue Provisionsregel hinzufügen</h4>
|
||
<div class="add-form">
|
||
<select id="provisionTarif">
|
||
<option value="">Tarif wählen...</option>
|
||
</select>
|
||
<input type="number" id="provisionBetrag" placeholder="Provision in Euro" step="0.01" min="0">
|
||
<button onclick="addProvisionRule()" class="btn btn-primary">Regel hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Bestehende Provisionsregeln</h4>
|
||
<div id="provisionsregelnList" class="admin-list"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Globale Provisionsregeln Management -->
|
||
<div id="admin-global-provisionsregeln" class="admin-category">
|
||
<div class="admin-page">
|
||
<div class="admin-header">
|
||
<h3>Globale Provisionsregeln verwalten</h3>
|
||
<p>Verwalten Sie globale Provisionsregeln für Anbieter.</p>
|
||
</div>
|
||
|
||
<div class="admin-form-section">
|
||
<h4>Neue globale Provisionsregel hinzufügen</h4>
|
||
<div class="add-form">
|
||
<select id="globalProvisionAnbieter">
|
||
<option value="">Anbieter wählen...</option>
|
||
</select>
|
||
<input type="number" id="globalProvisionBetrag" placeholder="Provision in Euro" step="0.01" min="0">
|
||
<button onclick="addGlobalProvisionRule()" class="btn btn-primary">Globale Regel hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="admin-content-section">
|
||
<h4>Bestehende globale Provisionsregeln</h4>
|
||
<div id="globalProvisionsregelnList" class="admin-list"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</main>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Benutzer-Verwaltung Tab (admin only) -->
|
||
<div id="users" class="tab-content">
|
||
<div class="flex flex-col gap-lg">
|
||
|
||
<!-- Page header -->
|
||
<div class="flex justify-between items-end flex-wrap gap-md">
|
||
<div>
|
||
<h1 class="text-headline-md text-on-background mb-xs">Benutzer-Verwaltung</h1>
|
||
<p class="text-body-sm text-on-surface-variant">Verwalten Sie die Anmeldedaten und Berechtigungen der Anwender.</p>
|
||
</div>
|
||
<button type="button" onclick="openUserModal()"
|
||
class="bg-primary-container text-on-primary hover:bg-primary transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-sm shadow-sm">
|
||
<span class="material-symbols-outlined text-[18px]">person_add</span>
|
||
Neuer Benutzer
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Data table -->
|
||
<div class="bg-surface-container-lowest border border-outline-variant rounded-lg shadow-[0_2px_4px_rgba(0,0,0,0.04)] overflow-hidden">
|
||
<div class="overflow-x-auto">
|
||
<table class="w-full text-left border-collapse">
|
||
<thead class="bg-surface-container-high border-b-2 border-outline-variant">
|
||
<tr>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Username</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase">Anzeigename</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-center w-[80px]">Admin</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase w-[180px]">Erstellt</th>
|
||
<th class="px-md py-sm text-label-caps text-on-surface-variant uppercase text-center w-[120px]">Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="usersTableBody" class="text-body-sm text-on-surface"></tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal: Benutzer anlegen / bearbeiten -->
|
||
<div id="userModal" class="app-modal" style="display:none;">
|
||
<div class="app-modal-card" style="max-width:480px;">
|
||
<div class="app-modal-header">
|
||
<div class="flex items-center gap-sm">
|
||
<span class="material-symbols-outlined text-primary">person</span>
|
||
<h3 id="userModalTitle" style="margin:0;">Neuer Benutzer</h3>
|
||
</div>
|
||
<button onclick="closeUserModal()" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
|
||
<span class="material-symbols-outlined">close</span>
|
||
</button>
|
||
</div>
|
||
<div class="app-modal-body app-modal-form">
|
||
<input type="hidden" id="userModalUuid">
|
||
<label class="app-modal-field">
|
||
<span>Username</span>
|
||
<input type="text" id="userModalUsername">
|
||
</label>
|
||
<label class="app-modal-field">
|
||
<span>Anzeigename</span>
|
||
<input type="text" id="userModalDisplay">
|
||
</label>
|
||
<label class="app-modal-field">
|
||
<span>Passwort <span id="userModalPasswordHint" style="font-weight:400; letter-spacing:normal; text-transform:none; font-size:12px;">(min. 8 Zeichen)</span></span>
|
||
<input type="password" id="userModalPassword" autocomplete="new-password">
|
||
<small id="userModalPasswordEditHint" style="display:none; color:#434655; font-size:12px;">Leer lassen, um Passwort unverändert zu lassen</small>
|
||
</label>
|
||
<label class="app-modal-checkbox">
|
||
<input type="checkbox" id="userModalIsAdmin">
|
||
<span>Administrator</span>
|
||
</label>
|
||
</div>
|
||
<div class="app-modal-footer">
|
||
<button type="button" onclick="closeUserModal()" class="app-modal-btn-secondary">Abbrechen</button>
|
||
<button type="button" onclick="saveUserFromModal()" class="app-modal-btn-primary">Speichern</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal: VO bearbeiten -->
|
||
<div id="voEditModal" class="app-modal" style="display:none;">
|
||
<div class="app-modal-card" style="max-width:480px;">
|
||
<div class="app-modal-header">
|
||
<div class="flex items-center gap-sm">
|
||
<span class="material-symbols-outlined text-primary">badge</span>
|
||
<h3 style="margin:0;">VO bearbeiten</h3>
|
||
</div>
|
||
<button onclick="closeVoEditModal()" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
|
||
<span class="material-symbols-outlined">close</span>
|
||
</button>
|
||
</div>
|
||
<div class="app-modal-body app-modal-form">
|
||
<input type="hidden" id="voEditId">
|
||
<label class="app-modal-field">
|
||
<span>Anbieter</span>
|
||
<input type="text" id="voEditAnbieter" readonly style="background:#eff4ff; color:#434655;">
|
||
</label>
|
||
<label class="app-modal-field">
|
||
<span>VO-Nummer</span>
|
||
<input type="text" id="voEditNummer">
|
||
</label>
|
||
<label class="app-modal-field">
|
||
<span>Bezeichnung</span>
|
||
<input type="text" id="voEditBezeichnung" placeholder="z.B. Fachhandel (leer = keine)">
|
||
</label>
|
||
<label class="app-modal-checkbox">
|
||
<input type="checkbox" id="voEditAktiv">
|
||
<span>Aktiv</span>
|
||
</label>
|
||
</div>
|
||
<div class="app-modal-footer">
|
||
<button type="button" onclick="closeVoEditModal()" class="app-modal-btn-secondary">Abbrechen</button>
|
||
<button type="button" onclick="saveVoFromModal()" class="app-modal-btn-primary">Speichern</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="messages"></div>
|
||
</div>
|
||
|
||
<!-- Edit Tarifoption Modal -->
|
||
<div id="editTarifoptionModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); z-index: 1000;">
|
||
<div style="position: absolute; top: 5%; left: 50%; transform: translateX(-50%); background: white; border-radius: 12px; width: 90%; max-width: 1200px; height: 90%; box-shadow: 0 20px 40px rgba(0,0,0,0.3); display: flex; flex-direction: column;">
|
||
|
||
<!-- Header -->
|
||
<div style="padding: 25px 35px 15px; border-bottom: 1px solid #eee; flex-shrink: 0;">
|
||
<div style="display: flex; justify-content: between; align-items: center;">
|
||
<h2 style="margin: 0; color: #333; font-size: 24px;">Tarifoption bearbeiten</h2>
|
||
<span style="position: absolute; top: 15px; right: 25px; font-size: 28px; cursor: pointer; color: #999; hover: #333;" onclick="closeModal('editTarifoptionModal')">×</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Content -->
|
||
<div style="flex: 1; overflow-y: auto; padding: 25px 35px;">
|
||
<form id="editTarifoptionForm">
|
||
<input type="hidden" id="editTarifoptionId">
|
||
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; height: 100%;">
|
||
<!-- Left Column -->
|
||
<div>
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="editTarifoptionAnbieter" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Anbieter</label>
|
||
<select id="editTarifoptionAnbieter" onchange="loadTarifeForEditOptions()" style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px; background: white;">
|
||
<option value="">Anbieter wählen...</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label style="display: flex; align-items: center; gap: 12px; padding: 15px; background: #f8f9fa; border-radius: 8px; cursor: pointer; border: 2px solid transparent; transition: all 0.2s;">
|
||
<input type="checkbox" id="editTarifoptionAnbieterWeit" onchange="toggleEditTarifSelection()" style="width: 18px; height: 18px; cursor: pointer;">
|
||
<span style="font-weight: 500; color: #495057;">Für alle Tarife des Anbieters (Anbieter-weit)</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="editTarifoptionName" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Name der Option</label>
|
||
<input type="text" id="editTarifoptionName" required style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px;">
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="editTarifoptionCode" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Code (optional)</label>
|
||
<input type="text" id="editTarifoptionCode" style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px;">
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="editTarifoptionProvisionBetrag" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Zusätzliche Provision (€)</label>
|
||
<input type="number" id="editTarifoptionProvisionBetrag" step="0.01" required style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px;">
|
||
<small style="color: #6c757d; font-size: 12px; margin-top: 5px; display: block;">Wird zur Tarif-Provision hinzugefügt (negativ = Abzug)</small>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="editTarifoptionBeschreibung" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Beschreibung (optional)</label>
|
||
<textarea id="editTarifoptionBeschreibung" rows="3" style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px; resize: vertical;"></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Right Column - Tarif Selection -->
|
||
<div>
|
||
<div id="editTarifSelectionContainer">
|
||
<label style="display: block; font-weight: 600; margin-bottom: 15px; color: #333; font-size: 16px;">Tarife auswählen:</label>
|
||
|
||
<div style="margin-bottom: 15px;">
|
||
<button type="button" onclick="selectAllEditTarifs()" style="background: #28a745; color: white; border: none; padding: 8px 16px; border-radius: 6px; margin-right: 8px; cursor: pointer; font-size: 13px; font-weight: 500;">Alle auswählen</button>
|
||
<button type="button" onclick="deselectAllEditTarifs()" style="background: #dc3545; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500;">Alle abwählen</button>
|
||
<input type="text" id="editTarifSearch" placeholder="Tarife filtern..." style="float: right; padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; width: 180px;" oninput="filterEditTarifs()">
|
||
</div>
|
||
|
||
<div id="editTarifCheckboxContainer" style="height: 400px; overflow-y: auto; border: 2px solid #e1e5e9; border-radius: 8px; background: #fefefe;">
|
||
<div style="padding: 40px; text-align: center; color: #6c757d; font-style: italic;">Erst Anbieter wählen...</div>
|
||
</div>
|
||
|
||
<div id="editTarifCounter" style="margin-top: 10px; font-size: 13px; color: #6c757d; text-align: right;"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Footer -->
|
||
<div style="padding: 20px 35px; border-top: 1px solid #eee; background: #f8f9fa; border-bottom-left-radius: 12px; border-bottom-right-radius: 12px; flex-shrink: 0;">
|
||
<div style="display: flex; justify-content: flex-end; gap: 15px;">
|
||
<button type="button" onclick="closeModal('editTarifoptionModal')" style="background: #6c757d; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500;">Abbrechen</button>
|
||
<button type="submit" form="editTarifoptionForm" style="background: #007bff; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500;">Speichern</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Edit Tariff Modal -->
|
||
<div id="editTariffModal" class="app-modal" style="display:none;">
|
||
<div class="app-modal-card" style="max-width:600px;">
|
||
<div class="app-modal-header">
|
||
<div class="flex items-center gap-sm">
|
||
<span class="material-symbols-outlined text-primary">receipt_long</span>
|
||
<h3 style="margin:0;">Tarif bearbeiten</h3>
|
||
</div>
|
||
<button onclick="closeModal('editTariffModal')" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
|
||
<span class="material-symbols-outlined">close</span>
|
||
</button>
|
||
</div>
|
||
<form id="editTariffForm" class="contents">
|
||
<div class="app-modal-body app-modal-form">
|
||
<input type="hidden" id="editTariffId">
|
||
<label class="app-modal-field">
|
||
<span>Tarif-Name</span>
|
||
<input type="text" id="editTariffName" required>
|
||
</label>
|
||
<label class="app-modal-field">
|
||
<span>VO</span>
|
||
<select id="editTariffVo">
|
||
<option value="">VO wählen…</option>
|
||
</select>
|
||
</label>
|
||
<label class="app-modal-field">
|
||
<span>Shop-Provision (€)</span>
|
||
<input type="number" id="editTariffProvisionBetrag" step="0.01" min="0" placeholder="Betrag in Euro">
|
||
</label>
|
||
<div class="app-modal-field">
|
||
<span>Tarifoptionen (Anbieter-weit)</span>
|
||
<div id="editTariffOptionenContainer"
|
||
style="border:1px solid #c3c6d7; border-radius:8px; padding:12px; max-height:200px; overflow-y:auto; background:#eff4ff; display:flex; flex-direction:column; gap:6px;">
|
||
<small style="color:#434655;">Keine Tarifoptionen für diesen Anbieter vorhanden</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="app-modal-footer">
|
||
<button type="button" onclick="closeModal('editTariffModal')" class="app-modal-btn-secondary">Abbrechen</button>
|
||
<button type="submit" class="app-modal-btn-primary">Speichern</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Edit Schaltung Modal -->
|
||
<div id="editSchaltungModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000;">
|
||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); background: white; padding: 30px; border-radius: 12px; width: 800px; max-width: 95%; max-height: 90%; overflow-y: auto; box-shadow: 0 10px 30px rgba(0,0,0,0.3);">
|
||
<h3>Schaltung bearbeiten</h3>
|
||
<form id="editSchaltungForm">
|
||
<input type="hidden" id="editSchaltungId">
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>Schaltungs-ID:</label>
|
||
<input type="text" id="editSchaltungsId" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Eingabe-Datum:</label>
|
||
<input type="date" id="editEingabeDatum" required>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Schaltungs-/Aktivierungsdatum:</label>
|
||
<input type="date" id="editSchaltungsDatum" required>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>Vorname:</label>
|
||
<input type="text" id="editVorname" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Nachname:</label>
|
||
<input type="text" id="editNachname" required>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Firma (optional):</label>
|
||
<input type="text" id="editFirma">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Rufnummer/Kundennummer:</label>
|
||
<input type="text" id="editRufnummer" required>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>Anbieter:</label>
|
||
<select id="editAnbieter" required onchange="loadTarifeForEdit()">
|
||
<option value="">Bitte wählen...</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Tarif:</label>
|
||
<select id="editTarif" required>
|
||
<option value="">Erst Anbieter wählen...</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Hardware:</label>
|
||
<input type="text" id="editHardware" onchange="toggleEditHardwarePricing()">
|
||
</div>
|
||
|
||
<!-- Hardware Pricing Fields -->
|
||
<div id="editHardwarePricingFields" style="display: none;">
|
||
<div class="form-row">
|
||
<div class="form-group">
|
||
<label>Hardware-EK (Einkaufspreis) €:</label>
|
||
<input type="number" id="editHardwareEk" step="0.01" placeholder="0.00">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Kundenverkaufspreis (netto) €:</label>
|
||
<input type="number" id="editKundenverkaufspreis" step="0.01" placeholder="0.00">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Tarifoptionen -->
|
||
<div class="form-group">
|
||
<label style="font-weight: 600; color: #2c3e50; margin-bottom: 10px; display: block;">Tarifoptionen/Aktionscodes:</label>
|
||
<div id="editTarifoptionenContainer" style="background: #f8f9fa; border: 2px solid #e9ecef; border-radius: 8px; padding: 15px; max-height: 250px; overflow-y: auto; box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);">
|
||
<div style="color: #6c757d; font-style: italic; text-align: center; padding: 20px;">Erst Tarif wählen...</div>
|
||
</div>
|
||
<small style="color: #6c757d; font-size: 12px; margin-top: 5px; display: block;">Wählen Sie die gewünschten Optionen aus. Mehrfachauswahl möglich.</small>
|
||
</div>
|
||
|
||
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
||
<button type="submit" class="btn-success">Speichern</button>
|
||
<button type="button" onclick="closeModal('editSchaltungModal')">Abbrechen</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Delete Schaltung Modal -->
|
||
<div id="deleteSchaltungModal" class="app-modal" style="display:none;">
|
||
<div class="app-modal-card" style="max-width:500px;">
|
||
<div class="app-modal-header">
|
||
<div class="flex items-center gap-sm">
|
||
<span class="material-symbols-outlined text-error">warning</span>
|
||
<h3 style="margin:0;">Schaltung löschen</h3>
|
||
</div>
|
||
<button onclick="closeModal('deleteSchaltungModal')" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
|
||
<span class="material-symbols-outlined">close</span>
|
||
</button>
|
||
</div>
|
||
<div class="app-modal-body app-modal-form">
|
||
<p style="color:#434655;">Sind Sie sicher, dass Sie diese Schaltung löschen möchten?</p>
|
||
<div style="padding:10px 14px; background:#eff4ff; border:1px solid #c3c6d7; border-radius:8px; color:#0b1c30; font-weight:600;" id="deleteSchaltungInfo"></div>
|
||
<label class="app-modal-field">
|
||
<span>Grund für die Löschung *</span>
|
||
<textarea id="deleteReason" rows="3" placeholder="Bitte geben Sie den Grund für die Löschung ein…" required style="resize: vertical;"></textarea>
|
||
</label>
|
||
<input type="hidden" id="deleteSchaltungId">
|
||
</div>
|
||
<div class="app-modal-footer">
|
||
<button type="button" onclick="closeModal('deleteSchaltungModal')" class="app-modal-btn-secondary">Abbrechen</button>
|
||
<button type="button" onclick="confirmDeleteSchaltung()" class="app-modal-btn-primary" style="background:#ba1a1a;">Löschen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Documents Modal -->
|
||
<div id="documentsModal" class="documents-modal fixed inset-0 z-[1000] hidden items-center justify-center bg-black/40 p-margin">
|
||
<div class="bg-surface-container-lowest rounded-xl shadow-[0_10px_30px_rgba(0,0,0,0.15)] border border-outline-variant/30 w-full max-w-[640px] max-h-[85vh] flex flex-col overflow-hidden">
|
||
<div class="flex items-center justify-between px-lg py-md border-b border-outline-variant">
|
||
<div class="flex items-center gap-sm">
|
||
<span class="material-symbols-outlined text-primary">description</span>
|
||
<h3 class="text-title-sm text-on-surface">Dokumente</h3>
|
||
</div>
|
||
<button onclick="closeDocumentsModal()" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
|
||
<span class="material-symbols-outlined">close</span>
|
||
</button>
|
||
</div>
|
||
<div class="flex-1 overflow-y-auto px-lg py-md flex flex-col gap-sm" id="documentsModalBody"></div>
|
||
<div class="flex items-center justify-between gap-md px-lg py-md border-t border-outline-variant bg-surface-container-low/50">
|
||
<input type="file" id="additionalDocumentUpload" multiple accept=".pdf,.jpg,.jpeg,.png,.doc,.docx" style="display:none;">
|
||
<button onclick="document.getElementById('additionalDocumentUpload').click()"
|
||
class="bg-primary-container text-on-primary hover:bg-primary transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-xs shadow-sm">
|
||
<span class="material-symbols-outlined text-[18px]">attach_file</span>
|
||
Dokumente hinzufügen
|
||
</button>
|
||
<button onclick="closeDocumentsModal()"
|
||
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded-lg px-md py-sm text-body-sm">
|
||
Schließen
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- PDF Viewer Modal -->
|
||
<div id="pdfViewerModal" class="pdf-viewer-modal fixed inset-0 z-[1100] hidden items-center justify-center bg-black/50 p-margin">
|
||
<div class="bg-surface-container-lowest rounded-xl shadow-[0_10px_30px_rgba(0,0,0,0.25)] border border-outline-variant/30 w-full max-w-[1100px] h-[90vh] flex flex-col overflow-hidden">
|
||
<div class="flex items-center justify-between px-lg py-md border-b border-outline-variant">
|
||
<div class="flex items-center gap-sm min-w-0">
|
||
<span class="material-symbols-outlined text-primary shrink-0">picture_as_pdf</span>
|
||
<h3 class="text-title-sm text-on-surface truncate" id="pdfViewerTitle">PDF Viewer</h3>
|
||
</div>
|
||
<button onclick="closePdfViewer()" class="icon-btn text-outline hover:text-on-surface transition-colors" title="Schließen">
|
||
<span class="material-symbols-outlined">close</span>
|
||
</button>
|
||
</div>
|
||
<div class="flex-1 overflow-auto bg-surface-container-low/50 flex items-start justify-center p-md">
|
||
<div class="pdf-canvas-container">
|
||
<canvas id="pdfCanvas"></canvas>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center justify-between gap-md px-lg py-md border-t border-outline-variant bg-surface-container-low/50">
|
||
<div class="flex items-center gap-sm">
|
||
<button id="prevPageBtn" onclick="prevPage()"
|
||
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-xs disabled:opacity-50 disabled:cursor-not-allowed">
|
||
<span class="material-symbols-outlined text-[18px]">chevron_left</span>
|
||
Vorherige
|
||
</button>
|
||
<span class="text-body-sm text-on-surface-variant">
|
||
Seite <span id="currentPage" class="font-label-numeric text-on-surface">1</span> von <span id="totalPages" class="font-label-numeric text-on-surface">1</span>
|
||
</span>
|
||
<button id="nextPageBtn" onclick="nextPage()"
|
||
class="bg-surface-container-high text-on-surface border border-outline-variant hover:bg-surface-variant transition-colors rounded-lg px-md py-sm text-body-sm flex items-center gap-xs disabled:opacity-50 disabled:cursor-not-allowed">
|
||
Nächste
|
||
<span class="material-symbols-outlined text-[18px]">chevron_right</span>
|
||
</button>
|
||
</div>
|
||
<div class="flex items-center gap-sm">
|
||
<button onclick="zoomOut()" class="icon-btn text-outline hover:text-primary transition-colors p-1" title="Verkleinern">
|
||
<span class="material-symbols-outlined text-[22px]">remove</span>
|
||
</button>
|
||
<span id="zoomLevel" class="font-label-numeric text-label-numeric text-on-surface min-w-[48px] text-center">100%</span>
|
||
<button onclick="zoomIn()" class="icon-btn text-outline hover:text-primary transition-colors p-1" title="Vergrößern">
|
||
<span class="material-symbols-outlined text-[22px]">add</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Add Tarifoption Modal -->
|
||
<div id="addTarifoptionModal" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); z-index: 1000;">
|
||
<div style="position: absolute; top: 5%; left: 50%; transform: translateX(-50%); background: white; border-radius: 12px; width: 90%; max-width: 1200px; height: 90%; box-shadow: 0 20px 40px rgba(0,0,0,0.3); display: flex; flex-direction: column;">
|
||
|
||
<!-- Header -->
|
||
<div style="padding: 25px 35px 15px; border-bottom: 1px solid #eee; flex-shrink: 0;">
|
||
<div style="display: flex; justify-content: between; align-items: center;">
|
||
<h2 style="margin: 0; color: #333; font-size: 24px;">Neue Tarifoption hinzufügen</h2>
|
||
<span style="position: absolute; top: 15px; right: 25px; font-size: 28px; cursor: pointer; color: #999; hover: #333;" onclick="closeModal('addTarifoptionModal')">×</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Content -->
|
||
<div style="flex: 1; overflow-y: auto; padding: 25px 35px;">
|
||
<form id="addTarifoptionForm">
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; height: 100%;">
|
||
<!-- Left Column -->
|
||
<div>
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="addTarifoptionAnbieter" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Anbieter</label>
|
||
<select id="addTarifoptionAnbieter" onchange="loadTarifeForAddOptions()" style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px; background: white;">
|
||
<option value="">Anbieter wählen...</option>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label style="display: flex; align-items: center; gap: 12px; padding: 15px; background: #f8f9fa; border-radius: 8px; cursor: pointer; border: 2px solid transparent; transition: all 0.2s;">
|
||
<input type="checkbox" id="addTarifoptionAnbieterWeit" onchange="toggleAddTarifSelection()" checked style="width: 18px; height: 18px; cursor: pointer;">
|
||
<span style="font-weight: 500; color: #495057;">Für alle Tarife des Anbieters (Anbieter-weit)</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="addTarifoptionName" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Name der Option</label>
|
||
<input type="text" id="addTarifoptionName" placeholder="z.B. Anschlusspreisrabatt" required style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px;">
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="addTarifoptionCode" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Code (optional)</label>
|
||
<input type="text" id="addTarifoptionCode" placeholder="z.B. RABATT2024" style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px;">
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="addTarifoptionProvisionBetrag" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Zusätzliche Provision (€)</label>
|
||
<input type="number" id="addTarifoptionProvisionBetrag" step="0.01" placeholder="Kann auch negativ sein" required style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px;">
|
||
<small style="color: #6c757d; font-size: 12px; margin-top: 5px; display: block;">Wird zur Tarif-Provision hinzugefügt (negativ = Abzug)</small>
|
||
</div>
|
||
|
||
<div class="form-group" style="margin-bottom: 20px;">
|
||
<label for="addTarifoptionBeschreibung" style="display: block; font-weight: 600; margin-bottom: 8px; color: #333;">Beschreibung (optional)</label>
|
||
<textarea id="addTarifoptionBeschreibung" rows="3" placeholder="Beschreibung der Tarifoption..." style="width: 100%; padding: 12px; border: 2px solid #e1e5e9; border-radius: 8px; font-size: 14px; resize: vertical;"></textarea>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Right Column - Tarif Selection -->
|
||
<div>
|
||
<div id="addTarifSelectionContainer" style="display: none;">
|
||
<label style="display: block; font-weight: 600; margin-bottom: 15px; color: #333; font-size: 16px;">Tarife auswählen:</label>
|
||
|
||
<div style="margin-bottom: 15px;">
|
||
<button type="button" onclick="selectAllAddTarifs()" style="background: #28a745; color: white; border: none; padding: 8px 16px; border-radius: 6px; margin-right: 8px; cursor: pointer; font-size: 13px; font-weight: 500;">Alle auswählen</button>
|
||
<button type="button" onclick="deselectAllAddTarifs()" style="background: #dc3545; color: white; border: none; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 500;">Alle abwählen</button>
|
||
<input type="text" id="addTarifSearch" placeholder="Tarife filtern..." style="float: right; padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; width: 180px;" oninput="filterAddTarifs()">
|
||
</div>
|
||
|
||
<div id="addTarifCheckboxContainer" style="height: 400px; overflow-y: auto; border: 2px solid #e1e5e9; border-radius: 8px; background: #fefefe;">
|
||
<div style="padding: 40px; text-align: center; color: #6c757d; font-style: italic;">Erst Anbieter wählen...</div>
|
||
</div>
|
||
|
||
<div id="addTarifCounter" style="margin-top: 10px; font-size: 13px; color: #6c757d; text-align: right;"></div>
|
||
</div>
|
||
|
||
<div id="addAnbieterWeitInfo" style="padding: 30px; text-align: center; color: #6c757d; border: 2px dashed #dee2e6; border-radius: 8px; background: #f8f9fa;">
|
||
<div style="font-size: 48px; margin-bottom: 15px; opacity: 0.5;">🏢</div>
|
||
<div style="font-weight: 500; margin-bottom: 8px;">Anbieter-weite Tarifoption</div>
|
||
<div style="font-size: 13px;">Diese Option wird automatisch allen Tarifen des gewählten Anbieters zugeordnet.</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Footer -->
|
||
<div style="padding: 20px 35px; border-top: 1px solid #eee; background: #f8f9fa; border-bottom-left-radius: 12px; border-bottom-right-radius: 12px; flex-shrink: 0;">
|
||
<div style="display: flex; justify-content: flex-end; gap: 15px;">
|
||
<button type="button" onclick="closeModal('addTarifoptionModal')" style="background: #6c757d; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500;">Abbrechen</button>
|
||
<button type="submit" form="addTarifoptionForm" style="background: #28a745; color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 14px; font-weight: 500;">Tarifoption hinzufügen</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
|
||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||
<script src="script.js"></script>
|
||
</body>
|
||
</html> |