miniprogram-payment.service.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import { Injectable, signal } from '@angular/core';
  2. import { Observable, of, delay, switchMap, catchError } from 'rxjs';
  3. export interface MiniprogramPaymentResult {
  4. success: boolean;
  5. transactionId: string;
  6. amount: number;
  7. paymentTime: Date;
  8. payerInfo: {
  9. openId: string;
  10. nickname?: string;
  11. avatar?: string;
  12. };
  13. settlementId: string;
  14. error?: string;
  15. }
  16. export interface ImageDecryptionResult {
  17. success: boolean;
  18. decryptedImageUrl: string;
  19. originalImageId: string;
  20. decryptionTime: Date;
  21. error?: string;
  22. }
  23. export interface NotificationResult {
  24. success: boolean;
  25. messageId: string;
  26. sentTime: Date;
  27. recipient: string;
  28. error?: string;
  29. }
  30. @Injectable({
  31. providedIn: 'root'
  32. })
  33. export class MiniprogramPaymentService {
  34. private isProcessing = signal(false);
  35. private paymentQueue = signal<string[]>([]);
  36. constructor() {}
  37. /**
  38. * 监听小程序支付完成事件
  39. */
  40. onPaymentCompleted(): Observable<MiniprogramPaymentResult> {
  41. // 模拟支付完成事件监听
  42. return new Observable(observer => {
  43. // 实际实现中会监听微信小程序支付回调
  44. console.log('开始监听小程序支付完成事件...');
  45. // 模拟支付完成事件
  46. setTimeout(() => {
  47. const mockPaymentResult: MiniprogramPaymentResult = {
  48. success: true,
  49. transactionId: `MP${Date.now()}`,
  50. amount: Math.floor(Math.random() * 50000) + 10000,
  51. paymentTime: new Date(),
  52. payerInfo: {
  53. openId: `openid_${Date.now()}`,
  54. nickname: '客户用户',
  55. avatar: 'https://example.com/avatar.jpg'
  56. },
  57. settlementId: `settlement_${Date.now()}`
  58. };
  59. observer.next(mockPaymentResult);
  60. }, 2000);
  61. });
  62. }
  63. /**
  64. * 处理支付完成后的自动化流程
  65. */
  66. processPaymentCompletedFlow(paymentResult: MiniprogramPaymentResult): Observable<boolean> {
  67. if (!paymentResult.success) {
  68. return of(false);
  69. }
  70. this.isProcessing.set(true);
  71. this.paymentQueue.update(queue => [...queue, paymentResult.settlementId]);
  72. console.log(`开始处理支付完成流程: ${paymentResult.transactionId}`);
  73. return this.decryptAndSendImages(paymentResult).pipe(
  74. switchMap(decryptResult => {
  75. if (decryptResult.success) {
  76. return this.sendPaymentCompletedNotification(paymentResult, decryptResult);
  77. }
  78. return of({ success: false, error: '图片解密失败' });
  79. }),
  80. switchMap(notificationResult => {
  81. if (notificationResult.success) {
  82. return this.updateSettlementStatus(paymentResult.settlementId, 'completed');
  83. }
  84. return of(false);
  85. }),
  86. catchError(error => {
  87. console.error('支付完成流程处理失败:', error);
  88. return of(false);
  89. }),
  90. delay(1000), // 模拟处理时间
  91. switchMap(result => {
  92. this.isProcessing.set(false);
  93. this.paymentQueue.update(queue =>
  94. queue.filter(id => id !== paymentResult.settlementId)
  95. );
  96. return of(result);
  97. })
  98. );
  99. }
  100. /**
  101. * 解密并发送大图给客户
  102. */
  103. private decryptAndSendImages(paymentResult: MiniprogramPaymentResult): Observable<ImageDecryptionResult> {
  104. console.log(`开始解密图片,结算ID: ${paymentResult.settlementId}`);
  105. return new Observable<ImageDecryptionResult>(observer => {
  106. // 模拟图片解密过程
  107. setTimeout(() => {
  108. const decryptResult: ImageDecryptionResult = {
  109. success: true,
  110. decryptedImageUrl: `https://example.com/decrypted/${paymentResult.settlementId}/high-res-image.jpg`,
  111. originalImageId: `img_${paymentResult.settlementId}`,
  112. decryptionTime: new Date()
  113. };
  114. console.log('图片解密完成:', decryptResult);
  115. observer.next(decryptResult);
  116. observer.complete();
  117. }, 1500);
  118. }).pipe(
  119. catchError(error => {
  120. console.error('图片解密失败:', error);
  121. return of({
  122. success: false,
  123. decryptedImageUrl: '',
  124. originalImageId: '',
  125. decryptionTime: new Date(),
  126. error: error.message
  127. });
  128. })
  129. );
  130. }
  131. /**
  132. * 发送支付完成通知
  133. */
  134. private sendPaymentCompletedNotification(
  135. paymentResult: MiniprogramPaymentResult,
  136. decryptResult: ImageDecryptionResult
  137. ): Observable<NotificationResult> {
  138. console.log('发送支付完成通知...');
  139. const notificationContent = {
  140. title: '尾款支付成功',
  141. message: `您的尾款 ¥${paymentResult.amount} 已成功支付,大图已解锁并发送至您的微信。`,
  142. imageUrl: decryptResult.decryptedImageUrl,
  143. paymentInfo: {
  144. amount: paymentResult.amount,
  145. transactionId: paymentResult.transactionId,
  146. paymentTime: paymentResult.paymentTime
  147. }
  148. };
  149. return new Observable<NotificationResult>(observer => {
  150. // 模拟发送通知
  151. setTimeout(() => {
  152. const notificationResult: NotificationResult = {
  153. success: true,
  154. messageId: `msg_${Date.now()}`,
  155. sentTime: new Date(),
  156. recipient: paymentResult.payerInfo.openId
  157. };
  158. console.log('通知发送成功:', notificationResult);
  159. console.log('通知内容:', notificationContent);
  160. observer.next(notificationResult);
  161. observer.complete();
  162. }, 800);
  163. }).pipe(
  164. catchError(error => {
  165. console.error('通知发送失败:', error);
  166. return of({
  167. success: false,
  168. messageId: '',
  169. sentTime: new Date(),
  170. recipient: paymentResult.payerInfo.openId,
  171. error: error.message
  172. });
  173. })
  174. );
  175. }
  176. /**
  177. * 更新结算状态
  178. */
  179. private updateSettlementStatus(settlementId: string, status: string): Observable<boolean> {
  180. console.log(`更新结算状态: ${settlementId} -> ${status}`);
  181. return new Observable<boolean>(observer => {
  182. // 模拟更新结算状态
  183. setTimeout(() => {
  184. console.log('结算状态更新成功');
  185. observer.next(true);
  186. observer.complete();
  187. }, 500);
  188. }).pipe(
  189. catchError(error => {
  190. console.error('结算状态更新失败:', error);
  191. return of(false);
  192. })
  193. );
  194. }
  195. /**
  196. * 启动自动化监听
  197. */
  198. startAutomationListener(): void {
  199. console.log('启动小程序支付自动化监听...');
  200. this.onPaymentCompleted().subscribe(paymentResult => {
  201. console.log('检测到支付完成事件:', paymentResult);
  202. this.processPaymentCompletedFlow(paymentResult).subscribe(success => {
  203. if (success) {
  204. console.log('自动化流程处理成功');
  205. } else {
  206. console.error('自动化流程处理失败');
  207. }
  208. });
  209. });
  210. }
  211. /**
  212. * 停止自动化监听
  213. */
  214. stopAutomationListener(): void {
  215. console.log('停止小程序支付自动化监听');
  216. this.isProcessing.set(false);
  217. this.paymentQueue.set([]);
  218. }
  219. /**
  220. * 获取处理状态
  221. */
  222. getProcessingStatus(): boolean {
  223. return this.isProcessing();
  224. }
  225. /**
  226. * 获取处理队列
  227. */
  228. getProcessingQueue(): string[] {
  229. return this.paymentQueue();
  230. }
  231. /**
  232. * 手动触发支付完成流程(用于测试)
  233. */
  234. triggerTestPaymentFlow(settlementId: string, amount: number): Observable<boolean> {
  235. const mockPaymentResult: MiniprogramPaymentResult = {
  236. success: true,
  237. transactionId: `TEST_${Date.now()}`,
  238. amount: amount,
  239. paymentTime: new Date(),
  240. payerInfo: {
  241. openId: `test_openid_${Date.now()}`,
  242. nickname: '测试用户',
  243. avatar: 'https://example.com/test-avatar.jpg'
  244. },
  245. settlementId: settlementId
  246. };
  247. return this.processPaymentCompletedFlow(mockPaymentResult);
  248. }
  249. /**
  250. * 获取支持的支付方式
  251. */
  252. getSupportedPaymentMethods(): string[] {
  253. return ['微信小程序支付', '微信H5支付', '微信扫码支付'];
  254. }
  255. /**
  256. * 验证支付结果
  257. */
  258. validatePaymentResult(paymentResult: MiniprogramPaymentResult): { valid: boolean, errors: string[] } {
  259. const errors: string[] = [];
  260. if (!paymentResult.transactionId) {
  261. errors.push('缺少交易ID');
  262. }
  263. if (!paymentResult.amount || paymentResult.amount <= 0) {
  264. errors.push('支付金额无效');
  265. }
  266. if (!paymentResult.payerInfo?.openId) {
  267. errors.push('缺少支付者信息');
  268. }
  269. if (!paymentResult.settlementId) {
  270. errors.push('缺少结算ID');
  271. }
  272. return {
  273. valid: errors.length === 0,
  274. errors
  275. };
  276. }
  277. }