upload_dialog.dart 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  4. import 'package:vitalapp/components/alert_dialog.dart';
  5. import 'package:vitalapp/database/entities/defines.dart';
  6. import 'package:vitalapp/database/entities/patient.dart';
  7. import 'package:vitalapp/global.dart';
  8. import 'package:vitalapp/managers/interfaces/data_sync.dart';
  9. class _SyncUploadDialogController extends GetxController {
  10. final syscManager = Get.find<IDataSyncManager>();
  11. /// 数据列表
  12. final dataList = RxList<PatientEntity>();
  13. /// 已上传数量
  14. final uploadedCount = RxInt(0);
  15. /// 数据总量
  16. int get totalCount => dataList.length;
  17. /// 当前处理索引
  18. int get handleIndex => uploadedCount.value;
  19. /// 当前处理数据
  20. PatientEntity? get handleData {
  21. if (dataList.isEmpty) {
  22. return null;
  23. }
  24. if (handleIndex == dataList.length) {
  25. return dataList.last;
  26. }
  27. return dataList[handleIndex];
  28. }
  29. @override
  30. void onReady() {
  31. super.onReady();
  32. _run();
  33. }
  34. Future<void> _run() async {
  35. final loaded = await _loadData();
  36. // 无数据也要等待页面显示一会
  37. await Future.delayed(const Duration(seconds: 1));
  38. if (!loaded) {
  39. PromptBox.toast("未查询到待上传记录");
  40. Get.back(result: false);
  41. return;
  42. }
  43. for (var i = 0; i < totalCount; i++) {
  44. if (!kIsOnline) {
  45. PromptBox.toast("请检查网络连接");
  46. Get.back(result: false);
  47. return;
  48. }
  49. final success = await _handleSingle();
  50. if (success) {
  51. } else {
  52. PromptBox.toast("上传 ${handleData?.name} 失败");
  53. await Future.delayed(const Duration(milliseconds: 500));
  54. }
  55. uploadedCount.value = uploadedCount.value + 1;
  56. // 等进度更新展示一下
  57. await Future.delayed(const Duration(milliseconds: 500));
  58. }
  59. if (uploadedCount > 0) {
  60. await Future.delayed(const Duration(milliseconds: 500));
  61. PromptBox.toast("批量同步结束");
  62. }
  63. Get.back(result: true);
  64. }
  65. Future<bool> _handleSingle() async {
  66. final data = dataList[handleIndex];
  67. final result = await syscManager.syncPatientAllData(data.code);
  68. return result;
  69. }
  70. Future<bool> _loadData() async {
  71. final list = await syscManager.getPatientWaitUploadAllList();
  72. if (list.isEmpty) {
  73. await Future.delayed(const Duration(milliseconds: 500));
  74. PromptBox.toast("暂无离线数据需要同步");
  75. Get.back(result: false);
  76. return false;
  77. }
  78. dataList.value = list;
  79. return true;
  80. }
  81. }
  82. class SyncUploadDialog extends GetView<_SyncUploadDialogController> {
  83. const SyncUploadDialog({super.key});
  84. static Future<bool> show() async {
  85. final result = await Get.dialog(
  86. const SyncUploadDialog(),
  87. barrierDismissible: false,
  88. );
  89. return result;
  90. }
  91. @override
  92. Widget build(BuildContext context) {
  93. return VAlertDialog(
  94. content: _buildBody(context),
  95. onCanceled: () {
  96. return false;
  97. },
  98. );
  99. }
  100. Widget _buildBody(BuildContext context) {
  101. return GetBuilder<_SyncUploadDialogController>(
  102. init: _SyncUploadDialogController(),
  103. builder: (context) {
  104. return Obx(() {
  105. // if (!controller.isRunning) {
  106. // return const SizedBox();
  107. // }
  108. final data = controller.handleData;
  109. return Container(
  110. height: 280,
  111. alignment: Alignment.center,
  112. child: data != null
  113. ? _SyncProgress(
  114. uploadedCount: controller.uploadedCount.value,
  115. totalCount: controller.totalCount,
  116. patientName: data.name,
  117. )
  118. : const SizedBox(
  119. width: 28,
  120. height: 28,
  121. child: CircularProgressIndicator(),
  122. ),
  123. );
  124. });
  125. },
  126. );
  127. }
  128. }
  129. class _SyncProgress extends StatelessWidget {
  130. static final textStyle = TextStyle(fontSize: 20, color: Colors.grey.shade700);
  131. static const textSpace = SizedBox(width: 12);
  132. final int uploadedCount;
  133. final int totalCount;
  134. final String patientName;
  135. const _SyncProgress({
  136. required this.uploadedCount,
  137. required this.totalCount,
  138. required this.patientName,
  139. });
  140. @override
  141. Widget build(BuildContext context) {
  142. return Column(
  143. mainAxisSize: MainAxisSize.max,
  144. mainAxisAlignment: MainAxisAlignment.end,
  145. crossAxisAlignment: CrossAxisAlignment.center,
  146. children: [
  147. const SizedBox(
  148. width: 28,
  149. height: 28,
  150. child: CircularProgressIndicator(),
  151. ),
  152. const SizedBox(height: 36),
  153. Row(
  154. mainAxisSize: MainAxisSize.min,
  155. children: [
  156. Text(
  157. "正在上传",
  158. style: textStyle,
  159. ),
  160. textSpace,
  161. Text(
  162. patientName,
  163. style: const TextStyle(fontSize: 20, color: Colors.black),
  164. ),
  165. textSpace,
  166. Text(
  167. "的离线数据",
  168. style: textStyle,
  169. ),
  170. ],
  171. ),
  172. const SizedBox(height: 20),
  173. Row(
  174. mainAxisSize: MainAxisSize.min,
  175. children: [
  176. Text(
  177. "已上传居民",
  178. style: TextStyle(fontSize: 18, color: Colors.grey.shade700),
  179. ),
  180. textSpace,
  181. Text(
  182. uploadedCount.toString(),
  183. style: const TextStyle(
  184. fontSize: 20,
  185. color: Colors.green,
  186. fontWeight: FontWeight.bold,
  187. ),
  188. ),
  189. Text(" /", style: textStyle),
  190. Text(
  191. "$totalCount",
  192. style: const TextStyle(fontSize: 20, color: Colors.black),
  193. ),
  194. textSpace,
  195. Text("人", style: textStyle),
  196. ],
  197. ),
  198. const SizedBox(height: 20),
  199. ],
  200. );
  201. }
  202. }