| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- 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<DetailedReviewDimensions>;
- }
- @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<string>('all');
- categoryFilter = signal<string>('all');
- scoreFilter = signal<string>('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<ReviewStats>(() => {
- 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<DetailedReviewDimensions> = {};
- 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<void> {
- 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('导出评价报告');
- // 这里可以实现导出功能
- }
- }
|