Initial commit: Task Printout pdf
This commit is contained in:
parent
46a84b4d95
commit
d778654837
|
|
@ -13,6 +13,11 @@ import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter_quill/flutter_quill.dart' as quill;
|
import 'package:flutter_quill/flutter_quill.dart' as quill;
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:flutter/services.dart' show rootBundle;
|
||||||
|
import 'package:pdf/widgets.dart' as pw;
|
||||||
|
import 'package:pdf/pdf.dart' as pdf;
|
||||||
|
import 'package:printing/printing.dart';
|
||||||
import '../../providers/supabase_provider.dart';
|
import '../../providers/supabase_provider.dart';
|
||||||
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||||
import '../../providers/profile_provider.dart';
|
import '../../providers/profile_provider.dart';
|
||||||
|
|
@ -334,17 +339,32 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
Wrap(
|
Row(
|
||||||
spacing: 12,
|
|
||||||
runSpacing: 8,
|
|
||||||
crossAxisAlignment: WrapCrossAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
_buildStatusChip(context, task, canUpdateStatus),
|
Expanded(
|
||||||
_MetaBadge(label: 'Office', value: officeName),
|
child: Wrap(
|
||||||
_MetaBadge(
|
spacing: 12,
|
||||||
label: 'Task #',
|
runSpacing: 8,
|
||||||
value: task.taskNumber ?? task.id,
|
crossAxisAlignment: WrapCrossAlignment.center,
|
||||||
isMono: true,
|
children: [
|
||||||
|
_buildStatusChip(context, task, canUpdateStatus),
|
||||||
|
_MetaBadge(label: 'Office', value: officeName),
|
||||||
|
_MetaBadge(
|
||||||
|
label: 'Task #',
|
||||||
|
value: task.taskNumber ?? task.id,
|
||||||
|
isMono: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Preview/print task',
|
||||||
|
onPressed: () async {
|
||||||
|
try {
|
||||||
|
await _showPdfPreview(task, ticket, officeName);
|
||||||
|
} catch (_) {}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.print),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -2734,6 +2754,186 @@ class _TaskDetailScreenState extends ConsumerState<TaskDetailScreen>
|
||||||
assignment.taskId == taskId && assignment.userId == profile.id,
|
assignment.taskId == taskId && assignment.userId == profile.id,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> _buildTaskPdfBytes(
|
||||||
|
Task task,
|
||||||
|
Ticket? ticket,
|
||||||
|
String officeName,
|
||||||
|
pdf.PdfPageFormat format,
|
||||||
|
) async {
|
||||||
|
final logoData = await rootBundle.load('crmc_logo.png');
|
||||||
|
final logoImage = pw.MemoryImage(logoData.buffer.asUint8List());
|
||||||
|
final doc = pw.Document();
|
||||||
|
final created = AppTime.formatDate(task.createdAt);
|
||||||
|
|
||||||
|
doc.addPage(
|
||||||
|
pw.Page(
|
||||||
|
pageFormat: format,
|
||||||
|
margin: pw.EdgeInsets.all(28),
|
||||||
|
build: (pw.Context ctx) {
|
||||||
|
return pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
pw.Row(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
pw.Container(
|
||||||
|
width: 64,
|
||||||
|
height: 64,
|
||||||
|
child: pw.Image(logoImage),
|
||||||
|
),
|
||||||
|
pw.SizedBox(width: 12),
|
||||||
|
pw.Expanded(
|
||||||
|
child: pw.Column(
|
||||||
|
crossAxisAlignment: pw.CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
pw.Text(
|
||||||
|
'Republic of the Philippines',
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
pw.Text(
|
||||||
|
'Department of Health',
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
pw.Text(
|
||||||
|
'Regional and Medical Center',
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 6),
|
||||||
|
pw.Text(
|
||||||
|
'Cotabato Regional and Medical Center',
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
style: pw.TextStyle(fontWeight: pw.FontWeight.bold),
|
||||||
|
),
|
||||||
|
pw.Text(
|
||||||
|
'Integrated Hospital Operations and Management Program',
|
||||||
|
textAlign: pw.TextAlign.center,
|
||||||
|
),
|
||||||
|
pw.Text('(IHOMP)', textAlign: pw.TextAlign.center),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 12),
|
||||||
|
pw.Center(
|
||||||
|
child: pw.Text(
|
||||||
|
'IT Job / Maintenance Request Form',
|
||||||
|
style: pw.TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: pw.FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 12),
|
||||||
|
pw.Row(
|
||||||
|
children: [
|
||||||
|
pw.Text('Task Number: ${task.taskNumber ?? task.id}'),
|
||||||
|
pw.Spacer(),
|
||||||
|
pw.Text('Filed At: $created'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 8),
|
||||||
|
pw.Row(
|
||||||
|
children: [
|
||||||
|
pw.Text('Service: ${task.title}'),
|
||||||
|
pw.SizedBox(width: 12),
|
||||||
|
pw.Text('Office: $officeName'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 8),
|
||||||
|
pw.Row(
|
||||||
|
children: [
|
||||||
|
pw.Text('Type: ${task.requestType ?? ''}'),
|
||||||
|
pw.SizedBox(width: 12),
|
||||||
|
pw.Text('Category: ${task.requestCategory ?? ''}'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 12),
|
||||||
|
pw.Text('Description:'),
|
||||||
|
pw.SizedBox(height: 6),
|
||||||
|
pw.Container(
|
||||||
|
height: 80,
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
border: pw.Border(
|
||||||
|
bottom: pw.BorderSide(
|
||||||
|
width: 0.5,
|
||||||
|
color: pdf.PdfColors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 12),
|
||||||
|
pw.Row(
|
||||||
|
children: [
|
||||||
|
pw.Text('Requested By: ${task.requestedBy ?? ''}'),
|
||||||
|
pw.Spacer(),
|
||||||
|
pw.Text('Noted by Supervisor/Senior'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 12),
|
||||||
|
pw.Text('Action Taken:'),
|
||||||
|
pw.SizedBox(height: 6),
|
||||||
|
pw.Container(
|
||||||
|
height: 80,
|
||||||
|
decoration: pw.BoxDecoration(
|
||||||
|
border: pw.Border(
|
||||||
|
bottom: pw.BorderSide(
|
||||||
|
width: 0.5,
|
||||||
|
color: pdf.PdfColors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
pw.SizedBox(height: 12),
|
||||||
|
pw.Row(
|
||||||
|
children: [
|
||||||
|
pw.Text('Performed By:'),
|
||||||
|
pw.Spacer(),
|
||||||
|
pw.Text('Received By: ___________________________'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return doc.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showPdfPreview(
|
||||||
|
Task task,
|
||||||
|
Ticket? ticket,
|
||||||
|
String officeName,
|
||||||
|
) async {
|
||||||
|
await showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (ctx) => AlertDialog(
|
||||||
|
contentPadding: const EdgeInsets.all(8),
|
||||||
|
content: SizedBox(
|
||||||
|
width: 700,
|
||||||
|
height: 900,
|
||||||
|
child: PdfPreview(
|
||||||
|
build: (format) => _buildTaskPdfBytes(
|
||||||
|
task,
|
||||||
|
ticket,
|
||||||
|
officeName,
|
||||||
|
format as pdf.PdfPageFormat,
|
||||||
|
),
|
||||||
|
allowPrinting: true,
|
||||||
|
allowSharing: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(ctx).pop(),
|
||||||
|
child: const Text('Close'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MetaBadge extends StatelessWidget {
|
class _MetaBadge extends StatelessWidget {
|
||||||
|
|
|
||||||
60
pubspec.lock
60
pubspec.lock
|
|
@ -121,6 +121,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.1"
|
version: "4.2.1"
|
||||||
|
barcode:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: barcode
|
||||||
|
sha256: "7b6729c37e3b7f34233e2318d866e8c48ddb46c1f7ad01ff7bb2a8de1da2b9f4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.9"
|
||||||
|
bidi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bidi
|
||||||
|
sha256: "77f475165e94b261745cf1032c751e2032b8ed92ccb2bf5716036db79320637d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.13"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -625,10 +641,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: "492bd52f6c4fbb6ee41f781ff27765ce5f627910e1e0cbecfa3d9add5562604c"
|
sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.7.2"
|
version: "4.5.4"
|
||||||
intl:
|
intl:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -789,6 +805,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.1"
|
version: "1.9.1"
|
||||||
|
path_parsing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_parsing
|
||||||
|
sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -837,6 +861,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
pdf:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: pdf
|
||||||
|
sha256: "28eacad99bffcce2e05bba24e50153890ad0255294f4dd78a17075a2ba5c8416"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.11.3"
|
||||||
|
pdf_widget_wrapper:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pdf_widget_wrapper
|
||||||
|
sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
petitparser:
|
petitparser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -893,6 +933,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.6.0"
|
version: "2.6.0"
|
||||||
|
printing:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: printing
|
||||||
|
sha256: "482cd5a5196008f984bb43ed0e47cbfdca7373490b62f3b27b3299275bf22a93"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.14.2"
|
||||||
proj4dart:
|
proj4dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -909,6 +957,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
quill_native_bridge:
|
quill_native_bridge:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ dependencies:
|
||||||
flutter_typeahead: ^4.1.0
|
flutter_typeahead: ^4.1.0
|
||||||
flutter_quill: ^11.5.0
|
flutter_quill: ^11.5.0
|
||||||
file_picker: ^10.3.10
|
file_picker: ^10.3.10
|
||||||
|
pdf: ^3.11.3
|
||||||
|
printing: ^5.10.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@
|
||||||
|
|
||||||
<title>tasq</title>
|
<title>tasq</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
|
<!-- PDF.js and printing support for Flutter Web (required by `printing` package) -->
|
||||||
|
<!-- Use a pdfjs-dist version compatible with the printing package (API/Worker versions must match) -->
|
||||||
|
<script src="https://unpkg.com/pdfjs-dist@3.2.146/build/pdf.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/pdfjs-dist@3.2.146/build/pdf.worker.min.js"></script>
|
||||||
|
<script src="packages/printing/printing.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script src="flutter_bootstrap.js" async></script>
|
<script src="flutter_bootstrap.js" async></script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user