import 'dart:io'; import 'package:auto_route/annotations.dart'; import 'package:dio/dio.dart'; import 'package:eitc_erm_dental_flutter/entity/clinic_info.dart'; import 'package:eitc_erm_dental_flutter/exts.dart'; import 'package:eitc_erm_dental_flutter/funcs.dart'; import 'package:eitc_erm_dental_flutter/global.dart'; import 'package:eitc_erm_dental_flutter/http/gzkj_response.dart'; import 'package:eitc_erm_dental_flutter/http/http.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:percent_indicator/percent_indicator.dart' as pi; import '../../entity/history_item_info.dart'; ///上传页面 @RoutePage(name: "uploadRoute") class UploadPage extends StatefulWidget { //医院信息 final ClinicInfo clinicInfo; ///要上传的历史记录列表 final List uploadList; ///是否是从查看页面上传 final bool isFromView; const UploadPage( {super.key, required this.uploadList, required this.clinicInfo, required this.isFromView}); @override State createState() => _UploadPageState(); } class _UploadPageState extends State { ///是否正在上传 bool _isUploading = false; ///是否显示停止上传dialog bool _isStopDialogShow = false; ///上传进度 double _uploadProgress = 0.0; CancelToken? cancelToken; ///上传索引 int _uploadingIndex = 0; //上传数量 int _uploadCount = 0; @override void initState() { super.initState(); screenDisableRotate(); WidgetsBinding.instance.addPostFrameCallback((_) => _startUpload()); } @override void dispose() { super.dispose(); cancelToken?.cancel(); cancelToken = null; //如果是从查看页面上传的,就需要恢复屏幕旋转 if (widget.isFromView) { screenEnableRotate(); } } @override Widget build(BuildContext context) { return PopScope( canPop: !_isUploading, onPopInvokedWithResult: _onPop, child: Scaffold( resizeToAvoidBottomInset: false, appBar: _getAppBar(), body: SafeArea( child: Padding( padding: EdgeInsets.only(top: 52.h), child: _isUploading ? _UploadingView( progress: _uploadProgress, fileIndex: _uploadingIndex, fileCount: _uploadCount, ) : SizedBox(), )), )); } ///获取appbar AppBar _getAppBar() { return AppBar( title: Text(getS().upload), ); } ///返回控制 void _onPop(bool didPop, dynamic result) async { if (didPop) { return; } _showStopDialog(); } ///显示停止弹窗 void _showStopDialog() async { _isStopDialogShow = true; bool? bo = await showDialog( context: context, barrierDismissible: false, builder: (ctx) => AlertDialog( title: Text(getS().hint), content: Text(getS().stopUploadAlert), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: Text(getS().cancel)), TextButton( onPressed: () => Navigator.pop(ctx, true), child: Text(getS().confirm)), ], )); _isStopDialogShow = false; if (bo == null || !bo) { return; } _stopUpload(); } ///关闭退出弹窗 void _dismissStopDialog() { if (!_isStopDialogShow) { return; } Navigator.pop(context, false); } ///开始上传 void _startUpload() { _doUpload(); } ///停止上传 void _stopUpload() { _dismissStopDialog(); setState(() { _isUploading = false; _uploadProgress = 0.0; cancelToken?.cancel(); cancelToken = null; }); } ///执行上传 void _doUpload() async { List toUploadList = []; Stream stream = Stream.fromIterable(widget.uploadList); await for (HistoryItemInfo info in stream) { //检查文件是否存在 if (await File(info.path).exists()) { toUploadList.add(info); } } //没有可上传的文件 if (toUploadList.isEmpty) { _showNothingToUpload(); return; } _uploadCount = toUploadList.length; logd("上传数量=$_uploadCount"); stream = Stream.fromIterable(toUploadList); //刷新页面 setState(() { _isUploading = true; }); await for (HistoryItemInfo info in stream) { File file = File(info.path); String suffix = file.path.substring(file.path.lastIndexOf(".")); String fileName = "HS${info.prefixInfo?.idCard ?? ""}_${info.time}$suffix"; MultipartFile part = await MultipartFile.fromFile(file.path, filename: fileName); cancelToken = CancelToken(); String deviceModel = info.prefixInfo?.wifi.replaceAll(deviceWifiPrefix, "") ?? ""; Map map = { "deviceID": deviceModel, "applicationKey": uploadApplicationKey, "idCardNo": info.prefixInfo?.idCard ?? "", "fileType": uploadFileType, "fileMedium": suffix, "fileName": fileName, "chunkData": part, }; FormData formData = FormData.fromMap(map); logd("上传数据=$map"); try { GzkjResponse response = await Http.instance.uploadGzkj( widget.clinicInfo.clinicApiUrl ?? "", data: formData, cancelToken: cancelToken, onSendProgress: _onUploadProgress, fromJsonT: (_) => 0); if (!response.isSuccess) { _showUploadExceptionDialog( response.message ?? getS().uploadFailedPleaseRetry); logd("上传失败,msg=${response.message}"); break; } else { //都上传完了 if (_uploadingIndex >= _uploadCount - 1) { _showUploadSuccessDialog(); break; } else { //刷新界面 setState(() { _uploadProgress = 0.0; _uploadingIndex++; logd("上传下一个,index=$_uploadingIndex"); }); } } } catch (e) { loge("上传失败", error: e); _showUploadExceptionDialog(getS().uploadFailedPleaseRetry); break; } } } ///显示上传成功弹窗 void _showUploadSuccessDialog() async { _dismissStopDialog(); await showDialog( context: context, builder: (ctx) => AlertDialog( title: Text(getS().hint), content: Text(getS().uploadSuccess), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text(getS().confirm)) ], )); if (mounted) { Navigator.pop(context); } } ///显示上传错误弹窗 void _showUploadExceptionDialog(String str) async { if (!_isUploading) { return; } _dismissStopDialog(); if (context.mounted) { await showDialog( context: context, builder: (ctx) { return AlertDialog( title: Text(getS().uploadFailed), content: Text(str), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text(getS().confirm)) ], ); }); if (mounted) { Navigator.pop(context); } } } ///显示没有可上传的文件的提示框 void _showNothingToUpload() async { _isUploading = false; if (context.mounted) { await showDialog( context: context, builder: (ctx) { return AlertDialog( title: Text(getS().hint), content: Text(getS().noFileCanUpload), actions: [ TextButton( onPressed: () => Navigator.pop(ctx), child: Text(getS().close)) ], ); }); if (mounted) { Navigator.pop(context); } } } //假的接口错误 void _fakeInterfaceError() async { await Future.delayed(const Duration(seconds: 2)); _showUploadExceptionDialog(getS().uploadFailedByInterfaceError); } ///上传进度 void _onUploadProgress(int count, int total) { double progress = count.toDouble() / total.toDouble(); /*logd( "上传进度,count=$count,total=$total,progress=$progress,uploadingIndex=$_uploadingIndex,uploadCount=$_uploadCount");*/ setState(() { _uploadProgress = progress; }); } } ///上传中视图 class _UploadingView extends StatelessWidget { ///进度,范围0到1 final double progress; final int fileIndex; final int fileCount; const _UploadingView( {required this.progress, required this.fileIndex, required this.fileCount}); @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.symmetric(horizontal: 30.w), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( getS().uploadingHint, style: context.titleMedium, ), SizedBox( height: 40.h, ), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ pi.LinearPercentIndicator( percent: progress, lineHeight: 15.h, progressColor: context.primaryColor, barRadius: Radius.circular(15.h), padding: EdgeInsets.zero, center: Text( "${(progress * 100.0).round()}%", style: TextStyle(fontSize: 12.sp, color: Colors.white), )), SizedBox( height: 5.h, ), Text("${fileIndex + 1}/$fileCount") ], ), ], ), ); } }