@php use Illuminate\Support\Facades\DB; // ── Parâmetros ──────────────────────────────────────────────────── $rawIds = request('ids', ''); $modelo = request('modelo', 'padrao'); // padrao | obreiro | pastor | congregado | pb $ids = array_values(array_filter(array_map('intval', explode(',', $rawIds)))); // ── Igreja (carregar antes para filtrar membros) ────────────────── $igrejas = session('igrejas', []); // ── IDs permitidos (somente membros das igrejas da sessão) ─────── $igrejasInt = array_map('intval', $igrejas); // Nota: pluck() não aceita nome qualificado (alias.coluna) — usar só o nome da coluna $idsPermitidos = !empty($igrejasInt) ? DB::table('cargoxmembroxigreja as cmi') ->join('departamentosxigreja as di', 'cmi.idDI', '=', 'di.idDI') ->whereIn('cmi.idMembro', $ids) ->whereIn('di.idIgreja', $igrejasInt) ->distinct() ->selectRaw('CAST(cmi.idMembro AS UNSIGNED) as idMembro') ->pluck('idMembro') ->map('intval') ->toArray() : $ids; // ── Buscar membros (somente os permitidos) ──────────────────────── $membros = !empty($idsPermitidos) ? DB::table('membros as m') ->whereIn('m.idMembro', $idsPermitidos) ->select('m.idMembro','m.Nome','m.Imagem','m.dtNascimento','m.Tipo','m.CPF') ->get()->all() : []; $igreja = $igrejas ? DB::table('igrejas')->whereIn('idIgreja', $igrejas)->first() : null; // ── Tipos de membro ─────────────────────────────────────────────── $tipos = ['E'=>'Membro','F'=>'Congregado','C'=>'Criança','V'=>'Visitante']; // Logo URL: usa logo da igreja se disponível, senão fallback do sistema (fundo escuro) $_lotLogoPath = (!empty($igreja->Imagem)) ? storage_path('app/public/logos/'.$igreja->Imagem) : null; $igrejaLogoUrl = ($_lotLogoPath && file_exists($_lotLogoPath)) ? asset('storage/logos/'.$igreja->Imagem) : asset('images/logo-atos-dark.png'); // ── Modelo personalizado (custom_{id}) ─────────────────────────── $modeloCustom = null; $customFields = []; if (str_starts_with($modelo, 'custom_')) { try { if (\Illuminate\Support\Facades\Schema::hasTable('credencial_modelos')) { $customId = (int) str_replace('custom_', '', $modelo); $modeloCustom = DB::table('credencial_modelos') ->where('idModelo', $customId) ->where('Ativo', 1) ->first(); if ($modeloCustom && $modeloCustom->ConfigJson) { $customFields = json_decode($modeloCustom->ConfigJson, true) ?? []; } } } catch (\Exception $e) { /* tabela ainda não criada */ } } // ── Helper: estilo inline para campos do modelo personalizado ──── $fStyle = function(array $f, bool $isFoto = false): string { $s = 'position:absolute;'; $s .= 'top:' . ($f['top'] ?? 0) . '%;'; $s .= 'left:' . ($f['left'] ?? 0) . '%;'; $s .= 'z-index:2;'; if ($isFoto) { $s .= 'width:' . ($f['w'] ?? 25) . '%;'; $s .= 'height:' . ($f['h'] ?? 55) . '%;'; $s .= 'overflow:hidden;border-radius:2px;'; } else { $s .= 'color:' . ($f['color'] ?? '#ffffff') . ';'; $s .= 'font-size:' . ($f['size'] ?? 2) . 'mm;'; $s .= 'font-weight:' . (!empty($f['bold']) ? 'bold' : 'normal') . ';'; $s .= 'white-space:nowrap;line-height:1.2;'; if (!empty($f['align'])) { $s .= 'text-align:' . $f['align'] . ';'; } } return $s; }; // ── Modelos visuais padrão ──────────────────────────────────────── $modelos = [ 'padrao' => [ 'label' => 'Padrão Azul', 'bg' => 'linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%)', 'bgDark' => '#1e3a8a', 'accent' => 'rgba(255,255,255,0.28)', 'bar' => 'rgba(255,255,255,0.35)', ], 'obreiro' => [ 'label' => 'Obreiro / Líder', 'bg' => 'linear-gradient(135deg, #0f172a 0%, #1e293b 60%, #334155 100%)', 'bgDark' => '#0f172a', 'accent' => '#d4af37', 'bar' => '#d4af37', ], 'pastor' => [ 'label' => 'Pastor / Presbitério', 'bg' => 'linear-gradient(135deg, #3b0764 0%, #7e22ce 60%, #a855f7 100%)', 'bgDark' => '#3b0764', 'accent' => '#fde68a', 'bar' => '#fde68a', ], 'congregado' => [ 'label' => 'Congregado', 'bg' => 'linear-gradient(135deg, #052e16 0%, #166534 60%, #22c55e 100%)', 'bgDark' => '#052e16', 'accent' => 'rgba(255,255,255,0.28)', 'bar' => 'rgba(255,255,255,0.4)', ], 'pb' => [ 'label' => 'P&B (Simples)', 'bg' => 'linear-gradient(135deg, #1f2937 0%, #374151 100%)', 'bgDark' => '#1f2937', 'accent' => 'rgba(255,255,255,0.2)', 'bar' => 'rgba(255,255,255,0.3)', ], ]; $mc = $modelos[$modelo] ?? $modelos['padrao']; $mcLabel = $modeloCustom ? $modeloCustom->Nome : $mc['label']; // ── Tokens dos membros para QR Code ────────────────────────────────── $memberTokens = []; try { if (\Illuminate\Support\Facades\Schema::hasTable('membros_tokens')) { $memberIds = array_values(array_filter(array_map(fn($m) => $m ? (int)$m->idMembro : null, $membros))); if (!empty($memberIds)) { $existingTokens = DB::table('membros_tokens') ->whereIn('idMembro', $memberIds) ->pluck('token', 'idMembro') ->toArray(); foreach ($memberIds as $mid) { if (!isset($existingTokens[$mid])) { $newToken = \Illuminate\Support\Str::uuid()->toString(); DB::table('membros_tokens')->insert([ 'idMembro' => $mid, 'token' => $newToken, 'expires_at' => now()->endOfYear()->toDateString(), 'created_at' => now(), ]); $memberTokens[$mid] = $newToken; } else { $memberTokens[$mid] = $existingTokens[$mid]; } } } } } catch (\Exception $e) {} $appUrl = rtrim(config('app.url'), '/'); // ── Montar folhas separadas: TODAS as frentes, depois TODOS os versos ── $cardsPerSheet = 8; $memberChunks = array_chunk($membros, $cardsPerSheet); $frontSheets = []; $backSheets = []; foreach ($memberChunks as $chunk) { while (count($chunk) < $cardsPerSheet) { $chunk[] = null; } // Verso espelhado: [0,1][2,3]... → [1,0][3,2]... (alinhamento duplex borda longa) $verso = []; for ($i = 0; $i < $cardsPerSheet; $i += 2) { $verso[] = $chunk[$i + 1] ?? null; $verso[] = $chunk[$i] ?? null; } $frontSheets[] = $chunk; $backSheets[] = $verso; } if (empty($frontSheets)) { $frontSheets = [array_fill(0, 8, null)]; $backSheets = [array_fill(0, 8, null)]; } $totalMembros = count(array_filter($membros)); $totalFolhas = count($frontSheets); // Verso custom: usa ImagemFundoVerso + campos do verso (cpf, rg, qrcode, etc.) $versoImgUrl = ($modeloCustom && !empty($modeloCustom->ImagemFundoVerso)) ? asset('storage/' . $modeloCustom->ImagemFundoVerso) : null; $versoFields = ['cpf','rg','dtBatismo','dtRecebimento','dtCadastro','endereco','telefone','qrcode','codigoBarras','assinatura']; $fStyleImg = function(array $f): string { $s = 'position:absolute;'; $s .= 'top:' . ($f['top'] ?? 0) . '%;'; $s .= 'left:' . ($f['left'] ?? 0) . '%;'; $s .= 'width:' . ($f['w'] ?? 25) . '%;'; $s .= 'height:' . ($f['h'] ?? 30) . '%;'; $s .= 'z-index:2;overflow:hidden;border-radius:3px;'; return $s; // o div filho com position:absolute;inset:0 cobre 100% deste container }; @endphp Credenciais em Lote — {{ $mc['label'] }} {{-- ── Barra de Controles ── --}}
🖨️ Credenciais em Lote — {{ $mcLabel }}
{{ $totalMembros }} credencial(is) • {{ $totalFolhas }} folha(s) A4 • Frente e verso @if(!$modeloCustom) • Modelos: {{ implode(' / ', array_column($modelos, 'label')) }} @else • Modelo personalizado da igreja @endif
{{-- Seletor de modelo --}}
Modelo: @foreach($modelos as $key => $m) @if($key !== $modelo) {{ $m['label'] }} @else {{ $m['label'] }} @endif @endforeach
← Voltar
{{-- Instrução --}}
Como imprimir frente e verso: Na janela de impressão, ative "Imprimir em ambos os lados" com "Virar na borda longa" (orientação retrato). As colunas do verso já foram reposicionadas automaticamente para alinhamento perfeito ao virar a folha. Para salvar PDF, imprima para arquivo sem duplex.
{{-- ════════════════════════════════════════════ TODAS AS FRENTES ════════════════════════════════════════════ --}} @foreach($frontSheets as $sheetIdx => $front) @if($totalFolhas > 1)
── Frente {{ $sheetIdx + 1 }} / {{ $totalFolhas }} ──
@endif
FOLHA {{ $sheetIdx + 1 }} • FRENTE
@foreach($front as $m)
@if($m) @if($modeloCustom && !empty($customFields)) {{-- ── Modelo Personalizado ── --}} @php $bgUrl = $modeloCustom->ImagemFundo ? asset('storage/' . $modeloCustom->ImagemFundo) : null; $nascFormatado = ($m->dtNascimento && $m->dtNascimento !== '0000-00-00') ? \Carbon\Carbon::parse($m->dtNascimento)->format('d/m/Y') : '—'; $regFormatado = '#' . str_pad($m->idMembro, 6, '0', STR_PAD_LEFT); $fieldValues = [ 'foto' => null, // tratado separado 'nomeIgreja' => $igreja->Nome ?? '', 'tipo' => $tipos[$m->Tipo] ?? 'Membro', 'nome' => strtoupper($m->Nome), 'nascimento' => $nascFormatado, 'registro' => $regFormatado, 'rodape' => 'Emitido ' . now()->format('d/m/Y'), ]; @endphp
@foreach($customFields as $fKey => $fData) @if($fKey === 'foto') @php $fs = $fStyle($fData, true); @endphp
@if($m->Imagem) {{ $m->Nome }} @else
👤
@endif
@elseif(isset($fieldValues[$fKey])) @php $fs = $fStyle($fData, false); @endphp
{{ $fieldValues[$fKey] }}
@endif @endforeach
@else {{-- ── Modelo Padrão ── --}}
{{ $igreja->Nome ?? 'Igreja' }}
{{ $tipos[$m->Tipo] ?? 'Membro' }}
@if($m->Imagem) {{ $m->Nome }} @else 👤 @endif
Nome Completo
{{ strtoupper($m->Nome) }}
Nascimento
@if($m->dtNascimento && $m->dtNascimento !== '0000-00-00') {{ \Carbon\Carbon::parse($m->dtNascimento)->format('d/m/Y') }} @else — @endif
Nº Registro
#{{ str_pad($m->idMembro, 6, '0', STR_PAD_LEFT) }}
Emitido {{ now()->format('d/m/Y') }} • {{ $igreja->Nome ?? '' }}
@endif @endif
@endforeach
@endforeach {{-- Separador tela entre frentes e versos --}}
↑ Imprima as FRENTES primeiro  │  Depois vire as folhas e imprima os VERSOS ↓
{{-- ════════════════════════════════════════════ TODOS OS VERSOS ════════════════════════════════════════════ --}} @foreach($backSheets as $sheetIdx => $back) @if($totalFolhas > 1)
── Verso {{ $sheetIdx + 1 }} / {{ $totalFolhas }} ──
@endif
FOLHA {{ $sheetIdx + 1 }} • VERSO
@foreach($back as $m)
@if($m) @if($modeloCustom && $versoImgUrl) {{-- ── Verso Personalizado (com imagem de fundo) ── --}} @php $versoFieldValues = [ 'cpf' => $m->CPF ? 'CPF: '.$m->CPF : null, 'rg' => null, // não está no select padrão do lote 'dtBatismo' => null, // requereria join histórico 'dtRecebimento' => null, 'dtCadastro' => null, 'endereco' => null, 'telefone' => null, ]; @endphp
@foreach($versoFields as $fKey) @if(isset($customFields[$fKey]) && !empty($customFields[$fKey]['visible'])) @php $fData = $customFields[$fKey]; @endphp @if(in_array($fKey, ['qrcode','codigoBarras','assinatura'])) {{-- campos de imagem do verso --}}
@if($fKey === 'qrcode') @php $qrToken = $memberTokens[$m->idMembro] ?? null; $qrUrl = $qrToken ? $appUrl.'/membro/'.$qrToken : $appUrl.'/portal?id='.$m->idMembro; @endphp {{-- Wrapper branco uniforme nos 4 lados --}}
@elseif($fKey === 'codigoBarras') {{-- Wrapper branco uniforme nos 4 lados --}}
@endif
@elseif(isset($versoFieldValues[$fKey]) && $versoFieldValues[$fKey])
{{ $versoFieldValues[$fKey] }}
@endif @endif @endforeach
@else {{-- ── Verso Padrão ── --}}
{{ $igreja->Nome ?? 'Igreja' }}
@if(!empty($igreja->Telefone)) Tel: {{ $igreja->Telefone }} @endif @if(!empty($igreja->Email)) {{ $igreja->Email }} @endif @if(empty($igreja->Telefone) && empty($igreja->Email)) Secretaria da Igreja @endif
Esta credencial é de uso pessoal e intransferível.
Em caso de perda, comunique à secretaria da igreja.
@php $qrTokenPad = $memberTokens[$m->idMembro] ?? null; $qrUrlPad = $qrTokenPad ? $appUrl.'/membro/'.$qrTokenPad : $appUrl.'/portal?id='.(int)$m->idMembro; @endphp
Válida para o ano de {{ now()->year }}
Assinatura do Responsável
@endif @endif
@endforeach
@endforeach