import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import '../../theme/app_colors.dart'; /// 文件上传区域组件 class UploadZone extends StatefulWidget { final Function(List)? onUpload; final Function(double)? onProgress; final List? accept; final double? maxSize; const UploadZone({ Key? key, this.onUpload, this.onProgress, this.accept, this.maxSize, }) : super(key: key); @override State createState() => _UploadZoneState(); } class _UploadZoneState extends State { bool _isDragging = false; bool _isUploading = false; double _uploadProgress = 0.0; @override Widget build(BuildContext context) { return DragTarget>( onWillAccept: (data) { setState(() => _isDragging = true); return true; }, onLeave: (data) { setState(() => _isDragging = false); }, onAccept: (files) { setState(() => _isDragging = false); _handleFiles(files); }, builder: (context, candidateData, rejectedData) { return GestureDetector( onTap: _isUploading ? null : _pickFiles, child: Container( width: double.infinity, height: 300, decoration: BoxDecoration( color: _isDragging ? AppColors.primary.withOpacity(0.1) : Colors.white, border: Border.all( color: _isDragging ? AppColors.primary : AppColors.border, width: 2, style: BorderStyle.solid, ), borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( LucideIcons.upload, size: 64, color: _isDragging ? AppColors.primary : AppColors.textSecondary, ), const SizedBox(height: 16), Text( _isDragging ? '释放以上传文件' : '拖拽文件到此处', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: _isDragging ? AppColors.primary : AppColors.textPrimary, ), ), const SizedBox(height: 8), Text( '或点击选择文件', style: TextStyle( fontSize: 14, color: AppColors.textSecondary, ), ), const SizedBox(height: 16), Text( '支持格式:${widget.accept?.join(', ') ?? 'PDF, Word, 图片'}', style: TextStyle( fontSize: 12, color: AppColors.textSecondary, ), ), if (_isUploading) ...[ const SizedBox(height: 24), SizedBox( width: 200, child: LinearProgressIndicator( value: _uploadProgress, backgroundColor: AppColors.borderLight, valueColor: const AlwaysStoppedAnimation( AppColors.primary, ), ), ), const SizedBox(height: 8), Text( '${(_uploadProgress * 100).toInt()}%', style: const TextStyle( fontSize: 12, color: AppColors.textSecondary, ), ), ], ], ), ), ); }, ); } Future _pickFiles() async { // 这里应该使用 file_picker,但为了演示使用静态数据 // 实际项目中应该调用 FilePicker.platform.pickFiles() _simulateUpload(); } Future _handleFiles(List files) async { _simulateUpload(); } Future _simulateUpload() async { setState(() { _isUploading = true; _uploadProgress = 0.0; }); // 模拟上传进度 for (int i = 0; i <= 100; i += 20) { await Future.delayed(const Duration(milliseconds: 60)); setState(() { _uploadProgress = i / 100; }); widget.onProgress?.call(_uploadProgress); } setState(() { _isUploading = false; _uploadProgress = 0.0; }); // 模拟文件对象 widget.onUpload?.call([]); } }