import { Component, Input, computed, signal } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { CustomerFeedback } from '../../../models/project.model'; export interface DetailedReviewDimensions { [key: string]: number; // 添加索引签名 overall: number; // 总体评价 0-5 serviceTimeliness: number; // 服务时效 0-5 suggestionResponse: number; // 建议回应 0-5 smallImageDelivery: number; // 小图交付 0-5 imageRevisionTimeliness: number; // 改图及时性 0-5 renderingQuality: number; // 图纸渲染 0-5 materialQuality: number; // 材质 0-5 lightingQuality: number; // 灯光 0-5 textureQuality: number; // 纹理 0-5 structureQuality: number; // 硬装结构 0-5 dataCompleteness: number; // 资料齐全情况 0-5 requirementUnderstanding: number; // 需求理解 0-5 communicationEffectiveness: number; // 沟通效果 0-5 sceneDesignQuality: number; // 场景设计质量 0-5 } export interface SceneReview { sceneType: 'bedroom' | 'dining_room' | 'living_room' | 'other'; sceneName: string; designerId: string; designerName: string; rating: number; // 0-5 feedback: string; } export interface DetailedCustomerReview { id: string; projectId: string; customerId: string; customerName: string; dimensions: DetailedReviewDimensions; sceneReviews: SceneReview[]; improvementSuggestions: string; // 下次合作希望优化的点 optimizationSuggestions?: string[]; // 优化建议列表 overallFeedback: string; submittedAt: Date; status: 'pending' | 'completed'; } export interface ReviewStats { totalCount: number; averageScore: number; satisfiedCount: number; unsatisfiedCount: number; pendingCount: number; processedCount: number; categoryStats: { [key: string]: number }; dimensionAverages: Partial; } @Component({ selector: 'app-customer-review-card', standalone: true, imports: [CommonModule, FormsModule], templateUrl: './customer-review-card.html', styleUrls: ['./customer-review-card.scss'] }) export class CustomerReviewCardComponent { @Input() feedbacks: CustomerFeedback[] = []; @Input() detailedReviews: DetailedCustomerReview[] = []; // 筛选条件 statusFilter = signal('all'); categoryFilter = signal('all'); scoreFilter = signal('all'); viewMode = signal<'simple' | 'detailed'>('detailed'); // 详细评价维度配置 reviewDimensions = [ { key: 'overall', label: '总体评价', description: '对整体服务的满意度' }, { key: 'serviceTimeliness', label: '服务时效', description: '响应速度和交付及时性' }, { key: 'suggestionResponse', label: '建议回应', description: '对客户建议的响应程度' }, { key: 'smallImageDelivery', label: '小图交付', description: '小图质量和交付效率' }, { key: 'imageRevisionTimeliness', label: '改图及时性', description: '修改图纸的响应速度' }, { key: 'renderingQuality', label: '图纸渲染', description: '渲染效果和技术质量' }, { key: 'materialQuality', label: '材质', description: '材质选择和表现效果' }, { key: 'lightingQuality', label: '灯光', description: '灯光设计和氛围营造' }, { key: 'textureQuality', label: '纹理', description: '纹理细节和真实感' }, { key: 'structureQuality', label: '硬装结构', description: '结构设计的合理性' }, { key: 'dataCompleteness', label: '资料齐全情况', description: '提供资料的完整性' }, { key: 'requirementUnderstanding', label: '需求理解', description: '对客户需求的理解准确度' }, { key: 'communicationEffectiveness', label: '沟通效果', description: '沟通的有效性和清晰度' }, { key: 'sceneDesignQuality', label: '场景设计质量', description: '各场景设计的整体质量' } ]; // 场景类型配置 sceneTypes = [ { value: 'bedroom', label: '卧室' }, { value: 'dining_room', label: '餐厅' }, { value: 'living_room', label: '客厅' }, { value: 'other', label: '其他' } ]; // 评价分类 categories = [ { value: 'color', label: '色彩问题' }, { value: 'furniture', label: '家具款式问题' }, { value: 'lighting', label: '光线问题' }, { value: 'layout', label: '布局问题' }, { value: 'material', label: '材质问题' }, { value: 'other', label: '其他问题' } ]; // 计算统计数据 stats = computed(() => { const feedbacks = this.feedbacks || []; const detailedReviews = this.detailedReviews || []; const categoryStats: { [key: string]: number } = {}; this.categories.forEach(cat => { categoryStats[cat.value] = feedbacks.filter(f => this.getFeedbackCategory(f) === cat.value).length; }); const scores = feedbacks.filter(f => f.rating !== undefined).map(f => f.rating || 0); const averageScore = scores.length > 0 ? scores.reduce((sum, score) => sum + score, 0) / scores.length : 0; // 计算详细评价维度的平均分 const dimensionAverages: Partial = {}; if (detailedReviews.length > 0) { this.reviewDimensions.forEach(dimension => { const key = dimension.key as keyof DetailedReviewDimensions; const values = detailedReviews.map(review => review.dimensions[key]).filter(v => v !== undefined); if (values.length > 0) { dimensionAverages[key] = values.reduce((sum, val) => sum + val, 0) / values.length; } }); } return { totalCount: feedbacks.length + detailedReviews.length, averageScore: Math.round(averageScore * 10) / 10, satisfiedCount: feedbacks.filter(f => f.isSatisfied).length + detailedReviews.filter(r => r.dimensions.overall >= 4).length, unsatisfiedCount: feedbacks.filter(f => !f.isSatisfied).length + detailedReviews.filter(r => r.dimensions.overall < 3).length, pendingCount: feedbacks.filter(f => f.status === '待处理').length + detailedReviews.filter(r => r.status === 'pending').length, processedCount: feedbacks.filter(f => f.status === '已解决').length + detailedReviews.filter(r => r.status === 'completed').length, categoryStats, dimensionAverages }; }); // 筛选后的评价列表 filteredFeedbacks = computed(() => { let filtered = this.feedbacks || []; // 状态筛选 const status = this.statusFilter(); if (status !== 'all') { if (status === 'satisfied') { filtered = filtered.filter(f => f.isSatisfied); } else if (status === 'unsatisfied') { filtered = filtered.filter(f => !f.isSatisfied); } else { filtered = filtered.filter(f => f.status === status); } } // 分类筛选 const category = this.categoryFilter(); if (category !== 'all') { filtered = filtered.filter(f => this.getFeedbackCategory(f) === category); } // 评分筛选 const score = this.scoreFilter(); if (score !== 'all') { if (score === 'high') { filtered = filtered.filter(f => (f.rating || 0) >= 4); } else if (score === 'medium') { filtered = filtered.filter(f => (f.rating || 0) >= 2 && (f.rating || 0) < 4); } else if (score === 'low') { filtered = filtered.filter(f => (f.rating || 0) < 2); } } return filtered.sort((a, b) => { // 按状态排序:待处理 > 已处理,按时间倒序 if (a.status !== b.status) { if (a.status === '待处理') return -1; if (b.status === '待处理') return 1; } return new Date(b.updatedAt || b.createdAt).getTime() - new Date(a.updatedAt || a.createdAt).getTime(); }); }); // 获取反馈分类 getFeedbackCategory(feedback: CustomerFeedback): string { const content = feedback.content.toLowerCase(); const location = (feedback.problemLocation || '').toLowerCase(); if (content.includes('色彩') || content.includes('颜色') || location.includes('色彩')) { return 'color'; } else if (content.includes('家具') || content.includes('沙发') || content.includes('桌子') || location.includes('家具')) { return 'furniture'; } else if (content.includes('光线') || content.includes('照明') || content.includes('灯光')) { return 'lighting'; } else if (content.includes('布局') || content.includes('空间') || content.includes('摆放')) { return 'layout'; } else if (content.includes('材质') || content.includes('质感') || content.includes('纹理')) { return 'material'; } return 'other'; } // 获取分类标签 getCategoryLabel(category: string): string { const cat = this.categories.find(c => c.value === category); return cat ? cat.label : '其他问题'; } // 获取评分星级 getStarRating(score: number): string[] { const stars = []; for (let i = 1; i <= 5; i++) { if (i <= score) { stars.push('★'); } else if (i - 0.5 <= score) { stars.push('☆'); } else { stars.push('☆'); } } return stars; } // 获取状态样式类 getStatusClass(feedback: CustomerFeedback): string { if (feedback.status === '已解决') return 'processed'; if (feedback.status === '处理中') return 'processing'; return 'pending'; } // 获取评分样式类 getScoreClass(score: number): string { if (score >= 4) return 'high'; if (score >= 2) return 'medium'; return 'low'; } // 更新筛选条件 updateStatusFilter(status: string): void { this.statusFilter.set(status); } updateCategoryFilter(event: any): void { this.categoryFilter.set(event.target.value); } updateScoreFilter(event: any): void { this.scoreFilter.set(event.target.value); } // 重置筛选条件 resetFilters(): void { this.statusFilter.set('all'); this.categoryFilter.set('all'); this.scoreFilter.set('all'); } // 处理客户评价的方法 startProcessing(feedbackId: string): void { console.log('开始处理客户评价:', feedbackId); // 这里可以调用服务更新状态 const feedback = this.feedbacks.find(f => f.id === feedbackId); if (feedback) { feedback.status = '处理中'; feedback.updatedAt = new Date(); } } markAsResolved(feedbackId: string): void { console.log('标记客户评价为已解决:', feedbackId); // 这里可以调用服务更新状态 const feedback = this.feedbacks.find(f => f.id === feedbackId); if (feedback) { feedback.status = '已解决'; feedback.updatedAt = new Date(); } } async openReplyModal(feedback: CustomerFeedback): Promise { console.log('打开回复模态框:', feedback); // 这里可以打开一个模态框让用户输入回复内容 const reply = await window?.fmode?.input('请输入回复内容:'); if (reply && reply.trim()) { feedback.response = reply.trim(); feedback.updatedAt = new Date(); if (feedback.status === '待处理') { feedback.status = '处理中'; } } } viewDetails(feedback: CustomerFeedback): void { console.log('查看客户评价详情:', feedback); // 这里可以打开详情页面或模态框 window?.fmode?.alert(`客户评价详情:\n\n客户: ${feedback.customerName}\n评分: ${feedback.rating}/5\n内容: ${feedback.content}\n回复: ${feedback.response || '暂无回复'}`); } // 新增方法:获取维度评分的星级显示 getDimensionStars(score: number): string[] { const stars = []; const fullStars = Math.floor(score); const hasHalfStar = score % 1 >= 0.5; for (let i = 0; i < 5; i++) { if (i < fullStars) { stars.push('★'); } else if (i === fullStars && hasHalfStar) { stars.push('☆'); } else { stars.push('☆'); } } return stars; } // 获取维度评分的颜色类 getDimensionScoreClass(score: number): string { if (score >= 4.5) return 'score-excellent'; if (score >= 3.5) return 'score-good'; if (score >= 2.5) return 'score-average'; return 'score-poor'; } // 获取场景类型标签 getSceneTypeLabel(sceneType: string): string { const scene = this.sceneTypes.find(s => s.value === sceneType); return scene ? scene.label : sceneType; } // 切换视图模式 toggleViewMode(): void { this.viewMode.set(this.viewMode() === 'simple' ? 'detailed' : 'simple'); } // 创建新的详细评价 createDetailedReview(projectId: string): void { console.log('创建详细评价:', projectId); // 这里可以打开评价表单模态框 } // 查看详细评价 viewDetailedReview(review: DetailedCustomerReview): void { console.log('查看详细评价:', review); // 这里可以打开详细评价查看模态框 } // 详细评价表单状态 showDetailedForm = false; currentRatings: { [key: string]: number } = {}; currentSceneRatings: { [key: string]: number } = {}; currentSceneFeedback: { [key: string]: string } = {}; selectedOptimizations: { [key: string]: boolean } = {}; customOptimizationSuggestion = ''; // 优化建议类别 optimizationCategories = [ { key: 'service_speed', label: '服务时效', description: '提高响应速度和交付效率' }, { key: 'communication', label: '沟通效果', description: '加强沟通频率和质量' }, { key: 'design_quality', label: '设计质量', description: '提升设计水平和创意' }, { key: 'material_quality', label: '材质表现', description: '优化材质和纹理效果' }, { key: 'lighting_effect', label: '灯光效果', description: '改善灯光设置和氛围' }, { key: 'detail_accuracy', label: '细节准确性', description: '提高细节还原度' }, { key: 'revision_efficiency', label: '修改效率', description: '加快修改响应速度' }, { key: 'requirement_understanding', label: '需求理解', description: '更准确理解客户需求' } ]; // 设置维度评分 setDimensionRating(dimensionKey: string, rating: number): void { this.currentRatings[dimensionKey] = rating; } // 设置场景评分 setSceneRating(sceneKey: string, rating: number): void { this.currentSceneRatings[sceneKey] = rating; } // 保存详细评价 saveDetailedReview(): void { const newReview: DetailedCustomerReview = { id: Date.now().toString(), customerName: 'Customer Name', projectId: 'proj_001', customerId: 'customer-' + Date.now(), overallFeedback: '', submittedAt: new Date(), status: 'completed' as 'pending' | 'completed', dimensions: { ...this.currentRatings } as unknown as DetailedReviewDimensions, sceneReviews: this.buildSceneReviews(), optimizationSuggestions: this.getSelectedOptimizations(), improvementSuggestions: this.customOptimizationSuggestion }; // 添加到详细评价列表 if (!this.detailedReviews) { this.detailedReviews = []; } this.detailedReviews.push(newReview); console.log('保存详细评价:', newReview); // 重置表单 this.resetDetailedForm(); this.showDetailedForm = false; } // 计算总体评分 calculateOverallRating(): number { const ratings = Object.values(this.currentRatings); if (ratings.length === 0) return 0; const sum = ratings.reduce((acc, rating) => acc + rating, 0); return Math.round(sum / ratings.length); } // 构建场景评价 buildSceneReviews(): SceneReview[] { return this.sceneTypes .filter(scene => this.currentSceneRatings[scene.value] > 0) .map(scene => ({ sceneType: scene.value as 'bedroom' | 'dining_room' | 'living_room' | 'other', sceneName: scene.label, designerId: 'current-designer', // 这里应该从项目数据中获取 designerName: '当前设计师', // 这里应该从项目数据中获取 rating: this.currentSceneRatings[scene.value], feedback: this.currentSceneFeedback[scene.value] || '' })); } // 获取选中的优化建议 getSelectedOptimizations(): string[] { return this.optimizationCategories .filter(category => this.selectedOptimizations[category.key]) .map(category => category.label); } // 重置详细评价表单 resetDetailedForm(): void { this.currentRatings = {}; this.currentSceneRatings = {}; this.currentSceneFeedback = {}; this.selectedOptimizations = {}; this.customOptimizationSuggestion = ''; } // 取消详细评价 cancelDetailedReview(): void { this.resetDetailedForm(); this.showDetailedForm = false; } // 编辑详细评价 editDetailedReview(reviewId: string): void { const review = this.detailedReviews?.find(r => r.id === reviewId); if (review) { // 填充维度评分 this.currentRatings = { ...review.dimensions }; // 填充场景评价数据 review.sceneReviews?.forEach(scene => { this.currentSceneRatings[scene.sceneType] = scene.rating; this.currentSceneFeedback[scene.sceneType] = scene.feedback || ''; }); // 填充优化建议 this.selectedOptimizations = {}; review.optimizationSuggestions?.forEach((suggestion: string) => { const category = this.optimizationCategories.find(cat => cat.label === suggestion); if (category) { this.selectedOptimizations[category.key] = true; } }); this.customOptimizationSuggestion = review.improvementSuggestions || ''; this.showDetailedForm = true; } } // 导出评价报告 exportReviewReport(): void { console.log('导出评价报告'); // 这里可以实现导出功能 } }