feat(client): 二维码打印功能
在商品详情二维码弹窗中新增「打印」按钮,使用 printing + pdf 生成含商品名称、编号、规格和二维码图片的 PDF,触发浏览器打印对话框。 嵌入 NotoSansSC-Regular 字体保证中文正常显示。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,9 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:pdf/pdf.dart';
|
||||
import 'package:pdf/widgets.dart' as pw;
|
||||
import 'package:printing/printing.dart';
|
||||
import '../../core/config/app_config.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../models/product.dart';
|
||||
@@ -152,7 +155,7 @@ class _ProductDetailScreenState extends ConsumerState<ProductDetailScreen> {
|
||||
void _showQRCode() {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => _QRCodeDialog(productId: widget.productId),
|
||||
builder: (_) => _QRCodeDialog(productId: widget.productId, product: _product!),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -498,7 +501,8 @@ class _UploadButton extends StatelessWidget {
|
||||
|
||||
class _QRCodeDialog extends ConsumerStatefulWidget {
|
||||
final int productId;
|
||||
const _QRCodeDialog({required this.productId});
|
||||
final Product product;
|
||||
const _QRCodeDialog({required this.productId, required this.product});
|
||||
|
||||
@override
|
||||
ConsumerState<_QRCodeDialog> createState() => _QRCodeDialogState();
|
||||
@@ -506,13 +510,51 @@ class _QRCodeDialog extends ConsumerStatefulWidget {
|
||||
|
||||
class _QRCodeDialogState extends ConsumerState<_QRCodeDialog> {
|
||||
late Future<Uint8List> _future;
|
||||
Uint8List? _bytes;
|
||||
bool _printing = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_future = ref
|
||||
.read(productRepositoryProvider)
|
||||
.getQRCodeBytes(widget.productId);
|
||||
.getQRCodeBytes(widget.productId)
|
||||
..then((b) => _bytes = b);
|
||||
}
|
||||
|
||||
Future<void> _print() async {
|
||||
if (_bytes == null || _printing) return;
|
||||
setState(() => _printing = true);
|
||||
try {
|
||||
final fontData = await rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf');
|
||||
final font = pw.Font.ttf(fontData);
|
||||
final p = widget.product;
|
||||
final doc = pw.Document();
|
||||
final qrImage = pw.MemoryImage(_bytes!);
|
||||
doc.addPage(pw.Page(
|
||||
pageFormat: PdfPageFormat.a4,
|
||||
build: (_) => pw.Center(
|
||||
child: pw.Column(
|
||||
mainAxisSize: pw.MainAxisSize.min,
|
||||
children: [
|
||||
pw.Image(qrImage, width: 200, height: 200),
|
||||
pw.SizedBox(height: 12),
|
||||
pw.Text(p.name,
|
||||
style: pw.TextStyle(font: font, fontSize: 18, fontWeight: pw.FontWeight.bold)),
|
||||
pw.SizedBox(height: 4),
|
||||
pw.Text('编号:${p.code}',
|
||||
style: pw.TextStyle(font: font, fontSize: 13)),
|
||||
if ((p.spec ?? '').isNotEmpty)
|
||||
pw.Text('规格:${p.spec}',
|
||||
style: pw.TextStyle(font: font, fontSize: 13)),
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
await Printing.layoutPdf(onLayout: (_) async => doc.save());
|
||||
} finally {
|
||||
if (mounted) setState(() => _printing = false);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -520,8 +562,8 @@ class _QRCodeDialogState extends ConsumerState<_QRCodeDialog> {
|
||||
return AlertDialog(
|
||||
title: const Text('商品二维码'),
|
||||
content: SizedBox(
|
||||
width: 200,
|
||||
height: 200,
|
||||
width: 220,
|
||||
height: 220,
|
||||
child: FutureBuilder<Uint8List>(
|
||||
future: _future,
|
||||
builder: (_, snap) {
|
||||
@@ -540,6 +582,15 @@ class _QRCodeDialogState extends ConsumerState<_QRCodeDialog> {
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: const Text('关闭'),
|
||||
),
|
||||
FilledButton.icon(
|
||||
onPressed: _bytes == null ? null : (_printing ? null : _print),
|
||||
icon: _printing
|
||||
? const SizedBox(
|
||||
width: 14, height: 14,
|
||||
child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white))
|
||||
: const Icon(Icons.print, size: 16),
|
||||
label: const Text('打印'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user