expense_list_controller.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. import 'package:flutter_riverpod/flutter_riverpod.dart';
  2. import '../../shared/models/approval_status.dart';
  3. import 'expense_model.dart';
  4. final expenseStatusFilterProvider = StateProvider<String>((ref) => '');
  5. final expenseScopeProvider = StateProvider<String>((ref) => 'mine');
  6. final mockExpenses = <ExpenseModel>[
  7. ExpenseModel(
  8. id: 'exp-001',
  9. reportNo: 'BX202605001',
  10. applicantId: 'u-001',
  11. applicantName: '张三',
  12. deptId: 'dept-001',
  13. deptName: '市场部',
  14. expenseType: '差旅费',
  15. totalAmount: 2580.00,
  16. invoiceCount: 3,
  17. status: 'pending',
  18. purpose: '北京出差拜访客户',
  19. bankName: '中国银行',
  20. accountName: '张三',
  21. paymentStatus: 'unpaid',
  22. projectName: '华北区客户拓展',
  23. budgetSubjectName: '差旅费预算',
  24. attachments: ['http://example.com/invoice1.jpg'],
  25. createTime: DateTime(2026, 5, 20),
  26. updateTime: DateTime(2026, 5, 20),
  27. details: [
  28. ExpenseDetailModel(
  29. id: 'det-001',
  30. expenseId: 'exp-001',
  31. expenseDate: DateTime(2026, 5, 19),
  32. expenseType: '交通费',
  33. expenseDesc: '北京-上海高铁',
  34. amount: 553.00,
  35. taxAmount: 27.65,
  36. totalAmount: 580.65,
  37. baseAmount: 580.65,
  38. currency: 'CNY',
  39. exchangeRate: 1.0,
  40. invoiceType: 'general',
  41. invoiceNo: 'INV20260519001',
  42. invoiceCode: '3100234567',
  43. taxRate: 0.05,
  44. ),
  45. ExpenseDetailModel(
  46. id: 'det-002',
  47. expenseId: 'exp-001',
  48. expenseDate: DateTime(2026, 5, 19),
  49. expenseType: '住宿费',
  50. expenseDesc: '上海酒店住宿',
  51. amount: 800.00,
  52. taxAmount: 40.00,
  53. totalAmount: 840.00,
  54. baseAmount: 840.00,
  55. currency: 'CNY',
  56. exchangeRate: 1.0,
  57. invoiceType: 'special',
  58. invoiceNo: 'INV20260519002',
  59. invoiceCode: '3100456789',
  60. taxRate: 0.05,
  61. ),
  62. ExpenseDetailModel(
  63. id: 'det-003',
  64. expenseId: 'exp-001',
  65. expenseDate: DateTime(2026, 5, 20),
  66. expenseType: '餐饮费',
  67. expenseDesc: '客户午餐',
  68. amount: 1100.00,
  69. taxAmount: 55.00,
  70. totalAmount: 1155.00,
  71. baseAmount: 1155.00,
  72. currency: 'CNY',
  73. exchangeRate: 1.0,
  74. invoiceType: 'general',
  75. invoiceNo: 'INV20260520003',
  76. invoiceCode: '3100567890',
  77. taxRate: 0.05,
  78. ),
  79. ],
  80. approvalRecords: [
  81. ApprovalRecord(
  82. id: 'ar-001',
  83. bizId: 'exp-001',
  84. bizType: 'expense',
  85. approverId: 'u-mgr',
  86. approverName: '李经理',
  87. approvalLevel: 1,
  88. action: 'pending',
  89. opinion: '',
  90. approvalTime: DateTime(2026, 5, 21),
  91. ),
  92. ],
  93. ),
  94. ExpenseModel(
  95. id: 'exp-002',
  96. reportNo: 'BX202605002',
  97. applicantId: 'u-001',
  98. applicantName: '张三',
  99. deptId: 'dept-001',
  100. deptName: '市场部',
  101. expenseType: '办公用品',
  102. totalAmount: 1280.50,
  103. invoiceCount: 2,
  104. status: 'approved',
  105. purpose: '部门办公用品采购',
  106. bankName: '中国银行',
  107. accountName: '张三',
  108. paymentStatus: 'paid',
  109. voucherNo: 'V202606001',
  110. projectName: '办公运营',
  111. budgetSubjectName: '办公费预算',
  112. createTime: DateTime(2026, 5, 15),
  113. updateTime: DateTime(2026, 5, 18),
  114. details: [
  115. ExpenseDetailModel(
  116. id: 'det-004',
  117. expenseId: 'exp-002',
  118. expenseDate: DateTime(2026, 5, 14),
  119. expenseType: '办公用品',
  120. expenseDesc: '打印纸、墨盒',
  121. amount: 1280.50,
  122. taxAmount: 64.03,
  123. totalAmount: 1344.53,
  124. baseAmount: 1344.53,
  125. currency: 'CNY',
  126. exchangeRate: 1.0,
  127. invoiceType: 'special',
  128. invoiceNo: 'INV20260514001',
  129. invoiceCode: '4400123456',
  130. taxRate: 0.05,
  131. ),
  132. ],
  133. approvalRecords: [
  134. ApprovalRecord(
  135. id: 'ar-002',
  136. bizId: 'exp-002',
  137. bizType: 'expense',
  138. approverId: 'u-mgr',
  139. approverName: '李经理',
  140. approvalLevel: 1,
  141. action: 'approve',
  142. opinion: '同意',
  143. approvalTime: DateTime(2026, 5, 18),
  144. ),
  145. ],
  146. ),
  147. ExpenseModel(
  148. id: 'exp-003',
  149. reportNo: 'BX202605003',
  150. applicantId: 'u-003',
  151. applicantName: '赵六',
  152. deptId: 'dept-003',
  153. deptName: '财务部',
  154. expenseType: '业务招待费',
  155. totalAmount: 3600.00,
  156. invoiceCount: 1,
  157. status: 'rejected',
  158. purpose: '客户答谢晚宴',
  159. bankName: '工商银行',
  160. accountName: '赵六',
  161. paymentStatus: 'unpaid',
  162. createTime: DateTime(2026, 5, 10),
  163. updateTime: DateTime(2026, 5, 12),
  164. details: [
  165. ExpenseDetailModel(
  166. id: 'det-005',
  167. expenseId: 'exp-003',
  168. expenseDate: DateTime(2026, 5, 9),
  169. expenseType: '招待费',
  170. expenseDesc: '客户晚宴',
  171. amount: 3600.00,
  172. taxAmount: 0.0,
  173. totalAmount: 3600.00,
  174. baseAmount: 3600.00,
  175. currency: 'CNY',
  176. exchangeRate: 1.0,
  177. invoiceType: 'none',
  178. invoiceNo: '',
  179. invoiceCode: '',
  180. taxRate: 0.0,
  181. ),
  182. ],
  183. approvalRecords: [
  184. ApprovalRecord(
  185. id: 'ar-003',
  186. bizId: 'exp-003',
  187. bizType: 'expense',
  188. approverId: 'u-mgr',
  189. approverName: '李经理',
  190. approvalLevel: 1,
  191. action: 'reject',
  192. opinion: '发票不符合规定',
  193. approvalTime: DateTime(2026, 5, 12),
  194. ),
  195. ],
  196. ),
  197. ExpenseModel(
  198. id: 'exp-004',
  199. reportNo: 'BX202605004',
  200. applicantId: 'u-004',
  201. applicantName: '钱七',
  202. deptId: 'dept-004',
  203. deptName: '技术部',
  204. expenseType: '交通费',
  205. totalAmount: 890.00,
  206. invoiceCount: 1,
  207. status: 'pending',
  208. purpose: '市内出行',
  209. bankName: '建设银行',
  210. accountName: '钱七',
  211. paymentStatus: 'unpaid',
  212. createTime: DateTime(2026, 5, 22),
  213. updateTime: DateTime(2026, 5, 22),
  214. details: [
  215. ExpenseDetailModel(
  216. id: 'det-006',
  217. expenseId: 'exp-004',
  218. expenseDate: DateTime(2026, 5, 21),
  219. expenseType: '交通费',
  220. expenseDesc: '市内打车',
  221. amount: 890.00,
  222. taxAmount: 44.50,
  223. totalAmount: 934.50,
  224. baseAmount: 934.50,
  225. currency: 'CNY',
  226. exchangeRate: 1.0,
  227. invoiceType: 'general',
  228. invoiceNo: 'INV20260521001',
  229. invoiceCode: '5100123456',
  230. taxRate: 0.05,
  231. ),
  232. ],
  233. ),
  234. ExpenseModel(
  235. id: 'exp-005',
  236. reportNo: 'BX202605005',
  237. applicantId: 'u-001',
  238. applicantName: '张三',
  239. deptId: 'dept-001',
  240. deptName: '市场部',
  241. expenseType: '差旅费',
  242. totalAmount: 4200.00,
  243. invoiceCount: 4,
  244. status: 'approved',
  245. purpose: '深圳出差',
  246. bankName: '中国银行',
  247. accountName: '张三',
  248. paymentStatus: 'unpaid',
  249. voucherNo: '',
  250. projectName: '华南区客户拓展',
  251. budgetSubjectName: '差旅费预算',
  252. createTime: DateTime(2026, 5, 25),
  253. updateTime: DateTime(2026, 5, 28),
  254. details: [
  255. ExpenseDetailModel(
  256. id: 'det-007',
  257. expenseId: 'exp-005',
  258. expenseDate: DateTime(2026, 5, 24),
  259. expenseType: '交通费',
  260. expenseDesc: '深圳往返机票',
  261. amount: 2500.00,
  262. taxAmount: 125.00,
  263. totalAmount: 2625.00,
  264. baseAmount: 2625.00,
  265. currency: 'CNY',
  266. exchangeRate: 1.0,
  267. invoiceType: 'special',
  268. invoiceNo: 'INV20260524001',
  269. invoiceCode: '4400789012',
  270. taxRate: 0.05,
  271. ),
  272. ExpenseDetailModel(
  273. id: 'det-008',
  274. expenseId: 'exp-005',
  275. expenseDate: DateTime(2026, 5, 24),
  276. expenseType: '住宿费',
  277. expenseDesc: '深圳酒店住宿',
  278. amount: 1200.00,
  279. taxAmount: 60.00,
  280. totalAmount: 1260.00,
  281. baseAmount: 1260.00,
  282. currency: 'CNY',
  283. exchangeRate: 1.0,
  284. invoiceType: 'special',
  285. invoiceNo: 'INV20260524002',
  286. invoiceCode: '4400789013',
  287. taxRate: 0.05,
  288. ),
  289. ],
  290. approvalRecords: [
  291. ApprovalRecord(
  292. id: 'ar-004',
  293. bizId: 'exp-005',
  294. bizType: 'expense',
  295. approverId: 'u-mgr',
  296. approverName: '李经理',
  297. approvalLevel: 1,
  298. action: 'approve',
  299. opinion: '同意',
  300. approvalTime: DateTime(2026, 5, 28),
  301. ),
  302. ],
  303. ),
  304. ExpenseModel(
  305. id: 'exp-006',
  306. reportNo: 'BX202605006',
  307. applicantId: 'u-001',
  308. applicantName: '张三',
  309. deptId: 'dept-001',
  310. deptName: '市场部',
  311. expenseType: '交通费',
  312. totalAmount: 350.00,
  313. invoiceCount: 1,
  314. status: 'draft',
  315. purpose: '日常办公用车',
  316. bankName: '中国银行',
  317. accountName: '张三',
  318. paymentStatus: 'unpaid',
  319. createTime: DateTime(2026, 6, 1),
  320. updateTime: DateTime(2026, 6, 1),
  321. details: [
  322. ExpenseDetailModel(
  323. id: 'det-009',
  324. expenseId: 'exp-006',
  325. expenseDate: DateTime(2026, 6, 1),
  326. expenseType: '交通费',
  327. expenseDesc: '打车',
  328. amount: 350.00,
  329. taxAmount: 17.50,
  330. totalAmount: 367.50,
  331. baseAmount: 367.50,
  332. currency: 'CNY',
  333. exchangeRate: 1.0,
  334. invoiceType: 'general',
  335. invoiceNo: 'INV20260601001',
  336. invoiceCode: '5100789012',
  337. taxRate: 0.05,
  338. ),
  339. ],
  340. ),
  341. ExpenseModel(
  342. id: 'exp-007',
  343. reportNo: 'BX202606001',
  344. applicantId: 'u-001',
  345. applicantName: '张三',
  346. deptId: 'dept-001',
  347. deptName: '市场部',
  348. expenseType: '差旅费',
  349. totalAmount: 1800.00,
  350. invoiceCount: 2,
  351. status: 'withdrawn',
  352. purpose: '上海出差(已撤回)',
  353. bankName: '中国银行',
  354. accountName: '张三',
  355. paymentStatus: 'unpaid',
  356. createTime: DateTime(2026, 6, 2),
  357. updateTime: DateTime(2026, 6, 3),
  358. details: [
  359. ExpenseDetailModel(
  360. id: 'det-010',
  361. expenseId: 'exp-007',
  362. expenseDate: DateTime(2026, 6, 2),
  363. expenseType: '交通费',
  364. expenseDesc: '上海往返高铁',
  365. amount: 1100.00,
  366. taxAmount: 55.00,
  367. totalAmount: 1155.00,
  368. baseAmount: 1155.00,
  369. currency: 'CNY',
  370. exchangeRate: 1.0,
  371. invoiceType: 'general',
  372. invoiceNo: 'INV20260602001',
  373. invoiceCode: '3100890123',
  374. taxRate: 0.05,
  375. ),
  376. ExpenseDetailModel(
  377. id: 'det-011',
  378. expenseId: 'exp-007',
  379. expenseDate: DateTime(2026, 6, 2),
  380. expenseType: '住宿费',
  381. expenseDesc: '上海酒店住宿',
  382. amount: 700.00,
  383. taxAmount: 35.00,
  384. totalAmount: 735.00,
  385. baseAmount: 735.00,
  386. currency: 'CNY',
  387. exchangeRate: 1.0,
  388. invoiceType: 'special',
  389. invoiceNo: 'INV20260602002',
  390. invoiceCode: '3100890124',
  391. taxRate: 0.05,
  392. ),
  393. ],
  394. ),
  395. ];
  396. final expensePageProvider = StateProvider<int>((ref) => 1);
  397. final expenseDateStartProvider = StateProvider<DateTime?>((ref) => null);
  398. final expenseDateEndProvider = StateProvider<DateTime?>((ref) => null);
  399. final expenseRefreshProvider = StateProvider<int>((ref) => 0);
  400. final expenseListProvider = FutureProvider
  401. .family<List<ExpenseModel>, String>((ref, status) async {
  402. ref.watch(expensePageProvider);
  403. ref.watch(expenseDateStartProvider);
  404. ref.watch(expenseDateEndProvider);
  405. ref.watch(expenseRefreshProvider);
  406. // 模拟网络延迟,使骨架屏可见
  407. await Future.delayed(const Duration(milliseconds: 1000));
  408. List<ExpenseModel> list;
  409. if (status.isEmpty) {
  410. list = mockExpenses;
  411. } else if (status == 'unpaid') {
  412. list = mockExpenses
  413. .where((e) => e.status == 'approved' && e.paymentStatus == 'unpaid')
  414. .toList();
  415. } else if (status == 'paid') {
  416. list = mockExpenses
  417. .where((e) => e.status == 'approved' && e.paymentStatus == 'paid')
  418. .toList();
  419. } else {
  420. list = mockExpenses.where((e) => e.status == status).toList();
  421. }
  422. final dateStart = ref.read(expenseDateStartProvider);
  423. final dateEnd = ref.read(expenseDateEndProvider);
  424. if (dateStart != null) {
  425. list = list
  426. .where(
  427. (e) => e.createTime.isAfter(
  428. dateStart.subtract(const Duration(days: 1)),
  429. ),
  430. )
  431. .toList();
  432. }
  433. if (dateEnd != null) {
  434. list = list
  435. .where(
  436. (e) =>
  437. e.createTime.isBefore(dateEnd.add(const Duration(days: 1))),
  438. )
  439. .toList();
  440. }
  441. return list;
  442. });