初始化

This commit is contained in:
zhu
2026-03-10 13:36:40 +08:00
commit b03e64957c
111 changed files with 4536 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
//下载文件
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class LocalDownload {
static Future<String> getLocalFilePath(String url, String path) async {
Uri uri = Uri.parse(url);
String fileName = uri.pathSegments.last;
//获取下载目录
Directory dir = await getApplicationCacheDirectory();
Directory uploadPath = Directory("${dir.path}$path/");
return uploadPath.path + fileName;
}
/// 公用下载方法
/// url 下载网络地址
/// path 存储地址,如/test
/// onProgress 下载回调函数
/// onDone 下载完毕回调
static downLoadFile({
required url,
required path,
required Function(double) onProgress,
required Function(String) onDone,
}) async {
HttpClient client = HttpClient();
Uri uri = Uri.parse(url);
//获取本地文件路径
String filePath = await getLocalFilePath(url, path);
// 发起 get 请求
HttpClientRequest request = await client.getUrl(uri);
// 响应
HttpClientResponse response = await request.close();
int contentLength = response.contentLength; // 获取文件总大小
int bytesReceived = 0; // 已接收的字节数
List<int> chunkList = [];
if (response.statusCode == 200) {
response.listen(
(List<int> chunk) {
chunkList.addAll(chunk);
bytesReceived += chunk.length; //更新已接受的字节数
//进度
double progress = bytesReceived * 100 / contentLength * 100;
progress = (progress / 100).truncateToDouble();
onProgress(progress);
},
onDone: () async {
//下载完毕
client.close();
File file = File(filePath);
if (!file.existsSync()) {
file.createSync(recursive: true);
await file.writeAsBytes(chunkList);
}
onDone(file.path);
},
onError: () {
client.close();
},
cancelOnError: true,
);
}
}
///获取本地地址
///
static Future<String> getFilePath({
required url,
required path,
}) async {
//获取本地文件路径
String filePath = await getLocalFilePath(url, path);
File file = File(filePath);
if (file.existsSync()) {
return file.path;
} else {
return '';
}
}
}

View File

@@ -0,0 +1,46 @@
enum FileType {
image,
pdf,
other,
}
class FileMeta {
final String name; // 不含后缀
final String extension; // 不含点
final FileType type;
const FileMeta({
required this.name,
required this.extension,
required this.type,
});
}
FileMeta parseFileMeta(String path) {
final uri = Uri.parse(path);
final fileName = uri.pathSegments.isNotEmpty ? uri.pathSegments.last : '';
if (!fileName.contains('.')) {
return const FileMeta(
name: '',
extension: '',
type: FileType.other,
);
}
final index = fileName.lastIndexOf('.');
final name = fileName.substring(0, index);
final ext = fileName.substring(index + 1).toLowerCase();
final type = switch (ext) {
'jpg' || 'jpeg' || 'png' || 'webp' || 'gif' => FileType.image,
'pdf' => FileType.pdf,
_ => FileType.other,
};
return FileMeta(
name: name,
extension: ext,
type: type,
);
}

View File

@@ -0,0 +1,70 @@
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
/// 选择文件
/// - [type] 文件类型
/// - [allowedExtensions] 允许的扩展名
/// - [maxSize] 最大文件大小
Future<List<File>> selectFile({
required FileType type,
List<String>? allowedExtensions,
int maxSize = 1024 * 1024 * 20,
}) async {
List<File> files = [];
bool hasOversize = false;
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: type,
allowedExtensions: allowedExtensions,
);
// 判断空
if (result == null) return [];
//进行文件大小,压缩、等操作
for (final e in result.files) {
if (e.size > maxSize) {
hasOversize = true;
continue;
}
if (e.path == null) continue;
if (type == FileType.image) {
final compressed = await compressImage(File(e.path!));
files.add(compressed);
} else {
files.add(File(e.path!));
}
}
//提示
if (hasOversize) {
EasyLoading.showInfo('已过滤超过 20MB 的文件');
}
return files;
}
/// 压缩图片
Future<File> compressImage(File file) async {
final dir = await getTemporaryDirectory();
final targetPath = p.join(
dir.path,
'${DateTime.now().millisecondsSinceEpoch}.jpg',
);
final result = await FlutterImageCompress.compressAndGetFile(
file.absolute.path,
targetPath,
quality: 80,
format: CompressFormat.jpeg,
minWidth: 1080,
minHeight: 1080,
);
if (result == null) {
throw Exception('Image compression failed');
}
return File(result.path);
}

View File

@@ -0,0 +1,59 @@
import 'dart:io';
import 'package:app/data/api/common_api.dart';
import 'package:app/data/models/common/qiu_token_dto.dart';
import 'package:crypto/crypto.dart';
import 'package:dio/dio.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import '../../config/global.dart';
class QinUpload {
///获取七牛token
static Future<QiuTokenDto> _getQiuToken(File file, String path) async {
// 读取文件的字节数据
final fileBytes = await file.readAsBytes();
String fileMd5 = md5.convert(fileBytes).toString();
//前缀
var prefix = Config.getEnv() == "dev" ? "test" : "release";
var suffix = file.path.split(".").last;
var res = await getQiuTokenApi(
"shangyiapp/$prefix/$path/$fileMd5.$suffix",
);
return res;
}
///上传文件
/// - [file] 文件
/// - [path] 目标目录,不以/开头和结尾
static Future<String?> upload({
required File file,
required String path,
}) async {
var qiuToken = await _getQiuToken(file, path);
//数据
FormData formData = FormData.fromMap({
"file": await MultipartFile.fromFile(file.path),
"token": qiuToken.upToken,
"fname": qiuToken.fileKey,
"key": qiuToken.fileKey,
});
try {
Dio dio = Dio();
Response response = await dio.post(
qiuToken.uploadUrl!,
data: formData,
onSendProgress: (int sent, int total) {
// double progress = sent * 100 / total * 100;
// progress = (progress / 100).truncateToDouble();
},
);
String key = response.data['key'];
return "https://${qiuToken.domain}/$key";
} catch (e) {
EasyLoading.showError("上传失败");
return null;
}
}
}