feat(back-end and front-end): back-office
This commit is contained in:
@@ -1,67 +1,167 @@
|
||||
<section class="admin-dashboard">
|
||||
<header class="dashboard-header">
|
||||
<div>
|
||||
<h1>Back-office ordini</h1>
|
||||
<p>Gestione pagamenti e dettaglio ordini</p>
|
||||
<h1>Ordini</h1>
|
||||
<p>Seleziona un ordine a sinistra e gestiscilo nel dettaglio a destra.</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button type="button" (click)="loadOrders()" [disabled]="loading">Aggiorna</button>
|
||||
<button type="button" class="ghost" (click)="logout()">Logout</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<p class="error" *ngIf="errorMessage">{{ errorMessage }}</p>
|
||||
|
||||
<div class="table-wrap" *ngIf="!loading; else loadingTpl">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ordine</th>
|
||||
<th>Email</th>
|
||||
<th>Stato</th>
|
||||
<th>Pagamento</th>
|
||||
<th>Totale</th>
|
||||
<th>Azioni</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let order of orders" [class.selected]="selectedOrder?.id === order.id">
|
||||
<td>{{ order.orderNumber }}</td>
|
||||
<td>{{ order.customerEmail }}</td>
|
||||
<td>{{ order.status }}</td>
|
||||
<td>{{ order.paymentStatus || 'PENDING' }}</td>
|
||||
<td>{{ order.totalChf | currency:'CHF':'symbol':'1.2-2' }}</td>
|
||||
<td class="actions">
|
||||
<button type="button" class="ghost" (click)="openDetails(order.id)">Dettaglio</button>
|
||||
<button
|
||||
type="button"
|
||||
(click)="confirmPayment(order.id)"
|
||||
[disabled]="confirmingOrderId === order.id || order.paymentStatus === 'COMPLETED'"
|
||||
>
|
||||
{{ confirmingOrderId === order.id ? 'Invio...' : 'Conferma pagamento' }}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<section class="details" *ngIf="selectedOrder">
|
||||
<h2>Dettaglio ordine {{ selectedOrder.orderNumber }}</h2>
|
||||
<p *ngIf="detailLoading">Caricamento dettaglio...</p>
|
||||
<p><strong>Cliente:</strong> {{ selectedOrder.customerEmail }}</p>
|
||||
<p><strong>Pagamento:</strong> {{ selectedOrder.paymentStatus || 'PENDING' }}</p>
|
||||
|
||||
<div class="items">
|
||||
<div class="item" *ngFor="let item of selectedOrder.items">
|
||||
<p><strong>File:</strong> {{ item.originalFilename }}</p>
|
||||
<p><strong>Qta:</strong> {{ item.quantity }}</p>
|
||||
<p><strong>Prezzo riga:</strong> {{ item.lineTotalChf | currency:'CHF':'symbol':'1.2-2' }}</p>
|
||||
<div class="workspace" *ngIf="!loading; else loadingTpl">
|
||||
<section class="list-panel">
|
||||
<h2>Lista ordini</h2>
|
||||
<div class="list-toolbar">
|
||||
<label for="order-search">Cerca UUID</label>
|
||||
<input
|
||||
id="order-search"
|
||||
type="search"
|
||||
[ngModel]="orderSearchTerm"
|
||||
(ngModelChange)="onSearchChange($event)"
|
||||
placeholder="UUID completo o prefisso (es. 738131d8)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ordine</th>
|
||||
<th>Email</th>
|
||||
<th>Pagamento</th>
|
||||
<th>Totale</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
*ngFor="let order of filteredOrders"
|
||||
[class.selected]="isSelected(order.id)"
|
||||
(click)="openDetails(order.id)"
|
||||
>
|
||||
<td>{{ order.orderNumber }}</td>
|
||||
<td>{{ order.customerEmail }}</td>
|
||||
<td>{{ order.paymentStatus || 'PENDING' }}</td>
|
||||
<td>{{ order.totalChf | currency:'CHF':'symbol':'1.2-2' }}</td>
|
||||
</tr>
|
||||
<tr class="no-results" *ngIf="filteredOrders.length === 0">
|
||||
<td colspan="4">Nessun ordine trovato per il filtro inserito.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="detail-panel" *ngIf="selectedOrder">
|
||||
<div class="detail-header">
|
||||
<h2>Dettaglio ordine {{ selectedOrder.orderNumber }}</h2>
|
||||
<p class="order-uuid">UUID: <code>{{ selectedOrder.id }}</code></p>
|
||||
<p *ngIf="detailLoading">Caricamento dettaglio...</p>
|
||||
</div>
|
||||
|
||||
<div class="meta-grid">
|
||||
<div><strong>Cliente</strong><span>{{ selectedOrder.customerEmail }}</span></div>
|
||||
<div><strong>Stato pagamento</strong><span>{{ selectedOrder.paymentStatus || 'PENDING' }}</span></div>
|
||||
<div><strong>Stato ordine</strong><span>{{ selectedOrder.status }}</span></div>
|
||||
<div><strong>Totale</strong><span>{{ selectedOrder.totalChf | currency:'CHF':'symbol':'1.2-2' }}</span></div>
|
||||
</div>
|
||||
|
||||
<div class="actions-block">
|
||||
<div class="status-editor">
|
||||
<label for="order-status">Stato ordine</label>
|
||||
<select id="order-status" [value]="selectedStatus" (change)="onStatusChange($event)">
|
||||
<option *ngFor="let option of orderStatusOptions" [value]="option">{{ option }}</option>
|
||||
</select>
|
||||
<button type="button" (click)="updateStatus()" [disabled]="updatingStatus">
|
||||
{{ updatingStatus ? 'Salvataggio...' : 'Aggiorna stato' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="status-editor">
|
||||
<label for="payment-method">Metodo pagamento</label>
|
||||
<select id="payment-method" [value]="selectedPaymentMethod" (change)="onPaymentMethodChange($event)">
|
||||
<option *ngFor="let option of paymentMethodOptions" [value]="option">{{ option }}</option>
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
(click)="confirmPayment()"
|
||||
[disabled]="confirmingPayment || selectedOrder.paymentStatus === 'COMPLETED'"
|
||||
>
|
||||
{{ confirmingPayment ? 'Invio...' : 'Conferma pagamento' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="doc-actions">
|
||||
<button type="button" class="ghost" (click)="downloadConfirmation()">
|
||||
Scarica conferma + QR bill
|
||||
</button>
|
||||
<button type="button" class="ghost" (click)="downloadInvoice()">
|
||||
Scarica fattura
|
||||
</button>
|
||||
<button type="button" class="ghost" (click)="openPrintDetails()">
|
||||
Dettagli stampa
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="items">
|
||||
<div class="item" *ngFor="let item of selectedOrder.items">
|
||||
<div class="item-main">
|
||||
<p class="file-name"><strong>{{ item.originalFilename }}</strong></p>
|
||||
<p class="item-meta">
|
||||
Qta: {{ item.quantity }} |
|
||||
Colore:
|
||||
<span class="color-swatch" *ngIf="isHexColor(item.colorCode)" [style.background-color]="item.colorCode"></span>
|
||||
<span>{{ item.colorCode || '-' }}</span>
|
||||
|
|
||||
Riga: {{ item.lineTotalChf | currency:'CHF':'symbol':'1.2-2' }}
|
||||
</p>
|
||||
</div>
|
||||
<button type="button" class="ghost" (click)="downloadItemFile(item.id, item.originalFilename)">
|
||||
Scarica file
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="detail-panel empty" *ngIf="!selectedOrder">
|
||||
<h2>Nessun ordine selezionato</h2>
|
||||
<p>Seleziona un ordine dalla lista per vedere i dettagli.</p>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ng-template #loadingTpl>
|
||||
<p>Caricamento ordini...</p>
|
||||
</ng-template>
|
||||
|
||||
<div class="modal-backdrop" *ngIf="showPrintDetails && selectedOrder" (click)="closePrintDetails()">
|
||||
<div class="modal-card" (click)="$event.stopPropagation()">
|
||||
<header class="modal-header">
|
||||
<h3>Dettagli stampa ordine {{ selectedOrder.orderNumber }}</h3>
|
||||
<button type="button" class="ghost close-btn" (click)="closePrintDetails()">Chiudi</button>
|
||||
</header>
|
||||
|
||||
<div class="modal-grid">
|
||||
<div><strong>Qualità</strong><span>{{ getQualityLabel(selectedOrder.printLayerHeightMm) }}</span></div>
|
||||
<div><strong>Materiale</strong><span>{{ selectedOrder.printMaterialCode || '-' }}</span></div>
|
||||
<div><strong>Layer height</strong><span>{{ selectedOrder.printLayerHeightMm || '-' }} mm</span></div>
|
||||
<div><strong>Nozzle</strong><span>{{ selectedOrder.printNozzleDiameterMm || '-' }} mm</span></div>
|
||||
<div><strong>Infill pattern</strong><span>{{ selectedOrder.printInfillPattern || '-' }}</span></div>
|
||||
<div><strong>Infill %</strong><span>{{ selectedOrder.printInfillPercent ?? '-' }}</span></div>
|
||||
<div><strong>Supporti</strong><span>{{ selectedOrder.printSupportsEnabled ? 'Sì' : 'No' }}</span></div>
|
||||
</div>
|
||||
|
||||
<h4>Colori file</h4>
|
||||
<div class="file-color-list">
|
||||
<div class="file-color-row" *ngFor="let item of selectedOrder.items">
|
||||
<span class="filename">{{ item.originalFilename }}</span>
|
||||
<span class="file-color">
|
||||
<span class="color-swatch" *ngIf="isHexColor(item.colorCode)" [style.background-color]="item.colorCode"></span>
|
||||
{{ item.colorCode || '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user