overtime_apply_api.dart 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. import 'dart:convert';
  2. import 'package:flutter_riverpod/flutter_riverpod.dart';
  3. import '../../app.dart';
  4. import '../../core/data/api_cache.dart';
  5. import '../../core/navigation/host_app_channel.dart';
  6. import '../../core/network/api_client.dart';
  7. import '../../shared/models/pagination_model.dart';
  8. import '../expense_apply/expense_apply_api.dart';
  9. import 'overtime_apply_model.dart';
  10. import 'ot_report_model.dart';
  11. final overtimeApplyApiProvider = Provider<OvertimeApplyApi>(
  12. (ref) => OvertimeApplyApi(ref.read(apiClientProvider)),
  13. );
  14. class OvertimeApplyApi {
  15. final ApiClient _client;
  16. final _cache = ApiCache(
  17. keyPrefix:
  18. '${HostAppChannel.sn}_${HostAppChannel.compNo}_${HostAppChannel.usr}',
  19. );
  20. OvertimeApplyApi(this._client);
  21. /// 清除所有基础资料缓存(picker 下拉刷新时调用)。
  22. void clearRefCache() => _cache.clear();
  23. /// 加班申请列表(分页)
  24. Future<PaginatedData<OvertimeApplyModel>> fetchList({
  25. String status = '',
  26. String keyword = '',
  27. String startDate = '',
  28. String endDate = '',
  29. String usr = '',
  30. String sortDir = 'DESC',
  31. int page = 1,
  32. int size = 20,
  33. }) async {
  34. final response = await _client.get<Map<String, dynamic>>(
  35. '/OA/GetOTApplyList',
  36. queryParameters: {
  37. 'status': status,
  38. 'keyword': keyword,
  39. 'startDate': startDate,
  40. 'endDate': endDate,
  41. 'usr': usr,
  42. 'sortDir': sortDir,
  43. 'page': page,
  44. 'size': size,
  45. },
  46. );
  47. return PaginatedData.fromJson(response.data!, OvertimeApplyModel.fromJson);
  48. }
  49. /// 加班申请详情(主表+明细)
  50. Future<OvertimeApplyModel> fetchDetail(String billNo) async {
  51. final response = await _client.get<Map<String, dynamic>>(
  52. '/OA/GetOTApplyDetail',
  53. queryParameters: {'billNo': billNo},
  54. );
  55. return OvertimeApplyModel.fromJson(response.data!);
  56. }
  57. /// 部门
  58. Future<List<DepartmentItem>> getDepartments({
  59. String keyword = '',
  60. bool onlyActive = true,
  61. int page = 1,
  62. int size = 100,
  63. }) async {
  64. final cacheKey = 'getDepartments_${keyword}_${onlyActive}_$page';
  65. return _cache.getOrFetch(cacheKey, () async {
  66. final response = await _client.get<Map<String, dynamic>>(
  67. '/OA/GetDepartments',
  68. queryParameters: {
  69. 'keyword': keyword,
  70. 'onlyActive': onlyActive,
  71. 'page': page,
  72. 'size': size,
  73. },
  74. );
  75. final list = (response.data?['list'] as List<dynamic>?) ?? [];
  76. return list
  77. .map((e) => DepartmentItem.fromJson(e as Map<String, dynamic>))
  78. .toList();
  79. });
  80. }
  81. /// 员工查询
  82. Future<List<EmployeeItem>> getEmployees({
  83. String keyword = '',
  84. String salNo = '',
  85. int page = 1,
  86. int size = 100,
  87. }) async {
  88. final cacheKey = 'getEmployees_${keyword}_${salNo}_$page';
  89. return _cache.getOrFetch(cacheKey, () async {
  90. final response = await _client.get<Map<String, dynamic>>(
  91. '/OA/GetEmployees',
  92. queryParameters: {
  93. 'keyword': keyword,
  94. 'salNo': salNo,
  95. 'page': page,
  96. 'size': size,
  97. },
  98. );
  99. final list = (response.data?['list'] as List<dynamic>?) ?? [];
  100. return list
  101. .map((e) => EmployeeItem.fromJson(e as Map<String, dynamic>))
  102. .toList();
  103. });
  104. }
  105. /// 提交审批,返回申请单号(提取失败时返回 null)
  106. Future<String?> submit(Map<String, dynamic> data) async {
  107. final response = await _client.post<Map<String, dynamic>>(
  108. '/OA/BillSave',
  109. data: {
  110. 'erpCategory': 'MasterService',
  111. 'billId': 'JB',
  112. 'procId': '',
  113. 'data': data,
  114. },
  115. );
  116. final resData = response.data;
  117. if (resData == null) return null;
  118. // 从 resultData 中取
  119. final resultData = resData['resultData'];
  120. if (resultData is Map<String, dynamic>) {
  121. final bilNo = resultData['BIL_NO'] as String?;
  122. if (bilNo != null && bilNo.isNotEmpty) return bilNo;
  123. }
  124. if (resultData is String && resultData.isNotEmpty) {
  125. try {
  126. final parsed = json.decode(resultData) as Map<String, dynamic>;
  127. final bilNo = parsed['BIL_NO'] as String?;
  128. if (bilNo != null && bilNo.isNotEmpty) return bilNo;
  129. } catch (_) {}
  130. }
  131. // 兜底
  132. final rootBilNo = resData['BIL_NO'] as String?;
  133. if (rootBilNo != null && rootBilNo.isNotEmpty) return rootBilNo;
  134. return null;
  135. }
  136. /// 提交审核流
  137. Future<bool> shSubmit({
  138. required String bilNo,
  139. required String bilDd,
  140. String dep = '',
  141. String rem = '',
  142. String usr = '',
  143. bool isCancel = false,
  144. }) async {
  145. try {
  146. final response = await _client.post<Map<String, dynamic>>(
  147. '/OA/SHSubmit',
  148. data: {
  149. 'erpCategory': 'MasterService',
  150. 'bilId': 'JB',
  151. 'bilNo': bilNo,
  152. 'bilDd': bilDd,
  153. 'dep': dep,
  154. 'rem': rem,
  155. 'usr': usr,
  156. 'isCancel': isCancel,
  157. },
  158. );
  159. return response.data?['code'] == 0;
  160. } catch (_) {
  161. return false;
  162. }
  163. }
  164. /// 获取单据状态
  165. Future<Map<String, dynamic>> getBillStatus(String billNo) async {
  166. final response = await _client.get<Map<String, dynamic>>(
  167. '/OA/GetBillStatus',
  168. queryParameters: {'billId': 'JB', 'billNo': billNo},
  169. );
  170. return response.data!;
  171. }
  172. /// 加班报表汇总+月度数据
  173. Future<OTReportData> getOTReport({
  174. String startDate = '',
  175. String endDate = '',
  176. }) async {
  177. final response = await _client.get<Map<String, dynamic>>(
  178. '/OA/GetOTReport',
  179. queryParameters: {
  180. if (startDate.isNotEmpty) 'startDate': startDate,
  181. if (endDate.isNotEmpty) 'endDate': endDate,
  182. },
  183. );
  184. return OTReportData.fromJson(response.data!);
  185. }
  186. /// 加班报表下属对比
  187. Future<List<OTSubordinateItem>> getOTSubordinateReport({
  188. String startDate = '',
  189. String endDate = '',
  190. }) async {
  191. final response = await _client.get<dynamic>(
  192. '/OA/GetOTSubordinateReport',
  193. queryParameters: {
  194. if (startDate.isNotEmpty) 'startDate': startDate,
  195. if (endDate.isNotEmpty) 'endDate': endDate,
  196. },
  197. );
  198. final list =
  199. (response.data as List<dynamic>?)
  200. ?.map((e) => OTSubordinateItem.fromJson(e as Map<String, dynamic>))
  201. .toList() ??
  202. [];
  203. return list;
  204. }
  205. /// 加班报表明细(分页)
  206. Future<Map<String, dynamic>> getOTReportDetail({
  207. String startDate = '',
  208. String endDate = '',
  209. int page = 1,
  210. int size = 20,
  211. }) async {
  212. final response = await _client.get<Map<String, dynamic>>(
  213. '/OA/GetOTReportDetail',
  214. queryParameters: {
  215. if (startDate.isNotEmpty) 'startDate': startDate,
  216. if (endDate.isNotEmpty) 'endDate': endDate,
  217. 'page': page,
  218. 'size': size,
  219. },
  220. );
  221. return response.data!;
  222. }
  223. /// 加班报表表身明细(分页)
  224. Future<Map<String, dynamic>> getOTBodyReport({
  225. String startDate = '',
  226. String endDate = '',
  227. int page = 1,
  228. int size = 20,
  229. }) async {
  230. final response = await _client.get<Map<String, dynamic>>(
  231. '/OA/GetOTBodyReport',
  232. queryParameters: {
  233. if (startDate.isNotEmpty) 'startDate': startDate,
  234. if (endDate.isNotEmpty) 'endDate': endDate,
  235. 'page': page,
  236. 'size': size,
  237. },
  238. );
  239. return response.data!;
  240. }
  241. }