mergerelatoriosnovo
This commit is contained in:
commit
52ae210ff7
@ -19,45 +19,59 @@ const DoctorRelatorioManager = () => {
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [index, setIndex] = useState();
|
||||
|
||||
// busca lista de relatórios
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
|
||||
const fetchReports = async () => {
|
||||
try {
|
||||
var myHeaders = new Headers();
|
||||
myHeaders.append('apikey', API_KEY);
|
||||
myHeaders.append('Authorization', authHeader);
|
||||
if (authHeader) myHeaders.append('Authorization', authHeader);
|
||||
var requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' };
|
||||
|
||||
const res = await fetch("https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/reports?select=*", requestOptions);
|
||||
const data = await res.json();
|
||||
setRelatorios(data || []);
|
||||
|
||||
const uniqueMap = new Map();
|
||||
(Array.isArray(data) ? data : []).forEach(r => {
|
||||
if (r && r.id) uniqueMap.set(r.id, r);
|
||||
});
|
||||
const unique = Array.from(uniqueMap.values())
|
||||
.sort((a, b) => new Date(b.created_at || 0) - new Date(a.created_at || 0));
|
||||
|
||||
if (mounted) setRelatorios(unique);
|
||||
} catch (err) {
|
||||
console.error('Erro listar relatórios', err);
|
||||
setRelatorios([]);
|
||||
if (mounted) setRelatorios([]);
|
||||
}
|
||||
};
|
||||
|
||||
fetchReports();
|
||||
|
||||
const refreshHandler = () => fetchReports();
|
||||
window.addEventListener('reports:refresh', refreshHandler);
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
window.removeEventListener('reports:refresh', refreshHandler);
|
||||
};
|
||||
}, [authHeader]);
|
||||
|
||||
// depois que RelatoriosFiltrados mudar, busca pacientes e médicos correspondentes
|
||||
useEffect(() => {
|
||||
const fetchRelData = async () => {
|
||||
const pacientes = [];
|
||||
const medicos = [];
|
||||
for (let i = 0; i < RelatoriosFiltrados.length; i++) {
|
||||
const rel = RelatoriosFiltrados[i];
|
||||
// paciente
|
||||
try {
|
||||
const pacienteRes = await GetPatientByID(rel.patient_id, authHeader);
|
||||
pacientes.push(Array.isArray(pacienteRes) ? pacienteRes[0] : pacienteRes);
|
||||
} catch (err) {
|
||||
pacientes.push(null);
|
||||
}
|
||||
// médico: tenta created_by ou requested_by id se existir
|
||||
try {
|
||||
const doctorId = rel.created_by || rel.requested_by || null;
|
||||
if (doctorId) {
|
||||
// se created_by é id (uuid) usamos GetDoctorByID, senão se requested_by for nome, guardamos nome
|
||||
const docRes = await GetDoctorByID(doctorId, authHeader);
|
||||
medicos.push(Array.isArray(docRes) ? docRes[0] : docRes);
|
||||
} else {
|
||||
@ -77,54 +91,73 @@ const DoctorRelatorioManager = () => {
|
||||
}
|
||||
}, [RelatoriosFiltrados, authHeader]);
|
||||
|
||||
const BaixarPDFdoRelatorio = (nome_paciente) => {
|
||||
const elemento = document.getElementById("folhaA4");
|
||||
const opt = { margin: 0, filename: `relatorio_${nome_paciente || "paciente"}.pdf`, html2canvas: { scale: 2 }, jsPDF: { unit: "mm", format: "a4", orientation: "portrait" } };
|
||||
const BaixarPDFdoRelatorio = (nome_paciente, idx) => {
|
||||
const elemento = document.getElementById(`folhaA4-${idx}`);
|
||||
if (!elemento) {
|
||||
console.error('Elemento para gerar PDF não encontrado:', `folhaA4-${idx}`);
|
||||
return;
|
||||
}
|
||||
const opt = {
|
||||
margin: 0,
|
||||
filename: `relatorio_${nome_paciente || "paciente"}.pdf`,
|
||||
html2canvas: { scale: 2 },
|
||||
jsPDF: { unit: "mm", format: "a4", orientation: "portrait" }
|
||||
};
|
||||
html2pdf().set(opt).from(elemento).save();
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{showModal && (
|
||||
<div className="modal">
|
||||
<div className="modal-dialog modal-tabela-relatorio">
|
||||
<div className="modal modal-centered" role="dialog" aria-modal="true" onClick={() => setShowModal(false)}>
|
||||
{/* aqui: classe modal-dialog-square para ficar quadrado */}
|
||||
<div className="modal-dialog modal-dialog-square" role="document" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="modal-content">
|
||||
<div className="modal-header text-white">
|
||||
<h5 className="modal-title ">Relatório de {PacientesComRelatorios[index]?.full_name}</h5>
|
||||
<button type="button" className="btn-close" onClick={() => setShowModal(false)}></button>
|
||||
<div className="modal-header custom-modal-header">
|
||||
<h5 className="modal-title">Relatório de {PacientesComRelatorios[index]?.full_name}</h5>
|
||||
<button type="button" className="btn-close modal-close-btn" aria-label="Close" onClick={() => setShowModal(false)}></button>
|
||||
</div>
|
||||
|
||||
<div className="modal-body">
|
||||
<div id="folhaA4">
|
||||
<div id='header-relatorio'>
|
||||
<p>Clinica Rise up</p>
|
||||
<p>Dr - CRM/SP 123456</p>
|
||||
<p>Avenida - (79) 9 4444-4444</p>
|
||||
<div id={`folhaA4-${index}`} className="folhaA4">
|
||||
<div id='header-relatorio' style={{ textAlign: 'center', marginBottom: 24 }}>
|
||||
<p style={{ margin: 0 }}>Clinica Rise up</p>
|
||||
<p style={{ margin: 0 }}>Dr - CRM/SP 123456</p>
|
||||
<p style={{ margin: 0 }}>Avenida - (79) 9 4444-4444</p>
|
||||
</div>
|
||||
|
||||
<div id='infoPaciente'>
|
||||
<p>Paciente: {PacientesComRelatorios[index]?.full_name}</p>
|
||||
<p>Data de nascimento: {PacientesComRelatorios[index]?.birth_date}</p>
|
||||
<p>Data do exame: {RelatoriosFiltrados[index]?.due_at || ''}</p>
|
||||
{/* Exibe conteúdo salvo (content_html) */}
|
||||
<p style={{ marginTop: '15px', fontWeight: 'bold' }}>Conteúdo do Relatório:</p>
|
||||
<TiptapViewer htmlContent={RelatoriosFiltrados[index]?.content_html || RelatoriosFiltrados[index]?.content || 'Relatório não preenchido.'} />
|
||||
<div id='infoPaciente' style={{ padding: '0 6px' }}>
|
||||
<p><strong>Paciente:</strong> {PacientesComRelatorios[index]?.full_name}</p>
|
||||
<p><strong>Data de nascimento:</strong> {PacientesComRelatorios[index]?.birth_date || '—'}</p>
|
||||
<p><strong>Data do exame:</strong> {RelatoriosFiltrados[index]?.due_at || '—'}</p>
|
||||
|
||||
<p style={{ marginTop: 12, fontWeight: '700' }}>Conteúdo do Relatório:</p>
|
||||
<div className="tiptap-viewer-wrapper">
|
||||
<TiptapViewer htmlContent={RelatoriosFiltrados[index]?.content_html || RelatoriosFiltrados[index]?.content || 'Relatório não preenchido.'} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div style={{ marginTop: 20, padding: '0 6px' }}>
|
||||
<p>Dr {MedicosComRelatorios[index]?.full_name || RelatoriosFiltrados[index]?.requested_by}</p>
|
||||
<p>Emitido em: {RelatoriosFiltrados[index]?.created_at || '—'}</p>
|
||||
<p style={{ color: '#6c757d', fontSize: '0.95rem' }}>Emitido em: {RelatoriosFiltrados[index]?.created_at || '—'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button className="btn btn-primary" onClick={() => BaixarPDFdoRelatorio(PacientesComRelatorios[index]?.full_name)}><i className='bi bi-file-pdf-fill'></i> baixar em pdf</button>
|
||||
<button type="button" className="btn btn-primary" onClick={() => { setShowModal(false) }}>Fechar</button>
|
||||
|
||||
<div className="modal-footer custom-modal-footer">
|
||||
<button className="btn btn-primary" onClick={() => BaixarPDFdoRelatorio(PacientesComRelatorios[index]?.full_name, index)}>
|
||||
<i className='bi bi-file-pdf-fill'></i> baixar em pdf
|
||||
</button>
|
||||
<button type="button" className="btn btn-outline-secondary" onClick={() => { setShowModal(false) }}>
|
||||
Fechar
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* restante da página (lista) permanece igual */}
|
||||
<div className="page-heading"><h3>Lista de Relatórios</h3></div>
|
||||
<div className="page-content">
|
||||
<section className="row">
|
||||
@ -173,7 +206,7 @@ const DoctorRelatorioManager = () => {
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr><td colSpan="8" className="text-center">Nenhum paciente encontrado.</td></tr>
|
||||
<tr><td colSpan="3" className="text-center">Nenhum paciente encontrado.</td></tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// EditPageRelatorio.jsx
|
||||
// src/PagesMedico/EditPageRelatorio.jsx
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import API_KEY from '../components/utils/apiKeys';
|
||||
@ -7,7 +7,6 @@ import TiptapEditor from '../PagesMedico/TiptapEditor';
|
||||
import { GetPatientByID } from '../components/utils/Functions-Endpoints/Patient';
|
||||
import { GetDoctorByID } from '../components/utils/Functions-Endpoints/Doctor';
|
||||
|
||||
|
||||
const EditPageRelatorio = () => {
|
||||
const params = useParams();
|
||||
const navigate = useNavigate();
|
||||
@ -19,7 +18,6 @@ const EditPageRelatorio = () => {
|
||||
const [doctor, setDoctor] = useState(null);
|
||||
const [html, setHtml] = useState('');
|
||||
|
||||
|
||||
const generateTemplate = (r = {}, p = {}, d = {}) => {
|
||||
const patientName = p?.full_name || '[NOME DO PACIENTE]';
|
||||
const birthDate = p?.birth_date || '';
|
||||
@ -48,34 +46,29 @@ const EditPageRelatorio = () => {
|
||||
`;
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const load = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const myHeaders = new Headers();
|
||||
myHeaders.append("apikey", API_KEY);
|
||||
myHeaders.append("Authorization", authHeader);
|
||||
if (authHeader) myHeaders.append("Authorization", authHeader);
|
||||
const requestOptions = { method: 'GET', headers: myHeaders, redirect: 'follow' };
|
||||
|
||||
|
||||
// Pega relatório por id (supabase geralmente retorna array para ?id=eq.X)
|
||||
const resp = await fetch(`https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/reports?id=eq.${params.id}`, requestOptions);
|
||||
const data = await resp.json();
|
||||
const rep = Array.isArray(data) ? data[0] : data;
|
||||
if (!rep) throw new Error('Relatório não encontrado');
|
||||
|
||||
|
||||
setReport(rep);
|
||||
|
||||
|
||||
// busca paciente
|
||||
if (rep.patient_id) {
|
||||
const p = await GetPatientByID(rep.patient_id, authHeader);
|
||||
setPatient(Array.isArray(p) ? p[0] : p);
|
||||
}
|
||||
|
||||
|
||||
// busca doctor se tiver created_by/requested_by id (tentamos fallback)
|
||||
if (rep.created_by) {
|
||||
try {
|
||||
@ -86,7 +79,6 @@ const EditPageRelatorio = () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// content_html preferencial
|
||||
let initial = rep.content_html || rep.content || rep.diagnosis || rep.conclusion || '';
|
||||
if (!initial || initial.trim() === '') {
|
||||
@ -104,16 +96,15 @@ const EditPageRelatorio = () => {
|
||||
// eslint-disable-next-line
|
||||
}, [params.id, authHeader]);
|
||||
|
||||
|
||||
const handleSave = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const myHeaders = new Headers();
|
||||
myHeaders.append('apikey', API_KEY);
|
||||
myHeaders.append('Authorization', authHeader);
|
||||
if (authHeader) myHeaders.append('Authorization', authHeader);
|
||||
myHeaders.append('Content-Type', 'application/json');
|
||||
|
||||
// Adicionado para que a API retorne o registro atualizado
|
||||
myHeaders.append('Accept', 'application/json');
|
||||
// pedir que o Supabase retorne a representação do registro atualizado (opcional)
|
||||
myHeaders.append('Prefer', 'return=representation');
|
||||
|
||||
const body = JSON.stringify({ content_html: html });
|
||||
@ -125,15 +116,21 @@ const EditPageRelatorio = () => {
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const txt = await res.text();
|
||||
let txt;
|
||||
try { txt = await res.text(); } catch (e) { txt = 'erro lendo resposta'; }
|
||||
console.error('Erro PATCH', res.status, txt);
|
||||
throw new Error('Erro na API');
|
||||
}
|
||||
|
||||
// Recebe o dado atualizado e atualiza o estado do componente
|
||||
const updatedData = await res.json();
|
||||
let updatedData;
|
||||
try {
|
||||
updatedData = await res.json();
|
||||
} catch (e) {
|
||||
updatedData = null;
|
||||
}
|
||||
const updatedReport = Array.isArray(updatedData) ? updatedData[0] : updatedData;
|
||||
|
||||
|
||||
if (updatedReport) {
|
||||
setReport(updatedReport);
|
||||
setHtml(updatedReport.content_html || '');
|
||||
@ -150,21 +147,17 @@ const EditPageRelatorio = () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if (loading) return <div>Carregando...</div>;
|
||||
|
||||
|
||||
return (
|
||||
<div className='container'>
|
||||
<h3 className='mb-4'>Editar Relatório do Paciente: {patient?.full_name || '...'}</h3>
|
||||
|
||||
|
||||
<div className='mb-3'>
|
||||
<h5 className='mb-2'>Conteúdo do Relatório</h5>
|
||||
<TiptapEditor content={html} onChange={(newHtml) => setHtml(newHtml)} />
|
||||
</div>
|
||||
|
||||
|
||||
<div className='d-flex justify-content-center mt-4'>
|
||||
<button className='btn btn-success' onClick={handleSave} disabled={loading}>
|
||||
{loading ? 'Salvando...' : 'Salvar Relatório'}
|
||||
@ -174,5 +167,4 @@ const EditPageRelatorio = () => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default EditPageRelatorio;
|
||||
@ -1,3 +1,4 @@
|
||||
// src/PagesMedico/FormNovoRelatorio.jsx
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import API_KEY from '../components/utils/apiKeys';
|
||||
@ -39,7 +40,7 @@ const FormNovoRelatorio = () => {
|
||||
const doctorRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
// carregar pacientes
|
||||
// carregar pacientes e médicos
|
||||
let mounted = true;
|
||||
const loadPatients = async () => {
|
||||
setLoadingPatients(true);
|
||||
@ -109,7 +110,7 @@ const FormNovoRelatorio = () => {
|
||||
patient_id: patient.id,
|
||||
patient_name: patient.full_name || '',
|
||||
patient_birth: patient.birth_date || '',
|
||||
contentHtml: generateTemplate(patient.full_name || '', patient.birth_date || '', form.doctor_name)
|
||||
contentHtml: generateTemplate(patient.full_name || '', patient.birth_date || '', prev.doctor_name)
|
||||
}));
|
||||
setPatientQuery('');
|
||||
setShowPatientDropdown(false);
|
||||
@ -120,7 +121,7 @@ const FormNovoRelatorio = () => {
|
||||
...prev,
|
||||
doctor_id: doctor.id,
|
||||
doctor_name: doctor.full_name || '',
|
||||
contentHtml: generateTemplate(form.patient_name, form.patient_birth, doctor.full_name || '')
|
||||
contentHtml: generateTemplate(prev.patient_name, prev.patient_birth, doctor.full_name || '')
|
||||
}));
|
||||
setDoctorQuery('');
|
||||
setShowDoctorDropdown(false);
|
||||
@ -137,7 +138,7 @@ const FormNovoRelatorio = () => {
|
||||
|
||||
const handleEditorChange = (html) => setForm(prev => ({ ...prev, contentHtml: html }));
|
||||
|
||||
// salvar novo relatório
|
||||
// salvar novo relatório (agora com Prefer: return=representation e dispatch para refresh)
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
if (!form.patient_id) return alert('Selecione o paciente (clicando no item) antes de salvar.');
|
||||
@ -146,35 +147,51 @@ const FormNovoRelatorio = () => {
|
||||
try {
|
||||
const myHeaders = new Headers();
|
||||
myHeaders.append('apikey', API_KEY);
|
||||
myHeaders.append('Authorization', authHeader);
|
||||
if (authHeader) myHeaders.append('Authorization', authHeader);
|
||||
myHeaders.append('Content-Type', 'application/json');
|
||||
myHeaders.append('Accept', 'application/json');
|
||||
// pedir que o Supabase retorne a representação do registro criado
|
||||
myHeaders.append('Prefer', 'return=representation');
|
||||
|
||||
const body = JSON.stringify({
|
||||
// monta o payload apenas com campos válidos
|
||||
const payload = {
|
||||
patient_id: form.patient_id,
|
||||
content: form.contentHtml,
|
||||
content_html: form.contentHtml,
|
||||
requested_by: form.doctor_name || '',
|
||||
created_by: form.doctor_id || null,
|
||||
status: 'draft'
|
||||
});
|
||||
requested_by: form.doctor_name || ''
|
||||
};
|
||||
// só inclui created_by se tiver um id válido
|
||||
if (form.doctor_id) payload.created_by = form.doctor_id;
|
||||
payload.status = 'draft';
|
||||
|
||||
const res = await fetch('https://yuanqfswhberkoevtmfr.supabase.co/rest/v1/reports', {
|
||||
method: 'POST',
|
||||
headers: myHeaders,
|
||||
body,
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const txt = await res.text();
|
||||
// tenta ler JSON, se não for JSON lê o texto
|
||||
let txt;
|
||||
try {
|
||||
txt = await res.json();
|
||||
} catch (err) {
|
||||
txt = await res.text();
|
||||
}
|
||||
console.error('Erro POST criar relatório:', res.status, txt);
|
||||
// mostra mensagem mais útil
|
||||
return alert(`Erro ao criar relatório (ver console). Status ${res.status}`);
|
||||
return alert(`Erro ao criar relatório (ver console). Status ${res.status}\nMensagem: ${JSON.stringify(txt)}`);
|
||||
}
|
||||
|
||||
const created = await res.json();
|
||||
console.log('Relatório criado:', created);
|
||||
|
||||
// dispara refresh global para a lista (DoctorRelatorioManager está escutando)
|
||||
window.dispatchEvent(new Event('reports:refresh'));
|
||||
|
||||
alert('Relatório criado com sucesso!');
|
||||
navigate('/medico/relatorios');
|
||||
} catch (err) {
|
||||
console.error('Erro salvar relatório:', err);
|
||||
console.error('Erro salvar relatório (catch):', err);
|
||||
alert('Erro ao salvar relatório. Veja console.');
|
||||
}
|
||||
};
|
||||
@ -185,7 +202,7 @@ const FormNovoRelatorio = () => {
|
||||
|
||||
<form onSubmit={handleSubmit} className="card p-4 mb-4">
|
||||
<div className="row g-3 align-items-end">
|
||||
<div className="col-md-6" ref={patientRef}>
|
||||
<div className="col-md-6" ref={patientRef} style={{ position: 'relative' }}>
|
||||
<label className="form-label">Buscar paciente (digite para filtrar)</label>
|
||||
<input
|
||||
className="form-control"
|
||||
@ -195,7 +212,7 @@ const FormNovoRelatorio = () => {
|
||||
onFocus={() => setShowPatientDropdown(true)}
|
||||
/>
|
||||
{showPatientDropdown && patientQuery && (
|
||||
<ul className="list-group position-absolute" style={{ zIndex: 50, maxHeight: 220, overflowY: 'auto', width: '45%' }}>
|
||||
<ul className="list-group position-absolute" style={{ zIndex: 50, maxHeight: 220, overflowY: 'auto', width: '100%' }}>
|
||||
{filteredPatients.length > 0 ? filteredPatients.map(p => (
|
||||
<li key={p.id} className="list-group-item list-group-item-action" onClick={() => choosePatient(p)}>
|
||||
{p.full_name} {p.cpf ? `- ${p.cpf}` : ''}
|
||||
@ -206,7 +223,7 @@ const FormNovoRelatorio = () => {
|
||||
<div className="form-text">Clique no paciente desejado para selecioná-lo e preencher o template.</div>
|
||||
</div>
|
||||
|
||||
<div className="col-md-6" ref={doctorRef}>
|
||||
<div className="col-md-6" ref={doctorRef} style={{ position: 'relative' }}>
|
||||
<label className="form-label">Buscar médico (digite para filtrar)</label>
|
||||
<input
|
||||
className="form-control"
|
||||
@ -216,7 +233,7 @@ const FormNovoRelatorio = () => {
|
||||
onFocus={() => setShowDoctorDropdown(true)}
|
||||
/>
|
||||
{showDoctorDropdown && doctorQuery && (
|
||||
<ul className="list-group position-absolute" style={{ zIndex: 50, maxHeight: 220, overflowY: 'auto', width: '45%', right: 0 }}>
|
||||
<ul className="list-group position-absolute" style={{ zIndex: 50, maxHeight: 220, overflowY: 'auto', width: '100%' }}>
|
||||
{filteredDoctors.length > 0 ? filteredDoctors.map(d => (
|
||||
<li key={d.id} className="list-group-item list-group-item-action" onClick={() => chooseDoctor(d)}>
|
||||
{d.full_name} {d.crm ? `- CRM ${d.crm}` : ''}
|
||||
|
||||
@ -12,4 +12,4 @@ const TiptapViewer = ({ htmlContent }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default TiptapViewer;
|
||||
export default TiptapViewer;
|
||||
|
||||
@ -112,4 +112,4 @@ function Relatorio() {
|
||||
);
|
||||
}
|
||||
|
||||
export default Relatorio;
|
||||
export default Relatorio;
|
||||
|
||||
@ -1,55 +1,152 @@
|
||||
#folhaA4 {
|
||||
width: 210mm;
|
||||
min-height: 207mm;
|
||||
padding: 20mm;
|
||||
margin: 10mm auto;
|
||||
border: 1px solid #ccc;
|
||||
background: white;
|
||||
|
||||
/* src/PagesMedico/styleMedico/FormNovoRelatorio.css */
|
||||
|
||||
/* --- Modal centralizada e quadrada (ajustada para ser mais larga e sem quadrado branco no botão fechar) --- */
|
||||
|
||||
/* backdrop + center */
|
||||
.modal.modal-centered {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(10, 20, 30, 0.45);
|
||||
z-index: 2000;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#primeiraLinha{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
margin-bottom: 20px;
|
||||
/* dialog box — maior horizontalmente e altura automática para scroll interno */
|
||||
.modal-dialog.modal-dialog-square {
|
||||
width: 880px; /* largura aumentada */
|
||||
max-width: 96vw;
|
||||
height: auto; /* deixa altura automática (melhor para conteúdo longo) */
|
||||
max-height: 92vh;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input,textarea,label{
|
||||
font-size: 1.1rem;
|
||||
/* caixa branca que contém o conteúdo - ocupa 100% da dialog */
|
||||
.modal-dialog.modal-dialog-square .modal-content {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 12px 30px rgba(11,22,35,0.18);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
textarea{
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
|
||||
/* header */
|
||||
.custom-modal-header {
|
||||
position: relative;
|
||||
background: linear-gradient(90deg, #203B75 0%, #274A8A 100%);
|
||||
color: #fff;
|
||||
padding: 14px 18px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.submitButton{
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
height:50% ;
|
||||
padding: 8px 20px;
|
||||
|
||||
font-size: medium;
|
||||
.custom-modal-header .modal-title {
|
||||
margin: 0;
|
||||
font-size: 1.05rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.bi-download{
|
||||
font-size: 1.2rem;
|
||||
margin-right: 5px;
|
||||
font-weight: bold;
|
||||
/* botão fechar no header — sem quadrado branco por trás */
|
||||
.modal-close-btn {
|
||||
background: transparent !important;
|
||||
border: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 4px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#infoPaciente{
|
||||
margin-top: 50px;
|
||||
margin-bottom: 40px;
|
||||
.modal-close-btn::after {
|
||||
content: '✕';
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
#header-relatorio{
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
/* body - faz scroll interno se for longo */
|
||||
.modal-body {
|
||||
padding: 18px;
|
||||
overflow: auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.info-paciente{
|
||||
font-weight: bold;
|
||||
/* footer */
|
||||
.custom-modal-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding: 14px 18px;
|
||||
border-top: 1px solid #eee;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
/* folhaA4 dentro da modal — adapta para caber */
|
||||
.folhaA4 {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* melhor espaçamento e leitura do conteúdo */
|
||||
#header-relatorio p {
|
||||
color: #374151;
|
||||
margin: 6px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#infoPaciente p {
|
||||
margin: 10px 0;
|
||||
color: #3d4650;
|
||||
}
|
||||
|
||||
/* tornar o viewer responsivo */
|
||||
.tiptap-viewer-wrapper {
|
||||
border: 1px dashed #e7e7e7;
|
||||
padding: 12px;
|
||||
margin-top: 10px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* barra de scroll customizada (opcional) */
|
||||
.modal-body::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.modal-body::-webkit-scrollbar-thumb {
|
||||
background: rgba(100,100,100,0.18);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.modal-body::-webkit-scrollbar-track {
|
||||
background: rgba(0,0,0,0.02);
|
||||
}
|
||||
|
||||
/* responsividade para telas pequenas: mantém centralizado, ajusta proporção */
|
||||
@media (max-width: 680px) {
|
||||
.modal-dialog.modal-dialog-square {
|
||||
width: 92vw;
|
||||
height: 86vh;
|
||||
}
|
||||
.modal-close-btn { width: 36px; height: 36px; }
|
||||
.custom-modal-footer { padding: 10px; }
|
||||
.modal-body { padding: 12px; }
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user