import 'dart:typed_data'; import 'package:flutter/material.dart'; import 'package:tdesign_flutter/tdesign_flutter.dart'; import '../../core/i18n/app_localizations.dart'; import '../../core/navigation/host_app_channel.dart'; import '../models/bill_attachment.dart'; import '../widgets/loading_dialog.dart'; /// 附件下载辅助类,供详情页复用下载逻辑。 class AttachmentDownloadHelper { /// 根据扩展名返回 MIME 类型 static String mimeType(String ext) { switch (ext.toLowerCase()) { case 'pdf': return 'application/pdf'; case 'doc': return 'application/msword'; case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; case 'xls': return 'application/vnd.ms-excel'; case 'xlsx': return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; case 'jpg': case 'jpeg': return 'image/jpeg'; case 'png': return 'image/png'; case 'gif': return 'image/gif'; case 'bmp': return 'image/bmp'; case 'webp': return 'image/webp'; default: return 'application/octet-stream'; } } /// 下载附件并保存到公共目录,成功显示路径弹窗。 static Future downloadAndSave( BuildContext context, BillAttachment attachment, Future Function(String id) downloader, ) async { final l10n = AppLocalizations.of(context); try { LoadingDialog.show(context, text: l10n.get('downloading')); final bytes = await downloader(attachment.id); if (!context.mounted) return; LoadingDialog.hide(context); if (bytes == null) { TDToast.showText(l10n.get('downloadFailed'), context: context); return; } final path = await HostAppChannel.saveFileToDownloads( bytes, attachment.fileName, mimeType(attachment.ext), ); if (!context.mounted) return; if (path != null) { _showSuccessDialog(context, l10n, path); } else { TDToast.showText(l10n.get('downloadFailed'), context: context); } } catch (_) { if (context.mounted) LoadingDialog.hide(context); if (context.mounted) { TDToast.showText(l10n.get('downloadFailed'), context: context); } } } static void _showSuccessDialog( BuildContext context, AppLocalizations l10n, String path, ) { showGeneralDialog( context: context, pageBuilder: (buildContext, animation, secondaryAnimation) { return TDConfirmDialog( title: l10n.get('downloadSuccess'), content: path, buttonStyle: TDDialogButtonStyle.text, buttonText: l10n.get('confirm'), ); }, ); } }