first commit
This commit is contained in:
@@ -0,0 +1,245 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:pdf/pdf.dart';
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:printing/printing.dart';
|
||||
|
||||
class DepartmentReferralPdfService {
|
||||
/// Genera el documento PDF de Referimiento a Departamento en formato Media Carta Horizontal
|
||||
/// (8.5 x 5.5 pulgadas / 612 x 396 pt), idéntico a AlfaMedical.
|
||||
static Future<Uint8List> buildDepartmentReferralPdf({
|
||||
required String doctorName,
|
||||
required String specialty,
|
||||
required String subspecialty,
|
||||
required String generalContact,
|
||||
required String referralText,
|
||||
DateTime? date,
|
||||
pw.Font? fontRegular,
|
||||
pw.Font? fontBold,
|
||||
pw.Font? fontTitle,
|
||||
String? logoSvg,
|
||||
}) async {
|
||||
final pdf = pw.Document(title: 'Referir a Departamento');
|
||||
final formattedDate = DateFormat('dd/MM/yyyy').format(date ?? DateTime.now());
|
||||
|
||||
// Formato exacto e idéntico a AlfaMedical (ReportLab):
|
||||
// pagesize = (8.5*inch, 5.5*inch)
|
||||
// leftMargin = 72, rightMargin = 72, topMargin = 18, bottomMargin = 18.
|
||||
const pageFormat = PdfPageFormat(
|
||||
8.5 * PdfPageFormat.inch,
|
||||
5.5 * PdfPageFormat.inch,
|
||||
marginLeft: 72,
|
||||
marginRight: 72,
|
||||
marginTop: 18,
|
||||
marginBottom: 18,
|
||||
);
|
||||
|
||||
// Tipografías estándar con fallback a fuentes base PDF si no hay conexión a internet
|
||||
pw.Font regular = fontRegular ?? pw.Font.helvetica();
|
||||
pw.Font bold = fontBold ?? pw.Font.helveticaBold();
|
||||
pw.Font titleFont = fontTitle ?? pw.Font.timesBoldItalic();
|
||||
|
||||
if (fontRegular == null || fontBold == null || fontTitle == null) {
|
||||
try {
|
||||
regular = await PdfGoogleFonts.robotoRegular();
|
||||
bold = await PdfGoogleFonts.robotoBold();
|
||||
titleFont = await PdfGoogleFonts.playfairDisplayItalic();
|
||||
} catch (_) {
|
||||
regular = pw.Font.helvetica();
|
||||
bold = pw.Font.helveticaBold();
|
||||
titleFont = pw.Font.timesBoldItalic();
|
||||
}
|
||||
}
|
||||
|
||||
String? svgContent = logoSvg;
|
||||
if (svgContent == null) {
|
||||
try {
|
||||
svgContent = await rootBundle.loadString('assets/images/hidalyx_logo_blue.svg');
|
||||
} catch (_) {
|
||||
svgContent = null;
|
||||
}
|
||||
}
|
||||
|
||||
pdf.addPage(
|
||||
pw.Page(
|
||||
pageFormat: pageFormat,
|
||||
build: (pw.Context context) {
|
||||
return pw.Column(
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// 1. Cabecera con Nombre del Doctor y Badge Sutil de Hidalyx Med
|
||||
pw.Stack(
|
||||
children: [
|
||||
pw.Align(
|
||||
alignment: pw.Alignment.center,
|
||||
child: pw.Column(
|
||||
children: [
|
||||
pw.Text(
|
||||
doctorName.isNotEmpty ? doctorName : 'Dr. Luis A. Castro Sosa',
|
||||
style: pw.TextStyle(
|
||||
font: titleFont,
|
||||
fontSize: 22,
|
||||
fontWeight: pw.FontWeight.bold,
|
||||
color: PdfColor.fromHex('1E293B'),
|
||||
),
|
||||
),
|
||||
pw.SizedBox(height: 3),
|
||||
if (specialty.isNotEmpty)
|
||||
pw.Text(
|
||||
specialty.toUpperCase(),
|
||||
style: pw.TextStyle(
|
||||
font: bold,
|
||||
fontSize: 10.5,
|
||||
letterSpacing: 0.5,
|
||||
color: PdfColor.fromHex('0F172A'),
|
||||
),
|
||||
),
|
||||
if (subspecialty.isNotEmpty) ...[
|
||||
pw.SizedBox(height: 2),
|
||||
pw.Text(
|
||||
subspecialty.toUpperCase(),
|
||||
textAlign: pw.TextAlign.center,
|
||||
style: pw.TextStyle(
|
||||
font: regular,
|
||||
fontSize: 8.5,
|
||||
color: PdfColor.fromHex('475569'),
|
||||
),
|
||||
),
|
||||
],
|
||||
pw.SizedBox(height: 3),
|
||||
pw.Text(
|
||||
'Fecha: $formattedDate',
|
||||
style: pw.TextStyle(
|
||||
font: regular,
|
||||
fontSize: 9.5,
|
||||
color: PdfColor.fromHex('334155'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Badge sutil de Hidalyx Med en la esquina superior derecha
|
||||
pw.Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
child: pw.Row(
|
||||
mainAxisSize: pw.MainAxisSize.min,
|
||||
crossAxisAlignment: pw.CrossAxisAlignment.center,
|
||||
children: [
|
||||
if (svgContent != null && svgContent.isNotEmpty) ...[
|
||||
pw.Opacity(
|
||||
opacity: 0.6,
|
||||
child: pw.SvgImage(
|
||||
svg: svgContent,
|
||||
width: 7.5,
|
||||
height: 7.5,
|
||||
),
|
||||
),
|
||||
pw.SizedBox(width: 3),
|
||||
],
|
||||
pw.Text(
|
||||
'hidalyx.com',
|
||||
style: pw.TextStyle(
|
||||
font: regular,
|
||||
fontSize: 6.0,
|
||||
color: PdfColor.fromHex('94A3B8'),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
pw.SizedBox(height: 6),
|
||||
|
||||
// Línea divisoria decorativa del membrete
|
||||
pw.Container(
|
||||
height: 1,
|
||||
color: PdfColor.fromHex('CBD5E1'),
|
||||
),
|
||||
pw.SizedBox(height: 8),
|
||||
|
||||
// 2. Contenido del Referimiento (Idéntico a AlfaMedical)
|
||||
pw.Expanded(
|
||||
child: pw.Container(
|
||||
padding: const pw.EdgeInsets.symmetric(vertical: 4),
|
||||
child: pw.Text(
|
||||
referralText.trim().isNotEmpty
|
||||
? referralText.trim()
|
||||
: 'Sin detalles de referimiento.',
|
||||
style: pw.TextStyle(
|
||||
font: regular,
|
||||
fontSize: 10.5,
|
||||
lineSpacing: 3.5,
|
||||
color: PdfColor.fromHex('1E293B'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
pw.SizedBox(height: 6),
|
||||
|
||||
// 3. Pie de página con Contacto del Consultorio
|
||||
if (generalContact.isNotEmpty) ...[
|
||||
pw.Container(
|
||||
padding: const pw.EdgeInsets.only(top: 4),
|
||||
child: pw.Text(
|
||||
generalContact.toUpperCase(),
|
||||
textAlign: pw.TextAlign.center,
|
||||
style: pw.TextStyle(
|
||||
font: regular,
|
||||
fontSize: 6.8,
|
||||
color: PdfColor.fromHex('64748B'),
|
||||
lineSpacing: 1.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
pw.SizedBox(height: 3),
|
||||
|
||||
// Confirmación institucional
|
||||
pw.Center(
|
||||
child: pw.Text(
|
||||
'Documento médico emitido electrónicamente',
|
||||
style: pw.TextStyle(
|
||||
font: regular,
|
||||
fontSize: 6.0,
|
||||
color: PdfColor.fromHex('94A3B8'),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
return pdf.save();
|
||||
}
|
||||
|
||||
/// Envía a imprimir directamente o abre el diálogo nativo de impresión/PDF.
|
||||
static Future<void> printDepartmentReferral({
|
||||
required String doctorName,
|
||||
required String specialty,
|
||||
required String subspecialty,
|
||||
required String generalContact,
|
||||
required String referralText,
|
||||
DateTime? date,
|
||||
}) async {
|
||||
final pdfBytes = await buildDepartmentReferralPdf(
|
||||
doctorName: doctorName,
|
||||
specialty: specialty,
|
||||
subspecialty: subspecialty,
|
||||
generalContact: generalContact,
|
||||
referralText: referralText,
|
||||
date: date,
|
||||
);
|
||||
|
||||
await Printing.layoutPdf(
|
||||
onLayout: (PdfPageFormat format) async => pdfBytes,
|
||||
name: 'Referimiento_Departamento',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user