settlement-card.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { Component, Input, computed, signal } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { Settlement } from '../../../models/project.model';
  5. export interface SettlementStats {
  6. totalAmount: number;
  7. pendingAmount: number;
  8. overdueAmount: number;
  9. completedAmount: number;
  10. totalCount: number;
  11. pendingCount: number;
  12. overdueCount: number;
  13. completedCount: number;
  14. }
  15. @Component({
  16. selector: 'app-settlement-card',
  17. standalone: true,
  18. imports: [CommonModule, FormsModule],
  19. templateUrl: './settlement-card.html',
  20. styleUrls: ['./settlement-card.scss']
  21. })
  22. export class SettlementCardComponent {
  23. @Input() settlements: Settlement[] = [];
  24. // 筛选条件
  25. statusFilter = signal<string>('all');
  26. searchKeyword = signal<string>('');
  27. // 计算统计数据
  28. stats = computed<SettlementStats>(() => {
  29. const settlements = this.settlements || [];
  30. return {
  31. totalAmount: settlements.reduce((sum, s) => sum + (s.amount || 0), 0),
  32. pendingAmount: settlements.filter(s => s.status === '待结算').reduce((sum, s) => sum + (s.amount || 0), 0),
  33. overdueAmount: settlements.filter(s => this.isOverdue(s)).reduce((sum, s) => sum + (s.amount || 0), 0),
  34. completedAmount: settlements.filter(s => s.status === '已结算').reduce((sum, s) => sum + (s.amount || 0), 0),
  35. totalCount: settlements.length,
  36. pendingCount: settlements.filter(s => s.status === '待结算').length,
  37. overdueCount: settlements.filter(s => this.isOverdue(s)).length,
  38. completedCount: settlements.filter(s => s.status === '已结算').length
  39. };
  40. });
  41. // 筛选后的结算列表
  42. filteredSettlements = computed(() => {
  43. let filtered = this.settlements || [];
  44. // 状态筛选
  45. const status = this.statusFilter();
  46. if (status !== 'all') {
  47. if (status === 'overdue') {
  48. filtered = filtered.filter(s => this.isOverdue(s));
  49. } else {
  50. filtered = filtered.filter(s => s.status === status);
  51. }
  52. }
  53. // 关键词搜索
  54. const keyword = this.searchKeyword().toLowerCase();
  55. if (keyword) {
  56. filtered = filtered.filter(s =>
  57. (s.projectName || '').toLowerCase().includes(keyword) ||
  58. (s.stage || '').toLowerCase().includes(keyword)
  59. );
  60. }
  61. return filtered;
  62. });
  63. // 判断是否逾期
  64. isOverdue(settlement: Settlement): boolean {
  65. if (settlement.status === '已结算') return false;
  66. // 简化逾期判断:如果是待结算状态且创建时间超过30天,则认为逾期
  67. const thirtyDaysAgo = new Date();
  68. thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  69. return settlement.createdAt < thirtyDaysAgo;
  70. }
  71. // 获取状态样式类
  72. getStatusClass(settlement: Settlement): string {
  73. if (this.isOverdue(settlement)) return 'overdue';
  74. return settlement.status === '已结算' ? 'completed' : 'pending';
  75. }
  76. // 格式化金额
  77. formatAmount(amount: number): string {
  78. return new Intl.NumberFormat('zh-CN', {
  79. style: 'currency',
  80. currency: 'CNY',
  81. minimumFractionDigits: 0,
  82. maximumFractionDigits: 2
  83. }).format(amount);
  84. }
  85. // 更新筛选条件
  86. updateStatusFilter(status: string): void {
  87. this.statusFilter.set(status);
  88. }
  89. updateSearchKeyword(keyword: string): void {
  90. this.searchKeyword.set(keyword);
  91. }
  92. // 计算逾期天数
  93. getDaysOverdue(settlement: Settlement): number {
  94. if (settlement.status === '已结算') return 0;
  95. const thirtyDaysAgo = new Date();
  96. thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  97. if (settlement.createdAt >= thirtyDaysAgo) return 0;
  98. const today = new Date();
  99. const diffTime = today.getTime() - thirtyDaysAgo.getTime();
  100. return Math.max(0, Math.ceil(diffTime / (1000 * 60 * 60 * 24)));
  101. }
  102. }