# 项目管理 - 售后归档阶段 PRD ## 1. 功能概述 ### 1.1 阶段定位 售后归档阶段是项目管理流程的收尾环节,包含尾款结算、全景图合成、客户评价、投诉处理、项目复盘五大核心模块。该阶段负责完成项目交付、收集反馈、总结经验,为后续项目优化提供数据支撑。 ### 1.2 核心目标 - 实现自动化尾款结算流程 - 生成全景图分享链接 - 收集客户多维度评价 - 处理客户投诉反馈 - 生成项目复盘报告 ### 1.3 涉及角色 - **客服人员**:跟进尾款支付、发送评价链接、处理投诉 - **技术人员**:验收交付物、启动自动结算、合成全景图 - **组长**:审核复盘报告、处理投诉、优化流程 - **财务人员**:确认款项到账、核对支付凭证 ### 1.4 五大核心模块 ```mermaid graph TD A[后期完成] --> B[尾款结算] B --> C[全景图合成] C --> D[客户评价] D --> E[投诉处理] E --> F[项目复盘] style B fill:#e8f5e9 style C fill:#fff3e0 style D fill:#e3f2fd style E fill:#fce4ec style F fill:#f3e5f5 ``` ## 2. 尾款结算模块 ### 2.1 功能特点 - 技术验收触发自动化结算 - 小程序支付自动监听 - 支付凭证智能识别 - 渲染大图自动解锁 - 客服一键发图 ### 2.2 自动化结算流程 #### 2.2.1 启动自动化结算 ```typescript // project-detail.ts lines 3892-3938 initiateAutoSettlement(): void { console.log('🚀 启动自动化尾款结算流程'); // 1. 权限验证 if (!this.isTechnicalView()) { alert('⚠️ 仅技术人员可以启动自动化结算流程'); return; } // 2. 验收状态检查 if (!this.isAllDeliveryCompleted()) { alert('⚠️ 请先完成所有交付阶段验收'); return; } console.log('✅ 验收状态检查通过'); // 3. 激活小程序支付监听 this.miniprogramPaymentStatus = 'active'; console.log('📱 小程序支付监听已激活'); // 4. 创建尾款结算记录 this.createFinalPaymentRecord(); // 5. 通知客服跟进尾款 this.notifyCustomerServiceForFinalPayment(); // 6. 启动支付自动化 this.setupPaymentAutomation(); alert('✅ 自动化结算流程已启动!\n\n- 小程序支付监听已激活\n- 客服已收到尾款跟进通知\n- 支付到账后将自动解锁大图'); } ``` **权限验证**: - 仅技术人员可以启动 - 确保所有交付阶段已完成 - 验证交付物质量合格 #### 2.2.2 创建结算记录 ```typescript // project-detail.ts lines 3940-3962 private createFinalPaymentRecord(): void { const totalAmount = this.orderAmount || 150000; const downPayment = totalAmount * 0.5; // 假设定金50% const remainingAmount = totalAmount - downPayment; this.settlementRecord = { id: `settlement-${Date.now()}`, projectId: this.projectId, totalAmount: totalAmount, downPayment: downPayment, remainingAmount: remainingAmount, paidAmount: 0, status: 'pending', createdAt: new Date(), dueDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7天后到期 paymentMethod: undefined, paidAt: undefined, notes: '技术验收完成,等待客户支付尾款' }; console.log('📝 尾款结算记录已创建:', this.settlementRecord); } ``` **结算记录结构**: ```typescript interface SettlementRecord { id: string; projectId: string; totalAmount: number; // 订单总金额 downPayment: number; // 定金金额 remainingAmount: number; // 尾款金额 paidAmount: number; // 已支付金额 status: 'pending' | 'partial' | 'completed' | 'overdue'; createdAt: Date; dueDate: Date; // 到期日期 paymentMethod?: 'wechat' | 'alipay' | 'bank'; paidAt?: Date; voucherUrl?: string; // 支付凭证URL notes?: string; } ``` #### 2.2.3 通知客服跟进 ```typescript // project-detail.ts lines 3964-3978 private notifyCustomerServiceForFinalPayment(): void { const notification = { type: 'final-payment-reminder', projectId: this.projectId, projectName: this.project?.name || '未命名项目', amount: this.settlementRecord?.remainingAmount || 0, dueDate: this.settlementRecord?.dueDate, message: `项目"${this.project?.name}"已完成技术验收,请跟进客户支付尾款 ¥${this.settlementRecord?.remainingAmount.toLocaleString()}` }; // 实际应用中调用通知服务 console.log('📧 已发送客服通知:', notification); // 模拟通知发送 alert(`✉️ 已通知客服跟进尾款\n\n项目: ${notification.projectName}\n尾款金额: ¥${notification.amount.toLocaleString()}`); } ``` ### 2.3 支付监听系统 #### 2.3.1 小程序支付监听 ```typescript // project-detail.ts lines 3980-4012 private setupPaymentAutomation(): void { console.log('🔧 设置支付自动化监听'); // 监听小程序支付状态变化 // 实际应用中应使用WebSocket或轮询API this.miniprogramPaymentStatus = 'active'; // 模拟支付监听(实际项目中应替换为真实的WebSocket连接) this.simulatePaymentMonitoring(); } private simulatePaymentMonitoring(): void { console.log('🔄 开始模拟支付监听...'); // 实际项目中应该是: // 1. 建立WebSocket连接到支付服务器 // 2. 监听支付成功事件 // 3. 接收支付信息(金额、方式、时间等) // 4. 自动触发解锁流程 // 这里仅作演示,实际不会自动触发 console.log('💡 提示: 客户通过小程序支付后,系统将自动接收通知'); console.log('💡 提示: 支付凭证识别功能可手动上传截图触发'); } ``` **监听流程**: ```mermaid sequenceDiagram participant Customer as 客户 participant MiniApp as 小程序 participant PaymentGateway as 支付网关 participant System as 系统 participant Designer as 设计师 Customer->>MiniApp: 发起尾款支付 MiniApp->>PaymentGateway: 调用支付接口 PaymentGateway-->>MiniApp: 支付成功回调 MiniApp->>System: 推送支付通知 System->>System: 更新结算状态 System->>System: 解锁渲染大图 System->>Designer: 通知客服发图 ``` #### 2.3.2 支付到账处理 ```typescript // project-detail.ts lines 4014-4048 onPaymentReceived(paymentInfo?: any): void { console.log('💰 收到支付通知:', paymentInfo); if (!this.settlementRecord) { console.error('❌ 结算记录不存在'); return; } // 更新结算状态 this.settlementRecord.status = 'completed'; this.settlementRecord.paidAmount = paymentInfo?.amount || this.settlementRecord.remainingAmount; this.settlementRecord.paymentMethod = paymentInfo?.method || 'wechat'; this.settlementRecord.paidAt = new Date(); console.log('✅ 结算状态已更新:', this.settlementRecord); // 自动解锁渲染大图 this.autoUnlockAndSendImages(); // 发送支付确认通知 this.sendPaymentConfirmationNotifications(); // 停止支付监听 this.miniprogramPaymentStatus = 'completed'; console.log('🎉 尾款结算流程完成'); } ``` #### 2.3.3 自动解锁大图 ```typescript // project-detail.ts lines 4050-4068 private autoUnlockAndSendImages(): void { console.log('🔓 开始自动解锁渲染大图'); // 解锁所有渲染大图 let unlockedCount = 0; this.renderLargeImages.forEach(img => { if (img.locked) { img.locked = false; unlockedCount++; } }); console.log(`✅ 已解锁${unlockedCount}张渲染大图`); // 通知客服可以发送大图 alert(`✅ 尾款已到账,${unlockedCount}张渲染大图已解锁!\n\n客服可一键发送给客户。`); // 触发界面更新 this.cdr.detectChanges(); } ``` ### 2.4 支付凭证识别 #### 2.4.1 凭证上传 ```typescript // 上传支付凭证 uploadPaymentVoucher(event: Event): void { const input = event.target as HTMLInputElement; if (!input.files || input.files.length === 0) return; const file = input.files[0]; // 验证文件类型 if (!file.type.startsWith('image/')) { alert('请上传图片格式的支付凭证'); return; } this.isUploadingVoucher = true; // 上传文件到服务器 this.uploadFile(file).then(url => { // 触发智能识别 this.recognizePaymentVoucher(url); }).catch(error => { console.error('支付凭证上传失败:', error); alert('上传失败,请重试'); this.isUploadingVoucher = false; }); } ``` #### 2.4.2 智能识别 ```typescript // 调用支付凭证识别服务 private recognizePaymentVoucher(imageUrl: string): void { this.paymentVoucherService.recognize(imageUrl).subscribe({ next: (result) => { console.log('识别结果:', result); // 显示识别结果 this.voucherRecognitionResult = { amount: result.amount, paymentMethod: result.method, transactionId: result.transactionId, transactionTime: result.time, confidence: result.confidence }; // 如果识别置信度高,自动填充 if (result.confidence > 0.8) { this.autoFillPaymentInfo(result); } this.isUploadingVoucher = false; }, error: (error) => { console.error('支付凭证识别失败:', error); alert('识别失败,请手动填写支付信息'); this.isUploadingVoucher = false; } }); } ``` **识别结果结构**: ```typescript interface VoucherRecognitionResult { amount: number; // 支付金额 paymentMethod: 'wechat' | 'alipay'; // 支付方式 transactionId: string; // 交易单号 transactionTime: Date; // 交易时间 confidence: number; // 识别置信度 0-1 merchantName?: string; // 商户名称 remarks?: string; // 备注信息 } ``` ### 2.5 一键发图功能 ```typescript // 客服一键发送渲染大图 sendImagesToCustomer(): void { const unlockedImages = this.renderLargeImages.filter(img => !img.locked); if (unlockedImages.length === 0) { alert('没有可发送的图片(渲染大图未解锁)'); return; } // 生成图片下载链接 const imageLinks = unlockedImages.map(img => ({ name: img.name, url: img.url, size: img.size })); // 调用发送服务 this.projectService.sendImagesToCustomer( this.projectId, imageLinks ).subscribe({ next: (result) => { if (result.success) { alert(`✅ 已成功发送${unlockedImages.length}张图片给客户!`); // 标记为已发送 unlockedImages.forEach(img => { img.synced = true; }); } }, error: (error) => { console.error('发送图片失败:', error); alert('发送失败,请重试'); } }); } ``` ## 3. 全景图合成模块 ### 3.1 功能特点 - KR Panel集成 - 智能空间标注 - 自动生成分享链接 - 漫游式预览体验 ### 3.2 全景图合成流程 #### 3.2.1 启动合成 ```typescript // 开始全景图合成 startPanoramicSynthesis(): void { console.log('🖼️ 启动全景图合成'); // 打开文件选择对话框 const input = document.createElement('input'); input.type = 'file'; input.multiple = true; input.accept = 'image/*'; input.onchange = (event: any) => { const files = Array.from(event.target.files) as File[]; if (files.length === 0) return; this.uploadAndSynthesizePanoramic(files); }; input.click(); } ``` #### 3.2.2 文件上传与合成 ```typescript // project-detail.ts lines 4217-4288 private uploadAndSynthesizePanoramic(files: File[]): void { console.log(`📤 开始上传${files.length}个文件...`); this.isUploadingPanoramicFiles = true; this.panoramicUploadProgress = 0; // 模拟文件上传进度 const uploadInterval = setInterval(() => { this.panoramicUploadProgress += 10; if (this.panoramicUploadProgress >= 100) { this.panoramicUploadProgress = 100; clearInterval(uploadInterval); // 上传完成,开始合成 this.synthesizePanoramicView(files); } }, 300); } private synthesizePanoramicView(files: File[]): void { console.log('🔧 开始合成全景图...'); this.isUploadingPanoramicFiles = false; this.isSynthesizingPanoramic = true; this.panoramicSynthesisProgress = 0; // 模拟合成进度 const synthesisInterval = setInterval(() => { this.panoramicSynthesisProgress += 5; if (this.panoramicSynthesisProgress >= 100) { this.panoramicSynthesisProgress = 100; clearInterval(synthesisInterval); // 合成完成 this.completePanoramicSynthesis(files); } }, 500); } ``` **KR Panel集成**: - 支持多角度图片合成 - 自动识别空间名称 - 生成3D漫游场景 - 支持VR模式预览 #### 3.2.3 完成合成 ```typescript // project-detail.ts lines 4290-4328 private completePanoramicSynthesis(files: File[]): void { this.isSynthesizingPanoramic = false; // 创建全景图合成记录 const synthesis: PanoramicSynthesis = { id: `panoramic-${Date.now()}`, name: `全景图_${new Date().toLocaleDateString()}`, createdAt: new Date(), spaces: files.map((file, index) => ({ id: `space-${index}`, name: this.extractSpaceName(file.name), imageUrl: URL.createObjectURL(file), angle: index * 60 // 假设每60度一个角度 })), previewUrl: 'https://example.com/panoramic/preview', downloadUrl: 'https://example.com/panoramic/download', shareLink: '', fileSize: files.reduce((sum, f) => sum + f.size, 0), status: 'completed' }; // 添加到历史记录 this.panoramicSynthesisHistory.push(synthesis); // 生成分享链接 this.generatePanoramicShareLink(synthesis); console.log('✅ 全景图合成完成:', synthesis); alert(`✅ 全景图合成完成!\n\n已生成${synthesis.spaces.length}个空间的全景图\n文件大小: ${this.formatFileSize(synthesis.fileSize)}`); } ``` **全景图数据结构**: ```typescript interface PanoramicSynthesis { id: string; name: string; createdAt: Date; spaces: Array<{ id: string; name: string; // 空间名称:客厅-角度1 imageUrl: string; angle: number; // 拍摄角度 }>; previewUrl: string; // 预览链接 downloadUrl: string; // 下载链接 shareLink: string; // 分享链接 fileSize: number; status: 'processing' | 'completed' | 'failed'; } ``` ### 3.3 自动生成分享链接 ```typescript // project-detail.ts lines 4330-4360 private generatePanoramicShareLink(synthesis: PanoramicSynthesis): void { // 生成唯一分享链接 const linkId = btoa(`panoramic-${synthesis.id}-${Date.now()}`); const shareLink = `https://vr.example.com/view/${linkId}`; synthesis.shareLink = shareLink; console.log('🔗 已生成分享链接:', shareLink); // 自动复制到剪贴板 this.copyToClipboard(shareLink); // 通知客服发送给客户 this.notifyCustomerServiceForPanoramicShare(synthesis); alert(`✅ 分享链接已生成并复制到剪贴板!\n\n${shareLink}\n\n客服已收到通知,可发送给客户。`); } private notifyCustomerServiceForPanoramicShare(synthesis: PanoramicSynthesis): void { const notification = { type: 'panoramic-ready', projectId: this.projectId, projectName: this.project?.name || '未命名项目', shareLink: synthesis.shareLink, spaceCount: synthesis.spaces.length, message: `项目"${this.project?.name}"的全景图已合成完成,请发送给客户查看` }; console.log('📧 已通知客服发送全景图:', notification); } ``` **分享链接特点**: - 唯一性标识 - 有效期控制(可选) - 访问统计 - VR模式支持 ## 4. 客户评价模块 ### 4.1 功能特点 - 多维度评分系统 - 评价链接自动生成 - 30天有效期 - 数据统计分析 ### 4.2 评价链接生成 #### 4.2.1 生成评价令牌 ```typescript // 生成客户评价链接 generateReviewLink(): void { console.log('📋 生成客户评价链接'); // 生成唯一评价令牌 const token = this.generateUniqueToken(); // 创建评价链接记录 const reviewLink: CustomerReviewLink = { id: `review-link-${Date.now()}`, projectId: this.projectId, token: token, link: `https://review.example.com/${token}`, createdAt: new Date(), expiresAt: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30天后过期 status: 'active', submittedAt: undefined }; this.customerReviewLink = reviewLink; // 复制到剪贴板 this.copyToClipboard(reviewLink.link); // 通知客服 this.notifyCustomerServiceForReview(reviewLink); console.log('✅ 评价链接已生成:', reviewLink); alert(`✅ 评价链接已生成并复制到剪贴板!\n\n${reviewLink.link}\n\n有效期: 30天\n客服已收到通知,可发送给客户。`); } ``` **评价链接结构**: ```typescript interface CustomerReviewLink { id: string; projectId: string; token: string; // 唯一令牌 link: string; // 完整链接 createdAt: Date; expiresAt: Date; // 过期时间 status: 'active' | 'submitted' | 'expired'; submittedAt?: Date; } ``` #### 4.2.2 生成唯一令牌 ```typescript private generateUniqueToken(): string { const timestamp = Date.now().toString(36); const randomStr = Math.random().toString(36).substring(2, 15); const projectIdHash = btoa(this.projectId).substring(0, 8); return `${timestamp}-${randomStr}-${projectIdHash}`; } ``` ### 4.3 评价数据结构 ```typescript interface CustomerReview { id: string; projectId: string; submittedAt: Date; // 多维度评分 (1-5星) ratings: { overall: number; // 整体满意度 timeliness: number; // 及时性 quality: number; // 设计质量 communication: number; // 沟通效率 professionalism: number; // 专业程度 }; // 文字评价 comments: { strengths: string; // 优点 improvements: string; // 改进建议 additional: string; // 其他意见 }; // 推荐意愿 wouldRecommend: boolean; // 附加信息 contact?: string; permitPublish: boolean; // 是否允许公开 } ``` ### 4.4 评价提交处理 ```typescript // 处理客户提交的评价 onReviewSubmitted(reviewData: CustomerReview): void { console.log('📝 收到客户评价:', reviewData); // 保存评价数据 this.customerReviews.push(reviewData); // 更新评价链接状态 if (this.customerReviewLink) { this.customerReviewLink.status = 'submitted'; this.customerReviewLink.submittedAt = new Date(); } // 计算平均分 this.calculateAverageRatings(); // 通知相关人员 this.notifyReviewReceived(reviewData); console.log('✅ 客户评价已保存'); alert('✅ 感谢客户的宝贵评价!\n\n评价数据已保存并通知相关人员。'); } ``` ### 4.5 评价数据分析 ```typescript // 计算平均评分 private calculateAverageRatings(): void { if (this.customerReviews.length === 0) { this.averageRatings = { overall: 0, timeliness: 0, quality: 0, communication: 0, professionalism: 0 }; return; } const sum = this.customerReviews.reduce((acc, review) => ({ overall: acc.overall + review.ratings.overall, timeliness: acc.timeliness + review.ratings.timeliness, quality: acc.quality + review.ratings.quality, communication: acc.communication + review.ratings.communication, professionalism: acc.professionalism + review.ratings.professionalism }), { overall: 0, timeliness: 0, quality: 0, communication: 0, professionalism: 0 }); const count = this.customerReviews.length; this.averageRatings = { overall: Math.round((sum.overall / count) * 10) / 10, timeliness: Math.round((sum.timeliness / count) * 10) / 10, quality: Math.round((sum.quality / count) * 10) / 10, communication: Math.round((sum.communication / count) * 10) / 10, professionalism: Math.round((sum.professionalism / count) * 10) / 10 }; console.log('📊 平均评分已更新:', this.averageRatings); } ``` ## 5. 投诉处理模块 ### 5.1 功能特点 - 人工创建投诉 - 关键词自动抓取 - 智能标注问题类型 - 处理进度跟踪 ### 5.2 人工创建投诉 #### 5.2.1 创建投诉记录 ```typescript // 人工创建投诉记录 createComplaintManually(): void { console.log('📝 人工创建投诉记录'); // 验证权限 if (!this.isTeamLeaderView() && !this.isCustomerServiceView()) { alert('⚠️ 仅组长和客服可以创建投诉记录'); return; } // 打开投诉创建表单 this.showComplaintForm = true; this.complaintFormData = { source: 'manual', stage: '', reason: '', description: '', severity: 'medium', tags: [] }; } ``` #### 5.2.2 提交投诉 ```typescript // 提交投诉记录 submitComplaint(): void { if (!this.complaintFormData.reason || !this.complaintFormData.description) { alert('请填写投诉原因和详细描述'); return; } const complaint: ComplaintRecord = { id: `complaint-${Date.now()}`, projectId: this.projectId, source: this.complaintFormData.source, stage: this.complaintFormData.stage || '未指定', reason: this.complaintFormData.reason, description: this.complaintFormData.description, severity: this.complaintFormData.severity, tags: this.complaintFormData.tags, status: '待处理', createdAt: new Date(), createdBy: this.getCurrentUserName(), assignedTo: undefined, resolvedAt: undefined, resolution: undefined }; // 添加到投诉列表 this.complaints.push(complaint); // 通知相关处理人员 this.notifyComplaintHandler(complaint); // 关闭表单 this.showComplaintForm = false; console.log('✅ 投诉记录已创建:', complaint); alert('✅ 投诉记录已创建!\n\n相关人员已收到通知。'); } ``` **投诉数据结构**: ```typescript interface ComplaintRecord { id: string; projectId: string; source: 'manual' | 'keyword-detection'; // 来源 stage: string; // 投诉环节 reason: string; // 投诉原因 description: string; // 详细描述 severity: 'low' | 'medium' | 'high'; // 严重程度 tags: string[]; // 问题标签 status: '待处理' | '处理中' | '已解决' | '已关闭'; createdAt: Date; createdBy: string; assignedTo?: string; // 分配给 resolvedAt?: Date; resolution?: string; // 解决方案 attachments?: Array<{ id: string; name: string; url: string; }>; } ``` ### 5.3 关键词自动监控 #### 5.3.1 设置关键词监测 ```typescript // 启动关键词监测 setupKeywordMonitoring(): void { console.log('🔍 设置关键词监测'); // 打开监控设置面板 this.showKeywordMonitoringSettings = true; // 初始化默认关键词 if (this.monitoringKeywords.length === 0) { this.monitoringKeywords = [ '不满意', '投诉', '退款', '差评', '质量问题', '延期', '态度差' ]; } console.log('📋 当前监控关键词:', this.monitoringKeywords); } ``` #### 5.3.2 关键词检测 ```typescript // 检测消息中的关键词 private detectKeywords(message: string): string[] { const detectedKeywords: string[] = []; this.monitoringKeywords.forEach(keyword => { if (message.includes(keyword)) { detectedKeywords.push(keyword); } }); return detectedKeywords; } ``` #### 5.3.3 自动创建投诉 ```typescript // 检测到关键词后自动创建投诉 onKeywordDetected(message: string, keyword: string): void { console.log(`🚨 检测到关键词: ${keyword}`); // 智能分析投诉严重程度 const severity = this.assessComplaintSeverity(keyword); // 智能识别投诉环节 const stage = this.identifyComplaintStage(message); // 智能标注问题类型 const tags = this.generateComplaintTags(message, keyword); // 自动创建投诉记录 const complaint: ComplaintRecord = { id: `complaint-auto-${Date.now()}`, projectId: this.projectId, source: 'keyword-detection', stage: stage, reason: `检测到关键词: ${keyword}`, description: message, severity: severity, tags: tags, status: '待处理', createdAt: new Date(), createdBy: '系统自动', assignedTo: undefined, resolvedAt: undefined, resolution: undefined }; this.complaints.push(complaint); // 立即通知处理人员 this.notifyUrgentComplaint(complaint); console.log('✅ 已自动创建投诉记录:', complaint); alert(`🚨 检测到客户投诉关键词: ${keyword}\n\n已自动创建投诉记录并通知相关人员。`); } ``` **智能分析方法**: ```typescript // 评估投诉严重程度 private assessComplaintSeverity(keyword: string): 'low' | 'medium' | 'high' { const highSeverityKeywords = ['退款', '投诉', '差评']; const mediumSeverityKeywords = ['不满意', '质量问题', '延期']; if (highSeverityKeywords.includes(keyword)) return 'high'; if (mediumSeverityKeywords.includes(keyword)) return 'medium'; return 'low'; } // 识别投诉环节 private identifyComplaintStage(message: string): string { if (message.includes('需求') || message.includes('沟通')) return '需求沟通'; if (message.includes('方案') || message.includes('设计')) return '方案确认'; if (message.includes('建模') || message.includes('模型')) return '建模'; if (message.includes('软装') || message.includes('家具')) return '软装'; if (message.includes('渲染') || message.includes('效果图')) return '渲染'; if (message.includes('交付') || message.includes('延期')) return '交付'; return '未识别'; } // 生成问题标签 private generateComplaintTags(message: string, keyword: string): string[] { const tags: string[] = []; // 根据消息内容添加标签 if (message.includes('需求') || message.includes('理解')) tags.push('需求理解'); if (message.includes('质量') || message.includes('效果')) tags.push('设计质量'); if (message.includes('延期') || message.includes('时间')) tags.push('交付延期'); if (message.includes('态度') || message.includes('服务')) tags.push('服务态度'); if (message.includes('价格') || message.includes('费用')) tags.push('价格问题'); // 添加关键词作为标签 tags.push(keyword); return [...new Set(tags)]; // 去重 } ``` ### 5.4 投诉处理流程 ```typescript // 处理投诉 handleComplaint(complaintId: string, resolution: string): void { const complaint = this.complaints.find(c => c.id === complaintId); if (!complaint) return; complaint.status = '已解决'; complaint.resolvedAt = new Date(); complaint.resolution = resolution; // 通知客户和相关人员 this.notifyComplaintResolved(complaint); console.log('✅ 投诉已处理:', complaint); alert('✅ 投诉处理完成!\n\n已通知客户和相关人员。'); } ``` ## 6. 项目复盘模块 ### 6.1 功能特点 - 三大核心板块(SOP执行数据、经验复盘、优化建议) - 数据可视化展示 - 自动生成复盘报告 - 导出为PDF/Excel ### 6.2 SOP执行数据 #### 6.2.1 数据收集 ```typescript // 收集SOP执行数据 collectSOPExecutionData(): any { return { requirementCommunications: this.countRequirementCommunications(), revisionCount: this.countRevisions(), deliveryCycleCompliance: this.checkDeliveryCycleCompliance(), customerSatisfaction: this.getCustomerSatisfactionScore(), stageDetails: this.getStageExecutionDetails() }; } ``` #### 6.2.2 阶段执行详情 ```typescript // 获取各阶段执行详情 private getStageExecutionDetails(): Array<{ stage: string; plannedDuration: number; actualDuration: number; status: 'on-time' | 'delayed' | 'ahead'; score: number; }> { return [ { stage: '需求沟通', plannedDuration: 2, actualDuration: 2, status: 'on-time', score: 95 }, { stage: '方案确认', plannedDuration: 3, actualDuration: 4, status: 'delayed', score: 85 }, { stage: '建模', plannedDuration: 5, actualDuration: 4, status: 'ahead', score: 92 }, { stage: '软装', plannedDuration: 3, actualDuration: 3, status: 'on-time', score: 90 }, { stage: '渲染', plannedDuration: 4, actualDuration: 5, status: 'delayed', score: 88 } ]; } ``` ### 6.3 经验复盘 #### 6.3.1 自动提取信息 ```typescript // 提取经验复盘数据 extractExperienceSummary(): any { return { customerNeeds: this.extractCustomerNeeds(), customerConcerns: this.extractCustomerConcerns(), complaintPoints: this.extractComplaintPoints(), projectHighlights: this.extractProjectHighlights(), keyConversations: this.extractKeyConversations() }; } ``` #### 6.3.2 提取客户需求 ```typescript private extractCustomerNeeds(): string[] { // 从需求沟通记录中提取 return [ '客户希望整体风格偏现代简约', '客户重视收纳空间的设计', '客户要求使用环保材料', '客户希望采光效果良好' ]; } ``` ### 6.4 优化建议 #### 6.4.1 生成优化建议 ```typescript // 生成优化建议 generateOptimizationSuggestions(): any[] { const suggestions = []; // 基于数据分析生成建议 const sopData = this.collectSOPExecutionData(); // 建议1:需求沟通优化 if (sopData.requirementCommunications > 5) { suggestions.push({ priority: 'high', priorityText: '高', category: '需求沟通', problem: '需求沟通次数过多(6次),影响项目效率', dataSupport: `需求沟通次数: ${sopData.requirementCommunications}次,标准为3-4次`, solution: '建议在首次沟通时使用标准化需求采集表,确保需求收集的完整性', actionPlan: [ '制定标准需求采集表模板', '培训设计师使用标准表单', '要求首次沟通必须完成80%需求确认' ], expectedImprovement: '减少30%的需求沟通次数', referenceCase: '参考项目#1234在使用标准表后沟通次数从6次降至3次', accepted: false }); } // 建议2:渲染阶段优化 const renderingStage = sopData.stageDetails.find((s: any) => s.stage === '渲染'); if (renderingStage && renderingStage.status === 'delayed') { suggestions.push({ priority: 'medium', priorityText: '中', category: '渲染效率', problem: '渲染阶段超期1天,影响整体交付时间', dataSupport: `计划4天,实际5天,超期率25%`, solution: '建议提前进行渲染设备性能检查,并预留缓冲时间', actionPlan: [ '每月检查渲染设备性能', '建模完成后立即启动预渲染', '渲染阶段预留20%缓冲时间' ], expectedImprovement: '降低渲染超期率至10%以下', referenceCase: '团队B采用预渲染机制后超期率从30%降至8%', accepted: false }); } return suggestions; } ``` **优化建议结构**: ```typescript interface OptimizationSuggestion { priority: 'high' | 'medium' | 'low'; priorityText: string; category: string; // 类别 problem: string; // 问题描述 dataSupport: string; // 数据支撑 solution: string; // 解决方案 actionPlan: string[]; // 行动计划 expectedImprovement: string; // 预期提升 referenceCase?: string; // 参考案例 accepted: boolean; // 是否已采纳 acceptedAt?: Date; } ``` ### 6.5 复盘报告生成 #### 6.5.1 生成报告 ```typescript // 生成完整复盘报告 generateReviewReport(): void { console.log('📊 生成项目复盘报告'); this.isGeneratingReview = true; // 模拟生成进度 let progress = 0; const interval = setInterval(() => { progress += 20; if (progress >= 100) { clearInterval(interval); this.completeReviewReportGeneration(); } }, 500); } private completeReviewReportGeneration(): void { // 收集所有数据 const reportData = { projectInfo: { name: this.project?.name || '未命名项目', id: this.projectId, startDate: this.project?.createdAt, endDate: new Date() }, sopData: this.collectSOPExecutionData(), experience: this.extractExperienceSummary(), suggestions: this.generateOptimizationSuggestions(), statistics: { overallScore: this.calculateOverallScore(), strengths: this.getProjectStrengths(), weaknesses: this.getProjectWeaknesses() } }; // 保存报告 this.reviewReport = reportData; this.isGeneratingReview = false; console.log('✅ 复盘报告生成完成:', reportData); alert('✅ 项目复盘报告已生成!\n\n您可以查看详情或导出报告。'); } ``` #### 6.5.2 导出报告 ```typescript // 导出复盘报告 exportReviewReport(format: 'pdf' | 'excel'): void { if (!this.reviewReport) { alert('请先生成复盘报告'); return; } console.log(`📤 导出复盘报告 (${format})`); if (format === 'excel') { this.exportAsExcel(this.reviewReport); } else { this.exportAsPDF(this.reviewReport); } } private exportAsExcel(data: any): void { // 转换为CSV格式 let csvContent = '\uFEFF'; // UTF-8 BOM // 项目概况 csvContent += '=== 项目概况 ===\n'; csvContent += `项目名称,${data.projectInfo.name}\n`; csvContent += `项目ID,${data.projectInfo.id}\n`; csvContent += `总耗时,${this.calculateProjectDuration()}天\n\n`; // SOP执行数据 csvContent += '=== SOP执行数据 ===\n'; csvContent += '阶段,计划时长,实际时长,状态,评分\n'; data.sopData.stageDetails.forEach((stage: any) => { csvContent += `${stage.stage},${stage.plannedDuration},${stage.actualDuration},${stage.status},${stage.score}\n`; }); // 优化建议 csvContent += '\n=== 优化建议 ===\n'; csvContent += '优先级,类别,问题,建议,预期提升\n'; data.suggestions.forEach((s: any) => { csvContent += `${s.priorityText},${s.category},"${s.problem}","${s.solution}",${s.expectedImprovement}\n`; }); // 创建下载 const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); const link = document.createElement('a'); const url = URL.createObjectURL(blob); link.href = url; link.download = `项目复盘报告_${data.projectInfo.name}_${this.formatDate(new Date())}.csv`; link.click(); URL.revokeObjectURL(url); console.log('✅ 报告已导出为Excel'); alert('✅ 报告已导出!\n\n文件已下载到您的下载文件夹。'); } ``` ## 7. 权限控制 ### 7.1 角色权限矩阵 | 操作 | 客服 | 设计师 | 组长 | 技术 | 财务 | |-----|------|--------|------|------|------| | 查看售后板块 | ✅ | ✅ | ✅ | ✅ | ✅ | | 启动自动结算 | ❌ | ❌ | ❌ | ✅ | ❌ | | 上传支付凭证 | ✅ | ❌ | ✅ | ❌ | ✅ | | 发送图片给客户 | ✅ | ❌ | ✅ | ❌ | ❌ | | 合成全景图 | ❌ | ❌ | ❌ | ✅ | ❌ | | 生成评价链接 | ✅ | ❌ | ✅ | ❌ | ❌ | | 创建投诉记录 | ✅ | ❌ | ✅ | ❌ | ❌ | | 处理投诉 | ✅ | ❌ | ✅ | ❌ | ❌ | | 生成复盘报告 | ❌ | ❌ | ✅ | ✅ | ❌ | | 导出复盘报告 | ❌ | ❌ | ✅ | ✅ | ✅ | ### 7.2 权限检查实现 ```typescript // 检查尾款结算权限 canInitiateSettlement(): boolean { return this.isTechnicalView(); } // 检查全景图合成权限 canSynthesizePanoramic(): boolean { return this.isTechnicalView(); } // 检查投诉处理权限 canHandleComplaints(): boolean { return this.isTeamLeaderView() || this.isCustomerServiceView(); } // 检查复盘报告权限 canGenerateReviewReport(): boolean { return this.isTeamLeaderView() || this.isTechnicalView(); } ``` ## 8. 数据流转 ### 8.1 售后流程总览 ```mermaid sequenceDiagram participant Tech as 技术 participant System as 系统 participant Payment as 支付网关 participant CS as 客服 participant Customer as 客户 Tech->>System: 启动自动结算 System->>Payment: 激活支付监听 System->>CS: 通知跟进尾款 CS->>Customer: 发送支付请求 Customer->>Payment: 完成支付 Payment->>System: 支付通知 System->>System: 解锁渲染大图 System->>CS: 通知发送大图 CS->>Customer: 发送渲染大图 System->>CS: 生成评价链接 CS->>Customer: 发送评价链接 Customer->>System: 提交评价 System->>Tech: 生成复盘报告 ``` ### 8.2 数据同步机制 ```typescript // 售后数据同步到项目 private syncAfterCareDataToProject(): void { if (!this.project) return; this.project.afterCare = { settlement: this.settlementRecord, panoramic: this.panoramicSynthesisHistory, reviews: this.customerReviews, complaints: this.complaints, reviewReport: this.reviewReport }; // 同步到服务器 this.projectService.updateProject(this.project).subscribe({ next: (result) => { console.log('✅ 售后数据已同步到项目'); }, error: (error) => { console.error('❌ 售后数据同步失败:', error); } }); } ``` ## 9. 异常处理 ### 9.1 支付监听失败 ```typescript // 支付监听连接失败处理 private handlePaymentMonitoringError(error: any): void { console.error('支付监听连接失败:', error); // 降级为手动模式 this.miniprogramPaymentStatus = 'error'; alert(`⚠️ 支付自动监听失败\n\n请使用"上传支付凭证"功能手动确认支付。`); // 显示手动上传入口 this.showManualPaymentVoucherUpload = true; } ``` ### 9.2 全景图合成失败 ```typescript // 全景图合成失败处理 private handlePanoramicSynthesisError(error: any): void { console.error('全景图合成失败:', error); this.isSynthesizingPanoramic = false; let errorMessage = '全景图合成失败'; if (error.code === 'INSUFFICIENT_IMAGES') { errorMessage = '图片数量不足,至少需要6张图片'; } else if (error.code === 'INVALID_FORMAT') { errorMessage = '图片格式不支持,请使用JPG或PNG格式'; } alert(`❌ ${errorMessage}\n\n请检查后重试。`); } ``` ### 9.3 评价链接过期 ```typescript // 检查评价链接是否过期 checkReviewLinkExpiry(linkId: string): boolean { const link = this.customerReviewLinks.find(l => l.id === linkId); if (!link) return true; if (link.status === 'expired') return true; // 检查是否超过有效期 if (new Date() > link.expiresAt) { link.status = 'expired'; return true; } return false; } // 重新生成过期的评价链接 regenerateReviewLink(oldLinkId: string): void { const oldLink = this.customerReviewLinks.find(l => l.id === oldLinkId); if (!oldLink) return; // 将旧链接标记为过期 oldLink.status = 'expired'; // 生成新链接 this.generateReviewLink(); alert('✅ 已重新生成评价链接!\n\n旧链接已失效,请使用新链接。'); } ``` ## 10. 性能优化 ### 10.1 报告生成优化 ```typescript // 使用Worker生成大型报告 private generateReportWithWorker(data: any): void { if (typeof Worker !== 'undefined') { const worker = new Worker(new URL('./report-generator.worker', import.meta.url)); worker.onmessage = ({ data }) => { console.log('报告生成完成:', data); this.reviewReport = data.report; this.isGeneratingReview = false; }; worker.postMessage({ type: 'generate', data }); } else { // 降级为同步生成 this.generateReportSync(data); } } ``` ### 10.2 图片压缩 ```typescript // 压缩全景图用于预览 private compressImageForPreview(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = (e) => { const img = new Image(); img.onload = () => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 压缩到最大1920px const maxDimension = 1920; const scale = Math.min(maxDimension / img.width, maxDimension / img.height, 1); canvas.width = img.width * scale; canvas.height = img.height * scale; ctx?.drawImage(img, 0, 0, canvas.width, canvas.height); canvas.toBlob((blob) => { if (blob) { resolve(blob); } else { reject(new Error('压缩失败')); } }, 'image/jpeg', 0.8); }; img.src = e.target?.result as string; }; reader.readAsDataURL(file); }); } ``` ### 10.3 数据缓存 ```typescript // 缓存复盘报告数据 private cacheReviewReport(report: any): void { try { localStorage.setItem( `review-report-${this.projectId}`, JSON.stringify(report) ); console.log('✅ 复盘报告已缓存'); } catch (error) { console.warn('缓存失败:', error); } } // 加载缓存的报告 private loadCachedReviewReport(): any | null { try { const cached = localStorage.getItem(`review-report-${this.projectId}`); if (cached) { return JSON.parse(cached); } } catch (error) { console.warn('加载缓存失败:', error); } return null; } ``` ## 11. 测试用例 ### 11.1 尾款结算测试 ```typescript describe('Final Payment Settlement', () => { it('should initiate auto settlement by technical user', () => { component.roleContext = 'technical'; spyOn(component, 'isAllDeliveryCompleted').and.returnValue(true); component.initiateAutoSettlement(); expect(component.miniprogramPaymentStatus).toBe('active'); expect(component.settlementRecord).toBeDefined(); }); it('should reject non-technical users', () => { component.roleContext = 'designer'; spyOn(window, 'alert'); component.initiateAutoSettlement(); expect(window.alert).toHaveBeenCalledWith(jasmine.stringContaining('仅技术人员')); }); it('should unlock images after payment received', () => { component.renderLargeImages = [ { id: '1', name: 'img1.jpg', url: 'blob:1', locked: true }, { id: '2', name: 'img2.jpg', url: 'blob:2', locked: true } ]; component.onPaymentReceived({ amount: 75000, method: 'wechat' }); expect(component.renderLargeImages.every(img => !img.locked)).toBe(true); }); }); ``` ### 11.2 投诉处理测试 ```typescript describe('Complaint Handling', () => { it('should create complaint manually', () => { component.roleContext = 'team-leader'; component.complaintFormData = { source: 'manual', stage: '渲染', reason: '质量问题', description: '渲染效果不符合预期', severity: 'medium', tags: ['设计质量'] }; component.submitComplaint(); expect(component.complaints.length).toBeGreaterThan(0); }); it('should detect keywords and create complaint', () => { const message = '我对渲染效果很不满意,要求退款'; component.monitoringKeywords = ['不满意', '退款']; component.onKeywordDetected(message, '不满意'); expect(component.complaints.length).toBeGreaterThan(0); expect(component.complaints[0].severity).toBe('high'); }); }); ``` ### 11.3 复盘报告测试 ```typescript describe('Review Report Generation', () => { it('should generate complete review report', () => { component.generateReviewReport(); // Wait for generation setTimeout(() => { expect(component.reviewReport).toBeDefined(); expect(component.reviewReport.sopData).toBeDefined(); expect(component.reviewReport.experience).toBeDefined(); expect(component.reviewReport.suggestions.length).toBeGreaterThan(0); }, 3000); }); it('should export report as Excel', () => { component.reviewReport = mockReviewReport; spyOn(document, 'createElement').and.callThrough(); component.exportReviewReport('excel'); expect(document.createElement).toHaveBeenCalledWith('a'); }); }); ``` --- **文档版本**:v1.0.0 **创建日期**:2025-10-16 **最后更新**:2025-10-16 **维护人**:产品团队 **相关文档**: - [AFTERCARE-FEATURES-README.md](/home/ryan/workspace/nova/yss-project/src/app/pages/designer/project-detail/AFTERCARE-FEATURES-README.md) - 售后模块功能实现说明