import 'dart:async'; import 'package:flyinsono/architecture/utils/prompt_box.dart'; import 'package:flyinsono/lab/architecture/task_center.dart'; import 'package:flyinsono/lab/color/lab_colors.dart'; import 'package:flyinsono/lab/components/classify_data_selector/classify_data_selector.dart'; import 'package:flyinsono/lab/components/lab_dialog.dart'; import 'package:flyinsono/lab/manager/interfaces/analysis.dart'; import 'package:flyinsono/lab/manager/interfaces/project.dart'; import 'package:flyinsono/lab/manager/interfaces/task.dart'; import 'package:flyinsono/lab/manager/page_manager.dart'; import 'package:flyinsono/lab/mixin/tab_hook_mixin.dart'; import 'package:flyinsono/lab/pages/lab_data/controller.dart'; import 'package:flyinsono/lab/router/lab_route_names.dart'; import 'package:flyinsono/managers/interfaces/entities/task_info.dart'; import 'package:flyinsono/managers/interfaces/remedical.dart'; import 'package:flyinsono/pages/schedule/schedule_notification/schedule_notification_controller.dart'; import 'package:get/get.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:intl/intl.dart'; import 'index.dart'; import 'package:fis_common/index.dart'; class LabTaskController extends GetxController with TabHookMixin { LabTaskController({required this.tabHashCode}); @override final int tabHashCode; static const taskPageId = "task_page_id"; // 页面id static const headerPanelId = "header_panel_id"; // 头部面板 static const taskListId = "task_list_id"; // 任务列表 static const taskDetailListId = "task_detail_list_id"; // 任务详情 final state = LabTaskState(); final serverTaskManager = Get.find(); /// 项目接口 final projectManager = Get.find(); // 任务数据总览 List> taskStatusClassifyData = []; //任务分类(进行中、已完成) int selectedClassifyIndex = 0; //分类中选中的位置 int selectedTaskIndex = 0; // 任务详情列表(deepcopy) List taskDetailList = []; // 当前不存在任何任务 bool noProcessingTask = false; ClassifyData get selectedClassify => taskStatusClassifyData.isNotEmpty ? taskStatusClassifyData[selectedClassifyIndex] : ClassifyData( classifyName: "", data: [], ); ///当前选中的任务 TaskBaseDTO? get currentSelectedTask => selectedClassify.data.isNotEmpty ? selectedClassify.data[selectedTaskIndex] : null; // 轮询定时器(用于获取当前选中的任务详情进度) Timer? timer; TaskInfo currentTaskInfo = TaskInfo( complateCount: 0, elapsedTime: '', startTime: '', title: '', totalCount: 0, patientCode: ""); void onTaskClick(int classifyIndex, int itemIndex) { selectedClassifyIndex = classifyIndex; selectedTaskIndex = itemIndex; _updateTaskDetailList(); if (currentSelectedTask?.status == VTaskStatus.Processing || currentSelectedTask?.status == VTaskStatus.Unhandled) { startUpdateTimer(); } update([taskListId]); } // 开启定时器 void startUpdateTimer() { if (timer != null) { return; } timer = Timer.periodic( Duration(milliseconds: 1000), (timer) { print("定时器执行 $tabHashCode"); ///如果是未完成的状态才需要更新状态 if (currentTaskInfo.status.index < VTaskStatus.Completed.index) { _updateTaskDetailList(); } else { updateTaskList(); cancelTimer(); } }, ); } // 销毁定时器 void cancelTimer() { timer?.cancel(); timer = null; } /// 更新任务列表总览 void updateTaskList() async { List processingTasks = localTaskCenter.getTaskList(); for (int i = 0; i < processingTasks.length; i++) { if ([VTaskStatus.Completed, VTaskStatus.Canceled] .contains(processingTasks[i].status)) { processingTasks.removeAt(i); } } List serverProjects = await serverTaskManager.getTaskList(status: VTaskStatus.Processing); ///若Server任务和本地任务有相同的,以本地任务为准 serverProjects = serverProjects .where((element) => !processingTasks.any((e) => e.code == element.code)) .toList(); processingTasks.addAll(serverProjects); processingTasks = updateTaskName(processingTasks); processingTasks.sort((a, b) { // 比较两个TaskBaseDTO对象的createTime属性 if (a.createTime == null && b.createTime == null) { return 0; // 都是null,视为相等 } else if (a.createTime == null) { return 1; // null的排在后面 } else if (b.createTime == null) { return -1; // null的排在后面 } else { return b.createTime!.compareTo(a.createTime!); // 按照时间降序排列,最近的时间排在最前面 } }); List completeTasks = await serverTaskManager.getTaskList(status: VTaskStatus.Completed); completeTasks = updateTaskName(completeTasks); taskStatusClassifyData = [ ClassifyData( classifyName: "进行中(${processingTasks.length})", data: processingTasks), ClassifyData( classifyName: "已完成(${completeTasks.length})", data: completeTasks), ]; _updateTaskDetailList(); update([taskListId]); if (processingTasks.isEmpty) { noProcessingTask = true; update([taskPageId]); } } List updateTaskName(List sourceTasks) { for (TaskBaseDTO p in sourceTasks) { if (p.taskName.isNullOrEmpty) { p.taskName = _getTaskNameByTaskType(p.taskType); var createTime = p.createTime?.toLocal(); if (createTime != null) { DateFormat formatter = DateFormat('yyyy-MM-dd-HH:mm'); String formattedDate = formatter.format(createTime); p.taskName = "${p.taskName}-$formattedDate"; } } } return sourceTasks; } // 查看已完成的任务详情 Future viewTaskDetail(TaskDetail task, String? patientCode) async { print("查看任务详情"); String taskCode = task.taskCode ?? ''; TaskDTO? taskInfo = await Get.find().getTaskDetail(taskCode); if (taskInfo == null) { PromptBox.toast("获取任务失败"); return; } var remedicalCode = taskInfo.businessCode ?? ''; RemedicalInfoDTO imageInfo = await Get.find().findRemedicalByCode(remedicalCode); String recordCode = imageInfo.recordCode ?? ''; String projectCode = imageInfo.projectCode ?? ''; PageCollection? researchProjectData = await projectManager.getResearchProjectDataPagesAsync( projectCode: projectCode, keyWord: "", pageSize: 1, pageIndex: 1, sort: 0, ); print("recordCode:$recordCode"); PageManager.ins.openTab( LabRouteNames.Data, args: LabDataActiveArguments( patientCode: patientCode ?? '', projectCode: projectCode, ), ); // PageManager.ins.openTab( // LabRouteNames.Image, // args: LabImageActiveArguments( // patient: selectedPatient, // record: selectedRecord, // images: imageList, // selectedImageIndex: index, // patientType: patientType, // ), // ); } @override void onSleep() { cancelTimer(); serverTaskManager.onReceiveNotification .removeListener(onReceiveNotification); } @override void onActive(arguments) { startUpdateTimer(); updateTaskList(); } /// 在 widget 内存中分配后立即调用。 @override void onInit() { super.onInit(); } /// 在 onInit() 之后调用 1 帧。这是进入的理想场所 @override void onReady() { super.onReady(); startUpdateTimer(); updateTaskList(); serverTaskManager.onReceiveNotification.addListener(onReceiveNotification); } /// 在 [onDelete] 方法之前调用。 @override void onClose() { super.onClose(); cancelTimer(); serverTaskManager.onReceiveNotification .removeListener(onReceiveNotification); } /// dispose 释放内存 @override void dispose() { super.dispose(); cancelTimer(); } Future _updateTaskDetailList() async { String currentSelectedTaskId = currentSelectedTask?.code ?? ""; if (currentSelectedTaskId.isEmpty) { return; } List localTasks = localTaskCenter.getLocalTasks(currentSelectedTaskId); if (localTasks.isNotEmpty) { taskDetailList = localTasks; currentTaskInfo = localTaskCenter.getTaskInfo(currentSelectedTaskId)!; if ([VTaskStatus.Completed, VTaskStatus.Canceled] .contains(currentTaskInfo.status)) { var targetTask = localTasks .firstWhereOrNull((element) => element.id == currentSelectedTaskId); if (targetTask != null) { localTasks.remove(targetTask); } taskDetailList = localTasks; updateTaskList(); } if (localTasks.isNotEmpty) { noProcessingTask = false; } } if (localTasks.isEmpty) { MainTaskDTO? serverTaskInfo = await Get.find() .getMainTaskDetailAsync(currentSelectedTaskId); if (serverTaskInfo != null) { taskDetailList = []; for (TaskDetail task in serverTaskInfo.taskDetailList ?? []) { if (task.name.isNullOrEmpty) { task.name = task.taskCode; } if (task.description.isNullOrEmpty) { task.description = task.rate.toStringAsFixed(2).replaceAll(RegExp(r'\.00$'), '') + "%"; } taskDetailList.add(task); } taskDetailList = serverTaskInfo.taskDetailList ?? []; if (taskDetailList.isNotEmpty) { noProcessingTask = false; } int complateCount = taskDetailList .where((element) => element.status == VTaskStatus.Completed) .length; DateFormat formatter = DateFormat('yyyy-MM-dd HH:mm:ss'); var startTime = serverTaskInfo.createTime?.toLocal() ?? DateTime.now(); String formattedDate = formatter.format(startTime); Duration difference; var endTime = serverTaskInfo.endTime?.toLocal(); if (endTime == null || endTime.year == 1) { difference = DateTime.now().difference(startTime); } else { difference = endTime.difference(startTime); } // 提取分钟和秒钟 int minutes = difference.inMinutes; int seconds = difference.inSeconds % 60; String elapsedTime = '${minutes}min${seconds}s'; currentTaskInfo = TaskInfo( complateCount: complateCount, elapsedTime: elapsedTime, startTime: formattedDate, status: serverTaskInfo.status, title: _getTaskNameByTaskType(serverTaskInfo.taskType), totalCount: taskDetailList.length, patientCode: serverTaskInfo.patientCode); } } update([taskPageId, taskDetailListId, headerPanelId]); } String _getTaskNameByTaskType(VTaskType status) { switch (status) { case VTaskType.Analysis: return "URM 分析"; case VTaskType.DeviceUpload: return "上传"; case VTaskType.UserExport: return "数据导出"; case VTaskType.UserImport: return "数据导入"; case VTaskType.URMSaveVideo: return "视频保存"; default: return ""; } } Future cancelCurrentTask() async { cancelTimer(); String currentSelectedTaskId = currentSelectedTask?.code ?? ""; if (currentSelectedTaskId.isEmpty) { return; } if (currentSelectedTask?.taskType == VTaskType.UserExport || currentSelectedTask?.taskType == VTaskType.UserImport) { TaskInfo? task = localTaskCenter.getTaskInfo(currentSelectedTaskId); if (task != null) { localTaskCenter.canCelTask(currentSelectedTaskId); } else { bool result = await Get.find() .canCelTasks(currentSelectedTaskId, taskDetailList); if (result) { PromptBox.toast("取消成功"); } } } else { if (taskDetailList.any((element) => element.rate == 100)) { PromptBox.toast("当前没有可以取消的任务"); } else { var dialogResult = await Get.dialog( LabDialog( title: "提示", content: "处理中的任务无法取消,是否取消待开始的任务?", ), barrierColor: LabColors.base100.withOpacity(0.1), ); if (dialogResult) { bool result = await Get.find() .cancelAnalysis(currentSelectedTaskId); if (result) { PromptBox.toast("取消成功"); } } } } updateTaskList(); Future.delayed(Duration(milliseconds: 1000), () { updateTaskList(); }); //3秒是壳子通讯超时时间 Future.delayed(Duration(milliseconds: 3100), () { updateTaskList(); }); } void onReceiveNotification(Object sender, ApplicationNotification e) { String currentSelectedTaskId = currentSelectedTask?.code ?? ""; print("通知接收:${e.code}"); if (e.code == currentSelectedTaskId) { Future.delayed(Duration(milliseconds: 800), () { updateTaskList(); }); } } }