line-gestao-frontend/src/app/pages/geral/geral.html

967 lines
49 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- Toast (Sucesso) -->
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 10000;">
<div #successToast class="toast text-bg-success border-0 shadow" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header border-bottom-0">
<strong class="me-auto text-primary">LineGestão</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Fechar"></button>
</div>
<div class="toast-body bg-white rounded-bottom text-dark">
{{ toastMessage }}
</div>
</div>
</div>
<section class="geral-page" (click)="closeClientDropdown()">
<span class="page-blob blob-1" aria-hidden="true"></span>
<span class="page-blob blob-2" aria-hidden="true"></span>
<span class="page-blob blob-3" aria-hidden="true"></span>
<span class="page-blob blob-4" aria-hidden="true"></span>
<!-- ✅ classe extra para permitir “crescer” em notebook/TV via SCSS sem mexer no monitor -->
<div class="container-geral container-geral-responsive">
<div class="geral-card geral-card-responsive" data-animate>
<div class="geral-header">
<div class="header-row-top">
<div class="title-badge" data-animate>
<i class="bi bi-grid-1x2"></i> Gerenciar Linhas
</div>
<div class="header-title" data-animate>
<h5 class="title mb-0">Geral</h5>
<small class="subtitle">Tabela de linhas e dados de telefonia</small>
</div>
<div class="header-actions d-flex gap-2 justify-content-end" data-animate>
<button
type="button"
class="btn btn-glass btn-sm"
(click)="onImportExcel()"
[disabled]="loading">
<i class="bi bi-file-earmark-excel me-1"></i> Importar Dados Excel
</button>
<input #excelInput type="file" class="d-none" accept=".xlsx" (change)="onExcelSelected($event)" />
<button
type="button"
class="btn btn-brand btn-sm"
(click)="onCadastrarLinha()"
[disabled]="loading">
<i class="bi bi-plus-circle me-1"></i> Novo Cliente
</button>
</div>
</div>
<div class="filters-row mt-4" data-animate>
<div class="filter-tabs">
<button type="button" class="filter-tab" [class.active]="filterSkil === 'ALL'" (click)="setFilter('ALL')" [disabled]="loading">
Todos
</button>
<button type="button" class="filter-tab" [class.active]="filterSkil === 'PF'" (click)="setFilter('PF')" [disabled]="loading">
<i class="bi bi-person me-1"></i> Pessoa Física
</button>
<button type="button" class="filter-tab" [class.active]="filterSkil === 'PJ'" (click)="setFilter('PJ')" [disabled]="loading">
<i class="bi bi-building me-1"></i> Pessoa Jurídica
</button>
<button type="button" class="filter-tab" [class.active]="filterSkil === 'RESERVA'" (click)="setFilter('RESERVA')" [disabled]="loading">
<i class="bi bi-archive me-1"></i> Reservas
</button>
</div>
<!-- CLIENTE MULTI-SELECT -->
<div class="client-filter-wrap" (click)="$event.stopPropagation()">
<button
type="button"
class="btn-client-filter"
[class.has-selection]="selectedClients.length > 0"
(click)="toggleClientMenu()"
[disabled]="loading">
<ng-container *ngIf="selectedClients.length === 0">
<i class="bi bi-people-fill me-2"></i>
<span>Clientes</span>
<i class="bi bi-chevron-down ms-2 small"></i>
</ng-container>
<ng-container *ngIf="selectedClients.length > 0">
<div class="chips-container">
<span *ngFor="let client of selectedClients" class="client-chip" (click)="$event.stopPropagation()">
{{ client }}
<i class="bi bi-x chip-close" (click)="removeClient(client, $event)"></i>
</span>
</div>
<i class="bi bi-chevron-down ms-1 small text-muted"></i>
</ng-container>
</button>
<div class="client-dropdown" *ngIf="showClientMenu">
<div class="dropdown-header-search">
<input
type="text"
class="form-control form-control-sm"
placeholder="Buscar na lista..."
[(ngModel)]="clientSearchTerm"
autofocus
(click)="$event.stopPropagation()">
</div>
<div class="dropdown-list">
<div class="dropdown-item-custom" [class.selected]="selectedClients.length === 0" (click)="selectClient(null)">
<i class="bi bi-grid me-2"></i> Todos os Clientes
</div>
<ng-container *ngFor="let client of filteredClientsList">
<div class="dropdown-item-custom" [class.selected]="isClientSelected(client)" (click)="selectClient(client)">
<div class="d-flex align-items-center justify-content-between w-100">
<span>{{ client }}</span>
<i class="bi bi-check-lg text-brand" *ngIf="isClientSelected(client)"></i>
</div>
</div>
</ng-container>
</div>
</div>
</div>
</div>
<!-- KPIs -->
<div class="geral-kpis mt-4 animate-fade-in" *ngIf="isGroupMode">
<div class="kpi">
<span class="lbl">Total Clientes</span>
<span class="val">
<span *ngIf="loadingKpis" class="spinner-border spinner-border-sm text-muted"></span>
<span *ngIf="!loadingKpis">{{ kpiTotalClientes || 0 }}</span>
</span>
</div>
<div class="kpi">
<span class="lbl">Total Linhas</span>
<span class="val">
<span *ngIf="loadingKpis" class="spinner-border spinner-border-sm text-muted"></span>
<span *ngIf="!loadingKpis">{{ kpiTotalLinhas || 0 }}</span>
</span>
</div>
<div class="kpi">
<span class="lbl text-success">Ativas</span>
<span class="val">
<span *ngIf="loadingKpis" class="spinner-border spinner-border-sm text-muted"></span>
<span *ngIf="!loadingKpis">{{ kpiAtivas || 0 }}</span>
</span>
</div>
<div class="kpi">
<span class="lbl text-danger">Bloqueadas</span>
<span class="val">
<span *ngIf="loadingKpis" class="spinner-border spinner-border-sm text-muted"></span>
<span *ngIf="!loadingKpis">{{ kpiBloqueadas || 0 }}</span>
</span>
</div>
</div>
<!-- CONTROLS -->
<div class="controls mt-3 mb-2" data-animate>
<div class="input-group input-group-sm search-group">
<span class="input-group-text">
<i
class="bi"
[class.bi-search]="!loading"
[class.bi-hourglass-split]="loading"
[class.text-brand]="loading"></i>
</span>
<input class="form-control" placeholder="Pesquisar..." [(ngModel)]="searchTerm" (ngModelChange)="onSearch()" />
<button class="btn btn-outline-secondary btn-clear" type="button" (click)="clearSearch()" *ngIf="searchTerm">
<i class="bi bi-x-lg"></i>
</button>
</div>
<div class="page-size d-flex align-items-center gap-2">
<span class="text-muted small fw-bold text-uppercase" style="letter-spacing: 0.5px; font-size: 0.75rem;">
Itens por pág:
</span>
<div class="select-wrapper">
<app-select class="select-glass" size="sm" [options]="pageSizeOptions" [(ngModel)]="pageSize" (ngModelChange)="onPageSizeChange()" [disabled]="loading"></app-select>
</div>
</div>
</div>
</div>
<div class="geral-body">
<!-- VIEW: GRUPOS -->
<div class="groups-container" *ngIf="isGroupMode; else tableView">
<div class="text-center p-5" *ngIf="loading">
<span class="spinner-border text-brand"></span>
</div>
<div class="empty-group" *ngIf="!loading && clientGroups.length === 0">
Nenhum dado encontrado.
</div>
<div class="group-list" *ngIf="!loading">
<div *ngFor="let group of clientGroups" class="client-group-card" [class.expanded]="expandedGroup === group.cliente">
<div class="group-header" (click)="toggleGroup(group.cliente)">
<div class="group-info">
<h6 class="mb-0 fw-bold text-dark">{{ group.cliente }}</h6>
<div class="group-badges">
<span class="badge-pill total">{{ group.totalLinhas }} Linhas</span>
<span class="badge-pill active" *ngIf="group.ativos > 0">{{ group.ativos }} Ativas</span>
<span class="badge-pill blocked" *ngIf="group.bloqueados > 0">{{ group.bloqueados }} Bloq.</span>
</div>
</div>
<div class="group-toggle-icon"><i class="bi bi-chevron-down"></i></div>
</div>
<div class="group-body" *ngIf="expandedGroup === group.cliente">
<div class="d-flex justify-content-between align-items-center px-4 py-2 border-bottom bg-white">
<small class="text-muted fw-bold">Gerenciar Grupo</small>
<button class="btn btn-sm btn-primary" (click)="onAddLineToGroup(group.cliente)">
<i class="bi bi-plus-lg me-1"></i> Adicionar Linha
</button>
</div>
<!-- ✅ wrapper com classe extra para permitir MAIS ALTURA em notebook/TV via SCSS -->
<div class="table-wrap inner-table-wrap table-wrap-responsive table-wrap-tall">
<div *ngIf="loadingLines" class="p-4 text-center text-muted">
<span class="spinner-border spinner-border-sm me-2"></span> Carregando linhas...
</div>
<table class="table table-modern table-modern-responsive align-middle text-center mb-0" *ngIf="!loadingLines">
<thead>
<tr>
<th>ITEM</th>
<th>LINHA</th>
<th>USUÁRIO</th>
<th>STATUS</th>
<th>VENCIMENTO</th>
<th>AÇÕES</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of groupLines" class="table-row-item">
<td class="text-muted fw-bold">{{ r.item }}</td>
<td class="fw-black text-blue">{{ r.linha }}</td>
<td class="text-dark">{{ r.usuario || '-' }}</td>
<td>
<span class="status-pill" [ngClass]="statusClass(r.status)">{{ statusLabel(r.status) }}</span>
</td>
<td class="text-muted small fw-bold">{{ r.contrato }}</td>
<td>
<div class="action-group justify-content-center">
<button class="btn-icon" (click)="onDetalhes(r)" title="Detalhes"><i class="bi bi-eye"></i></button>
<button class="btn-icon success" (click)="onFinanceiro(r)" title="Financeiro"><i class="bi bi-cash-coin"></i></button>
<button class="btn-icon primary" (click)="onEditar(r)" title="Editar"><i class="bi bi-pencil-square"></i></button>
<button class="btn-icon danger" (click)="onRemover(r, true)" title="Remover"><i class="bi bi-trash"></i></button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- ✅ espaçador para afastar da área do footer (notebook/TV via SCSS) -->
<div class="footer-spacer footer-spacer-responsive" aria-hidden="true"></div>
</div>
</div>
</div>
</div>
<!-- VIEW: TABELA -->
<ng-template #tableView>
<!-- ✅ wrapper com classe extra para permitir MAIS ALTURA em notebook/TV via SCSS -->
<div class="table-wrap table-wrap-responsive table-wrap-tall">
<table class="table table-modern table-modern-responsive align-middle text-center">
<colgroup>
<col style="width: 80px;">
<col style="width: 140px;">
<col style="width: 280px;">
<col style="width: 160px;">
<col style="width: 130px;">
<col style="width: 130px;">
<col style="width: 160px;">
</colgroup>
<thead>
<tr>
<th class="sortable text-center" (click)="setSort('item')">
<div class="th-content justify-content-center">
ITEM
<span class="sort-caret" [class.active]="sortKey==='item'">
{{ sortKey==='item' && sortDir==='desc' ? '▼' : '▲' }}
</span>
</div>
</th>
<th class="sortable text-center" (click)="setSort('linha')">
<div class="th-content justify-content-center">
LINHA
<span class="sort-caret" [class.active]="sortKey==='linha'">
{{ sortKey==='linha' && sortDir==='desc' ? '▼' : '▲' }}
</span>
</div>
</th>
<th class="sortable text-center" (click)="setSort('cliente')">
<div class="th-content justify-content-center">
CLIENTE
<span class="sort-caret" [class.active]="sortKey==='cliente'">
{{ sortKey==='cliente' && sortDir==='desc' ? '▼' : '▲' }}
</span>
</div>
</th>
<th class="sortable text-center" (click)="setSort('status')">
<div class="th-content justify-content-center">
STATUS
<span class="sort-caret" [class.active]="sortKey==='status'">
{{ sortKey==='status' && sortDir==='desc' ? '▼' : '▲' }}
</span>
</div>
</th>
<th class="sortable text-center" (click)="setSort('skil')">
<div class="th-content justify-content-center">
SKIL
<span class="sort-caret" [class.active]="sortKey==='skil'">
{{ sortKey==='skil' && sortDir==='desc' ? '▼' : '▲' }}
</span>
</div>
</th>
<th class="sortable text-center" (click)="setSort('contrato')">
<div class="th-content justify-content-center">
VENCIMENTO
<span class="sort-caret" [class.active]="sortKey==='contrato'">
{{ sortKey==='contrato' && sortDir==='desc' ? '▼' : '▲' }}
</span>
</div>
</th>
<th class="text-center">AÇÕES</th>
</tr>
</thead>
<tbody>
<tr *ngIf="loading">
<td colspan="7" class="text-center py-5 empty-state">
<span class="spinner-border spinner-border-sm me-2 text-brand"></span> Carregando...
</td>
</tr>
<tr *ngIf="!loading && pagedRows.length === 0">
<td colspan="7" class="text-center py-5 empty-state text-muted fw-bold">
Nenhum registro encontrado.
</td>
</tr>
<tr *ngFor="let r of pagedRows; trackBy: trackById" class="table-row-item">
<td class="text-center text-muted fw-bold">{{ r.item }}</td>
<td class="text-center fw-black text-blue">{{ r.linha }}</td>
<td class="text-center fw-bold text-dark td-clip" [title]="r.cliente">{{ r.cliente }}</td>
<td class="text-center">
<span class="status-pill" [ngClass]="statusClass(r.status)" [title]="r.status || ''">{{ statusLabel(r.status) }}</span>
</td>
<td class="text-center fw-bold text-muted small">{{ r.skil }}</td>
<td class="text-center fw-bold text-muted small">{{ r.contrato }}</td>
<td class="text-center">
<div class="action-group justify-content-center">
<button class="btn-icon" (click)="onDetalhes(r)" title="Detalhes"><i class="bi bi-eye"></i></button>
<button class="btn-icon success" (click)="onFinanceiro(r)" title="Financeiro"><i class="bi bi-cash-coin"></i></button>
<button class="btn-icon primary" (click)="onEditar(r)" title="Editar"><i class="bi bi-pencil-square"></i></button>
<button class="btn-icon danger" (click)="onRemover(r)" title="Remover"><i class="bi bi-trash"></i></button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- ✅ espaçador para afastar da área do footer (notebook/TV via SCSS) -->
<div class="footer-spacer footer-spacer-responsive" aria-hidden="true"></div>
</ng-template>
</div>
<div class="geral-footer">
<div class="small text-muted fw-bold">Mostrando {{ pageStart }}{{ pageEnd }} de {{ filteredCount }}</div>
<nav>
<ul class="pagination pagination-sm mb-0 pagination-modern">
<li class="page-item" [class.disabled]="page === 1 || loading">
<button class="page-link" (click)="goToPage(page - 1)">Anterior</button>
</li>
<li class="page-item" *ngFor="let p of pageNumbers" [class.active]="p === page">
<button class="page-link" (click)="goToPage(p)">{{ p }}</button>
</li>
<li class="page-item" [class.disabled]="page === totalPages || loading">
<button class="page-link" (click)="goToPage(page + 1)">Próxima</button>
</li>
</ul>
</nav>
</div>
</div>
</div>
</section>
<!-- =========================================================
✅ MODAIS (corrigido: remove duplicações e divs soltas)
- fechamento centralizado em closeAllModals()
========================================================= -->
<!-- Backdrop -->
<div
class="modal-backdrop-custom"
*ngIf="detailOpen || financeOpen || editOpen || createOpen"
(click)="closeAllModals()">
</div>
<!-- Overlay (captura clique fora) -->
<div
class="modal-custom"
*ngIf="detailOpen || financeOpen || editOpen || createOpen"
(click)="closeAllModals()"
>
<!-- CREATE MODAL -->
<div
*ngIf="createOpen"
#createModal
class="modal-card modal-lg"
(click)="$event.stopPropagation()"
style="width: 1100px; max-width: 95vw;"
>
<div class="modal-header">
<div class="modal-title">
<span class="icon-bg brand-soft"><i class="bi bi-plus-lg"></i></span>
{{ createMode === 'NEW_CLIENT' ? 'Cadastrar Novo Cliente' : 'Nova Linha para ' + createModel.cliente }}
</div>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-glass btn-sm" (click)="closeAllModals()" [disabled]="createSaving">
<i class="bi bi-x-lg me-1"></i> Cancelar
</button>
<button class="btn btn-brand btn-sm" (click)="saveCreate()" [disabled]="createSaving">
<span *ngIf="!createSaving"><i class="bi bi-check2-circle me-1"></i> Cadastrar</span>
<span *ngIf="createSaving"><span class="spinner-border spinner-border-sm me-2"></span> Salvando...</span>
</button>
</div>
</div>
<div class="modal-body modern-body bg-light-gray">
<div class="details-dashboard">
<div class="dashboard-column">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-person-badge me-2"></i> Identificação</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field span-2" *ngIf="createMode === 'NEW_CLIENT'">
<div class="d-flex gap-4 p-2 bg-white rounded border align-items-center justify-content-center">
<div class="form-check">
<input class="form-check-input" type="radio" name="docType" value="PF" [(ngModel)]="createModel.docType" (change)="onDocTypeChange()">
<label class="form-check-label fw-bold small">Pessoa Física</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" name="docType" value="PJ" [(ngModel)]="createModel.docType" (change)="onDocTypeChange()">
<label class="form-check-label fw-bold small">Pessoa Jurídica</label>
</div>
</div>
</div>
<div class="form-field span-2" *ngIf="createMode === 'NEW_CLIENT'">
<label>Nome do Cliente <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.cliente" placeholder="Razão Social ou Nome Completo" />
</div>
<div class="form-field span-2" *ngIf="createMode === 'NEW_CLIENT'">
<label>{{ createModel.docType === 'PF' ? 'CPF' : 'CNPJ' }}</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.docNumber" (input)="onDocInput($event)" placeholder="Somente números" />
</div>
<div class="form-field">
<label>Item (Automático)</label>
<input class="form-control form-control-sm bg-light fst-italic text-muted" value="Gerado ao Salvar" readonly title="O ID será gerado automaticamente pelo sistema" />
</div>
<div class="form-field">
<label>Conta <span class="text-danger">*</span></label>
<app-select class="form-select" size="sm" [options]="contaOptions" [(ngModel)]="createModel.conta"></app-select>
</div>
<div class="form-field">
<label>Linha <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.linha" placeholder="119..." />
</div>
<div class="form-field">
<label>Chip (ICCID) <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.chip" />
</div>
<div class="form-field span-2">
<label>Usuário da Linha</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.usuario" />
</div>
</div>
</div>
</details>
<details class="detail-box mt-3">
<summary class="box-header">
<span><i class="bi bi-sliders me-2"></i> Gestão</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field">
<label>Skil (Automático)</label>
<input class="form-control form-control-sm bg-light" [(ngModel)]="createModel.skil" readonly />
</div>
<div class="form-field">
<label>Cedente</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.cedente" />
</div>
<div class="form-field span-2">
<label>Solicitante</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.solicitante" />
</div>
</div>
</div>
</details>
</div>
<div class="dashboard-column">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-file-earmark-text me-2"></i> Contrato & Status</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field span-2">
<label>Plano Contrato <span class="text-danger">*</span></label>
<app-select class="form-select" size="sm" [options]="planOptions" [(ngModel)]="createModel.planoContrato"></app-select>
</div>
<div class="form-field">
<label>Venc. Conta</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.vencConta" placeholder="ex: Dia 10" />
</div>
<div class="form-field">
<label>Modalidade</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.modalidade" />
</div>
<div class="form-field span-2">
<label>Status <span class="text-danger">*</span></label>
<app-select class="form-select" size="sm" [options]="statusOptions" [(ngModel)]="createModel.status"></app-select>
</div>
</div>
</div>
</details>
<details class="detail-box mt-3">
<summary class="box-header">
<span><i class="bi bi-calendar-event me-2"></i> Datas Importantes</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field span-2">
<label>Data Entrega Operadora</label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="createModel.dataEntregaOpera" />
</div>
<div class="form-field span-2">
<label>Data Entrega Cliente</label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="createModel.dataEntregaCliente" />
</div>
<div class="form-field span-2">
<label>Data de Bloqueio</label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="createModel.dataBloqueio" />
</div>
</div>
</div>
</details>
</div>
<div class="dashboard-column">
<details class="detail-box vivo-border">
<summary class="box-header header-vivo">
<span><i class="bi bi-telephone-fill me-2"></i> Financeiro Vivo</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label>Franquia (GB)</label><input class="form-control form-control-sm" type="number" step="0.1" [(ngModel)]="createModel.franquiaVivo" /></div>
<div class="form-field"><label>Valor Plano</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.valorPlanoVivo" (change)="onFinancialChange(false)" /></div>
<div class="form-field"><label>Gestão Voz</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.gestaoVozDados" (change)="onFinancialChange(false)" /></div>
<div class="form-field"><label>Skeelo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.skeelo" (change)="onFinancialChange(false)" /></div>
<div class="form-field"><label>News+</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.vivoNewsPlus" (change)="onFinancialChange(false)" /></div>
<div class="form-field"><label>Travel Mundo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.vivoTravelMundo" (change)="onFinancialChange(false)" /></div>
<div class="form-field"><label>Gestão Disp.</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.vivoGestaoDispositivo" (change)="onFinancialChange(false)" /></div>
<div class="form-field"><label class="text-vivo fw-bold">Total Vivo (Auto)</label><input class="form-control form-control-sm fw-bold border-vivo bg-light" type="number" step="0.01" [(ngModel)]="createModel.valorContratoVivo" readonly /></div>
</div>
</div>
</details>
<details class="detail-box line-border mt-3">
<summary class="box-header header-line">
<span><i class="bi bi-hdd-network-fill me-2"></i> Financeiro Line</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label>Franquia Line</label><input class="form-control form-control-sm" type="number" step="0.1" [(ngModel)]="createModel.franquiaLine" /></div>
<div class="form-field"><label>Franquia Gestão</label><input class="form-control form-control-sm" type="number" step="0.1" [(ngModel)]="createModel.franquiaGestao" /></div>
<div class="form-field"><label>Locação Ap.</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.locacaoAp" /></div>
<div class="form-field"><label class="text-line fw-bold">Total Line (Manual)</label><input class="form-control form-control-sm fw-bold border-line" type="number" step="0.01" [(ngModel)]="createModel.valorContratoLine" (change)="onFinancialChange(false)" /></div>
</div>
</div>
</details>
<details class="detail-box mt-3">
<summary class="box-header">
<span><i class="bi bi-graph-up-arrow me-2"></i> Resultados</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label class="text-danger fw-bold">DESCONTO</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.desconto" /></div>
<div class="form-field"><label class="text-brand">LUCRO ESTIMADO</label><input class="form-control form-control-sm bg-light fw-bold" type="number" step="0.01" [(ngModel)]="createModel.lucro" readonly /></div>
</div>
</div>
</details>
</div>
</div>
</div>
</div>
<!-- DETAIL MODAL -->
<div
*ngIf="detailOpen"
#detailModal
class="modal-card modal-xl-custom"
(click)="$event.stopPropagation()"
>
<div class="modal-header">
<div class="modal-title">
<span class="icon-bg primary-soft"><i class="bi bi-sim"></i></span>
Detalhes da Linha
</div>
<button class="btn btn-sm btn-icon" (click)="closeAllModals()"><i class="bi bi-x-lg"></i></button>
</div>
<div class="modal-body modern-body bg-light-gray" *ngIf="detailData; else detailLoading">
<div class="details-dashboard">
<div class="dashboard-column">
<div class="detail-box h-100">
<div class="box-header justify-content-center">
<span><i class="bi bi-person-badge me-2"></i> Identificação</span>
</div>
<div class="box-body">
<div class="info-grid">
<div class="info-item span-2">
<span class="lbl">Linha</span>
<span class="val text-blue fs-4">{{ detailData.linha || '-' }}</span>
</div>
<div class="info-item span-2">
<span class="lbl">Cliente</span>
<span class="val text-dark" [title]="detailData.cliente">{{ detailData.cliente || '-' }}</span>
</div>
<div class="info-item span-2">
<span class="lbl">Usuário</span>
<span class="val">{{ detailData.usuario || '-' }}</span>
</div>
<div class="info-item">
<span class="lbl">Item</span>
<span class="val">{{ detailData.item }}</span>
</div>
<div class="info-item">
<span class="lbl">Chip (ICCID)</span>
<span class="val small-text">{{ detailData.chip || '-' }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-column d-flex flex-column gap-2">
<div class="detail-box">
<div class="box-header justify-content-center">
<span><i class="bi bi-sliders me-2"></i> Gestão</span>
</div>
<div class="box-body compact-padding">
<div class="info-grid compact-gap">
<div class="info-item span-2">
<span class="lbl">Tipo (Skil)</span>
<span class="val">{{ detailData.skil || '-' }}</span>
</div>
<div class="info-item">
<span class="lbl">Cedente</span>
<span class="val">{{ detailData.cedente || '-' }}</span>
</div>
<div class="info-item">
<span class="lbl">Solicitante</span>
<span class="val">{{ detailData.solicitante || '-' }}</span>
</div>
</div>
</div>
</div>
<div class="detail-box flex-grow-1">
<div class="box-header justify-content-center">
<span><i class="bi bi-calendar-event me-2"></i> Datas</span>
</div>
<div class="box-body compact-padding">
<div class="info-grid compact-gap">
<div class="info-item">
<span class="lbl">Entrega Operadora</span>
<span class="val">{{ formatDateBr(detailData.dataEntregaOpera) }}</span>
</div>
<div class="info-item">
<span class="lbl">Entrega Cliente</span>
<span class="val">{{ formatDateBr(detailData.dataEntregaCliente) }}</span>
</div>
<div class="info-item span-2">
<span class="lbl text-danger">Data Bloqueio</span>
<span class="val">{{ formatDateBr(detailData.dataBloqueio) }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-column">
<div class="detail-box h-100">
<div class="box-header justify-content-center">
<span><i class="bi bi-file-earmark-text me-2"></i> Contrato & Status</span>
</div>
<div class="box-body">
<div class="info-grid">
<div class="info-item span-2">
<span class="lbl">Plano Contratado</span>
<span class="val fw-bold text-brand">{{ detailData.planoContrato || '-' }}</span>
</div>
<div class="info-item">
<span class="lbl">Conta</span>
<span class="val">{{ detailData.conta || '-' }}</span>
</div>
<div class="info-item">
<span class="lbl">Vencimento</span>
<span class="val">{{ detailData.vencConta || '-' }}</span>
</div>
<div class="info-item span-2">
<span class="lbl">Status Atual</span>
<div class="mt-1">
<span class="status-pill static scale-up" [ngClass]="statusClass(detailData.status)">{{ statusLabel(detailData.status) }}</span>
</div>
</div>
<div class="info-item span-2">
<span class="lbl">Modalidade</span>
<span class="val">{{ detailData.modalidade || '-' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<ng-template #detailLoading>
<div class="p-5 text-center text-muted">Carregando detalhes...</div>
</ng-template>
</div>
<!-- FINANCE MODAL -->
<div
*ngIf="financeOpen"
#financeModal
class="modal-card modal-lg"
(click)="$event.stopPropagation()"
>
<div class="modal-header">
<div class="modal-title">
<span class="icon-bg success"><i class="bi bi-wallet2"></i></span> Financeiro
</div>
<button class="btn btn-sm btn-icon" (click)="closeAllModals()"><i class="bi bi-x-lg"></i></button>
</div>
<div class="modal-body modern-body bg-light-gray" *ngIf="financeData; else financeLoading">
<div class="finance-dashboard">
<div class="finance-card vivo-card">
<div class="card-header-f"><i class="bi bi-telephone-fill me-2"></i> Vivo</div>
<div class="card-body-f">
<div class="row-item"><span>Franquia</span> <strong>{{ formatFranquia(financeData.franquiaVivo) }}</strong></div>
<div class="row-item"><span>Valor Plano</span> <strong>{{ formatMoney(financeData.valorPlanoVivo) }}</strong></div>
<div class="row-item"><span>Gestão Voz/Dados</span> <strong>{{ formatMoney(financeData.gestaoVozDados) }}</strong></div>
<div class="row-item"><span>Skeelo</span> <strong>{{ formatMoney(financeData.skeelo) }}</strong></div>
<div class="row-item"><span>Vivo News+</span> <strong>{{ formatMoney(financeData.vivoNewsPlus) }}</strong></div>
<div class="row-item"><span>Travel Mundo</span> <strong>{{ formatMoney(financeData.vivoTravelMundo) }}</strong></div>
<div class="row-item"><span>Gestão Disp.</span> <strong>{{ formatMoney(financeData.vivoGestaoDispositivo) }}</strong></div>
<div class="divider"></div>
<div class="row-item total"><span>Total Vivo</span> <strong>{{ formatMoney(financeData.valorContratoVivo) }}</strong></div>
</div>
</div>
<div class="finance-card line-card">
<div class="card-header-f"><i class="bi bi-hdd-network-fill me-2"></i> Line Móvel</div>
<div class="card-body-f">
<div class="row-item"><span>Franquia Line</span> <strong>{{ formatFranquia(financeData.franquiaLine) }}</strong></div>
<div class="row-item"><span>Franquia Gestão</span> <strong>{{ formatFranquia(financeData.franquiaGestao) }}</strong></div>
<div class="row-item"><span>Locação Ap.</span> <strong>{{ formatMoney(financeData.locacaoAp) }}</strong></div>
<div class="divider"></div>
<div class="row-item total"><span>Total Line</span> <strong>{{ formatMoney(financeData.valorContratoLine) }}</strong></div>
</div>
</div>
</div>
<div class="finance-summary mt-3">
<div class="summary-item">
<span class="lbl text-danger">Desconto</span>
<span class="val text-danger">{{ formatMoney(financeData.desconto) }}</span>
</div>
<div class="vertical-line"></div>
<div class="summary-item">
<span class="lbl">Lucro Estimado</span>
<span class="val text-brand">{{ formatMoney(financeData.lucro) }}</span>
</div>
</div>
</div>
<ng-template #financeLoading>
<div class="p-5 text-center text-muted">Carregando financeiro...</div>
</ng-template>
</div>
<!-- EDIT MODAL -->
<div
*ngIf="editOpen"
#editModal
class="modal-card modal-edit"
(click)="$event.stopPropagation()"
>
<div class="modal-header">
<div class="modal-title">
<span class="icon-bg primary-soft"><i class="bi bi-pencil-square"></i></span> Editar Linha
</div>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-glass btn-sm" (click)="closeAllModals()" [disabled]="editSaving">
<i class="bi bi-x-lg me-1"></i> Cancelar
</button>
<button class="btn btn-brand btn-sm" (click)="saveEdit()" [disabled]="!editModel || editSaving">
Salvar
</button>
</div>
</div>
<div class="modal-body modern-body bg-light-gray">
<ng-container *ngIf="editModel; else editLoadingTpl">
<div class="edit-sections">
<details open class="detail-box">
<summary class="box-header"><span><i class="bi bi-person-badge me-2"></i> Identificação</span><i class="bi bi-chevron-down ms-auto transition-icon"></i></summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label>Item</label><input class="form-control form-control-sm bg-light" type="number" [(ngModel)]="editModel.item" disabled title="O ID não pode ser alterado" /></div>
<div class="form-field"><label>Conta</label><app-select class="form-select" size="sm" [options]="contaOptionsForEdit" [(ngModel)]="editModel.conta"></app-select></div>
<div class="form-field"><label>Linha</label><input class="form-control form-control-sm" [(ngModel)]="editModel.linha" /></div>
<div class="form-field"><label>Chip</label><input class="form-control form-control-sm" [(ngModel)]="editModel.chip" /></div>
<div class="form-field"><label>Cliente</label><input class="form-control form-control-sm" [(ngModel)]="editModel.cliente" /></div>
<div class="form-field"><label>Usuário</label><input class="form-control form-control-sm" [(ngModel)]="editModel.usuario" /></div>
</div>
</div>
</details>
<details open class="detail-box">
<summary class="box-header"><span><i class="bi bi-file-earmark-text me-2"></i> Contrato & Plano</span><i class="bi bi-chevron-down ms-auto transition-icon"></i></summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field span-2"><label>Plano Contrato</label><app-select class="form-select" size="sm" [options]="planOptionsForEdit" [(ngModel)]="editModel.planoContrato"></app-select></div>
<div class="form-field"><label>Venc. da Conta</label><input class="form-control form-control-sm" [(ngModel)]="editModel.vencConta" /></div>
<div class="form-field"><label>Modalidade</label><input class="form-control form-control-sm" [(ngModel)]="editModel.modalidade" /></div>
</div>
</div>
</details>
<details open class="detail-box">
<summary class="box-header"><span><i class="bi bi-activity me-2"></i> Status & Logística</span><i class="bi bi-chevron-down ms-auto transition-icon"></i></summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label>Status</label><app-select class="form-select" size="sm" [options]="statusOptionsForEdit" [(ngModel)]="editModel.status"></app-select></div>
<div class="form-field"><label>Data do Bloqueio</label><input class="form-control form-control-sm" type="date" [(ngModel)]="editModel.dataBloqueio" /></div>
<div class="form-field"><label>Entrega Operadora</label><input class="form-control form-control-sm" type="date" [(ngModel)]="editModel.dataEntregaOpera" /></div>
<div class="form-field"><label>Entrega Cliente</label><input class="form-control form-control-sm" type="date" [(ngModel)]="editModel.dataEntregaCliente" /></div>
<div class="form-field"><label>Skil</label><app-select class="form-select" size="sm" [options]="skilOptionsForEdit" [(ngModel)]="editModel.skil"></app-select></div>
<div class="form-field"><label>Cedente</label><input class="form-control form-control-sm" [(ngModel)]="editModel.cedente" /></div>
<div class="form-field span-2"><label>Solicitante</label><input class="form-control form-control-sm" [(ngModel)]="editModel.solicitante" /></div>
</div>
</div>
</details>
<details class="detail-box vivo-border">
<summary class="box-header header-vivo"><span><i class="bi bi-telephone-fill me-2"></i> Financeiro Vivo</span><i class="bi bi-chevron-down ms-auto transition-icon"></i></summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label>Franquia Vivo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.franquiaVivo" /></div>
<div class="form-field"><label>Valor Plano Vivo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.valorPlanoVivo" (change)="onFinancialChange(true)" /></div>
<div class="form-field"><label>Gestão Voz/Dados</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.gestaoVozDados" (change)="onFinancialChange(true)" /></div>
<div class="form-field"><label>Skeelo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.skeelo" (change)="onFinancialChange(true)" /></div>
<div class="form-field"><label>Vivo News+</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.vivoNewsPlus" (change)="onFinancialChange(true)" /></div>
<div class="form-field"><label>Vivo Travel Mundo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.vivoTravelMundo" (change)="onFinancialChange(true)" /></div>
<div class="form-field"><label>Vivo Gestão Disp.</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.vivoGestaoDispositivo" (change)="onFinancialChange(true)" /></div>
<div class="form-field"><label class="text-vivo fw-bold">Valor Contrato Vivo</label><input class="form-control form-control-sm fw-bold border-vivo bg-light" type="number" step="0.01" [(ngModel)]="editModel.valorContratoVivo" readonly /></div>
</div>
</div>
</details>
<details class="detail-box line-border">
<summary class="box-header header-line"><span><i class="bi bi-hdd-network-fill me-2"></i> Financeiro Line</span><i class="bi bi-chevron-down ms-auto transition-icon"></i></summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label>Franquia Line</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.franquiaLine" /></div>
<div class="form-field"><label>Franquia Gestão</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.franquiaGestao" /></div>
<div class="form-field"><label>Locação Ap.</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.locacaoAp" /></div>
<div class="form-field"><label class="text-line fw-bold">Valor Contrato Line</label><input class="form-control form-control-sm fw-bold border-line" type="number" step="0.01" [(ngModel)]="editModel.valorContratoLine" (change)="onFinancialChange(true)" /></div>
</div>
</div>
</details>
<details class="detail-box">
<summary class="box-header"><span><i class="bi bi-graph-up-arrow me-2"></i> Resultado</span><i class="bi bi-chevron-down ms-auto transition-icon"></i></summary>
<div class="box-body">
<div class="form-grid">
<div class="form-field"><label class="text-danger fw-bold">Desconto</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.desconto" /></div>
<div class="form-field"><label class="text-brand">Lucro Estimado</label><input class="form-control form-control-sm bg-light fw-bold" type="number" step="0.01" [(ngModel)]="editModel.lucro" readonly /></div>
</div>
</div>
</details>
</div>
</ng-container>
<ng-template #editLoadingTpl>
<div class="p-5 text-center text-muted">Carregando...</div>
</ng-template>
</div>
</div>
</div>