settlement-card.ts 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. import { Component, Input, computed, signal, OnInit } from '@angular/core';
  2. import { CommonModule, DatePipe } from '@angular/common';
  3. import { FormsModule } from '@angular/forms';
  4. import { MatButtonModule } from '@angular/material/button';
  5. import { MatIconModule } from '@angular/material/icon';
  6. import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
  7. import { MatTooltipModule } from '@angular/material/tooltip';
  8. import { MatDialogModule, MatDialog } from '@angular/material/dialog';
  9. import { MatSnackBarModule, MatSnackBar } from '@angular/material/snack-bar';
  10. import { Settlement } from '../../../models/project.model';
  11. import { AutoSettlementService } from '../../../services/auto-settlement.service';
  12. import { ProjectService } from '../../../services/project.service';
  13. export interface SettlementStats {
  14. totalAmount: number;
  15. pendingAmount: number;
  16. overdueAmount: number;
  17. completedAmount: number;
  18. totalCount: number;
  19. pendingCount: number;
  20. overdueCount: number;
  21. completedCount: number;
  22. }
  23. // 项目验收确认接口
  24. export interface ProjectAcceptance {
  25. id: string;
  26. projectId: string;
  27. projectName: string;
  28. technicianId: string;
  29. technicianName: string;
  30. acceptanceStatus: 'pending' | 'confirmed' | 'rejected';
  31. acceptanceDate?: Date;
  32. acceptanceNotes?: string;
  33. customerNotified: boolean;
  34. }
  35. // 客服跟进提醒接口
  36. export interface CustomerServiceReminder {
  37. id: string;
  38. projectId: string;
  39. projectName: string;
  40. customerName: string;
  41. reminderType: 'payment_follow_up' | 'acceptance_notification' | 'delivery_confirmation';
  42. reminderStatus: 'pending' | 'in_progress' | 'completed';
  43. assignedTo: string;
  44. dueDate: Date;
  45. notes?: string;
  46. createdAt: Date;
  47. }
  48. // 企业微信群发图接口
  49. export interface WeChatImageDelivery {
  50. id: string;
  51. projectId: string;
  52. groupId: string;
  53. groupName: string;
  54. imageUrls: string[];
  55. deliveryStatus: 'pending' | 'sending' | 'completed' | 'failed';
  56. deliveryDate?: Date;
  57. errorMessage?: string;
  58. }
  59. @Component({
  60. selector: 'app-settlement-card',
  61. standalone: true,
  62. imports: [
  63. CommonModule,
  64. DatePipe,
  65. FormsModule,
  66. MatButtonModule,
  67. MatIconModule,
  68. MatProgressSpinnerModule,
  69. MatTooltipModule,
  70. MatDialogModule,
  71. MatSnackBarModule
  72. ],
  73. templateUrl: './settlement-card.html',
  74. styleUrls: ['./settlement-card.scss']
  75. })
  76. export class SettlementCardComponent implements OnInit {
  77. @Input() settlements: Settlement[] = [];
  78. @Input() showAutomationControls = false;
  79. @Input() projectAcceptances: ProjectAcceptance[] = [];
  80. @Input() customerServiceReminders: CustomerServiceReminder[] = [];
  81. // 筛选条件
  82. statusFilter = signal<string>('all');
  83. searchKeyword = signal<string>('');
  84. // 自动化处理状态
  85. isProcessing = signal(false);
  86. processingSettlementId = signal<string | null>(null);
  87. // 新增功能状态
  88. acceptanceStatus = signal<{[key: string]: 'pending' | 'confirming' | 'confirmed'}>({});
  89. reminderStatus = signal<{[key: string]: 'pending' | 'creating' | 'created'}>({});
  90. isSendingImages = signal(false);
  91. sendingProjectId = signal<string | null>(null);
  92. constructor(
  93. private autoSettlementService: AutoSettlementService,
  94. private dialog: MatDialog,
  95. private snackBar: MatSnackBar,
  96. private projectService: ProjectService
  97. ) { }
  98. ngOnInit() {
  99. // 启动定时自动化处理
  100. this.autoSettlementService.startScheduledProcessing();
  101. // 初始化项目验收状态
  102. this.initializeAcceptanceStatus();
  103. // 初始化客服提醒状态
  104. this.initializeReminderStatus();
  105. }
  106. // 初始化项目验收状态
  107. private initializeAcceptanceStatus(): void {
  108. const status: {[key: string]: 'pending' | 'confirming' | 'confirmed'} = {};
  109. this.settlements.forEach(settlement => {
  110. const acceptance = this.projectAcceptances.find(a => a.projectId === settlement.projectId);
  111. if (acceptance) {
  112. status[settlement.projectId] = acceptance.acceptanceStatus === 'confirmed' ? 'confirmed' : 'pending';
  113. } else {
  114. status[settlement.projectId] = 'pending';
  115. }
  116. });
  117. this.acceptanceStatus.set(status);
  118. }
  119. // 初始化客服提醒状态
  120. private initializeReminderStatus(): void {
  121. const status: {[key: string]: 'pending' | 'creating' | 'created'} = {};
  122. this.settlements.forEach(settlement => {
  123. const reminder = this.customerServiceReminders.find(r =>
  124. r.projectId === settlement.projectId && r.reminderType === 'payment_follow_up'
  125. );
  126. if (reminder) {
  127. status[settlement.projectId] = reminder.reminderStatus === 'completed' ? 'created' : 'pending';
  128. } else {
  129. status[settlement.projectId] = 'pending';
  130. }
  131. });
  132. this.reminderStatus.set(status);
  133. }
  134. // 技术确认项目验收
  135. confirmProjectAcceptance(settlement: Settlement): void {
  136. const currentStatus = this.acceptanceStatus();
  137. currentStatus[settlement.projectId] = 'confirming';
  138. this.acceptanceStatus.set({...currentStatus});
  139. // 模拟API调用
  140. setTimeout(() => {
  141. const updatedStatus = this.acceptanceStatus();
  142. updatedStatus[settlement.projectId] = 'confirmed';
  143. this.acceptanceStatus.set({...updatedStatus});
  144. this.snackBar.open(`项目 ${settlement.projectName} 验收确认成功`, '关闭', {
  145. duration: 3000,
  146. horizontalPosition: 'center',
  147. verticalPosition: 'top'
  148. });
  149. // 自动创建客服跟进提醒
  150. this.createCustomerServiceReminder(settlement, 'acceptance_notification');
  151. // 验收完成后,自动发起尾款结算申请
  152. this.initiateFinalSettlement(settlement);
  153. }, 1500);
  154. }
  155. // 创建客服跟进提醒
  156. createCustomerServiceReminder(settlement: Settlement, type: 'payment_follow_up' | 'acceptance_notification' | 'delivery_confirmation'): void {
  157. const currentStatus = this.reminderStatus();
  158. currentStatus[settlement.projectId] = 'creating';
  159. this.reminderStatus.set({...currentStatus});
  160. // 模拟API调用创建提醒
  161. setTimeout(() => {
  162. const updatedStatus = this.reminderStatus();
  163. updatedStatus[settlement.projectId] = 'created';
  164. this.reminderStatus.set({...updatedStatus});
  165. let message = '';
  166. switch(type) {
  167. case 'payment_follow_up':
  168. message = `已创建尾款跟进提醒`;
  169. break;
  170. case 'acceptance_notification':
  171. message = `已创建验收通知提醒`;
  172. break;
  173. case 'delivery_confirmation':
  174. message = `已创建交付确认提醒`;
  175. break;
  176. }
  177. this.snackBar.open(`${settlement.projectName} ${message}`, '关闭', {
  178. duration: 3000,
  179. horizontalPosition: 'center',
  180. verticalPosition: 'top'
  181. });
  182. }, 1000);
  183. }
  184. // 一键发图到企业微信群
  185. sendImagesToWeChatGroup(settlement: Settlement): void {
  186. this.isSendingImages.set(true);
  187. this.sendingProjectId.set(settlement.projectId);
  188. // 模拟获取项目大图和发送到企业微信群
  189. setTimeout(() => {
  190. this.isSendingImages.set(false);
  191. this.sendingProjectId.set(null);
  192. this.snackBar.open(`项目 ${settlement.projectName} 大图已发送到企业微信群`, '关闭', {
  193. duration: 4000,
  194. horizontalPosition: 'center',
  195. verticalPosition: 'top'
  196. });
  197. // 自动创建交付确认提醒
  198. this.createCustomerServiceReminder(settlement, 'delivery_confirmation');
  199. }, 3000);
  200. }
  201. // 获取项目验收状态
  202. getAcceptanceStatus(projectId: string): 'pending' | 'confirming' | 'confirmed' {
  203. return this.acceptanceStatus()[projectId] || 'pending';
  204. }
  205. // 获取客服提醒状态
  206. getReminderStatus(projectId: string): 'pending' | 'creating' | 'created' {
  207. return this.reminderStatus()[projectId] || 'pending';
  208. }
  209. // 检查是否可以发送图片
  210. canSendImages(settlement: Settlement): boolean {
  211. return settlement.status === '已结算' && this.getAcceptanceStatus(settlement.projectId) === 'confirmed';
  212. }
  213. // 检查是否正在发送图片
  214. isSendingImagesForProject(projectId: string): boolean {
  215. return this.isSendingImages() && this.sendingProjectId() === projectId;
  216. }
  217. // 处理单个结算
  218. processSettlement(settlementId: string): void {
  219. const settlement = this.settlements.find(s => s.id === settlementId);
  220. if (!settlement) return;
  221. // 如果是逾期状态,显示逾期处理弹窗
  222. if (settlement.status === '逾期' || this.isOverdue(settlement)) {
  223. this.handleOverdueSettlement(settlement);
  224. } else {
  225. this.processSettlementAutomation(settlement);
  226. }
  227. }
  228. // 处理逾期结算
  229. async handleOverdueSettlement(settlement: Settlement): Promise<void> {
  230. const daysOverdue = this.getDaysOverdue(settlement);
  231. const overdueMessage = `
  232. 项目:${settlement.projectName}
  233. 阶段:${settlement.stage}
  234. 金额:¥${settlement.amount}
  235. 逾期天数:${daysOverdue}天
  236. 请选择处理方式:
  237. 1. 立即催款
  238. 2. 延期处理
  239. 3. 标记为已结算
  240. `.trim();
  241. if (await window?.fmode?.confirm(overdueMessage + '\n\n点击"确定"发送催款提醒,点击"取消"查看更多选项')) {
  242. // 发送催款提醒
  243. this.sendOverdueReminder(settlement);
  244. } else {
  245. // 显示更多处理选项
  246. await this.showOverdueOptions(settlement);
  247. }
  248. }
  249. // 发送逾期催款提醒
  250. private sendOverdueReminder(settlement: Settlement): void {
  251. this.snackBar.open('正在发送催款提醒...', '', {
  252. duration: 2000,
  253. horizontalPosition: 'center',
  254. verticalPosition: 'top'
  255. });
  256. setTimeout(() => {
  257. // 创建客服跟进提醒
  258. this.createCustomerServiceReminder(settlement, 'payment_follow_up');
  259. // 模拟发送多渠道催款通知
  260. const channels = ['短信', '微信', '电话'];
  261. const channelText = channels.join('、');
  262. this.snackBar.open(
  263. `✅ 催款提醒已通过${channelText}发送给客户\n项目:${settlement.projectName}\n金额:¥${settlement.amount}`,
  264. '关闭',
  265. {
  266. duration: 5000,
  267. horizontalPosition: 'center',
  268. verticalPosition: 'top'
  269. }
  270. );
  271. // 记录催款历史
  272. console.log('催款记录:', {
  273. settlementId: settlement.id,
  274. projectName: settlement.projectName,
  275. amount: settlement.amount,
  276. daysOverdue: this.getDaysOverdue(settlement),
  277. reminderDate: new Date(),
  278. channels: channels
  279. });
  280. }, 2000);
  281. }
  282. // 显示逾期处理选项
  283. private async showOverdueOptions(settlement: Settlement): Promise<void> {
  284. const option = await window?.fmode?.input(`
  285. 逾期处理选项:
  286. 1 - 延期7天
  287. 2 - 延期15天
  288. 3 - 延期30天
  289. 4 - 标记为已结算
  290. 5 - 取消结算
  291. 请输入选项编号(1-5):
  292. `.trim());
  293. switch(option) {
  294. case '1':
  295. this.extendSettlementDeadline(settlement, 7);
  296. break;
  297. case '2':
  298. this.extendSettlementDeadline(settlement, 15);
  299. break;
  300. case '3':
  301. this.extendSettlementDeadline(settlement, 30);
  302. break;
  303. case '4':
  304. this.markSettlementAsCompleted(settlement);
  305. break;
  306. case '5':
  307. this.cancelSettlement(settlement);
  308. break;
  309. default:
  310. if (option !== null) {
  311. this.snackBar.open('无效的选项', '关闭', {
  312. duration: 2000,
  313. horizontalPosition: 'center',
  314. verticalPosition: 'top'
  315. });
  316. }
  317. }
  318. }
  319. // 延长结算期限
  320. private extendSettlementDeadline(settlement: Settlement, days: number): void {
  321. const currentDueDate = settlement.dueDate || new Date();
  322. const newDeadline = new Date(currentDueDate);
  323. newDeadline.setDate(newDeadline.getDate() + days);
  324. settlement.dueDate = newDeadline;
  325. settlement.status = '待结算';
  326. this.snackBar.open(
  327. `✅ 已将结算期限延长${days}天\n新期限:${newDeadline.toLocaleDateString()}`,
  328. '关闭',
  329. {
  330. duration: 4000,
  331. horizontalPosition: 'center',
  332. verticalPosition: 'top'
  333. }
  334. );
  335. console.log('延期记录:', {
  336. settlementId: settlement.id,
  337. projectName: settlement.projectName,
  338. extendedDays: days,
  339. newDeadline: newDeadline
  340. });
  341. }
  342. // 标记为已结算
  343. private async markSettlementAsCompleted(settlement: Settlement): Promise<void> {
  344. const reason = await window?.fmode?.input('请输入标记为已结算的原因:');
  345. if (reason && reason.trim()) {
  346. settlement.status = '已结算';
  347. settlement.paidDate = new Date();
  348. this.snackBar.open(
  349. `✅ 已标记为已结算\n项目:${settlement.projectName}\n原因:${reason}`,
  350. '关闭',
  351. {
  352. duration: 4000,
  353. horizontalPosition: 'center',
  354. verticalPosition: 'top'
  355. }
  356. );
  357. console.log('手动结算记录:', {
  358. settlementId: settlement.id,
  359. projectName: settlement.projectName,
  360. reason: reason,
  361. completedDate: new Date()
  362. });
  363. }
  364. }
  365. // 取消结算
  366. private async cancelSettlement(settlement: Settlement): Promise<void> {
  367. const reason = await window?.fmode?.input('请输入取消结算的原因:');
  368. if (reason && reason.trim()) {
  369. if (await window?.fmode?.confirm(`确定要取消此结算吗?\n项目:${settlement.projectName}\n金额:¥${settlement.amount}`)) {
  370. settlement.status = '已取消';
  371. this.snackBar.open(
  372. `✅ 已取消结算\n项目:${settlement.projectName}\n原因:${reason}`,
  373. '关闭',
  374. {
  375. duration: 4000,
  376. horizontalPosition: 'center',
  377. verticalPosition: 'top'
  378. }
  379. );
  380. console.log('取消结算记录:', {
  381. settlementId: settlement.id,
  382. projectName: settlement.projectName,
  383. reason: reason,
  384. cancelledDate: new Date()
  385. });
  386. }
  387. }
  388. }
  389. // 发送提醒
  390. sendReminder(settlementId: string): void {
  391. const settlement = this.settlements.find(s => s.id === settlementId);
  392. if (settlement) {
  393. this.createCustomerServiceReminder(settlement, 'payment_follow_up');
  394. }
  395. }
  396. // 处理单个结算自动化
  397. processSettlementAutomation(settlement: Settlement): void {
  398. this.processingSettlementId.set(settlement.id);
  399. this.isProcessing.set(true);
  400. this.autoSettlementService.processSettlementAutomation(settlement).subscribe({
  401. next: (processed) => {
  402. if (processed) {
  403. console.log(`结算 ${settlement.id} 已自动处理`);
  404. }
  405. this.processingSettlementId.set(null);
  406. this.isProcessing.set(false);
  407. },
  408. error: (error) => {
  409. console.error('自动化处理失败:', error);
  410. this.processingSettlementId.set(null);
  411. this.isProcessing.set(false);
  412. }
  413. });
  414. }
  415. // 项目验收确认相关方法
  416. isProjectAccepted(projectId: string): boolean {
  417. return this.projectAcceptances.some(acceptance =>
  418. acceptance.projectId === projectId && acceptance.acceptanceStatus === 'confirmed'
  419. );
  420. }
  421. // 客服跟进提醒相关方法
  422. hasCustomerServiceReminder(projectId: string): boolean {
  423. return this.customerServiceReminders.some(reminder =>
  424. reminder.projectId === projectId && reminder.reminderStatus === 'completed'
  425. );
  426. }
  427. // 企业微信发图相关方法
  428. canSendToWeChat(projectId: string): boolean {
  429. return this.isProjectAccepted(projectId) && !this.isSendingImagesForProject(projectId);
  430. }
  431. // 批量处理自动化
  432. processAllAutomation(): void {
  433. const pendingSettlements = this.settlements.filter(
  434. s => s.status === '待结算' && !this.isOverdue(s)
  435. );
  436. this.isProcessing.set(true);
  437. // 模拟批量处理
  438. let processedCount = 0;
  439. const processNext = () => {
  440. if (processedCount >= pendingSettlements.length) {
  441. this.isProcessing.set(false);
  442. return;
  443. }
  444. const settlement = pendingSettlements[processedCount];
  445. this.processingSettlementId.set(settlement.id);
  446. this.autoSettlementService.processSettlementAutomation(settlement).subscribe({
  447. next: () => {
  448. processedCount++;
  449. this.processingSettlementId.set(null);
  450. setTimeout(processNext, 500); // 添加延迟以避免同时处理过多
  451. },
  452. error: () => {
  453. processedCount++;
  454. this.processingSettlementId.set(null);
  455. setTimeout(processNext, 500);
  456. }
  457. });
  458. };
  459. processNext();
  460. }
  461. // 计算统计数据
  462. stats = computed<SettlementStats>(() => {
  463. const settlements = this.settlements || [];
  464. return {
  465. totalAmount: settlements.reduce((sum, s) => sum + (s.amount || 0), 0),
  466. pendingAmount: settlements.filter(s => s.status === '待结算').reduce((sum, s) => sum + (s.amount || 0), 0),
  467. overdueAmount: settlements.filter(s => this.isOverdue(s)).reduce((sum, s) => sum + (s.amount || 0), 0),
  468. completedAmount: settlements.filter(s => s.status === '已结算').reduce((sum, s) => sum + (s.amount || 0), 0),
  469. totalCount: settlements.length,
  470. pendingCount: settlements.filter(s => s.status === '待结算').length,
  471. overdueCount: settlements.filter(s => this.isOverdue(s)).length,
  472. completedCount: settlements.filter(s => s.status === '已结算').length
  473. };
  474. });
  475. // 筛选后的结算列表
  476. filteredSettlements = computed(() => {
  477. let filtered = this.settlements || [];
  478. // 状态筛选
  479. const status = this.statusFilter();
  480. if (status !== 'all') {
  481. if (status === 'overdue') {
  482. filtered = filtered.filter(s => this.isOverdue(s));
  483. } else {
  484. filtered = filtered.filter(s => s.status === status);
  485. }
  486. }
  487. // 关键词搜索
  488. const keyword = this.searchKeyword().toLowerCase();
  489. if (keyword) {
  490. filtered = filtered.filter(s =>
  491. (s.projectName || '').toLowerCase().includes(keyword) ||
  492. (s.stage || '').toLowerCase().includes(keyword)
  493. );
  494. }
  495. return filtered;
  496. });
  497. // 判断是否逾期
  498. isOverdue(settlement: Settlement): boolean {
  499. if (settlement.status === '已结算') return false;
  500. // 简化逾期判断:如果是待结算状态且创建时间超过30天,则认为逾期
  501. const thirtyDaysAgo = new Date();
  502. thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  503. return settlement.createdAt < thirtyDaysAgo;
  504. }
  505. // 获取状态样式类
  506. getStatusClass(settlement: Settlement): string {
  507. if (this.isOverdue(settlement)) return 'overdue';
  508. return settlement.status === '已结算' ? 'completed' : 'pending';
  509. }
  510. // 格式化金额
  511. formatAmount(amount: number): string {
  512. return new Intl.NumberFormat('zh-CN', {
  513. style: 'currency',
  514. currency: 'CNY',
  515. minimumFractionDigits: 0,
  516. maximumFractionDigits: 2
  517. }).format(amount);
  518. }
  519. // 更新筛选条件
  520. updateStatusFilter(status: string): void {
  521. this.statusFilter.set(status);
  522. }
  523. updateSearchKeyword(keyword: string): void {
  524. this.searchKeyword.set(keyword);
  525. }
  526. onSearchInput(event: Event): void {
  527. const target = event.target as HTMLInputElement;
  528. if (target) {
  529. this.updateSearchKeyword(target.value);
  530. }
  531. }
  532. // 计算逾期天数
  533. getDaysOverdue(settlement: Settlement): number {
  534. if (settlement.status === '已结算') return 0;
  535. const thirtyDaysAgo = new Date();
  536. thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
  537. if (settlement.createdAt >= thirtyDaysAgo) return 0;
  538. const today = new Date();
  539. const diffTime = today.getTime() - thirtyDaysAgo.getTime();
  540. return Math.max(0, Math.ceil(diffTime / (1000 * 60 * 60 * 24)));
  541. }
  542. // 验收完成后自动发起尾款结算申请
  543. private initiateFinalSettlement(contextSettlement: Settlement): void {
  544. // 查找当前项目的“尾款结算”记录
  545. this.projectService.getSettlements().subscribe(settlements => {
  546. const finalSettlement = settlements.find(s => s.projectId === contextSettlement.projectId && s.stage === '尾款结算');
  547. if (finalSettlement) {
  548. // 标记为已发起(更新时间)并触发自动化处理
  549. finalSettlement.createdAt = new Date();
  550. this.snackBar.open(`已自动发起尾款结算申请:${finalSettlement.projectName}`, '关闭', {
  551. duration: 3000,
  552. horizontalPosition: 'center',
  553. verticalPosition: 'top'
  554. });
  555. // 触发自动化处理(提醒/折扣/自动确认等)
  556. this.processSettlementAutomation(finalSettlement);
  557. } else {
  558. // 若不存在尾款结算记录,则创建一条默认记录并发起
  559. const newSettlement: Settlement = {
  560. id: `s${Date.now()}`,
  561. projectId: contextSettlement.projectId,
  562. projectName: contextSettlement.projectName,
  563. stage: '尾款结算',
  564. amount: 0,
  565. percentage: 100,
  566. status: '待结算',
  567. createdAt: new Date()
  568. };
  569. this.projectService.addSettlement(newSettlement).subscribe(() => {
  570. this.snackBar.open(`已创建并自动发起尾款结算申请:${newSettlement.projectName}`, '关闭', {
  571. duration: 3000,
  572. horizontalPosition: 'center',
  573. verticalPosition: 'top'
  574. });
  575. this.processSettlementAutomation(newSettlement);
  576. });
  577. }
  578. });
  579. }
  580. }