controller.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:pull_to_refresh/pull_to_refresh.dart';
  4. import '../../../../common/api/index.dart';
  5. import '../../../../common/models/index.dart';
  6. import '../../../../common/utils/index.dart';
  7. import '../../../../common/values/index.dart';
  8. import '../../../../common/widgets/index.dart';
  9. import '../../../common/process_webview/index.dart';
  10. import 'index.dart';
  11. import 'widgets/QuickProcessing/index.dart';
  12. class OfficeCenterController extends GetxController {
  13. OfficeCenterController();
  14. final state = OfficeCenterState();
  15. final refreshController = RefreshController();
  16. final TextEditingController searchController = TextEditingController();
  17. String? _type;
  18. String _lastId = O2.o2DefaultPageFirstKey;
  19. bool isLoading = false; // 防止重复刷新
  20. bool isRefresh = true; // 刷新还是加载更多
  21. /// 在 widget 内存中分配后立即调用。
  22. @override
  23. void onInit() {
  24. super.onInit();
  25. }
  26. /// 在 onInit() 之后调用 1 帧。这是进入的理想场所
  27. @override
  28. void onReady() {
  29. final type = Get.parameters['type'];
  30. _type = type;
  31. var title = '';
  32. if (O2NativeAppEnum.task.key == type) {
  33. title = O2NativeAppEnum.task.name;
  34. } else if (O2NativeAppEnum.taskcompleted.key == type) {
  35. title = O2NativeAppEnum.taskcompleted.name;
  36. } else if (O2NativeAppEnum.read.key == type) {
  37. title = O2NativeAppEnum.read.name;
  38. } else if (O2NativeAppEnum.readcompleted.key == type) {
  39. title = O2NativeAppEnum.readcompleted.name;
  40. }
  41. state.title = Get.parameters['displayName'] ?? title;
  42. onRefresh();
  43. super.onReady();
  44. }
  45. /// 在 [onDelete] 方法之前调用。
  46. @override
  47. void onClose() {
  48. super.onClose();
  49. }
  50. /// dispose 释放内存
  51. @override
  52. void dispose() {
  53. super.dispose();
  54. }
  55. Future<void> onRefresh() async {
  56. if (_type == null) return;
  57. if (isLoading) return;
  58. _lastId = O2.o2DefaultPageFirstKey;
  59. isRefresh = true;
  60. state.hasMoreData = true;
  61. state.taskSelectedList.clear();
  62. await loadDataFromServer();
  63. refreshController.refreshCompleted();
  64. }
  65. Future<void> onLoadMore() async {
  66. if (isLoading) return;
  67. if (!state.hasMoreData) {
  68. refreshController.loadComplete();
  69. return;
  70. }
  71. isRefresh = false;
  72. await loadDataFromServer();
  73. refreshController.loadComplete();
  74. }
  75. ///
  76. /// 搜索
  77. ///
  78. void onSearch(String key) {
  79. OLogger.d("搜索关键字:$key");
  80. onRefresh();
  81. }
  82. Future<void> clickTask(TaskData task) async {
  83. if (task.work != null && task.work?.isNotEmpty == true) {
  84. await ProcessWebviewPage.open(task.work!,
  85. title: task.title ??
  86. 'process_work_no_title'.trArgs(['${task.processName}']));
  87. onRefresh();
  88. }
  89. }
  90. Future<void> clickTaskCompleted(TaskCompletedData taskcompleted) async {
  91. Loading.show();
  92. final reference = await ProcessSurfaceService.to
  93. .getTaskCompletedReference(taskcompleted.id!);
  94. if (reference != null) {
  95. Loading.dismiss();
  96. openReference(reference.workLogList ?? [], taskCompleted: taskcompleted);
  97. }
  98. }
  99. Future<void> clickRead(ReadData read) async {
  100. Loading.show();
  101. final reference = await ProcessSurfaceService.to.getReadReference(read.id!);
  102. if (reference != null) {
  103. Loading.dismiss();
  104. openReference(reference.workLogList ?? [], read: read);
  105. }
  106. }
  107. Future<void> clickReadCompleted(ReadCompletedData readcompleted) async {
  108. Loading.show();
  109. final reference = await ProcessSurfaceService.to
  110. .getReadCompletedReference(readcompleted.id!);
  111. if (reference != null) {
  112. Loading.dismiss();
  113. openReference(reference.workLogList ?? [], readCompleted: readcompleted);
  114. }
  115. }
  116. /// 展现 workLog 列表
  117. void openReference(List<WorkLog> workLogList,
  118. {TaskCompletedData? taskCompleted,
  119. ReadData? read,
  120. ReadCompletedData? readCompleted}) {
  121. final context = Get.context;
  122. if (context != null) {
  123. String title = '';
  124. String detailTitle = '';
  125. String detailActiviyName = '';
  126. Work work = Work();
  127. if (taskCompleted != null) {
  128. title = 'process_taskcompleted_detail_title'.tr;
  129. detailTitle = '[${taskCompleted.processName}] ${taskCompleted.title}';
  130. detailActiviyName = '${taskCompleted.activityName}';
  131. work.id = taskCompleted.work;
  132. work.title = taskCompleted.title;
  133. work.processName = taskCompleted.processName;
  134. } else if (read != null) {
  135. title = 'process_read_detail_title'.tr;
  136. detailTitle = '[${read.processName}] ${read.title}';
  137. detailActiviyName = '${read.activityName}';
  138. work.id = read.work;
  139. work.title = read.title;
  140. work.processName = read.processName;
  141. } else if (readCompleted != null) {
  142. title = 'process_readcompleted_detail_title'.tr;
  143. detailTitle = '[${readCompleted.processName}] ${readCompleted.title}';
  144. detailActiviyName = '${readCompleted.activityName}';
  145. work.id = readCompleted.work;
  146. work.title = readCompleted.title;
  147. work.processName = readCompleted.processName;
  148. } else {
  149. return;
  150. }
  151. WorkLog? endLog;
  152. for (var element in workLogList) {
  153. if (element.arrivedActivityType == 'end') {
  154. endLog = element.copywith();
  155. endLog.isEnd = true;
  156. break;
  157. }
  158. }
  159. if (endLog != null) {
  160. workLogList.add(endLog);
  161. }
  162. showModalBottomSheet(
  163. context: context,
  164. shape: const RoundedRectangleBorder(
  165. borderRadius: BorderRadius.only(
  166. topLeft: Radius.circular(10.0),
  167. topRight: Radius.circular(10.0)),
  168. ),
  169. builder: ((context) {
  170. return Padding(
  171. padding: const EdgeInsets.all(10),
  172. child: Container(
  173. height: 350.0,
  174. color: Colors.transparent,
  175. child: Column(
  176. crossAxisAlignment: CrossAxisAlignment.start,
  177. children: [
  178. Padding(
  179. padding: const EdgeInsets.all(10),
  180. child: Text(title,
  181. style: Theme.of(context).textTheme.bodyLarge)),
  182. Card(
  183. child: ListTile(
  184. title: Text(detailTitle),
  185. subtitle: Text(detailActiviyName,
  186. style: Theme.of(context).textTheme.bodySmall),
  187. trailing: TextButton(
  188. child: Text('open'.tr),
  189. onPressed: () {
  190. Navigator.of(context).pop();
  191. openWork(work);
  192. }),
  193. ),
  194. ),
  195. Expanded(
  196. flex: 1,
  197. child: ListView(
  198. children: workLogList.map((e) {
  199. var time = e.arrivedTime;
  200. if (time == null || time.isEmpty) {
  201. time = e.fromTime;
  202. }
  203. if ((time?.length ?? 0) > 16) {
  204. time = time!.substring(0, 16);
  205. }
  206. var title = e.fromActivityName ?? '';
  207. var routeName = e.routeName;
  208. var imageName = 'icon_process_pass.png';
  209. List<String> identities = [];
  210. if (e.taskList != null &&
  211. e.taskList!.isNotEmpty) {
  212. for (var task in e.taskList!) {
  213. identities
  214. .add(task.identity!.split('@').first);
  215. }
  216. }
  217. if (e.taskCompletedList != null &&
  218. e.taskCompletedList!.isNotEmpty) {
  219. for (var taskcompleted
  220. in e.taskCompletedList!) {
  221. identities.add(
  222. taskcompleted.identity!.split('@').first);
  223. }
  224. }
  225. if (e.fromActivityType == 'begin') {
  226. routeName = '';
  227. imageName = 'icon_process_begin.png';
  228. }
  229. if (e.isEnd) {
  230. title = e.arrivedActivityName ?? '';
  231. routeName = '';
  232. identities = [];
  233. imageName = 'icon_process_end.png';
  234. }
  235. var subtitle = '';
  236. if (routeName != null && routeName.isNotEmpty) {
  237. subtitle = '$routeName $time';
  238. } else {
  239. subtitle = time ?? '';
  240. }
  241. return IntrinsicHeight(
  242. child: Row(
  243. children: [
  244. AssetsImageView(imageName),
  245. Expanded(
  246. flex: 1,
  247. child: Column(
  248. children: [
  249. Padding(
  250. padding: const EdgeInsets.only(
  251. left: 10,
  252. right: 10,
  253. top: 10,
  254. bottom: 10),
  255. child: Row(
  256. children: [
  257. Expanded(
  258. flex: 1,
  259. child: Column(
  260. crossAxisAlignment:
  261. CrossAxisAlignment
  262. .start,
  263. children: [
  264. Text(
  265. title,
  266. style: Theme.of(
  267. context)
  268. .textTheme
  269. .bodyLarge,
  270. ),
  271. const SizedBox(
  272. height: 5),
  273. Text(subtitle,
  274. style: Theme.of(
  275. context)
  276. .textTheme
  277. .bodySmall)
  278. ],
  279. )),
  280. SizedBox(
  281. width: 48,
  282. child: Text(
  283. identities.join(',')))
  284. ],
  285. )),
  286. // ListTile(
  287. // contentPadding: const EdgeInsets.symmetric(vertical: 10.0),
  288. // title: Text(title),
  289. // subtitle: Text(subtitle,
  290. // style: Theme.of(context)
  291. // .textTheme
  292. // .bodySmall),
  293. // trailing: SizedBox(
  294. // width: 48.w,
  295. // child:
  296. // Text(identities.join(','))),
  297. // ),
  298. const Spacer(),
  299. const Divider(height: 1)
  300. ],
  301. ))
  302. ],
  303. ));
  304. // return ListTile(
  305. // title: Text(time ?? ''),
  306. // subtitle: Text(
  307. // 'process_work_go_to_activity'
  308. // .trArgs([e.activityName ?? '']),
  309. // style: TextStyle(
  310. // color: Theme.of(context)
  311. // .colorScheme
  312. // .primary)),
  313. // );
  314. }).toList()))
  315. ],
  316. )));
  317. }));
  318. }
  319. }
  320. Future<void> openWork(Work work) async {
  321. if (work.id != null && work.id?.isNotEmpty == true) {
  322. await ProcessWebviewPage.open(work.id!,
  323. title: work.title ??
  324. 'process_work_no_title'.trArgs(['${work.processName}']));
  325. onRefresh();
  326. }
  327. }
  328. Future<void> loadDataFromServer() async {
  329. String searchKey = searchController.text;
  330. OLogger.d(
  331. '开始加载数据,type: $_type , lastId: $_lastId, isrefresh: $isRefresh searchKey: $searchKey ');
  332. Map<String, dynamic>? filter;
  333. if (searchKey.isNotEmpty) {
  334. filter = {'key': searchKey};
  335. }
  336. isLoading = true;
  337. if (O2NativeAppEnum.task.key == _type) {
  338. final list = await ProcessSurfaceService.to
  339. .getTaskListByPage(_lastId, body: filter);
  340. if (list != null) {
  341. if (list.isNotEmpty) {
  342. if (isRefresh) {
  343. state.dataList.clear();
  344. }
  345. state.dataList.addAll(list);
  346. _lastId = list[list.length - 1].id!; // 最后一个id
  347. state.hasMoreData = list.length >= O2.o2DefaultPageSize;
  348. } else {
  349. state.hasMoreData = false;
  350. }
  351. }
  352. } else if (O2NativeAppEnum.taskcompleted.key == _type) {
  353. final list = await ProcessSurfaceService.to
  354. .getTaskCompletedListByPage(_lastId, body: filter);
  355. if (list != null) {
  356. if (list.isNotEmpty) {
  357. if (isRefresh) {
  358. state.dataList.clear();
  359. }
  360. state.dataList.addAll(list);
  361. _lastId = list[list.length - 1].id!; // 最后一个id
  362. state.hasMoreData = list.length >= O2.o2DefaultPageSize;
  363. } else {
  364. state.hasMoreData = false;
  365. }
  366. }
  367. } else if (O2NativeAppEnum.read.key == _type) {
  368. final list = await ProcessSurfaceService.to
  369. .getReadListByPage(_lastId, body: filter);
  370. if (list != null) {
  371. if (list.isNotEmpty) {
  372. if (isRefresh) {
  373. state.dataList.clear();
  374. }
  375. state.dataList.addAll(list);
  376. _lastId = list[list.length - 1].id!; // 最后一个id
  377. state.hasMoreData = list.length >= O2.o2DefaultPageSize;
  378. } else {
  379. state.hasMoreData = false;
  380. }
  381. }
  382. } else if (O2NativeAppEnum.readcompleted.key == _type) {
  383. final list = await ProcessSurfaceService.to
  384. .getReadCompletedListByPage(_lastId, body: filter);
  385. if (list != null) {
  386. if (list.isNotEmpty) {
  387. if (isRefresh) {
  388. state.dataList.clear();
  389. }
  390. state.dataList.addAll(list);
  391. _lastId = list[list.length - 1].id!; // 最后一个id
  392. state.hasMoreData = list.length >= O2.o2DefaultPageSize;
  393. } else {
  394. state.hasMoreData = false;
  395. }
  396. }
  397. }
  398. isLoading = false;
  399. }
  400. bool isItemChecked(TaskData item) {
  401. final isCheced =
  402. state.taskSelectedList.firstWhereOrNull((element) => element.id == item.id);
  403. return isCheced != null;
  404. }
  405. void onSelectChange(bool? value, TaskData item) {
  406. if (value == true) {
  407. state.taskSelectedList.add(item);
  408. } else {
  409. state.taskSelectedList.removeWhere((element) => element.id == item.id);
  410. }
  411. }
  412. Future<void> gotoQuickProcess() async {
  413. final result = await QuickprocessingPage.startQuickProcess(state.taskSelectedList.toList());
  414. if (result != null && result is bool) { // 处理完成 刷新数据
  415. onRefresh();
  416. }
  417. }
  418. }