| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158 |
- 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<File>)? onUpload;
- final Function(double)? onProgress;
- final List<String>? accept;
- final double? maxSize;
- const UploadZone({
- Key? key,
- this.onUpload,
- this.onProgress,
- this.accept,
- this.maxSize,
- }) : super(key: key);
- @override
- State<UploadZone> createState() => _UploadZoneState();
- }
- class _UploadZoneState extends State<UploadZone> {
- bool _isDragging = false;
- bool _isUploading = false;
- double _uploadProgress = 0.0;
- @override
- Widget build(BuildContext context) {
- return DragTarget<List<File>>(
- 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<Color>(
- AppColors.primary,
- ),
- ),
- ),
- const SizedBox(height: 8),
- Text(
- '${(_uploadProgress * 100).toInt()}%',
- style: const TextStyle(
- fontSize: 12,
- color: AppColors.textSecondary,
- ),
- ),
- ],
- ],
- ),
- ),
- );
- },
- );
- }
- Future<void> _pickFiles() async {
- // 这里应该使用 file_picker,但为了演示使用静态数据
- // 实际项目中应该调用 FilePicker.platform.pickFiles()
- _simulateUpload();
- }
- Future<void> _handleFiles(List<File> files) async {
- _simulateUpload();
- }
- Future<void> _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([]);
- }
- }
|