358 lines
20 KiB
HTML
358 lines
20 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="pt-BR">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||
<title>Gerenciador de Imagens Dentais</title>
|
||
<meta name="description" content="Sistema de gerenciamento de imagens de raio-X dental">
|
||
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||
<link rel="stylesheet" href="/style.css">
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<!-- Sidebar -->
|
||
<aside class="sidebar">
|
||
<div class="sidebar-header">
|
||
<h2>🦷 DentalSys</h2>
|
||
</div>
|
||
<nav class="sidebar-nav">
|
||
<a href="/" class="nav-item active">
|
||
<span class="icon">🖼️</span> Pacientes
|
||
</a>
|
||
<a href="#" class="nav-item" onclick="openCreatePatientModal(); return false;">
|
||
<span class="icon">➕</span> Novo Paciente
|
||
</a>
|
||
<a href="/clients" class="nav-item">
|
||
<span class="icon">🖥️</span> Dispositivos
|
||
</a>
|
||
<a href="#" class="nav-item admin-only" id="navAdminClinics" style="display: none;" onclick="showAdminClinics(); return false;">
|
||
<span class="icon">🏢</span> Gerenciar Clínicas
|
||
</a>
|
||
<a href="#" class="nav-item" onclick="openSettingsModal(); return false;">
|
||
<span class="icon">⚙️</span> Configurações
|
||
</a>
|
||
<a href="/reset" class="nav-item" style="color: #dc3545;">
|
||
<span class="icon">⚠️</span> Zerar Sistema
|
||
</a>
|
||
<div class="nav-divider"></div>
|
||
<button id="toggleDisabledBtn" class="btn btn-secondary" style="margin: 10px 20px; width: calc(100% - 40px);">
|
||
<span id="toggleText">Ocultas</span>
|
||
</button>
|
||
</nav>
|
||
</aside>
|
||
|
||
<!-- Main Content -->
|
||
<main class="main-content">
|
||
<!-- Header -->
|
||
<header class="header">
|
||
<div class="header-content">
|
||
<div class="header-left">
|
||
<button id="backBtn" class="btn btn-back" style="display:none;">
|
||
← Voltar
|
||
</button>
|
||
<h1 id="mainTitle">Galeria de Imagens</h1>
|
||
</div>
|
||
<div class="header-actions">
|
||
<select id="clientFilter" class="client-filter">
|
||
<option value="">📋 Todos os Clientes</option>
|
||
</select>
|
||
<input
|
||
type="search"
|
||
id="searchInput"
|
||
class="search-input"
|
||
placeholder="🔍 Pesquisar paciente..."
|
||
>
|
||
<button class="btn btn-secondary" onclick="loadClientsList()">
|
||
<span class="icon">🔄</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Patient sub-header (shown in patient-images view) -->
|
||
<div id="patientHeader" class="patient-header" style="display:none;">
|
||
<div class="patient-header-info">
|
||
<div id="patientTitle" class="patient-header-name"></div>
|
||
<div id="patientMeta" class="patient-header-meta"></div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Scrollable content area -->
|
||
<div class="content-scroll">
|
||
|
||
<!-- Loading State -->
|
||
<div id="loadingState" class="loading">
|
||
<div class="spinner"></div>
|
||
<p>Carregando...</p>
|
||
</div>
|
||
|
||
<!-- Empty State -->
|
||
<div id="emptyState" class="empty-state" style="display: none;">
|
||
<div class="empty-icon">📭</div>
|
||
<h2>Nenhum resultado encontrado</h2>
|
||
<p>As imagens aparecerão aqui quando forem enviadas pelo cliente Windows</p>
|
||
</div>
|
||
|
||
<!-- Admin Clínicas State -->
|
||
<div id="adminClinicsState" style="display: none; padding: 20px;">
|
||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||
<h2>🏢 Gerenciamento de Clínicas</h2>
|
||
<button class="btn btn-primary" onclick="openCreateClinicModal()">+ Nova Clínica</button>
|
||
</div>
|
||
<div class="table-responsive" style="background: white; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); overflow: hidden;">
|
||
<table class="data-table" id="clinicsTable" style="width: 100%; border-collapse: collapse; text-align: left;">
|
||
<thead style="background: #f8f9fa; border-bottom: 1px solid #eee;">
|
||
<tr>
|
||
<th style="padding: 15px;">ID</th>
|
||
<th style="padding: 15px;">Login (Username)</th>
|
||
<th style="padding: 15px;">Clínica</th>
|
||
<th style="padding: 15px;">Email</th>
|
||
<th style="padding: 15px;">Nome PC</th>
|
||
<th style="padding: 15px; text-align: center;">Ações</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="clinicsTableBody">
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Images / Patients Grid -->
|
||
<div id="imagesGrid" class="images-grid"> </div>
|
||
|
||
</div><!-- end .content-scroll -->
|
||
</main>
|
||
</div>
|
||
|
||
<!-- Transform Modal -->
|
||
<div id="transformModal" class="modal">
|
||
<div class="modal-content modal-large">
|
||
<div class="modal-header" style="display: flex; justify-content: space-between; width: 100%; align-items: center; border-bottom: 1px solid #eee; padding-bottom: 15px;">
|
||
<div style="display: flex; align-items: center; gap: 15px; flex-wrap: wrap;">
|
||
<h2 id="transformModalTitle" style="margin: 0; font-size: 1.4rem;"><!-- Dynamic Title (Patient + Date) --></h2>
|
||
<div style="display: flex; gap: 8px;">
|
||
<button id="btnShowTransform" class="btn btn-primary" onclick="toggleModalView('transform')" style="width: 60px; height: 40px; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 1.2rem;" title="Ajustar Imagem">🔄</button>
|
||
<button id="btnShowGto" class="btn btn-secondary" onclick="toggleModalView('gto')" style="width: 60px; height: 40px; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 1.2rem;" title="Gerenciar GTOs">📋</button>
|
||
<button id="btnShowInfo" class="btn btn-secondary" onclick="toggleModalInfo()" style="width: 60px; height: 40px; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 1.2rem;" title="Informações">ℹ️</button>
|
||
<button id="btnResetImage" class="btn btn-danger" onclick="resetImageToOriginal()" style="width: 60px; height: 40px; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; background-color: #ff6b6b; border-color: #ff6b6b; color: white;" title="Resetar para Original">↩️</button>
|
||
</div>
|
||
</div>
|
||
<span class="modal-close" id="closeTransformModal">×</span>
|
||
</div>
|
||
|
||
<div class="modal-body" style="padding-top: 15px;">
|
||
<!-- Bloco oculto de informações -->
|
||
<div id="transformExtraInfo" style="display: none; font-size: 0.95rem; color: #555; background: #f8f9fa; padding: 12px 20px; border-radius: 8px; border: 1px solid #eee; margin-bottom: 15px;">
|
||
<!-- Preenchido via JS -->
|
||
</div>
|
||
|
||
<!-- View 1: Transforms -->
|
||
<div id="transformViewWrapper" style="display: flex; flex-direction: column; flex: 1; min-height: 0; height: 100%;">
|
||
<div id="transformOptions" class="transform-grid" style="flex: 1; min-height: 0;"></div>
|
||
<div id="transformActionArea" style="display: none; margin-top: 20px; background: #f8f9fa; padding: 15px; border-radius: 8px; flex-shrink: 0;">
|
||
<label style="font-weight: 600; display: block; margin-bottom: 8px;">Nova Observação / Detalhes (Opcional):</label>
|
||
<textarea id="newImageRemark" class="search-input" rows="2" style="width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 6px;" placeholder="Ex: Raio-X Dente 45..."></textarea>
|
||
<div style="display: flex; gap: 10px; margin-top: 10px;">
|
||
<button class="btn btn-secondary" style="flex: 1; padding: 12px; font-size: 1.1rem;" onclick="clearTransformSelection()">Cancelar</button>
|
||
<button id="btnSaveTransform" class="btn btn-primary" style="flex: 2; padding: 12px; font-size: 1.1rem;" onclick="saveSelectedTransform()">Salvar Nova Imagem</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- View 2: GTO List & Link -->
|
||
<div id="gtoView" style="display: none;">
|
||
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
||
<h3 style="margin-top: 0; font-size: 1.1rem; margin-bottom: 15px;">Cadastrar Nova GTO</h3>
|
||
<div style="display: flex; gap: 10px;">
|
||
<input type="text" id="inlineGtoNumber" class="search-input" placeholder="Número/ID da GTO" style="flex: 1; padding: 10px;">
|
||
<input type="text" id="inlineGtoDesc" class="search-input" placeholder="Descrição (Opcional)" style="flex: 2; padding: 10px;">
|
||
<button class="btn btn-primary" onclick="inlineCreateGto()">Cadastrar</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px;">
|
||
<h3 style="margin: 0; font-size: 1.1rem;">Vincular esta imagem a uma GTO:</h3>
|
||
<button class="btn btn-success" onclick="linkImageToGto()" id="btnLinkGto">✅ Vincular Selecionada</button>
|
||
</div>
|
||
|
||
<div id="gtoListContainer" style="border: 1px solid #ddd; border-radius: 8px; overflow: hidden;">
|
||
<!-- GTO list goes here -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Novo Paciente -->
|
||
<div class="modal" id="create-patient-modal">
|
||
<div class="modal-content" style="max-width: 500px; height: auto; border-radius: var(--radius);">
|
||
<div class="modal-header">
|
||
<h2>Novo Paciente</h2>
|
||
<div class="modal-close" onclick="closeCreatePatientModal()">×</div>
|
||
</div>
|
||
<div class="modal-body" style="overflow-y: auto;">
|
||
<form id="create-patient-form" onsubmit="submitCreatePatient(event)">
|
||
<div class="form-group">
|
||
<label>Nome *</label>
|
||
<input type="text" id="patient-first-name" required placeholder="Ex: João">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Sobrenome *</label>
|
||
<input type="text" id="patient-last-name" required placeholder="Ex: Silva">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Dentista</label>
|
||
<input type="text" id="patient-doctor" placeholder="Nome do dentista responsável">
|
||
</div>
|
||
<div style="display: flex; gap: 12px;">
|
||
<div class="form-group" style="flex: 1;">
|
||
<label>Data de Nascimento</label>
|
||
<input type="date" id="patient-birthday">
|
||
</div>
|
||
<div class="form-group" style="flex: 1;">
|
||
<label>Gênero</label>
|
||
<select id="patient-gender">
|
||
<option value="0">Masculino</option>
|
||
<option value="1">Feminino</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Telefone</label>
|
||
<input type="text" id="patient-phone" placeholder="(11) 99999-9999">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Observações</label>
|
||
<textarea id="patient-remark" rows="3" placeholder="Informações adicionais..."></textarea>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary" style="width: 100%; margin-top: 10px;">
|
||
Salvar Paciente
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Nova GTO -->
|
||
<div class="modal" id="create-gto-modal">
|
||
<div class="modal-content" style="max-width: 400px; height: auto; border-radius: var(--radius);">
|
||
<div class="modal-header">
|
||
<h2>Nova GTO</h2>
|
||
<div class="modal-close" onclick="closeCreateGtoModal()">×</div>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="create-gto-form" onsubmit="submitCreateGto(event)">
|
||
<div class="form-group">
|
||
<label>Número/ID da GTO *</label>
|
||
<input type="text" id="gto-number" required placeholder="Ex: GTO-2023-001">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Descrição (opcional)</label>
|
||
<textarea id="gto-description" rows="3" placeholder="Informações da guia..."></textarea>
|
||
</div>
|
||
<button type="submit" class="btn btn-primary" style="width: 100%; margin-top: 10px;">
|
||
Criar GTO
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Toast de Notificação -->
|
||
<div class="toast" id="toast">Operação realizada com sucesso!</div>
|
||
|
||
<!-- Settings Modal -->
|
||
<div id="settingsModal" class="modal">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h2>⚙️ Configurações da Conta</h2>
|
||
<span class="close-modal" onclick="closeSettingsModal()">×</span>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="settingsForm" onsubmit="updateCredentials(event)">
|
||
<div class="form-group">
|
||
<label for="currentPassword">Senha Atual (Obrigatório)*</label>
|
||
<input type="password" id="currentPassword" class="form-control" placeholder="Digite sua senha atual para autorizar" required>
|
||
</div>
|
||
|
||
<hr style="margin: 20px 0; border: none; border-top: 1px solid #eee;">
|
||
<p style="margin-bottom: 15px; color: #666; font-size: 0.9rem;">Preencha apenas os campos que deseja alterar:</p>
|
||
|
||
<div class="form-group">
|
||
<label for="newUsername">Novo Nome de Usuário</label>
|
||
<input type="text" id="newUsername" class="form-control" placeholder="Deixe em branco para não alterar">
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="newPassword">Nova Senha</label>
|
||
<input type="password" id="newPassword" class="form-control" placeholder="Deixe em branco para não alterar">
|
||
</div>
|
||
|
||
<div class="form-actions" style="margin-top: 25px; display: flex; justify-content: flex-end; gap: 10px;">
|
||
<button type="button" class="btn btn-secondary" onclick="closeSettingsModal()">Cancelar</button>
|
||
<button type="submit" class="btn btn-primary" id="btnSaveSettings">Salvar Alterações</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Nova Clínica -->
|
||
<div class="modal" id="createClinicModal">
|
||
<div class="modal-content" style="max-width: 500px; height: auto; border-radius: var(--radius);">
|
||
<div class="modal-header">
|
||
<h2>Nova Clínica (Acesso Desktop)</h2>
|
||
<div class="modal-close" onclick="closeCreateClinicModal()">×</div>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form id="createClinicForm" onsubmit="submitCreateClinic(event)">
|
||
<div class="form-group">
|
||
<label>Login (Username) *</label>
|
||
<input type="text" id="clinicUsername" class="form-control" required placeholder="Ex: clinica_sorriso">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Email *</label>
|
||
<input type="email" id="clinicEmail" class="form-control" required placeholder="Ex: contato@clinicasorriso.com">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Senha de Acesso *</label>
|
||
<input type="password" id="clinicPassword" class="form-control" required placeholder="Senha para o cliente desktop">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Nome da Clínica (Opcional)</label>
|
||
<input type="text" id="clinicName" class="form-control" placeholder="Ex: Clínica Odonto Sorriso">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Nome do PC (Opcional)</label>
|
||
<input type="text" id="clinicPcName" class="form-control" placeholder="Ex: PC-Recepção">
|
||
</div>
|
||
<button type="submit" class="btn btn-primary" style="width: 100%; margin-top: 15px;">Cadastrar Clínica</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Mostrar Token -->
|
||
<div class="modal" id="showTokenModal">
|
||
<div class="modal-content" style="max-width: 600px; border-radius: var(--radius);">
|
||
<div class="modal-header">
|
||
<h2>🔑 Token de Acesso Desktop</h2>
|
||
<div class="modal-close" onclick="closeShowTokenModal()">×</div>
|
||
</div>
|
||
<div class="modal-body">
|
||
<p style="margin-bottom: 15px; color: #555;">Copie o token abaixo e cole no cliente desktop junto com o email e a senha para autenticar esta clínica.</p>
|
||
<div style="display: flex; gap: 10px;">
|
||
<input type="text" id="clinicTokenInput" class="form-control" readonly style="flex: 1; font-family: monospace; font-size: 14px;">
|
||
<button class="btn btn-primary" onclick="copyTokenToClipboard()">📋 Copiar</button>
|
||
</div>
|
||
<p id="tokenCopySuccess" style="color: green; margin-top: 10px; display: none;">✅ Token copiado para a área de transferência!</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Application Script -->
|
||
<script src="/socket.io/socket.io.js"></script>
|
||
<script src="/app.js"></script>
|
||
</body>
|
||
</html>
|