Taller
-Órdenes de servicio y control de reparaciones
+diff --git a/pos/static/css/workshop.css b/pos/static/css/workshop.css index d408358..c691f29 100644 --- a/pos/static/css/workshop.css +++ b/pos/static/css/workshop.css @@ -1,28 +1,556 @@ -:root { - --kanban-column-width: 280px; - --kanban-card-bg: var(--glass-bg-strong); - --kanban-card-border: var(--glass-border); +/* workshop.css — Taller / Service Orders Kanban (design-system aligned) */ + +/* ═══════════════════════════════════════════════════════════════ + BASE RESET & SHELL + ═══════════════════════════════════════════════════════════════ */ + +*, *::before, *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, body { + height: 100%; +} + +body { + font-family: var(--font-body); + font-size: var(--text-body-sm); + color: var(--color-text-primary); + background-color: var(--color-bg-base); + overflow: hidden; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +[data-theme="modern"] body { + background-color: var(--color-bg-base); + background-image: radial-gradient( + circle, + var(--dot-grid-color) 1px, + transparent 1px + ); + background-size: var(--dot-grid-size) var(--dot-grid-size); +} + +.app-shell { + display: flex; + height: 100vh; +} + +.main { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + min-width: 0; +} + +/* ═══════════════════════════════════════════════════════════════ + PAGE HEADER + ═══════════════════════════════════════════════════════════════ */ + +.page-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4) var(--space-6); + background: var(--color-bg-elevated); + border-bottom: 1px solid var(--color-border); + flex-shrink: 0; +} + +[data-theme="industrial"] .page-header { + background: var(--color-surface-1); +} + +.page-header__title-group { + display: flex; + flex-direction: column; + gap: 2px; +} + +.page-header__eyebrow { + font-size: var(--text-caption); + font-weight: var(--font-weight-semibold); + letter-spacing: var(--tracking-widest); + text-transform: uppercase; + color: var(--color-text-muted); +} + +.page-header__title { + font-family: var(--font-heading); + font-weight: var(--heading-weight-primary); + font-size: var(--text-h4); + letter-spacing: var(--heading-tracking-h4); + color: var(--color-text-primary); + line-height: 1.2; +} + +[data-theme="industrial"] .page-header__title { + text-transform: uppercase; +} + +.page-header__actions { + display: flex; + align-items: center; + gap: var(--space-3); } .page-header__subtitle { color: var(--color-text-muted); - font-size: var(--text-sm); + font-size: var(--text-body-sm); margin-top: var(--space-1); } +/* ═══════════════════════════════════════════════════════════════ + SUMMARY CARDS + ═══════════════════════════════════════════════════════════════ */ + +.summary-strip { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-4); + padding: var(--space-4) var(--space-6); + background: var(--color-bg-base); + border-bottom: 1px solid var(--color-border); + flex-shrink: 0; +} + +[data-theme="modern"] .summary-strip { + background: transparent; +} + +.summary-card { + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + padding: var(--space-4) var(--space-5); + display: flex; + align-items: flex-start; + gap: var(--space-3); + box-shadow: var(--shadow-sm); + transition: var(--transition-normal); +} + +.summary-card:hover { + box-shadow: var(--shadow-md); + border-color: var(--color-border-strong); +} + +[data-theme="industrial"] .summary-card { + border-left: 3px solid var(--color-primary); +} + +[data-theme="modern"] .summary-card { + background: var(--color-bg-overlay); +} + +.summary-card__icon { + width: 38px; + height: 38px; + border-radius: var(--radius-md); + background: var(--color-primary-muted); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.summary-card__icon svg { + width: 20px; + height: 20px; + stroke: var(--color-primary); + fill: none; + stroke-width: 1.75; + stroke-linecap: round; + stroke-linejoin: round; +} + +.summary-card__icon--ok { + background: rgba(34, 197, 94, 0.12); +} +.summary-card__icon--ok svg { + stroke: var(--color-success); +} + +.summary-card__icon--alert { + background: rgba(239, 68, 68, 0.12); +} +.summary-card__icon--alert svg { + stroke: var(--color-error); +} + +.summary-card__body { + flex: 1; + min-width: 0; +} + +.summary-card__label { + font-size: var(--text-caption); + font-weight: var(--font-weight-semibold); + letter-spacing: var(--tracking-wider); + text-transform: uppercase; + color: var(--color-text-muted); + margin-bottom: var(--space-1); +} + +.summary-card__value { + font-family: var(--font-heading); + font-weight: var(--heading-weight-primary); + font-size: 1.5rem; + color: var(--color-text-primary); + line-height: 1.1; +} + +.summary-card__value--danger { + color: var(--color-error); +} + +/* ═══════════════════════════════════════════════════════════════ + BUTTONS + ═══════════════════════════════════════════════════════════════ */ + +.btn { + display: inline-flex; + align-items: center; + gap: var(--space-2); + padding: 0 var(--space-4); + height: 36px; + border-radius: var(--radius-md); + font-family: var(--font-body); + font-size: var(--text-body-sm); + font-weight: var(--font-weight-semibold); + letter-spacing: var(--tracking-wide); + cursor: pointer; + border: 1px solid transparent; + transition: var(--transition-fast); + text-decoration: none; + white-space: nowrap; +} + +.btn svg { + width: 15px; + height: 15px; + stroke: currentColor; + fill: none; + stroke-width: 2; + stroke-linecap: round; + stroke-linejoin: round; + flex-shrink: 0; +} + +.btn--primary { + background: var(--btn-primary-bg); + color: var(--btn-primary-text); + border-color: var(--btn-primary-border); +} + +.btn--primary:hover { + background: var(--btn-primary-bg-hover); +} + +.btn--secondary { + background: var(--btn-secondary-bg); + color: var(--btn-secondary-text); + border-color: var(--btn-secondary-border); +} + +.btn--secondary:hover { + background: var(--btn-secondary-bg-hover); +} + +.btn--ghost { + background: var(--btn-ghost-bg); + color: var(--btn-ghost-text); + border-color: var(--btn-ghost-border); +} + +.btn--ghost:hover { + background: var(--color-surface-2); + border-color: var(--color-border-strong); + color: var(--color-text-primary); +} + +.btn--sm { + height: 28px; + padding: 0 var(--space-3); + font-size: var(--text-caption); +} + +/* ═══════════════════════════════════════════════════════════════ + DATA TABLE + ═══════════════════════════════════════════════════════════════ */ + +.table-wrapper { + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + overflow: hidden; + box-shadow: var(--shadow-sm); +} + +[data-theme="modern"] .table-wrapper { + background: var(--color-bg-overlay); +} + +.data-table { + width: 100%; + border-collapse: collapse; + font-size: var(--text-body-sm); +} + +.data-table thead { + position: sticky; + top: 0; + background: var(--color-surface-2); + border-bottom: 1px solid var(--color-border); + z-index: 10; +} + +[data-theme="industrial"] .data-table thead { + background: var(--color-surface-3); +} + +.data-table th { + padding: var(--space-3) var(--space-4); + text-align: left; + font-size: var(--text-caption); + font-weight: var(--font-weight-semibold); + letter-spacing: var(--tracking-wider); + text-transform: uppercase; + color: var(--color-text-muted); + white-space: nowrap; +} + +.data-table th:first-child { padding-left: var(--space-5); } +.data-table th:last-child { padding-right: var(--space-5); } + +.data-table tbody tr { + border-bottom: 1px solid var(--color-border); + transition: background var(--duration-fast) var(--ease-in-out); +} + +.data-table tbody tr:last-child { + border-bottom: none; +} + +.data-table tbody tr:hover { + background: var(--color-surface-2); +} + +.data-table td { + padding: var(--space-3) var(--space-4); + color: var(--color-text-secondary); + vertical-align: middle; +} + +.data-table td:first-child { padding-left: var(--space-5); } +.data-table td:last-child { padding-right: var(--space-5); } + +.data-table .td--primary { + color: var(--color-text-primary); + font-weight: var(--font-weight-semibold); +} + +.data-table .td--mono { + font-family: var(--font-mono); + font-size: 0.8125rem; + color: var(--color-text-accent); +} + +.data-table .td--amount { + font-family: var(--font-mono); + font-size: 0.8125rem; + color: var(--color-text-primary); + font-weight: var(--font-weight-semibold); +} + +/* ═══════════════════════════════════════════════════════════════ + BADGES + ═══════════════════════════════════════════════════════════════ */ + +.badge--reserved { + background: rgba(99, 102, 241, 0.12); + color: #818cf8; +} + +.badge--installed { + background: rgba(34, 197, 94, 0.12); + color: var(--color-success); +} + +.badge--normal { + background: var(--color-primary-muted); + color: var(--color-primary); +} + +.badge--high { + background: rgba(234, 179, 8, 0.12); + color: var(--color-warning); +} + +.badge--urgent { + background: rgba(239, 68, 68, 0.12); + color: var(--color-error); +} + +/* ═══════════════════════════════════════════════════════════════ + FORMS + ═══════════════════════════════════════════════════════════════ */ + +.form-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-3); +} + +.form-field { + display: flex; + flex-direction: column; + gap: var(--space-1); +} + +.form-field--span2, +.form-field--span3, +.form-field--span4 { + grid-column: 1 / -1; +} + +.form-label { + font-size: var(--text-caption); + font-weight: var(--font-weight-semibold); + color: var(--color-text-secondary); + letter-spacing: var(--tracking-wide); + text-transform: uppercase; +} + +.form-input, +.form-select { + padding: var(--space-2) var(--space-3); + background: var(--color-surface-1); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + color: var(--color-text-primary); + font-family: var(--font-body); + font-size: var(--text-body-sm); + outline: none; + transition: var(--transition-fast); + width: 100%; +} + +.form-input:focus, +.form-select:focus { + border-color: var(--color-primary); + box-shadow: 0 0 0 2px var(--color-primary-muted); +} + +.form-field textarea.form-input { + min-height: 80px; + resize: vertical; +} + +/* ═══════════════════════════════════════════════════════════════ + MODALS + ═══════════════════════════════════════════════════════════════ */ + +.modal-overlay { + display: none; + position: fixed; + inset: 0; + z-index: 9000; + background: rgba(0,0,0,0.6); + backdrop-filter: blur(4px); + align-items: center; + justify-content: center; +} + +.modal-overlay.is-open { + display: flex; +} + +.modal { + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + width: 520px; + max-height: 85vh; + overflow-y: auto; + box-shadow: 0 20px 60px rgba(0,0,0,0.4); + display: flex; + flex-direction: column; +} + +.modal--lg { + width: 720px; + max-width: 90vw; +} + +.modal__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--space-4) var(--space-5); + border-bottom: 1px solid var(--color-border); + flex-shrink: 0; +} + +.modal__header h2, +.modal__header h3 { + font-family: var(--font-heading); + font-weight: var(--heading-weight-primary); + font-size: var(--text-h5); + color: var(--color-text-primary); + margin: 0; +} + +.modal__close { + background: none; + border: none; + font-size: 1.5rem; + color: var(--color-text-muted); + cursor: pointer; + padding: 0 var(--space-1); + line-height: 1; +} + +.modal__close:hover { + color: var(--color-text-primary); +} + +.modal__body { + padding: var(--space-4) var(--space-5); + overflow-y: auto; +} + +.modal__footer { + display: flex; + justify-content: flex-end; + gap: var(--space-3); + padding: var(--space-3) var(--space-5); + border-top: 1px solid var(--color-border); + flex-shrink: 0; +} + +/* ═══════════════════════════════════════════════════════════════ + KANBAN BOARD + ═══════════════════════════════════════════════════════════════ */ + .kanban-board { + flex: 1; display: flex; gap: var(--space-4); overflow-x: auto; - padding-bottom: var(--space-4); - min-height: 60vh; + padding: var(--space-4) var(--space-6); + min-height: 0; } .kanban-column { - flex: 0 0 var(--kanban-column-width); + flex: 0 0 280px; display: flex; flex-direction: column; - max-height: 75vh; + max-height: 100%; } .kanban-column__header { @@ -30,20 +558,25 @@ align-items: center; justify-content: space-between; padding: var(--space-3) var(--space-4); - background: var(--glass-bg-strong); - border: 1px solid var(--glass-border); + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); border-radius: var(--radius-md) var(--radius-md) 0 0; font-family: var(--font-heading); - font-size: var(--text-sm); + font-size: var(--text-body-sm); font-weight: var(--font-weight-bold); text-transform: uppercase; letter-spacing: var(--tracking-wide); + flex-shrink: 0; +} + +[data-theme="modern"] .kanban-column__header { + background: var(--color-bg-overlay); } .kanban-column__count { background: var(--color-primary); - color: var(--color-bg); - font-size: var(--text-xs); + color: var(--color-text-inverse); + font-size: var(--text-caption); padding: 2px 8px; border-radius: var(--radius-full); } @@ -51,8 +584,8 @@ .kanban-column__body { flex: 1; overflow-y: auto; - background: rgba(0, 0, 0, 0.15); - border: 1px solid var(--glass-border); + background: var(--color-surface-2); + border: 1px solid var(--color-border); border-top: none; border-radius: 0 0 var(--radius-md) var(--radius-md); padding: var(--space-3); @@ -62,17 +595,22 @@ } .kanban-card { - background: var(--kanban-card-bg); - border: 1px solid var(--kanban-card-border); + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-3); cursor: pointer; - transition: transform 0.15s ease, box-shadow 0.15s ease; + transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease; } .kanban-card:hover { transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + box-shadow: var(--shadow-lg); + border-color: var(--color-border-strong); +} + +[data-theme="modern"] .kanban-card { + background: var(--color-bg-overlay); } .kanban-card__header { @@ -80,34 +618,28 @@ justify-content: space-between; align-items: flex-start; margin-bottom: var(--space-2); + gap: var(--space-2); } .kanban-card__id { font-family: var(--font-mono); - font-size: var(--text-xs); + font-size: var(--text-caption); color: var(--color-primary); font-weight: var(--font-weight-bold); } .kanban-card__priority { - font-size: var(--text-xs); - padding: 2px 6px; - border-radius: var(--radius-sm); - text-transform: uppercase; - font-weight: var(--font-weight-bold); + font-size: var(--text-caption); } -.kanban-card__priority--urgent { background: var(--color-error); color: #fff; } -.kanban-card__priority--high { background: var(--color-warn); color: #000; } -.kanban-card__priority--normal { background: var(--color-info); color: #fff; } - .kanban-card__customer { - font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-semibold); margin-bottom: var(--space-1); + color: var(--color-text-primary); } .kanban-card__vehicle { - font-size: var(--text-sm); + font-size: var(--text-body-sm); color: var(--color-text-muted); margin-bottom: var(--space-2); } @@ -115,7 +647,8 @@ .kanban-card__meta { display: flex; justify-content: space-between; - font-size: var(--text-xs); + align-items: center; + font-size: var(--text-caption); color: var(--color-text-muted); } @@ -125,25 +658,33 @@ gap: var(--space-1); } -/* Detail modal */ +/* ═══════════════════════════════════════════════════════════════ + SERVICE ORDER DETAIL + ═══════════════════════════════════════════════════════════════ */ + .so-detail { display: grid; gap: var(--space-4); } .so-detail__section { - background: var(--glass-bg-strong); - border: 1px solid var(--glass-border); + background: var(--color-bg-elevated); + border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-4); } +[data-theme="modern"] .so-detail__section { + background: var(--color-bg-overlay); +} + .so-detail__section h3 { font-family: var(--font-heading); - font-size: var(--text-sm); + font-size: var(--text-body-sm); text-transform: uppercase; letter-spacing: var(--tracking-wide); margin-bottom: var(--space-3); + color: var(--color-text-primary); } .so-detail__grid { @@ -159,13 +700,14 @@ } .so-detail__label { - font-size: var(--text-xs); + font-size: var(--text-caption); color: var(--color-text-muted); text-transform: uppercase; } .so-detail__value { - font-weight: var(--font-weight-bold); + font-weight: var(--font-weight-semibold); + color: var(--color-text-primary); } .so-detail__actions { @@ -174,44 +716,19 @@ flex-wrap: wrap; } -/* Tables inside modal */ -.data-table--compact { - width: 100%; - border-collapse: collapse; - font-size: var(--text-sm); -} - -.data-table--compact th, -.data-table--compact td { - padding: var(--space-2) var(--space-3); - text-align: left; - border-bottom: 1px solid var(--glass-border); -} - -.data-table--compact th { - color: var(--color-text-muted); - font-weight: var(--font-weight-bold); - text-transform: uppercase; - font-size: var(--text-xs); -} - -.status-badge { - display: inline-block; - padding: 2px 8px; - border-radius: var(--radius-sm); - font-size: var(--text-xs); - font-weight: var(--font-weight-bold); - text-transform: uppercase; -} - -.status-badge--pending { background: var(--color-warn); color: #000; } -.status-badge--reserved { background: var(--color-info); color: #fff; } -.status-badge--installed { background: var(--color-success); color: #000; } +/* ═══════════════════════════════════════════════════════════════ + RESPONSIVE + ═══════════════════════════════════════════════════════════════ */ @media (max-width: 1024px) { + .summary-strip { + grid-template-columns: repeat(2, 1fr); + } + .kanban-board { flex-direction: column; overflow-x: visible; + overflow-y: auto; } .kanban-column { @@ -219,3 +736,34 @@ max-height: none; } } + +@media (max-width: 768px) { + .page-header { + flex-direction: column; + align-items: flex-start; + gap: var(--space-3); + } + + .page-header__actions { + width: 100%; + flex-wrap: wrap; + } + + .summary-strip { + grid-template-columns: 1fr; + } + + .form-grid { + grid-template-columns: 1fr; + } + + .form-field--span2, + .form-field--span3, + .form-field--span4 { + grid-column: span 1; + } + + .so-detail__grid { + grid-template-columns: 1fr; + } +} diff --git a/pos/static/js/workshop.js b/pos/static/js/workshop.js index 4bd38a4..3e74700 100644 --- a/pos/static/js/workshop.js +++ b/pos/static/js/workshop.js @@ -96,7 +96,7 @@ var Workshop = (function() { }) .catch(function(e) { console.error(e); - document.getElementById('kanbanBoard').innerHTML = '
| Concepto | Cant. | Precio | Estado |
|---|
| Concepto | Cant. | Precio | Estado | ||
|---|---|---|---|---|---|
| ' + esc(it.name) + ' ' + esc(it.part_number || '') + ' | ' +
'' + fmt(it.quantity) + ' | ' + '' + fmtMoney(it.unit_price) + ' | ' + - '' + (it.reserved_quantity >= it.quantity ? 'Reservado' : esc(it.status)) + ' | ' + + '' + statusLabel(itemStatus) + ' | ' + '' + (it.reserved_quantity < it.quantity && it.status !== 'cancelled' ? '' : '') + ' | ' + '
| Concepto | Horas | Precio/hr | Total | Estado |
|---|
| Concepto | Horas | Precio/hr | Total | Estado | |
|---|---|---|---|---|---|
| ' + esc(l.description) + ' | ' + '' + fmt(l.hours) + ' | ' + '' + fmtMoney(l.hourly_rate) + ' | ' + '' + fmtMoney(l.total_cost) + ' | ' + - '' + esc(l.status) + ' | ' + + '' + statusLabel(l.status) + ' | ' + '
Órdenes de servicio y control de reparaciones
+