attachment_file.dart 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import 'dart:io';
  2. import 'package:dio/dio.dart';
  3. import 'package:file_picker/file_picker.dart';
  4. import 'package:image_picker/image_picker.dart';
  5. class AttachmentFile {
  6. final String path;
  7. final String name;
  8. final int sizeBytes;
  9. final String extension;
  10. final String mimeType;
  11. const AttachmentFile({
  12. required this.path,
  13. required this.name,
  14. required this.sizeBytes,
  15. required this.extension,
  16. required this.mimeType,
  17. });
  18. /// 根据扩展名判断是否为图片
  19. bool get isImage {
  20. const imageExts = {'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'heic'};
  21. return imageExts.contains(extension);
  22. }
  23. /// 从本地路径创建(读取文件大小)
  24. static Future<AttachmentFile> fromPath(String path) async {
  25. final name = _extractName(path);
  26. final ext = _extractExt(name);
  27. final size = await File(path).length();
  28. return AttachmentFile(
  29. path: path,
  30. name: name,
  31. sizeBytes: size,
  32. extension: ext,
  33. mimeType: _inferMimeType(ext),
  34. );
  35. }
  36. /// 从 FilePicker 的 PlatformFile 创建
  37. factory AttachmentFile.fromPlatformFile(PlatformFile file) {
  38. final name = file.name;
  39. final ext = _extractExt(name);
  40. return AttachmentFile(
  41. path: file.path ?? '',
  42. name: name,
  43. sizeBytes: file.size,
  44. extension: ext,
  45. mimeType: _inferMimeType(ext),
  46. );
  47. }
  48. /// 从 ImagePicker 的 XFile 创建
  49. static Future<AttachmentFile> fromXFile(XFile xfile) async {
  50. final name = _extractName(xfile.path);
  51. final ext = _extractExt(name);
  52. final size = await xfile.length();
  53. return AttachmentFile(
  54. path: xfile.path,
  55. name: name,
  56. sizeBytes: size,
  57. extension: ext,
  58. mimeType: _inferMimeType(ext),
  59. );
  60. }
  61. /// 转换为 Dio MultipartFile,可直接用于 FormData 上传
  62. Future<MultipartFile> toMultipartFile({String fieldName = 'files'}) {
  63. return MultipartFile.fromFile(
  64. path,
  65. filename: name,
  66. contentType: DioMediaType.parse(mimeType),
  67. );
  68. }
  69. /// 文件大小(MB)
  70. double get sizeMB => sizeBytes / (1024 * 1024);
  71. // ── 私有工具方法 ──
  72. static String _extractName(String path) {
  73. return path.split('/').last.split('\\').last;
  74. }
  75. static String _extractExt(String name) {
  76. return name.split('.').last.toLowerCase();
  77. }
  78. static String _inferMimeType(String ext) {
  79. switch (ext) {
  80. case 'jpg':
  81. case 'jpeg':
  82. return 'image/jpeg';
  83. case 'png':
  84. return 'image/png';
  85. case 'gif':
  86. return 'image/gif';
  87. case 'bmp':
  88. return 'image/bmp';
  89. case 'webp':
  90. return 'image/webp';
  91. case 'heic':
  92. return 'image/heic';
  93. case 'pdf':
  94. return 'application/pdf';
  95. case 'doc':
  96. return 'application/msword';
  97. case 'docx':
  98. return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
  99. case 'xls':
  100. return 'application/vnd.ms-excel';
  101. case 'xlsx':
  102. return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
  103. case 'ppt':
  104. return 'application/vnd.ms-powerpoint';
  105. case 'pptx':
  106. return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
  107. case 'txt':
  108. return 'text/plain';
  109. default:
  110. return 'application/octet-stream';
  111. }
  112. }
  113. }