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

2014 lines
106 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)="closeFilterDropdowns()">
<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"
*ngIf="isSysAdmin"
(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)" />
<input #batchExcelInput type="file" class="d-none" accept=".xlsx" (change)="onBatchExcelSelected($event)" />
<button
type="button"
class="btn btn-brand btn-sm"
*ngIf="!isClientRestricted"
(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>
<ng-container *ngIf="!isClientRestricted">
<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>
</ng-container>
</div>
<!-- CLIENTE MULTI-SELECT -->
<div class="client-filter-wrap" *ngIf="!isClientRestricted" (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 class="additional-filter-wrap" *ngIf="!isClientRestricted" (click)="$event.stopPropagation()">
<button
type="button"
class="btn-client-filter btn-additional-filter"
[class.has-selection]="hasAdditionalFiltersApplied"
(click)="toggleAdditionalMenu()"
[disabled]="loading">
<ng-container *ngIf="!hasAdditionalFiltersApplied">
<i class="bi bi-sliders2-vertical me-2"></i>
<span>Adicionais</span>
<i class="bi bi-chevron-down ms-2 small"></i>
</ng-container>
<ng-container *ngIf="hasAdditionalFiltersApplied">
<div class="chips-container">
<span class="client-chip">
{{ additionalModeLabel }}
</span>
<span *ngFor="let label of additionalSelectedLabels" class="client-chip">
{{ label }}
</span>
</div>
<i class="bi bi-chevron-down ms-1 small text-muted"></i>
</ng-container>
</button>
<div class="client-dropdown additional-dropdown" *ngIf="showAdditionalMenu">
<div class="additional-dropdown-section">
<div class="additional-dropdown-title">Modo</div>
<div class="additional-mode-tabs">
<button
type="button"
class="additional-mode-btn"
[class.active]="additionalMode === 'ALL'"
(click)="setAdditionalMode('ALL')"
[disabled]="loading">
Todos os adicionais
</button>
<button
type="button"
class="additional-mode-btn"
[class.active]="additionalMode === 'WITH'"
(click)="setAdditionalMode('WITH')"
[disabled]="loading">
Com adicionais
</button>
<button
type="button"
class="additional-mode-btn"
[class.active]="additionalMode === 'WITHOUT'"
(click)="setAdditionalMode('WITHOUT')"
[disabled]="loading">
Sem adicionais
</button>
</div>
</div>
<div class="additional-dropdown-section">
<div class="additional-dropdown-title">Serviços</div>
<div class="additional-services-chips">
<button
type="button"
class="additional-chip-btn"
*ngFor="let svc of additionalServiceOptions"
[class.active]="isAdditionalServiceSelected(svc.key)"
(click)="toggleAdditionalService(svc.key)"
[disabled]="loading">
{{ svc.label }}
</button>
</div>
</div>
<div class="additional-dropdown-footer">
<button
type="button"
class="additional-chip-btn clear"
(click)="clearAdditionalFilters()"
[disabled]="loading">
Limpar filtros adicionais
</button>
</div>
</div>
</div>
</div>
<!-- KPIs -->
<div class="geral-kpis mt-4 animate-fade-in" [class.geral-kpis-client]="isClientRestricted" *ngIf="isGroupMode">
<div class="kpi" *ngIf="!isClientRestricted">
<span class="lbl">Total Clientes</span>
<span class="val val-loading" *ngIf="isKpiLoading">
<span class="spinner-border spinner-border-sm text-brand"></span>
</span>
<span class="val" *ngIf="!isKpiLoading">{{ kpiTotalClientes || 0 }}</span>
</div>
<div class="kpi">
<span class="lbl">Total Linhas</span>
<span class="val val-loading" *ngIf="isKpiLoading">
<span class="spinner-border spinner-border-sm text-brand"></span>
</span>
<span class="val" *ngIf="!isKpiLoading">{{ kpiTotalLinhas || 0 }}</span>
</div>
<div class="kpi">
<span class="lbl text-success">Ativas</span>
<span class="val val-loading" *ngIf="isKpiLoading">
<span class="spinner-border spinner-border-sm text-brand"></span>
</span>
<span class="val" *ngIf="!isKpiLoading">{{ kpiAtivas || 0 }}</span>
</div>
<div class="kpi">
<span class="lbl text-danger">Bloqueadas</span>
<span class="val val-loading" *ngIf="isKpiLoading">
<span class="spinner-border spinner-border-sm text-brand"></span>
</span>
<span class="val" *ngIf="!isKpiLoading">{{ kpiBloqueadas || 0 }}</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-tags">
<span class="tag-pill">{{ group.totalLinhas }} linhas</span>
<span class="tag-pill active" *ngIf="group.ativos > 0">{{ group.ativos }} ativas</span>
<span class="tag-pill blocked" *ngIf="group.bloqueados > 0">{{ group.bloqueados }} bloqueadas</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>
<div class="d-flex align-items-center gap-2 flex-wrap justify-content-end">
<ng-container *ngIf="hasGroupLineSelectionTools">
<button class="btn btn-sm btn-glass" type="button" (click)="toggleSelectAllReservaGroupLines()">
<i class="bi bi-check2-square me-1"></i>
{{ reservaSelectedCount > 0 && reservaSelectedCount === groupLines.length ? 'Limpar seleção' : 'Selecionar todas' }}
</button>
</ng-container>
<ng-container *ngIf="isReservaExpandedGroup && hasGroupLineSelectionTools">
<button
class="btn btn-sm btn-brand"
type="button"
(click)="openReservaTransferModal()"
[disabled]="reservaSelectedCount === 0"
>
<i class="bi bi-arrow-left-right me-1"></i> Atribuir Selecionadas ({{ reservaSelectedCount }})
</button>
</ng-container>
<ng-container *ngIf="canMoveSelectedLinesToReserva">
<button
class="btn btn-sm btn-send-reserva-group"
type="button"
(click)="openMoveToReservaModal()"
[disabled]="reservaSelectedCount === 0"
>
<i class="bi bi-box-arrow-left me-1"></i> Enviar p/ Reserva ({{ reservaSelectedCount }})
</button>
</ng-container>
<button class="btn btn-sm btn-add-line-group" *ngIf="!isClientRestricted" (click)="onAddLineToGroup(group.cliente)">
<i class="bi bi-plus-lg me-1"></i> Adicionar Linha
</button>
</div>
</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 *ngIf="hasGroupLineSelectionTools" style="width: 52px;">
<input
class="line-select-checkbox"
type="checkbox"
[checked]="groupLines.length > 0 && reservaSelectedCount === groupLines.length"
(click)="$event.stopPropagation()"
(change)="toggleSelectAllReservaGroupLines()"
aria-label="Selecionar todas as linhas do grupo"
/>
</th>
<th>ITEM</th>
<th>LINHA</th>
<th>USUÁRIO</th>
<th>STATUS</th>
<th *ngIf="!isClientRestricted">VENCIMENTO</th>
<th>AÇÕES</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let r of groupLines" class="table-row-item">
<td *ngIf="hasGroupLineSelectionTools">
<input
class="line-select-checkbox"
type="checkbox"
[checked]="isReservaLineSelected(r.id)"
(click)="$event.stopPropagation()"
(change)="toggleReservaLineSelection(r.id, $any($event.target).checked)"
[attr.aria-label]="'Selecionar linha ' + (r.linha || r.item)"
/>
</td>
<td class="text-muted fw-bold">{{ r.item }}</td>
<td class="fw-black text-blue" [attr.title]="(r.chip || '') ? ('ICCID: ' + r.chip) : ''">
{{ r.linha }}
<div class="small text-muted fw-normal" *ngIf="r.chip">ICCID: {{ r.chip }}</div>
</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" *ngIf="!isClientRestricted">{{ 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>
<ng-container *ngIf="!isClientRestricted">
<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 *ngIf="isSysAdmin" class="btn-icon danger" (click)="onRemover(r, true)" title="Remover"><i class="bi bi-trash"></i></button>
</ng-container>
</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;" *ngIf="!isClientRestricted">
<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 *ngIf="!isClientRestricted" 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 actions-col-main">AÇÕES</th>
</tr>
</thead>
<tbody>
<tr *ngIf="loading">
<td [attr.colspan]="isClientRestricted ? 6 : 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 [attr.colspan]="isClientRestricted ? 6 : 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" *ngIf="!isClientRestricted">{{ 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>
<ng-container *ngIf="!isClientRestricted">
<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 *ngIf="isSysAdmin" class="btn-icon danger" (click)="onRemover(r)" title="Remover"><i class="bi bi-trash"></i></button>
</ng-container>
</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 || reservaTransferOpen || moveToReservaOpen"
(click)="closeAllModals()">
</div>
<!-- Overlay (captura clique fora) -->
<div
class="modal-custom"
*ngIf="detailOpen || financeOpen || editOpen || createOpen || reservaTransferOpen || moveToReservaOpen"
(click)="closeAllModals()"
>
<!-- CREATE MODAL -->
<div
*ngIf="createOpen"
#createModal
class="modal-card modal-lg modal-create"
[class.batch-mode]="isCreateBatchMode"
(click)="$event.stopPropagation()"
>
<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'
? (isCreateBatchMode ? 'Cadastrar Novo Cliente + Lote de Linhas' : 'Cadastrar Novo Cliente')
: ((isCreateBatchMode ? 'Novo Lote de Linhas para ' : '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]="isCreateSaveDisabled">
<span *ngIf="!createSaving"><i class="bi bi-check2-circle me-1"></i> {{ createSubmitText }}</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="create-entry-mode mb-3">
<div class="mode-pill-group" role="tablist" aria-label="Modo de cadastro">
<button
type="button"
class="mode-pill"
[class.active]="!isCreateBatchMode"
(click)="setCreateEntryMode('SINGLE')"
[disabled]="createSaving"
>
<i class="bi bi-file-earmark-plus me-1"></i> Unitário
</button>
<button
type="button"
class="mode-pill"
[class.active]="isCreateBatchMode"
(click)="setCreateEntryMode('BATCH')"
[disabled]="createSaving"
>
<i class="bi bi-collection me-1"></i> Lote de Linhas
</button>
</div>
<div class="mode-helper" *ngIf="isCreateBatchMode">
Modo lote focado em volume: use a grade para preencher rapidamente e abra o painel lateral de <strong>Detalhes</strong>
da linha quando precisar completar campos de contrato, datas e financeiro.
</div>
</div>
<div class="details-dashboard" *ngIf="!isCreateBatchMode">
<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>Empresa (Conta) <span class="text-danger">*</span></label>
<app-select
class="form-select"
size="sm"
[options]="contaEmpresaOptions"
[placeholder]="loadingAccountCompanies ? 'Carregando empresas...' : 'Selecione a empresa'"
[(ngModel)]="createModel.contaEmpresa"
(ngModelChange)="onContaEmpresaChange(false)"
></app-select>
</div>
<div class="form-field">
<label>Conta <span class="text-danger">*</span></label>
<app-select
class="form-select"
size="sm"
[options]="contaOptionsForCreate"
[disabled]="!createModel.contaEmpresa"
[placeholder]="createModel.contaEmpresa ? 'Selecione a conta' : 'Selecione a empresa primeiro'"
[(ngModel)]="createModel.conta"
></app-select>
</div>
<div class="form-field">
<label>Linha <span class="text-danger">*</span></label>
<app-select
class="form-select"
size="sm"
[options]="createReservaLineOptions"
labelKey="label"
valueKey="value"
[searchable]="true"
searchPlaceholder="Pesquisar linha da reserva..."
[placeholder]="loadingCreateReservaLines ? 'Carregando linhas da Reserva...' : 'Selecione uma linha da Reserva'"
[disabled]="loadingCreateReservaLines"
[(ngModel)]="createModel.reservaLineId"
(ngModelChange)="onCreateReservaLineChange()"
></app-select>
</div>
<div class="form-field">
<label>
{{ isCreateBatchMode ? 'Chip (ICCID) (Preencher no Lote)' : 'Chip (ICCID)' }}
<span class="text-danger" *ngIf="!isCreateBatchMode">*</span>
</label>
<input
class="form-control form-control-sm"
[(ngModel)]="createModel.chip"
[disabled]="isCreateBatchMode"
[placeholder]="isCreateBatchMode ? 'Use a tabela de lote abaixo' : ''"
/>
</div>
<div class="form-field">
<label>Tipo de Chip</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.tipoDeChip" />
</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" open>
<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" (ngModelChange)="onPlanoChange(false)"></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" open>
<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 class="form-field span-2">
<label>Dt. Efetivação Serviço <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="createModel.dtEfetivacaoServico" required />
</div>
<div class="form-field span-2">
<label>Dt. Término Fidelização <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="createModel.dtTerminoFidelizacao" required />
</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>Vivo Sync</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="createModel.vivoSync" (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 class="batch-client-setup mt-2" *ngIf="isCreateBatchMode">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-person-badge me-2"></i> Contexto do Lote</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="docTypeBatch" 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="docTypeBatch" 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' }} <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.docNumber" (input)="onDocInput($event)" placeholder="Somente números" />
</div>
<div class="form-field span-2" *ngIf="createMode === 'NEW_LINE_IN_GROUP'">
<label>Cliente Selecionado</label>
<input class="form-control form-control-sm bg-light" [value]="createModel.cliente" readonly />
</div>
<div class="form-field">
<label>Usuário padrão (opcional)</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.usuario" placeholder="Usado como referência para novas linhas" />
</div>
<div class="form-field">
<label>Tipo de Chip padrão (opcional)</label>
<input class="form-control form-control-sm" [(ngModel)]="createModel.tipoDeChip" placeholder="Usado como referência para novas linhas" />
</div>
</div>
</div>
</details>
</div>
<div class="batch-lines-panel mt-3" *ngIf="isCreateBatchMode">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-collection me-2"></i> Lote de Linhas</span>
<span class="batch-count-badge ms-2">{{ createBatchCount }} item(ns)</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="batch-summary-strip">
<span class="summary-pill total">Total: {{ createBatchValidationSummary.total }}</span>
<span class="summary-pill ok">Válidas: {{ createBatchValidationSummary.valid }}</span>
<span class="summary-pill warn" *ngIf="createBatchValidationSummary.invalid > 0">
Inválidas: {{ createBatchValidationSummary.invalid }}
</span>
<span class="summary-pill dup" *ngIf="createBatchValidationSummary.duplicates > 0">
Duplicadas: {{ createBatchValidationSummary.duplicates }}
</span>
</div>
<div
class="batch-validation-banner"
[class.is-danger]="createBatchValidationSummary.invalid > 0"
[class.is-ok]="createBatchValidationSummary.total > 0 && createBatchValidationSummary.invalid === 0"
>
<i class="bi" [ngClass]="createBatchValidationSummary.invalid > 0 ? 'bi-exclamation-triangle-fill' : 'bi-check-circle-fill'"></i>
<span>{{ batchValidationMessage }}</span>
</div>
<div class="batch-inheritance-note">
O cliente é definido pelo contexto do cadastro (novo cliente ou cliente existente). Na grade você preenche os
campos rápidos e usa <strong>Detalhes</strong> para completar os dados obrigatórios e opcionais da linha
(<strong>Conta, Plano Contrato, Status, Datas</strong>, financeiro, etc.). Esses campos são <strong>por linha</strong>
e podem ser diferentes entre linhas.
</div>
<div class="batch-mass-input-box mb-3">
<div class="batch-mass-input-head">
<div>
<div class="batch-mass-title"><i class="bi bi-file-earmark-excel me-2"></i>Importar Planilha (Colunas da GERAL)</div>
<div class="batch-mass-sub">
Use uma planilha Excel com os mesmos cabeçalhos da <strong>GERAL</strong> (não precisa ter uma aba chamada <strong>GERAL</strong>). A coluna <code>ITÉM</code> não é necessária; se vier preenchida, será ignorada e o sistema gera a sequência automaticamente.
</div>
</div>
<div class="d-flex gap-2 align-items-center flex-wrap justify-content-end">
<button type="button" class="btn btn-sm btn-glass" (click)="onDownloadBatchExcelTemplate()" [disabled]="createSaving || batchExcelTemplateDownloading || batchExcelPreviewLoading">
<span *ngIf="!batchExcelTemplateDownloading"><i class="bi bi-download me-1"></i> Baixar Modelo (GERAL)</span>
<span *ngIf="batchExcelTemplateDownloading"><span class="spinner-border spinner-border-sm me-2"></span> Baixando...</span>
</button>
<button type="button" class="btn btn-sm btn-brand" (click)="onImportBatchExcel()" [disabled]="createSaving || batchExcelPreviewLoading">
<span *ngIf="!batchExcelPreviewLoading"><i class="bi bi-paperclip me-1"></i> Anexar Excel</span>
<span *ngIf="batchExcelPreviewLoading"><span class="spinner-border spinner-border-sm me-2"></span> Lendo...</span>
</button>
<button type="button" class="btn btn-sm btn-glass" (click)="clearBatchExcelPreview()" [disabled]="createSaving || (!batchExcelPreview && !batchExcelPreviewLoading)">
<i class="bi bi-x-circle me-1"></i> Limpar Prévia
</button>
</div>
</div>
<div class="batch-mass-preview" *ngIf="batchExcelPreview as excelPreview">
<div class="batch-mass-preview-pills">
<span class="summary-pill total">Aba: {{ excelPreview.sheetName || 'GERAL' }}</span>
<span class="summary-pill total">Linhas lidas: {{ excelPreview.totalRows || 0 }}</span>
<span class="summary-pill ok">Válidas: {{ excelPreview.validRows || 0 }}</span>
<span class="summary-pill warn" *ngIf="(excelPreview.invalidRows || 0) > 0">Inválidas: {{ excelPreview.invalidRows || 0 }}</span>
<span class="summary-pill dup" *ngIf="(excelPreview.duplicateRows || 0) > 0">Duplicadas: {{ excelPreview.duplicateRows || 0 }}</span>
<span class="summary-pill" *ngIf="excelPreview.nextItemStart > 0">Próx. ITÉM (sistema): {{ excelPreview.nextItemStart }}</span>
</div>
<div class="batch-mass-preview-errors" *ngIf="(excelPreview.headerErrors?.length || 0) > 0">
<strong>Erros de cabeçalho/estrutura</strong>
<ul class="mb-0 mt-1">
<li *ngFor="let err of excelPreview.headerErrors">
<strong *ngIf="err.column">{{ err.column }}:</strong> {{ err.message }}
</li>
</ul>
</div>
<div class="batch-mass-preview-errors" *ngIf="(excelPreview.headerWarnings?.length || 0) > 0">
<strong>Avisos</strong>
<ul class="mb-0 mt-1">
<li *ngFor="let warn of excelPreview.headerWarnings">
<strong *ngIf="warn.column">{{ warn.column }}:</strong> {{ warn.message }}
</li>
</ul>
</div>
<div class="batch-mass-actions mt-2">
<button
type="button"
class="btn btn-sm btn-brand"
(click)="applyBatchExcelPreview('ADD')"
[disabled]="createSaving || batchExcelPreviewLoading || !excelPreview.canProceed"
>
<i class="bi bi-plus-circle me-1"></i> Adicionar Linhas Válidas ao Lote
</button>
<button
type="button"
class="btn btn-sm btn-glass"
(click)="applyBatchExcelPreview('REPLACE')"
[disabled]="createSaving || batchExcelPreviewLoading || !excelPreview.canProceed"
>
<i class="bi bi-arrow-repeat me-1"></i> Substituir Lote com Linhas Válidas
</button>
</div>
<div class="batch-mass-preview-table-wrap mt-2" *ngIf="(excelPreview.rows.length || 0) > 0">
<table class="batch-mass-preview-table">
<thead>
<tr>
<th>Planilha</th>
<th>ITÉM (origem)</th>
<th>ITÉM (sistema)</th>
<th>Linha</th>
<th>Chip</th>
<th>Conta</th>
<th>Status</th>
<th>Validação</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let row of batchExcelPreviewRowsPreview">
<td>#{{ row.sourceRowNumber }}</td>
<td>{{ row.sourceItem ?? '-' }}</td>
<td>{{ row.generatedItemPreview ?? '-' }}</td>
<td>{{ row.data.linha || '-' }}</td>
<td>{{ row.data.chip || '-' }}</td>
<td>{{ row.data.conta || '-' }}</td>
<td>{{ row.data.status || '-' }}</td>
<td class="validation-cell">
<div class="batch-row-valid" *ngIf="(row.errors.length || 0) === 0">
<i class="bi bi-check-circle-fill"></i> OK
</div>
<div
class="batch-row-errors-compact"
*ngIf="(row.errors.length || 0) > 0"
[attr.title]="getBatchExcelRowErrorsTitle(row)"
>
<div class="batch-row-error-main">
{{ getBatchExcelRowPrimaryError(row) }}
</div>
<div class="batch-row-more" *ngIf="(row.errors.length || 0) > 1">
+{{ (row.errors.length || 0) - 1 }} pendência(s)
</div>
</div>
</td>
</tr>
</tbody>
</table>
<div class="batch-mass-preview-foot" *ngIf="(excelPreview.rows.length || 0) > (batchExcelPreviewRowsPreview.length || 0)">
Mostrando {{ batchExcelPreviewRowsPreview.length }} de {{ excelPreview.rows.length || 0 }} linha(s) na prévia da planilha.
</div>
</div>
</div>
</div>
<div class="batch-actions-row">
<button
type="button"
class="btn btn-sm btn-glass"
(click)="removeInvalidBatchLines()"
[disabled]="createSaving || createBatchValidationSummary.invalid === 0"
>
<i class="bi bi-eraser me-1"></i> Remover Inválidas
</button>
<button
type="button"
class="btn btn-sm btn-glass text-danger"
(click)="clearBatchLines()"
[disabled]="createSaving || createBatchCount === 0"
>
<i class="bi bi-trash3 me-1"></i> Limpar Lote
</button>
</div>
<div class="batch-lines-empty" *ngIf="createBatchCount === 0">
Nenhuma linha no lote ainda. Use a <strong>importação por planilha</strong> acima para pré-visualizar e
carregar as linhas na grade.
</div>
<div class="batch-editor-layout" *ngIf="createBatchCount > 0">
<div class="batch-grid-pane">
<div class="batch-lines-table-wrap">
<table class="batch-lines-table">
<thead>
<tr>
<th>#</th>
<th>Linha <span class="text-danger">*</span></th>
<th>Chip (ICCID) <span class="text-danger">*</span></th>
<th>Usuário</th>
<th>Tipo de Chip</th>
<th>Validação</th>
<th>Ações</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="let row of createBatchLines; let i = index; trackBy: trackBatchLine"
[class.is-selected]="isBatchLineSelected(row.uid)"
[class.is-invalid-row]="hasBatchLineError(row.uid)"
(click)="selectBatchLine(row.uid)"
>
<td class="index-cell">{{ i + 1 }}</td>
<td>
<input
class="form-control form-control-sm"
[class.batch-input-invalid]="hasBatchFieldError(row.uid, 'linha')"
[(ngModel)]="row.linha"
(ngModelChange)="onBatchLineFieldChange(row.uid)"
(click)="$event.stopPropagation(); selectBatchLine(row.uid)"
placeholder="119..."
/>
</td>
<td>
<input
class="form-control form-control-sm"
[class.batch-input-invalid]="hasBatchFieldError(row.uid, 'chip')"
[(ngModel)]="row.chip"
(ngModelChange)="onBatchLineFieldChange(row.uid)"
(click)="$event.stopPropagation(); selectBatchLine(row.uid)"
placeholder="8955..."
/>
</td>
<td>
<input
class="form-control form-control-sm"
[(ngModel)]="row.usuario"
(ngModelChange)="onBatchLineFieldChange(row.uid)"
(click)="$event.stopPropagation(); selectBatchLine(row.uid)"
[placeholder]="createModel.usuario ? 'Opcional (padrão no contexto)' : 'Opcional'"
/>
</td>
<td>
<input
class="form-control form-control-sm"
[(ngModel)]="row.tipoDeChip"
(ngModelChange)="onBatchLineFieldChange(row.uid)"
(click)="$event.stopPropagation(); selectBatchLine(row.uid)"
[placeholder]="createModel.tipoDeChip ? 'Opcional (padrão no contexto)' : 'Opcional'"
/>
</td>
<td class="validation-cell">
<div class="batch-row-valid" *ngIf="getBatchLineErrors(row.uid).length === 0">
<i class="bi bi-check-circle-fill"></i> OK
</div>
<div
class="batch-row-errors-compact"
*ngIf="getBatchLineErrors(row.uid).length > 0"
[attr.title]="getBatchLineErrors(row.uid).join(' | ')"
>
<div class="batch-row-error-main">
{{ getBatchLineErrors(row.uid)[0] }}
</div>
<div class="batch-row-more" *ngIf="getBatchLineErrors(row.uid).length > 1">
+{{ getBatchLineErrors(row.uid).length - 1 }} pendência(s)
</div>
</div>
</td>
<td class="actions-cell">
<button
type="button"
class="btn btn-sm btn-glass btn-icon"
[class.batch-detail-attention]="hasBatchDetailError(row.uid)"
title="Abrir detalhes da linha"
aria-label="Abrir detalhes da linha"
(click)="$event.stopPropagation(); openBatchLineDetails(row.uid)"
[disabled]="createSaving"
>
<i class="bi bi-sliders2"></i>
</button>
<button
type="button"
class="btn btn-sm btn-icon danger"
title="Remover linha do lote"
(click)="$event.stopPropagation(); removeBatchLine(row.uid)"
[disabled]="createSaving"
>
<i class="bi bi-trash3"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="batch-selected-hint">
<i class="bi bi-cursor-fill"></i>
Após carregar o lote pela <strong>importação da planilha</strong>, selecione uma linha e clique em
<strong>Detalhes</strong> para preencher `Contrato`, `Datas`, `Financeiro` e demais campos obrigatórios do
cadastro unitário. `Plano Contrato`, `Status`, `Conta` e datas obrigatórias são validados por linha.
</div>
</div>
<div class="batch-drawer-col" *ngIf="batchActiveDetailLine as activeLine; else batchDrawerPlaceholder">
<aside class="batch-detail-drawer" (click)="$event.stopPropagation()">
<div class="batch-detail-header">
<div>
<div class="batch-detail-title">Detalhes da Linha #{{ selectedBatchLineIndex + 1 }}</div>
<div class="batch-detail-sub">
Cliente: <strong>{{ createModel.cliente || 'Novo cliente (preencha acima)' }}</strong>
</div>
</div>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-glass btn-sm" type="button" (click)="selectPreviousBatchLine()" [disabled]="createSaving || selectedBatchLineIndex <= 0">
<i class="bi bi-chevron-left"></i>
</button>
<button class="btn btn-glass btn-sm" type="button" (click)="selectNextBatchLine()" [disabled]="createSaving || selectedBatchLineIndex >= createBatchCount - 1">
<i class="bi bi-chevron-right"></i>
</button>
<button class="btn btn-glass btn-sm" type="button" (click)="applySelectedBatchLineDetailsToAll()" [disabled]="createSaving || createBatchCount <= 1">
<i class="bi bi-arrow-repeat me-1"></i> Aplicar Detalhes em Todas
</button>
<button class="btn btn-glass btn-sm" type="button" (click)="closeBatchLineDetails()" [disabled]="createSaving">
<i class="bi bi-x-lg"></i>
</button>
</div>
</div>
<div class="batch-detail-body">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-person-badge me-2"></i> Identificação & Contrato</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>Linha (na grade) <span class="text-danger">*</span></label>
<input class="form-control form-control-sm bg-light" [value]="activeLine.linha || ''" readonly />
</div>
<div class="form-field">
<label>Chip (na grade) <span class="text-danger">*</span></label>
<input class="form-control form-control-sm bg-light" [value]="activeLine.chip || ''" readonly />
</div>
<div class="form-field">
<label>Empresa (Conta) <span class="text-danger">*</span></label>
<app-select
class="form-select"
[class.batch-input-invalid]="hasBatchRequiredFieldError(activeLine.uid, 'empresa')"
size="sm"
[options]="getContaEmpresaOptionsForBatchLine(activeLine)"
[placeholder]="loadingAccountCompanies ? 'Carregando empresas...' : 'Selecione a empresa'"
[(ngModel)]="activeLine.contaEmpresa"
(ngModelChange)="onBatchContaEmpresaChange(activeLine)"
></app-select>
</div>
<div class="form-field">
<label>Conta <span class="text-danger">*</span></label>
<app-select
class="form-select"
[class.batch-input-invalid]="hasBatchRequiredFieldError(activeLine.uid, 'conta')"
size="sm"
[options]="getContaOptionsForBatchLine(activeLine)"
[disabled]="!activeLine.contaEmpresa"
[placeholder]="activeLine.contaEmpresa ? 'Selecione a conta' : 'Selecione a empresa primeiro'"
[(ngModel)]="activeLine.conta"
(ngModelChange)="onBatchLineDetailsChange()"
></app-select>
</div>
<div class="form-field span-2">
<label>Plano Contrato <span class="text-danger">*</span></label>
<app-select
class="form-select"
[class.batch-input-invalid]="hasBatchRequiredFieldError(activeLine.uid, 'plano')"
size="sm"
[options]="getPlanOptionsForBatchLine(activeLine)"
[(ngModel)]="activeLine.planoContrato"
(ngModelChange)="onBatchPlanoChange(activeLine)"
></app-select>
</div>
<div class="form-field">
<label>Status <span class="text-danger">*</span></label>
<app-select
class="form-select"
[class.batch-input-invalid]="hasBatchRequiredFieldError(activeLine.uid, 'status')"
size="sm"
[options]="getStatusOptionsForBatchLine(activeLine)"
[(ngModel)]="activeLine.status"
(ngModelChange)="onBatchLineDetailsChange()"
></app-select>
</div>
<div class="form-field">
<label>Skil</label>
<app-select
class="form-select"
size="sm"
[options]="getSkilOptionsForBatchLine(activeLine)"
[(ngModel)]="activeLine.skil"
(ngModelChange)="onBatchLineDetailsChange()"
></app-select>
</div>
<div class="form-field">
<label>Venc. Conta</label>
<input class="form-control form-control-sm" [(ngModel)]="activeLine.vencConta" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field">
<label>Modalidade</label>
<input class="form-control form-control-sm" [(ngModel)]="activeLine.modalidade" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field span-2">
<label>Usuário da Linha</label>
<input class="form-control form-control-sm" [(ngModel)]="activeLine.usuario" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field span-2">
<label>Tipo de Chip</label>
<input class="form-control form-control-sm" [(ngModel)]="activeLine.tipoDeChip" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
</div>
</div>
</details>
<details class="detail-box mt-3" open>
<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>Cedente</label>
<input class="form-control form-control-sm" [(ngModel)]="activeLine.cedente" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field">
<label>Solicitante</label>
<input class="form-control form-control-sm" [(ngModel)]="activeLine.solicitante" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
</div>
</div>
</details>
<details class="detail-box mt-3" open>
<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">
<label>Data Entrega Operadora</label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="activeLine.dataEntregaOpera" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field">
<label>Data Entrega Cliente</label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="activeLine.dataEntregaCliente" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field">
<label>Data de Bloqueio</label>
<input class="form-control form-control-sm" type="date" [(ngModel)]="activeLine.dataBloqueio" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field">
<label>Dt. Efetivação Serviço <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" [class.batch-input-invalid]="hasBatchRequiredFieldError(activeLine.uid, 'efetivação')" type="date" [(ngModel)]="activeLine.dtEfetivacaoServico" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
<div class="form-field span-2">
<label>Dt. Término Fidelização <span class="text-danger">*</span></label>
<input class="form-control form-control-sm" [class.batch-input-invalid]="hasBatchRequiredFieldError(activeLine.uid, 'fidelização')" type="date" [(ngModel)]="activeLine.dtTerminoFidelizacao" (ngModelChange)="onBatchLineDetailsChange()" />
</div>
</div>
</div>
</details>
<details class="detail-box mt-3 vivo-border" open>
<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)]="activeLine.franquiaVivo" (ngModelChange)="onBatchLineDetailsChange()" /></div>
<div class="form-field"><label>Valor Plano</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.valorPlanoVivo" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>Gestão Voz</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.gestaoVozDados" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>Skeelo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.skeelo" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>News+</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.vivoNewsPlus" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>Travel Mundo</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.vivoTravelMundo" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>Gestão Disp.</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.vivoGestaoDispositivo" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>Vivo Sync</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.vivoSync" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
<div class="form-field"><label>Total Vivo (Auto)</label><input class="form-control form-control-sm bg-light" type="number" step="0.01" [(ngModel)]="activeLine.valorContratoVivo" readonly /></div>
</div>
</div>
</details>
<details class="detail-box mt-3 line-border" open>
<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)]="activeLine.franquiaLine" (ngModelChange)="onBatchLineDetailsChange()" /></div>
<div class="form-field"><label>Franquia Gestão</label><input class="form-control form-control-sm" type="number" step="0.1" [(ngModel)]="activeLine.franquiaGestao" (ngModelChange)="onBatchLineDetailsChange()" /></div>
<div class="form-field"><label>Locação Ap.</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.locacaoAp" (ngModelChange)="onBatchLineDetailsChange()" /></div>
<div class="form-field"><label>Total Line (Manual)</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.valorContratoLine" (ngModelChange)="onBatchFinancialChange(activeLine)" /></div>
</div>
</div>
</details>
<details class="detail-box mt-3" open>
<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>Desconto</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="activeLine.desconto" (ngModelChange)="onBatchLineDetailsChange()" /></div>
<div class="form-field"><label>Lucro Estimado</label><input class="form-control form-control-sm bg-light" type="number" step="0.01" [(ngModel)]="activeLine.lucro" readonly /></div>
</div>
</div>
</details>
</div>
</aside>
</div>
<ng-template #batchDrawerPlaceholder>
<div class="batch-drawer-col">
<div class="batch-detail-placeholder">
<i class="bi bi-layout-sidebar-inset"></i>
<p>Selecione uma linha e clique em <strong>Detalhes</strong> para preencher os campos completos da linha.</p>
<small>Os obrigatórios do cadastro unitário também são validados aqui (conta, plano, status, datas, etc.).</small>
</div>
</div>
</ng-template>
</div>
</div>
</details>
</div>
</div>
</div>
<!-- MOVE TO RESERVA MODAL -->
<div
*ngIf="moveToReservaOpen"
class="modal-card modal-lg modal-move-reserva"
(click)="$event.stopPropagation()"
>
<div class="modal-header">
<div class="modal-title">
<span class="icon-bg warning"><i class="bi bi-box-arrow-left"></i></span>
Enviar Linhas para Reserva
</div>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-glass btn-sm" (click)="closeAllModals()" [disabled]="moveToReservaSaving">
<i class="bi bi-x-lg me-1"></i> Cancelar
</button>
<button class="btn btn-sm btn-send-reserva-group" (click)="submitMoveToReserva()" [disabled]="moveToReservaSaving || reservaSelectedCount === 0">
<span *ngIf="!moveToReservaSaving"><i class="bi bi-check2-circle me-1"></i> Confirmar Envio</span>
<span *ngIf="moveToReservaSaving"><span class="spinner-border spinner-border-sm me-2"></span> Processando...</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-info-circle me-2"></i>Confirmação</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="small text-muted mb-2">
As linhas selecionadas serão movidas para a <strong>Reserva</strong> e ficarão disponíveis para reatribuição.
</div>
<div class="reserva-confirmation-pills">
<div class="summary-pill total">Cliente: {{ expandedGroup || '-' }}</div>
<div class="summary-pill warn">Selecionadas: {{ reservaSelectedCount }}</div>
</div>
</div>
</details>
</div>
<div class="dashboard-column">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-list-check me-2"></i>Linhas Selecionadas ({{ reservaSelectedCount }})</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="table-wrap inner-table-wrap" style="max-height: 520px;">
<table class="table table-modern table-compact align-middle text-center mb-0">
<thead>
<tr>
<th>ITEM</th>
<th>LINHA</th>
<th>CHIP (ICCID)</th>
<th>USUÁRIO</th>
</tr>
</thead>
<tbody>
<tr *ngIf="reservaSelectedLines.length === 0">
<td colspan="4" class="text-muted py-3">Nenhuma linha selecionada.</td>
</tr>
<tr *ngFor="let r of reservaSelectedLines">
<td>{{ r.item }}</td>
<td class="fw-black text-blue">{{ r.linha || '-' }}</td>
<td>{{ r.chip || '-' }}</td>
<td>{{ r.usuario || '-' }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</details>
</div>
</div>
</div>
</div>
<!-- RESERVA TRANSFER MODAL -->
<div
*ngIf="reservaTransferOpen"
class="modal-card modal-lg modal-reserva-transfer"
(click)="$event.stopPropagation()"
>
<div class="modal-header">
<div class="modal-title">
<span class="icon-bg brand-soft"><i class="bi bi-arrow-left-right"></i></span>
Atribuir Linhas da Reserva
</div>
<div class="d-flex align-items-center gap-2">
<button class="btn btn-glass btn-sm" (click)="closeAllModals()" [disabled]="reservaTransferSaving">
<i class="bi bi-x-lg me-1"></i> Cancelar
</button>
<button class="btn btn-brand btn-sm" (click)="submitReservaTransfer()" [disabled]="reservaTransferSaving || reservaSelectedCount === 0">
<span *ngIf="!reservaTransferSaving"><i class="bi bi-check2-circle me-1"></i> Confirmar Atribuição</span>
<span *ngIf="reservaTransferSaving"><span class="spinner-border spinner-border-sm me-2"></span> Processando...</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>Destino da Atribuiçã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">
<label>Cliente de destino <span class="text-danger">*</span></label>
<app-select
class="form-select"
size="sm"
[options]="reservaTransferTargetClientsOptions"
[placeholder]="'Selecione o cliente'"
[(ngModel)]="reservaTransferModel.clienteDestino"
></app-select>
</div>
<div class="form-field span-2">
<label>Usuário (opcional)</label>
<input
class="form-control form-control-sm"
[(ngModel)]="reservaTransferModel.usuarioDestino"
placeholder="Se informado, substitui o usuário nas linhas selecionadas"
/>
</div>
<div class="form-field span-2">
<label>Skil (opcional)</label>
<app-select
class="form-select"
size="sm"
[options]="skilOptions"
[placeholder]="'Manter/inferir automaticamente'"
[(ngModel)]="reservaTransferModel.skilDestino"
></app-select>
</div>
</div>
</div>
</details>
</div>
<div class="dashboard-column">
<details class="detail-box" open>
<summary class="box-header">
<span><i class="bi bi-list-check me-2"></i>Linhas Selecionadas ({{ reservaSelectedCount }})</span>
<i class="bi bi-chevron-down ms-auto transition-icon"></i>
</summary>
<div class="box-body">
<div class="table-wrap inner-table-wrap" style="max-height: 460px;">
<table class="table table-modern table-compact align-middle text-center mb-0">
<thead>
<tr>
<th>ITEM</th>
<th>LINHA</th>
<th>CHIP (ICCID)</th>
<th>USUÁRIO</th>
</tr>
</thead>
<tbody>
<tr *ngIf="reservaSelectedLines.length === 0">
<td colspan="4" class="text-muted py-3">Nenhuma linha selecionada.</td>
</tr>
<tr *ngFor="let r of reservaSelectedLines">
<td>{{ r.item }}</td>
<td class="fw-black text-blue">{{ r.linha || '-' }}</td>
<td>{{ r.chip || '-' }}</td>
<td>{{ r.usuario || '-' }}</td>
</tr>
</tbody>
</table>
</div>
<div class="small text-muted mt-2">
Somente linhas que ainda estiverem aptas na <strong>Reserva</strong> serão atribuídas. O backend retorna sucesso/erro por linha.
</div>
</div>
</details>
</div>
</div>
</div>
</div>
<!-- DETAIL MODAL -->
<div
*ngIf="detailOpen"
#detailModal
class="modal-card modal-xl-custom"
[class.modal-client-detail]="isClientRestricted"
(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" *ngIf="!isClientRestricted">
<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-2" *ngIf="isClientRestricted">
<span class="lbl">Centro de Custos</span>
<span class="val text-dark">&nbsp;</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 class="info-item">
<span class="lbl">Tipo de Chip</span>
<span class="val">{{ detailData.tipoDeChip || '-' }}</span>
</div>
<div class="info-item" *ngIf="isClientRestricted">
<span class="lbl">Franquia Line</span>
<span class="val">{{ formatFranquia(detailData.franquiaLine) }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-column d-flex flex-column gap-2" *ngIf="!isClientRestricted">
<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 class="info-item">
<span class="lbl">Efetivação Serviço</span>
<span class="val">{{ formatDateBr(detailData.dtEfetivacaoServico) }}</span>
</div>
<div class="info-item">
<span class="lbl">Término Fidelização</span>
<span class="val">{{ formatDateBr(detailData.dtTerminoFidelizacao) }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-column" *ngIf="!isClientRestricted">
<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="row-item"><span>Vivo Sync</span> <strong>{{ formatMoney(financeData.vivoSync) }}</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>Empresa (Conta)</label><app-select class="form-select" size="sm" [options]="contaEmpresaOptionsForEdit" [(ngModel)]="editModel.contaEmpresa" (ngModelChange)="onContaEmpresaChange(true)"></app-select></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>Tipo de Chip</label><input class="form-control form-control-sm" [(ngModel)]="editModel.tipoDeChip" /></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" (ngModelChange)="onPlanoChange(true)"></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>Dt. Efetivação Serviço</label><input class="form-control form-control-sm" type="date" [(ngModel)]="editModel.dtEfetivacaoServico" /></div>
<div class="form-field"><label>Dt. Término Fidelização</label><input class="form-control form-control-sm" type="date" [(ngModel)]="editModel.dtTerminoFidelizacao" /></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>Vivo Sync</label><input class="form-control form-control-sm" type="number" step="0.01" [(ngModel)]="editModel.vivoSync" (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>