import { Injectable, signal, computed, inject } from '@angular/core'; import { BehaviorSubject, Observable, of, timer, interval, forkJoin } from 'rxjs'; import { map, switchMap, catchError } from 'rxjs/operators'; import { Settlement } from '../models/project.model'; import { ProjectService } from './project.service'; import { PaymentVoucherRecognitionService, PaymentVoucherRecognitionResult } from './payment-voucher-recognition.service'; import { MiniprogramPaymentService, MiniprogramPaymentResult } from './miniprogram-payment.service'; import { NotificationService, NotificationType, NotificationChannel } from './notification.service'; export interface AutoSettlementRule { id: string; name: string; enabled: boolean; conditions: SettlementCondition[]; actions: SettlementAction[]; priority: number; description?: string; } export interface SettlementCondition { type: 'projectType' | 'amountRange' | 'customerTier' | 'overdueDays' | 'paymentMethod'; operator: 'equals' | 'greaterThan' | 'lessThan' | 'between' | 'contains'; value: any; } export interface SettlementAction { type: 'sendReminder' | 'applyDiscount' | 'extendDueDate' | 'autoConfirm' | 'notifyManager'; params: any; } export interface SettlementReminder { id: string; settlementId: string; type: 'email' | 'sms' | 'wechat' | 'system'; content: string; sentAt: Date; status: 'pending' | 'sent' | 'failed'; } @Injectable({ providedIn: 'root' }) export class AutoSettlementService { private scheduledProcesses = new Map(); private paymentRecognitionService = inject(PaymentVoucherRecognitionService); private miniprogramPaymentService = inject(MiniprogramPaymentService); private notificationService = inject(NotificationService); constructor(private projectService: ProjectService) { // 启动小程序支付自动化监听 this.initializeMiniprogramPaymentAutomation(); } private rules = signal([ { id: 'rule-1', name: '小额自动确认', enabled: true, priority: 1, conditions: [ { type: 'amountRange', operator: 'lessThan', value: 5000 } ], actions: [ { type: 'autoConfirm', params: { immediate: true } } ], description: '金额小于5000元时自动确认结算' }, { id: 'rule-2', name: '逾期提醒', enabled: true, priority: 2, conditions: [ { type: 'overdueDays', operator: 'greaterThan', value: 7 } ], actions: [ { type: 'sendReminder', params: { channels: ['wechat', 'sms'], frequency: 'daily' } } ], description: '逾期7天以上时每天发送提醒' }, { id: 'rule-3', name: 'VIP客户优惠', enabled: true, priority: 3, conditions: [ { type: 'customerTier', operator: 'equals', value: 'vip' }, { type: 'overdueDays', operator: 'greaterThan', value: 15 } ], actions: [ { type: 'applyDiscount', params: { percentage: 5, maxAmount: 1000 } } ], description: 'VIP客户逾期15天以上时提供5%折扣' } ]); private reminders = signal([]); private isProcessing = signal(false); // 获取所有规则 getRules(): Observable { return of(this.rules()); } // 添加新规则 addRule(rule: AutoSettlementRule): void { this.rules.update(rules => [...rules, rule]); } // 更新规则 updateRule(ruleId: string, updates: Partial): void { this.rules.update(rules => rules.map(rule => rule.id === ruleId ? { ...rule, ...updates } : rule) ); } // 删除规则 deleteRule(ruleId: string): void { this.rules.update(rules => rules.filter(rule => rule.id !== ruleId)); } // 处理结算自动化 processSettlementAutomation(settlement: Settlement): Observable { this.isProcessing.set(true); return of(this.rules()) .pipe( map(rules => rules.filter(rule => rule.enabled)), map(enabledRules => { let processed = false; // 按优先级排序处理规则 enabledRules.sort((a, b) => a.priority - b.priority); for (const rule of enabledRules) { if (this.checkConditions(rule.conditions, settlement)) { this.executeActions(rule.actions, settlement); processed = true; // 高优先级规则可能中断后续规则执行 if (rule.priority >= 10) { break; } } } return processed; }), switchMap(processed => { this.isProcessing.set(false); return of(processed); }) ); } // 检查条件是否满足 private checkConditions(conditions: SettlementCondition[], settlement: Settlement): boolean { return conditions.every(condition => { switch (condition.type) { case 'amountRange': return this.checkAmountCondition(condition, settlement.amount || 0); case 'overdueDays': const overdueDays = this.calculateOverdueDays(settlement); return this.checkNumericCondition(condition, overdueDays); case 'customerTier': // 简化实现,实际中需要从客户服务获取层级信息 return condition.operator === 'equals' && condition.value === 'vip'; default: return false; } }); } // 执行动作 private executeActions(actions: SettlementAction[], settlement: Settlement): void { actions.forEach(action => { switch (action.type) { case 'sendReminder': this.sendReminder(settlement, action.params); break; case 'applyDiscount': this.applyDiscount(settlement, action.params); break; case 'autoConfirm': this.autoConfirmSettlement(settlement, action.params); break; case 'notifyManager': this.notifyManager(settlement, action.params); break; } }); } // 发送提醒 private sendReminder(settlement: Settlement, params: any): void { const reminder: SettlementReminder = { id: `reminder-${Date.now()}`, settlementId: settlement.id, type: 'system', content: `结算提醒:项目 ${settlement.projectName} 的 ${settlement.amount} 元结算${this.calculateOverdueDays(settlement) > 0 ? '已逾期' : '待处理'}`, sentAt: new Date(), status: 'sent' }; this.reminders.update(reminders => [...reminders, reminder]); // 实际实现中这里会调用消息服务发送到不同渠道 console.log('发送结算提醒:', reminder); } // 应用折扣 private applyDiscount(settlement: Settlement, params: any): void { const discountAmount = Math.min( (settlement.amount || 0) * (params.percentage / 100), params.maxAmount || 0 ); console.log(`为结算 ${settlement.id} 应用折扣: ${discountAmount}元`); // 实际实现中需要更新结算金额 } // 自动确认结算 private autoConfirmSettlement(settlement: Settlement, params: any): void { console.log(`自动确认结算: ${settlement.id}`); // 实际实现中需要调用结算服务确认结算 } // 通知经理 private notifyManager(settlement: Settlement, params: any): void { console.log(`通知经理处理大额结算: ${settlement.id}, 金额: ${settlement.amount}`); } // 计算逾期天数 private calculateOverdueDays(settlement: Settlement): number { if (settlement.status === '已结算') return 0; const dueDate = settlement.dueDate || new Date(settlement.createdAt.getTime() + 30 * 24 * 60 * 60 * 1000); const today = new Date(); const diffTime = today.getTime() - dueDate.getTime(); return Math.max(0, Math.ceil(diffTime / (1000 * 60 * 60 * 24))); } // 检查金额条件 private checkAmountCondition(condition: SettlementCondition, amount: number): boolean { return this.checkNumericCondition(condition, amount); } // 检查数值条件 private checkNumericCondition(condition: SettlementCondition, value: number): boolean { switch (condition.operator) { case 'equals': return value === condition.value; case 'greaterThan': return value > condition.value; case 'lessThan': return value < condition.value; case 'between': return value >= condition.value[0] && value <= condition.value[1]; default: return false; } } // 获取处理状态 getProcessingStatus() { return this.isProcessing(); } // 获取提醒记录 getReminders(): Observable { return of(this.reminders()); } // 启动定时任务 startScheduledProcessing(): void { // 清理现有的定时任务 this.stopAllScheduledProcessing(); // 每30分钟检查一次逾期结算 this.scheduledProcesses.set('overdueCheck', timer(0, 30 * 60 * 1000).subscribe(() => { this.processOverdueSettlements(); }) ); // 每天早上9点发送每日提醒 this.scheduledProcesses.set('dailyReminder', this.scheduleDailyTask(9, 0, () => { this.sendDailyReminders(); }) ); // 每周一早上10点发送周报 this.scheduledProcesses.set('weeklyReport', this.scheduleWeeklyTask(1, 10, 0, () => { this.sendWeeklySettlementReport(); }) ); // 每小时检查高优先级规则 this.scheduledProcesses.set('hourlyCheck', timer(0, 60 * 60 * 1000).subscribe(() => { this.processHighPrioritySettlements(); }) ); console.log('自动化结算定时任务已启动'); } // 停止所有定时任务 stopAllScheduledProcessing(): void { this.scheduledProcesses.forEach((subscription, key) => { subscription.unsubscribe(); }); this.scheduledProcesses.clear(); } // 安排每日定时任务 private scheduleDailyTask(hour: number, minute: number, task: () => void): any { const now = new Date(); const targetTime = new Date(); targetTime.setHours(hour, minute, 0, 0); let initialDelay = targetTime.getTime() - now.getTime(); if (initialDelay < 0) { initialDelay += 24 * 60 * 60 * 1000; // 第二天同一时间 } return timer(initialDelay, 24 * 60 * 60 * 1000).subscribe(() => { task(); }); } // 安排每周定时任务 private scheduleWeeklyTask(dayOfWeek: number, hour: number, minute: number, task: () => void): any { const now = new Date(); const targetTime = new Date(); // 计算下一个指定星期几 const daysUntilTarget = (dayOfWeek - now.getDay() + 7) % 7; targetTime.setDate(now.getDate() + daysUntilTarget); targetTime.setHours(hour, minute, 0, 0); let initialDelay = targetTime.getTime() - now.getTime(); if (initialDelay < 0) { initialDelay += 7 * 24 * 60 * 60 * 1000; // 下一周同一时间 } return timer(initialDelay, 7 * 24 * 60 * 60 * 1000).subscribe(() => { task(); }); } // 处理逾期结算 private processOverdueSettlements(): void { console.log('执行定时逾期结算检查'); // 获取所有待结算的记录 this.projectService.getSettlements().pipe( map(settlements => settlements.filter(s => s.status === '待结算')), switchMap(pendingSettlements => { const overdueSettlements = pendingSettlements.filter(settlement => this.calculateOverdueDays(settlement) > 0 ); // 对每个逾期结算应用自动化规则 const processingObservables = overdueSettlements.map(settlement => this.processSettlementAutomation(settlement).pipe( catchError(error => { console.error(`处理结算 ${settlement.id} 时出错:`, error); return of(false); }) ) ); return processingObservables.length > 0 ? forkJoin(processingObservables) : of([]); }) ).subscribe(results => { const successful = results.filter(result => result).length; console.log(`逾期结算处理完成,成功处理 ${successful} 个结算`); }); } // 处理高优先级结算 private processHighPrioritySettlements(): void { this.projectService.getSettlements().pipe( map(settlements => settlements.filter(s => s.status === '待结算')), map(pendingSettlements => { // 筛选需要立即处理的高优先级结算(大金额或特定客户) return pendingSettlements.filter(settlement => (settlement.amount || 0) > 10000 || // 大金额 settlement.projectName?.includes('VIP') // VIP客户 ); }), switchMap(highPrioritySettlements => { const processingObservables = highPrioritySettlements.map(settlement => this.processSettlementAutomation(settlement).pipe( catchError(error => { console.error(`处理高优先级结算 ${settlement.id} 时出错:`, error); return of(false); }) ) ); return processingObservables.length > 0 ? forkJoin(processingObservables) : of([]); }) ).subscribe(results => { const successful = results.filter(result => result).length; if (successful > 0) { console.log(`高优先级结算处理完成,成功处理 ${successful} 个结算`); } }); } // 发送每日提醒 private sendDailyReminders(): void { this.projectService.getSettlements().pipe( map(settlements => settlements.filter(s => s.status === '待结算')), map(pendingSettlements => { const today = new Date(); return pendingSettlements.filter(settlement => { const dueDate = settlement.dueDate || new Date(settlement.createdAt.getTime() + 30 * 24 * 60 * 60 * 1000); const daysUntilDue = Math.ceil((dueDate.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)); // 发送即将到期(3天内)和已逾期的提醒 return daysUntilDue <= 3 || this.calculateOverdueDays(settlement) > 0; }); }) ).subscribe(settlementsToRemind => { settlementsToRemind.forEach(settlement => { this.sendReminder(settlement, { channels: ['system', 'email'], frequency: 'daily', type: 'dueDateReminder' }); }); console.log(`每日提醒发送完成,共发送 ${settlementsToRemind.length} 个提醒`); }); } // 发送周报 private sendWeeklySettlementReport(): void { this.projectService.getSettlements().subscribe(allSettlements => { const pendingCount = allSettlements.filter(s => s.status === '待结算').length; const overdueCount = allSettlements.filter(s => s.status === '待结算' && this.calculateOverdueDays(s) > 0 ).length; const completedThisWeek = allSettlements.filter(s => s.status === '已结算' && s.settledAt && new Date(s.settledAt).getTime() > Date.now() - 7 * 24 * 60 * 60 * 1000 ).length; const report = { totalPending: pendingCount, totalOverdue: overdueCount, completedThisWeek: completedThisWeek, generatedAt: new Date() }; console.log('周度结算报告:', report); // 这里可以添加发送邮件或系统通知的逻辑 this.sendManagerNotification('weeklyReport', report); }); } // 发送经理通知 private sendManagerNotification(type: string, data: any): void { const notification = { id: `notification-${Date.now()}`, type: type, data: data, timestamp: new Date(), read: false }; console.log('发送经理通知:', notification); // 实际实现中会调用通知服务 } // 获取定时任务状态 getScheduledTasksStatus(): { [key: string]: boolean } { const status: { [key: string]: boolean } = {}; this.scheduledProcesses.forEach((subscription, key) => { status[key] = !subscription.closed; }); return status; } // 支付凭证识别相关方法 /** * 处理支付凭证上传并自动识别 */ async processPaymentVoucherUpload(file: File, settlementId: string): Promise { try { const result = await this.paymentRecognitionService.recognizePaymentVoucher(file).toPromise(); if (result && result.success) { // 识别成功,更新结算状态 await this.updateSettlementWithPaymentInfo(settlementId, result); // 检查是否需要自动确认结算 if (this.shouldAutoConfirmAfterPayment(result)) { await this.autoConfirmSettlementAfterPayment(settlementId, result); } } return result || { success: false, confidence: 0, error: '支付凭证处理失败' }; } catch (error) { console.error('支付凭证处理失败:', error); return { success: false, confidence: 0, error: '支付凭证处理失败' }; } } /** * 批量处理支付凭证 */ async processBatchPaymentVouchers(files: File[], settlementId: string): Promise { const results: PaymentVoucherRecognitionResult[] = []; for (const file of files) { try { const result = await this.processPaymentVoucherUpload(file, settlementId); results.push(result); } catch (error) { results.push({ success: false, confidence: 0, error: `文件 ${file.name} 处理失败` }); } } return results; } /** * 使用支付信息更新结算记录 */ private async updateSettlementWithPaymentInfo(settlementId: string, paymentInfo: PaymentVoucherRecognitionResult): Promise { // 这里需要实现更新结算记录的逻辑 // 实际实现中会调用项目服务更新结算信息 console.log(`更新结算 ${settlementId} 的支付信息:`, paymentInfo); // 模拟更新操作 const settlements = await this.projectService.getSettlements().toPromise(); const settlement = settlements?.find(s => s.id === settlementId); if (settlement) { // 更新结算记录的支付相关信息 console.log('结算记录已更新支付信息'); } } /** * 检查支付后是否需要自动确认结算 */ private shouldAutoConfirmAfterPayment(paymentInfo: PaymentVoucherRecognitionResult): boolean { // 根据支付金额、支付方式等条件判断是否需要自动确认 const hasAmount = paymentInfo.amount !== undefined && paymentInfo.amount > 0; const highConfidence = paymentInfo.confidence > 0.8; // 识别置信度大于80% const trustedPaymentMethod = ['alipay', 'wechat', 'bank_transfer'].includes(paymentInfo.paymentMethod || ''); return hasAmount && highConfidence && trustedPaymentMethod; } /** * 支付后自动确认结算 */ private async autoConfirmSettlementAfterPayment(settlementId: string, paymentInfo: PaymentVoucherRecognitionResult): Promise { console.log(`支付凭证验证通过,自动确认结算 ${settlementId}`); // 获取结算记录 const settlements = await this.projectService.getSettlements().toPromise(); const settlement = settlements?.find(s => s.id === settlementId); if (settlement) { // 调用自动确认逻辑 this.autoConfirmSettlement(settlement, { immediate: true, paymentVerified: true, paymentAmount: paymentInfo.amount, paymentMethod: paymentInfo.paymentMethod }); console.log('结算已自动确认'); } } /** * 获取支持的支付凭证类型 */ getSupportedPaymentVoucherTypes(): { extensions: string[], description: string } { const supportedTypes = this.paymentRecognitionService.getSupportedFileTypes(); return { extensions: supportedTypes, description: this.paymentRecognitionService.getSupportedFileTypesDescription() }; } /** * 验证支付凭证文件 */ validatePaymentVoucherFile(file: File): { valid: boolean, error?: string } { const result = this.paymentRecognitionService.validateFile(file); return { valid: result.isValid, error: result.error }; } /** * 初始化小程序支付自动化流程 */ private initializeMiniprogramPaymentAutomation(): void { console.log('初始化小程序支付自动化流程...'); // 监听小程序支付完成事件 this.miniprogramPaymentService.onPaymentCompleted().subscribe({ next: (paymentResult: MiniprogramPaymentResult) => { console.log('检测到小程序支付完成:', paymentResult); this.handleMiniprogramPaymentCompleted(paymentResult); }, error: (error) => { console.error('小程序支付监听出错:', error); } }); // 启动小程序支付自动化监听 this.miniprogramPaymentService.startAutomationListener(); } /** * 处理小程序支付完成事件 */ private handleMiniprogramPaymentCompleted(paymentResult: MiniprogramPaymentResult): void { if (!paymentResult.success) { console.error('支付失败,跳过自动化处理'); return; } console.log(`开始处理小程序支付自动化流程: ${paymentResult.transactionId}`); // 处理支付完成后的自动化流程 this.miniprogramPaymentService.processPaymentCompletedFlow(paymentResult).subscribe({ next: (success) => { if (success) { console.log('小程序支付自动化流程处理成功'); this.createAutomationLog(paymentResult.settlementId, 'miniprogram_payment_success', { transactionId: paymentResult.transactionId, amount: paymentResult.amount, processedAt: new Date() }); // 发送支付完成通知 this.sendPaymentCompletedNotifications(paymentResult); } else { console.error('小程序支付自动化流程处理失败'); this.createAutomationLog(paymentResult.settlementId, 'miniprogram_payment_failed', { transactionId: paymentResult.transactionId, error: '自动化流程处理失败' }); } }, error: (error) => { console.error('小程序支付自动化流程出错:', error); this.createAutomationLog(paymentResult.settlementId, 'miniprogram_payment_error', { transactionId: paymentResult.transactionId, error: error.message }); } }); } /** * 发送支付完成通知 */ private sendPaymentCompletedNotifications(paymentResult: MiniprogramPaymentResult): void { console.log('发送支付完成通知...'); // 获取客户信息(模拟) const customerInfo = this.getCustomerInfo(paymentResult.settlementId); // 发送支付完成通知 this.notificationService.sendPaymentCompletedNotification({ recipient: customerInfo.phone, paymentMethod: '小程序支付', // 使用固定值而不是paymentResult.paymentMethod amount: paymentResult.amount, customerName: customerInfo.name, projectName: customerInfo.projectName, channels: [NotificationChannel.SMS, NotificationChannel.WECHAT, NotificationChannel.IN_APP] }).subscribe({ next: (result) => { if (result.success) { console.log('支付完成通知发送成功:', result); // 发送大图解锁通知 this.sendImageUnlockedNotifications(paymentResult, customerInfo); } else { console.error('支付完成通知发送失败:', result.error); } }, error: (error) => { console.error('支付完成通知发送出错:', error); } }); } /** * 发送大图解锁通知 */ private sendImageUnlockedNotifications(paymentResult: MiniprogramPaymentResult, customerInfo: any): void { console.log('发送大图解锁通知...'); this.notificationService.sendImageUnlockedNotification({ recipient: customerInfo.phone, customerName: customerInfo.name, projectName: customerInfo.projectName, imageCount: customerInfo.imageCount || 8, resolution: '4K高清', validUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toLocaleDateString(), // 30天有效期 downloadLink: `https://download.yinsanse.com/project/${paymentResult.settlementId}`, channels: [NotificationChannel.SMS, NotificationChannel.EMAIL, NotificationChannel.IN_APP] }).subscribe({ next: (result) => { if (result.success) { console.log('大图解锁通知发送成功:', result); } else { console.error('大图解锁通知发送失败:', result.error); } }, error: (error) => { console.error('大图解锁通知发送出错:', error); } }); } /** * 获取客户信息(模拟) */ private getCustomerInfo(settlementId: string): { name: string; phone: string; email: string; projectName: string; imageCount: number; } { // 模拟客户信息 return { name: '张先生', phone: '138****8888', email: 'customer@example.com', projectName: '现代简约三居室设计', imageCount: 8 }; } /** * 创建自动化日志 */ private createAutomationLog(settlementId: string, type: string, data: any): void { const log = { id: `log_${Date.now()}`, settlementId, type, data, timestamp: new Date() }; console.log('创建自动化日志:', log); // 实际实现中会保存到数据库或日志系统 } /** * 手动触发小程序支付测试流程 */ triggerMiniprogramPaymentTest(settlementId: string, amount: number): Observable { console.log(`触发小程序支付测试流程: ${settlementId}, 金额: ${amount}`); return this.miniprogramPaymentService.triggerTestPaymentFlow(settlementId, amount); } /** * 获取小程序支付自动化状态 */ getMiniprogramPaymentAutomationStatus(): { isProcessing: boolean; processingQueue: string[]; supportedMethods: string[]; } { return { isProcessing: this.miniprogramPaymentService.getProcessingStatus(), processingQueue: this.miniprogramPaymentService.getProcessingQueue(), supportedMethods: this.miniprogramPaymentService.getSupportedPaymentMethods() }; } /** * 停止小程序支付自动化监听 */ stopMiniprogramPaymentAutomation(): void { console.log('停止小程序支付自动化监听'); this.miniprogramPaymentService.stopAutomationListener(); } }