|  | @@ -1,30 +1,12 @@
 | 
	
		
			
				|  |  | -import { Component, OnInit } from '@angular/core';
 | 
	
		
			
				|  |  | +import { Component, OnInit, OnDestroy } from '@angular/core';
 | 
	
		
			
				|  |  |  import { CommonModule } from '@angular/common';
 | 
	
		
			
				|  |  |  import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 | 
	
		
			
				|  |  |  import { FormControl } from '@angular/forms';
 | 
	
		
			
				|  |  |  import { Router } from '@angular/router';
 | 
	
		
			
				|  |  |  import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
 | 
	
		
			
				|  |  | -import { CaseDetailPanelComponent } from './case-detail-panel.component';
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -interface Case {
 | 
	
		
			
				|  |  | -  id: string;
 | 
	
		
			
				|  |  | -  name: string;
 | 
	
		
			
				|  |  | -  coverImage: string;
 | 
	
		
			
				|  |  | -  projectType: '工装' | '家装';
 | 
	
		
			
				|  |  | -  spaceType: '平层' | '复式' | '别墅' | '自建房';
 | 
	
		
			
				|  |  | -  renderingLevel: '高端' | '中端' | '低端';
 | 
	
		
			
				|  |  | -  designer: string;
 | 
	
		
			
				|  |  | -  team: string;
 | 
	
		
			
				|  |  | -  area: number;
 | 
	
		
			
				|  |  | -  styleTags: string[];
 | 
	
		
			
				|  |  | -  customerReview?: string;
 | 
	
		
			
				|  |  | -  viewCount: number;
 | 
	
		
			
				|  |  | -  shareCount: number;
 | 
	
		
			
				|  |  | -  favoriteCount: number;
 | 
	
		
			
				|  |  | -  isFavorite: boolean;
 | 
	
		
			
				|  |  | -  isExcellent: boolean;
 | 
	
		
			
				|  |  | -  createdAt: Date;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | +import { CaseDetailPanelComponent, Case } from './case-detail-panel.component';
 | 
	
		
			
				|  |  | +import { CaseManagementModalComponent } from './case-management-modal.component';
 | 
	
		
			
				|  |  | +import { CaseService } from '../../../services/case.service';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  interface StatItem {
 | 
	
		
			
				|  |  |    id: string;
 | 
	
	
		
			
				|  | @@ -45,11 +27,11 @@ interface DesignerStat {
 | 
	
		
			
				|  |  |  @Component({
 | 
	
		
			
				|  |  |    selector: 'app-case-library',
 | 
	
		
			
				|  |  |    standalone: true,
 | 
	
		
			
				|  |  | -  imports: [CommonModule, FormsModule, ReactiveFormsModule, CaseDetailPanelComponent],
 | 
	
		
			
				|  |  | +  imports: [CommonModule, FormsModule, ReactiveFormsModule, CaseDetailPanelComponent, CaseManagementModalComponent],
 | 
	
		
			
				|  |  |    templateUrl: './case-library.html',
 | 
	
		
			
				|  |  |    styleUrls: ['./case-library.scss']
 | 
	
		
			
				|  |  |  })
 | 
	
		
			
				|  |  | -export class CaseLibrary implements OnInit {
 | 
	
		
			
				|  |  | +export class CaseLibrary implements OnInit, OnDestroy {
 | 
	
		
			
				|  |  |    // 表单控件
 | 
	
		
			
				|  |  |    searchControl = new FormControl('');
 | 
	
		
			
				|  |  |    projectTypeControl = new FormControl('');
 | 
	
	
		
			
				|  | @@ -71,9 +53,13 @@ export class CaseLibrary implements OnInit {
 | 
	
		
			
				|  |  |    showStatsPanel = false;
 | 
	
		
			
				|  |  |    selectedCase: Case | null = null; // 用于详情面板
 | 
	
		
			
				|  |  |    selectedCaseForShare: Case | null = null; // 用于分享模态框
 | 
	
		
			
				|  |  | +  showManagementModal = false; // 用于管理模态框
 | 
	
		
			
				|  |  | +  editingCase: Case | null = null; // 正在编辑的案例
 | 
	
		
			
				|  |  |    currentPage = 1;
 | 
	
		
			
				|  |  |    itemsPerPage = 10; // 每页显示10个案例
 | 
	
		
			
				|  |  |    totalPages = 1;
 | 
	
		
			
				|  |  | +  totalCount = 0;
 | 
	
		
			
				|  |  | +  loading = false;
 | 
	
		
			
				|  |  |    
 | 
	
		
			
				|  |  |    // 用户类型(模拟)
 | 
	
		
			
				|  |  |    isInternalUser = true; // 可根据实际用户权限设置
 | 
	
	
		
			
				|  | @@ -82,38 +68,119 @@ export class CaseLibrary implements OnInit {
 | 
	
		
			
				|  |  |    private pageStartTime = Date.now();
 | 
	
		
			
				|  |  |    private caseViewStartTimes = new Map<string, number>();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  constructor(private router: Router) {}
 | 
	
		
			
				|  |  | +  constructor(
 | 
	
		
			
				|  |  | +    private router: Router,
 | 
	
		
			
				|  |  | +    private caseService: CaseService
 | 
	
		
			
				|  |  | +  ) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ngOnInit() {
 | 
	
		
			
				|  |  | -    this.initializeData();
 | 
	
		
			
				|  |  | +    this.loadCases();
 | 
	
		
			
				|  |  | +    this.loadStatistics();
 | 
	
		
			
				|  |  |      this.setupFilterListeners();
 | 
	
		
			
				|  |  |      this.setupBehaviorTracking();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  ngOnDestroy() {
 | 
	
		
			
				|  |  | +    // 页面销毁时的清理工作
 | 
	
		
			
				|  |  | +    console.log('案例库页面销毁');
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    
 | 
	
		
			
				|  |  |    private setupBehaviorTracking() {
 | 
	
		
			
				|  |  | -    // 记录页面访问
 | 
	
		
			
				|  |  | -    this.recordBehavior('page_view', 'case-library', {
 | 
	
		
			
				|  |  | -      timestamp: new Date().toISOString()
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    // 页面卸载时记录停留时长
 | 
	
		
			
				|  |  | -    window.addEventListener('beforeunload', () => {
 | 
	
		
			
				|  |  | -      const stayDuration = Date.now() - this.pageStartTime;
 | 
	
		
			
				|  |  | -      this.recordBehavior('page_stay', 'case-library', {
 | 
	
		
			
				|  |  | -        duration: stayDuration,
 | 
	
		
			
				|  |  | -        durationMinutes: Math.round(stayDuration / 60000 * 100) / 100
 | 
	
		
			
				|  |  | +    // 记录页面访问(可选)
 | 
	
		
			
				|  |  | +    console.log('案例库页面已加载');
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 加载案例列表
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  async loadCases() {
 | 
	
		
			
				|  |  | +    this.loading = true;
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      const filters = this.getFilters();
 | 
	
		
			
				|  |  | +      const result = await this.caseService.findCases({
 | 
	
		
			
				|  |  | +        ...filters,
 | 
	
		
			
				|  |  | +        page: this.currentPage,
 | 
	
		
			
				|  |  | +        pageSize: this.itemsPerPage
 | 
	
		
			
				|  |  |        });
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      this.cases = result.cases;
 | 
	
		
			
				|  |  | +      this.filteredCases = result.cases;
 | 
	
		
			
				|  |  | +      this.totalCount = result.total;
 | 
	
		
			
				|  |  | +      this.totalPages = Math.ceil(result.total / this.itemsPerPage) || 1;
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 如果没有数据,显示友好提示
 | 
	
		
			
				|  |  | +      if (result.total === 0) {
 | 
	
		
			
				|  |  | +        console.log('暂无案例数据,请先在Parse数据库中创建Case表并添加数据');
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } catch (error) {
 | 
	
		
			
				|  |  | +      console.error('加载案例列表失败:', error);
 | 
	
		
			
				|  |  | +      // 即使出错也设置为空数组,避免页面崩溃
 | 
	
		
			
				|  |  | +      this.cases = [];
 | 
	
		
			
				|  |  | +      this.filteredCases = [];
 | 
	
		
			
				|  |  | +      this.totalCount = 0;
 | 
	
		
			
				|  |  | +      this.totalPages = 1;
 | 
	
		
			
				|  |  | +      this.showToast('加载案例列表失败,请检查数据库连接', 'error');
 | 
	
		
			
				|  |  | +    } finally {
 | 
	
		
			
				|  |  | +      this.loading = false;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  private initializeData() {
 | 
	
		
			
				|  |  | -    // 模拟案例数据
 | 
	
		
			
				|  |  | -    this.cases = this.generateMockCases();
 | 
	
		
			
				|  |  | -    this.filteredCases = [...this.cases];
 | 
	
		
			
				|  |  | -    this.updatePagination();
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    // 初始化统计数据
 | 
	
		
			
				|  |  | -    this.initializeStats();
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 加载统计数据
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  async loadStatistics() {
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      // 暂时使用空数据,后续可以添加统计功能
 | 
	
		
			
				|  |  | +      this.topSharedCases = [];
 | 
	
		
			
				|  |  | +      this.favoriteStyles = [];
 | 
	
		
			
				|  |  | +      this.designerRecommendations = [];
 | 
	
		
			
				|  |  | +    } catch (error) {
 | 
	
		
			
				|  |  | +      console.error('加载统计数据失败:', error);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 获取当前筛选条件
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  private getFilters() {
 | 
	
		
			
				|  |  | +    const filters: any = {
 | 
	
		
			
				|  |  | +      isPublished: true
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const searchKeyword = this.searchControl.value?.trim();
 | 
	
		
			
				|  |  | +    if (searchKeyword) {
 | 
	
		
			
				|  |  | +      filters.searchKeyword = searchKeyword;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const projectType = this.projectTypeControl.value;
 | 
	
		
			
				|  |  | +    if (projectType) {
 | 
	
		
			
				|  |  | +      filters.projectType = projectType;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const spaceType = this.spaceTypeControl.value;
 | 
	
		
			
				|  |  | +    if (spaceType) {
 | 
	
		
			
				|  |  | +      filters.spaceType = spaceType;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const renderingLevel = this.renderingLevelControl.value;
 | 
	
		
			
				|  |  | +    if (renderingLevel) {
 | 
	
		
			
				|  |  | +      filters.renderingLevel = renderingLevel;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const style = this.styleControl.value;
 | 
	
		
			
				|  |  | +    if (style) {
 | 
	
		
			
				|  |  | +      // 使用tags数组进行筛选
 | 
	
		
			
				|  |  | +      filters.tags = [style];
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    const areaRange = this.areaRangeControl.value;
 | 
	
		
			
				|  |  | +    if (areaRange) {
 | 
	
		
			
				|  |  | +      // 解析面积范围 "0-50" -> { min: 0, max: 50 }
 | 
	
		
			
				|  |  | +      const [min, max] = areaRange.split('-').map(Number);
 | 
	
		
			
				|  |  | +      filters.areaRange = { min, max: max || undefined };
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return filters;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    private setupFilterListeners() {
 | 
	
	
		
			
				|  | @@ -135,147 +202,9 @@ export class CaseLibrary implements OnInit {
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  private generateMockCases(): Case[] {
 | 
	
		
			
				|  |  | -    const mockCases: Case[] = [];
 | 
	
		
			
				|  |  | -    const projectTypes: ('工装' | '家装')[] = ['工装', '家装'];
 | 
	
		
			
				|  |  | -    const spaceTypes: ('平层' | '复式' | '别墅' | '自建房')[] = ['平层', '复式', '别墅', '自建房'];
 | 
	
		
			
				|  |  | -    const renderingLevels: ('高端' | '中端' | '低端')[] = ['高端', '中端', '低端'];
 | 
	
		
			
				|  |  | -    const styles = ['现代', '中式', '欧式', '美式', '日式', '工业风', '极简风', '轻奢风'];
 | 
	
		
			
				|  |  | -    const designers = ['张三', '李四', '王五', '赵六', '钱七'];
 | 
	
		
			
				|  |  | -    const teams = ['设计一组', '设计二组', '设计三组', '设计四组'];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    for (let i = 1; i <= 50; i++) {
 | 
	
		
			
				|  |  | -      const projectType = projectTypes[Math.floor(Math.random() * projectTypes.length)];
 | 
	
		
			
				|  |  | -      const spaceType = spaceTypes[Math.floor(Math.random() * spaceTypes.length)];
 | 
	
		
			
				|  |  | -      const renderingLevel = renderingLevels[Math.floor(Math.random() * renderingLevels.length)];
 | 
	
		
			
				|  |  | -      const styleCount = Math.floor(Math.random() * 3) + 1;
 | 
	
		
			
				|  |  | -      const styleTags = Array.from({ length: styleCount }, () => 
 | 
	
		
			
				|  |  | -        styles[Math.floor(Math.random() * styles.length)]
 | 
	
		
			
				|  |  | -      );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      mockCases.push({
 | 
	
		
			
				|  |  | -        id: `case-${i}`,
 | 
	
		
			
				|  |  | -        name: `${projectType}${spaceType}设计案例 ${i}`,
 | 
	
		
			
				|  |  | -        coverImage: this.generatePlaceholderImage(400, 300, i),
 | 
	
		
			
				|  |  | -        projectType,
 | 
	
		
			
				|  |  | -        spaceType,
 | 
	
		
			
				|  |  | -        renderingLevel,
 | 
	
		
			
				|  |  | -        designer: designers[Math.floor(Math.random() * designers.length)],
 | 
	
		
			
				|  |  | -        team: teams[Math.floor(Math.random() * teams.length)],
 | 
	
		
			
				|  |  | -        area: Math.floor(Math.random() * 200) + 50,
 | 
	
		
			
				|  |  | -        styleTags: [...new Set(styleTags)], // 去重
 | 
	
		
			
				|  |  | -        customerReview: Math.random() > 0.3 ? `客户非常满意这次${projectType}设计,${spaceType}空间利用得很合理` : undefined,
 | 
	
		
			
				|  |  | -        viewCount: Math.floor(Math.random() * 1000),
 | 
	
		
			
				|  |  | -        shareCount: Math.floor(Math.random() * 100),
 | 
	
		
			
				|  |  | -        favoriteCount: Math.floor(Math.random() * 50),
 | 
	
		
			
				|  |  | -        isFavorite: Math.random() > 0.7,
 | 
	
		
			
				|  |  | -        isExcellent: Math.random() > 0.5,
 | 
	
		
			
				|  |  | -        createdAt: new Date(Date.now() - Math.floor(Math.random() * 365 * 24 * 60 * 60 * 1000))
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    return mockCases;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  private generatePlaceholderImage(width: number, height: number, seed: number): string {
 | 
	
		
			
				|  |  | -    return `https://picsum.photos/seed/${seed}/${width}/${height}`;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  private initializeStats() {
 | 
	
		
			
				|  |  | -    // Top5 分享案例
 | 
	
		
			
				|  |  | -    this.topSharedCases = this.cases
 | 
	
		
			
				|  |  | -      .sort((a, b) => b.shareCount - a.shareCount)
 | 
	
		
			
				|  |  | -      .slice(0, 5)
 | 
	
		
			
				|  |  | -      .map(caseItem => ({
 | 
	
		
			
				|  |  | -        id: caseItem.id,
 | 
	
		
			
				|  |  | -        name: caseItem.name,
 | 
	
		
			
				|  |  | -        shareCount: caseItem.shareCount
 | 
	
		
			
				|  |  | -      }));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // 客户最喜欢案例风格
 | 
	
		
			
				|  |  | -    const styleCounts = new Map<string, number>();
 | 
	
		
			
				|  |  | -    this.cases.forEach(caseItem => {
 | 
	
		
			
				|  |  | -      caseItem.styleTags.forEach(style => {
 | 
	
		
			
				|  |  | -        styleCounts.set(style, (styleCounts.get(style) || 0) + caseItem.favoriteCount);
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    this.favoriteStyles = Array.from(styleCounts.entries())
 | 
	
		
			
				|  |  | -      .sort(([, a], [, b]) => b - a)
 | 
	
		
			
				|  |  | -      .slice(0, 5)
 | 
	
		
			
				|  |  | -      .map(([style, count]) => ({ style, count }));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    // 设计师作品推荐率
 | 
	
		
			
				|  |  | -    const designerStats = new Map<string, { total: number; excellent: number }>();
 | 
	
		
			
				|  |  | -    this.cases.forEach(caseItem => {
 | 
	
		
			
				|  |  | -      const stats = designerStats.get(caseItem.designer) || { total: 0, excellent: 0 };
 | 
	
		
			
				|  |  | -      stats.total++;
 | 
	
		
			
				|  |  | -      if (caseItem.isExcellent) stats.excellent++;
 | 
	
		
			
				|  |  | -      designerStats.set(caseItem.designer, stats);
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.designerRecommendations = Array.from(designerStats.entries())
 | 
	
		
			
				|  |  | -      .map(([designer, stats]) => ({
 | 
	
		
			
				|  |  | -        designer,
 | 
	
		
			
				|  |  | -        rate: Math.round((stats.excellent / stats.total) * 100)
 | 
	
		
			
				|  |  | -      }))
 | 
	
		
			
				|  |  | -      .sort((a, b) => b.rate - a.rate)
 | 
	
		
			
				|  |  | -      .slice(0, 5);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    applyFilters() {
 | 
	
		
			
				|  |  | -    const searchTerm = this.searchControl.value?.toLowerCase() || '';
 | 
	
		
			
				|  |  | -    const projectType = this.projectTypeControl.value;
 | 
	
		
			
				|  |  | -    const spaceType = this.spaceTypeControl.value;
 | 
	
		
			
				|  |  | -    const renderingLevel = this.renderingLevelControl.value;
 | 
	
		
			
				|  |  | -    const style = this.styleControl.value;
 | 
	
		
			
				|  |  | -    const areaRange = this.areaRangeControl.value;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    this.filteredCases = this.cases.filter(caseItem => {
 | 
	
		
			
				|  |  | -      // 搜索条件
 | 
	
		
			
				|  |  | -      if (searchTerm && !(
 | 
	
		
			
				|  |  | -        caseItem.name.toLowerCase().includes(searchTerm) ||
 | 
	
		
			
				|  |  | -        caseItem.designer.toLowerCase().includes(searchTerm) ||
 | 
	
		
			
				|  |  | -        caseItem.styleTags.some(tag => tag.toLowerCase().includes(searchTerm))
 | 
	
		
			
				|  |  | -      )) {
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // 项目类型筛选
 | 
	
		
			
				|  |  | -      if (projectType && caseItem.projectType !== projectType) {
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // 空间类型筛选
 | 
	
		
			
				|  |  | -      if (spaceType && caseItem.spaceType !== spaceType) {
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // 渲染水平筛选
 | 
	
		
			
				|  |  | -      if (renderingLevel && caseItem.renderingLevel !== renderingLevel) {
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // 风格筛选
 | 
	
		
			
				|  |  | -      if (style && !caseItem.styleTags.includes(style)) {
 | 
	
		
			
				|  |  | -        return false;
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      // 面积范围筛选
 | 
	
		
			
				|  |  | -      if (areaRange) {
 | 
	
		
			
				|  |  | -        const [min, max] = areaRange.split('-').map(Number);
 | 
	
		
			
				|  |  | -        if (max === undefined) {
 | 
	
		
			
				|  |  | -          if (caseItem.area < min) return false;
 | 
	
		
			
				|  |  | -        } else if (caseItem.area < min || caseItem.area > max) {
 | 
	
		
			
				|  |  | -          return false;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      return true;
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |      this.currentPage = 1;
 | 
	
		
			
				|  |  | -    this.updatePagination();
 | 
	
		
			
				|  |  | +    this.loadCases();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    resetFilters() {
 | 
	
	
		
			
				|  | @@ -286,132 +215,75 @@ export class CaseLibrary implements OnInit {
 | 
	
		
			
				|  |  |      this.styleControl.setValue('');
 | 
	
		
			
				|  |  |      this.areaRangeControl.setValue('');
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    this.filteredCases = [...this.cases];
 | 
	
		
			
				|  |  |      this.currentPage = 1;
 | 
	
		
			
				|  |  | -    this.updatePagination();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  updatePagination() {
 | 
	
		
			
				|  |  | -    this.totalPages = Math.ceil(this.filteredCases.length / this.itemsPerPage);
 | 
	
		
			
				|  |  | -    if (this.currentPage > this.totalPages) {
 | 
	
		
			
				|  |  | -      this.currentPage = this.totalPages || 1;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +    this.loadCases();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    get paginatedCases(): Case[] {
 | 
	
		
			
				|  |  | -    const startIndex = (this.currentPage - 1) * this.itemsPerPage;
 | 
	
		
			
				|  |  | -    return this.filteredCases.slice(startIndex, startIndex + this.itemsPerPage);
 | 
	
		
			
				|  |  | +    return this.filteredCases;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    nextPage() {
 | 
	
		
			
				|  |  |      if (this.currentPage < this.totalPages) {
 | 
	
		
			
				|  |  |        this.currentPage++;
 | 
	
		
			
				|  |  | +      this.loadCases();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    previousPage() {
 | 
	
		
			
				|  |  |      if (this.currentPage > 1) {
 | 
	
		
			
				|  |  |        this.currentPage--;
 | 
	
		
			
				|  |  | +      this.loadCases();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  showStatistics() {
 | 
	
		
			
				|  |  | -    this.showStatsPanel = !this.showStatsPanel;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  viewCaseDetail(caseItem: Case) {
 | 
	
		
			
				|  |  | +  async viewCaseDetail(caseItem: Case) {
 | 
	
		
			
				|  |  |      // 记录案例查看开始时间
 | 
	
		
			
				|  |  |      this.caseViewStartTimes.set(caseItem.id, Date.now());
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    // 增加浏览次数
 | 
	
		
			
				|  |  | -    caseItem.viewCount++;
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    // 记录浏览行为
 | 
	
		
			
				|  |  | -    this.recordBehavior('case_view', caseItem.id, {
 | 
	
		
			
				|  |  | -      caseName: caseItem.name,
 | 
	
		
			
				|  |  | -      designer: caseItem.designer,
 | 
	
		
			
				|  |  | -      projectType: caseItem.projectType,
 | 
	
		
			
				|  |  | -      spaceType: caseItem.spaceType
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    // 设置当前选中的案例以显示详情面板
 | 
	
		
			
				|  |  | -    this.selectedCase = caseItem;
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      // 从数据库获取完整的案例详情
 | 
	
		
			
				|  |  | +      const detail = await this.caseService.getCase(caseItem.id);
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      // 设置当前选中的案例以显示详情面板
 | 
	
		
			
				|  |  | +      this.selectedCase = detail;
 | 
	
		
			
				|  |  | +    } catch (error) {
 | 
	
		
			
				|  |  | +      console.error('查看案例详情失败:', error);
 | 
	
		
			
				|  |  | +      this.showToast('查看案例详情失败', 'error');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    // 跳转到独立的案例详情页面
 | 
	
		
			
				|  |  | -  navigateToCaseDetail(caseItem: Case) {
 | 
	
		
			
				|  |  | +  async navigateToCaseDetail(caseItem: Case) {
 | 
	
		
			
				|  |  |      // 记录案例查看开始时间
 | 
	
		
			
				|  |  |      this.caseViewStartTimes.set(caseItem.id, Date.now());
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    // 增加浏览次数
 | 
	
		
			
				|  |  | -    caseItem.viewCount++;
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    // 记录浏览行为
 | 
	
		
			
				|  |  | -    this.recordBehavior('case_view', caseItem.id, {
 | 
	
		
			
				|  |  | -      caseName: caseItem.name,
 | 
	
		
			
				|  |  | -      designer: caseItem.designer,
 | 
	
		
			
				|  |  | -      projectType: caseItem.projectType,
 | 
	
		
			
				|  |  | -      spaceType: caseItem.spaceType
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  |      // 跳转到独立的案例详情页面
 | 
	
		
			
				|  |  |      this.router.navigate(['/customer-service/case-detail', caseItem.id]);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    closeCaseDetail() {
 | 
	
		
			
				|  |  | -    // 记录案例查看时长
 | 
	
		
			
				|  |  | -    if (this.selectedCase) {
 | 
	
		
			
				|  |  | -      const viewStartTime = this.caseViewStartTimes.get(this.selectedCase.id);
 | 
	
		
			
				|  |  | -      if (viewStartTime) {
 | 
	
		
			
				|  |  | -        const viewDuration = Date.now() - viewStartTime;
 | 
	
		
			
				|  |  | -        this.recordBehavior('case_view_duration', this.selectedCase.id, {
 | 
	
		
			
				|  |  | -          duration: viewDuration,
 | 
	
		
			
				|  |  | -          durationSeconds: Math.round(viewDuration / 1000)
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -        this.caseViewStartTimes.delete(this.selectedCase.id);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  |      this.selectedCase = null;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  toggleFavorite(caseItem: Case) {
 | 
	
		
			
				|  |  | -    const wasLiked = caseItem.isFavorite;
 | 
	
		
			
				|  |  | -    caseItem.isFavorite = !caseItem.isFavorite;
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    if (caseItem.isFavorite) {
 | 
	
		
			
				|  |  | -      caseItem.favoriteCount++;
 | 
	
		
			
				|  |  | -      this.showToast('已收藏该案例', 'success');
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | -      // 记录收藏行为
 | 
	
		
			
				|  |  | -      this.recordBehavior('case_favorite', caseItem.id, {
 | 
	
		
			
				|  |  | -        action: 'add',
 | 
	
		
			
				|  |  | -        caseName: caseItem.name,
 | 
	
		
			
				|  |  | -        designer: caseItem.designer
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      caseItem.favoriteCount = Math.max(0, caseItem.favoriteCount - 1);
 | 
	
		
			
				|  |  | -      this.showToast('已取消收藏', 'info');
 | 
	
		
			
				|  |  | +  async toggleFavorite(caseItem: Case) {
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      // 暂时只切换前端状态,后续可添加收藏功能
 | 
	
		
			
				|  |  | +      caseItem.isFavorite = !caseItem.isFavorite;
 | 
	
		
			
				|  |  |        
 | 
	
		
			
				|  |  | -      // 记录取消收藏行为
 | 
	
		
			
				|  |  | -      this.recordBehavior('case_favorite', caseItem.id, {
 | 
	
		
			
				|  |  | -        action: 'remove',
 | 
	
		
			
				|  |  | -        caseName: caseItem.name,
 | 
	
		
			
				|  |  | -        designer: caseItem.designer
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | +      if (caseItem.isFavorite) {
 | 
	
		
			
				|  |  | +        this.showToast('已收藏该案例', 'success');
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        this.showToast('已取消收藏', 'info');
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } catch (error) {
 | 
	
		
			
				|  |  | +      console.error('切换收藏状态失败:', error);
 | 
	
		
			
				|  |  | +      this.showToast('操作失败,请重试', 'error');
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  shareCase(caseItem: Case) {
 | 
	
		
			
				|  |  | +  async shareCase(caseItem: Case) {
 | 
	
		
			
				|  |  |      this.selectedCaseForShare = caseItem;
 | 
	
		
			
				|  |  | -    caseItem.shareCount++;
 | 
	
		
			
				|  |  | -    
 | 
	
		
			
				|  |  | -    // 记录分享行为数据
 | 
	
		
			
				|  |  | -    this.recordBehavior('share', caseItem.id, {
 | 
	
		
			
				|  |  | -      caseName: caseItem.name,
 | 
	
		
			
				|  |  | -      designer: caseItem.designer,
 | 
	
		
			
				|  |  | -      projectType: caseItem.projectType
 | 
	
		
			
				|  |  | -    });
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    closeShareModal() {
 | 
	
	
		
			
				|  | @@ -440,64 +312,118 @@ export class CaseLibrary implements OnInit {
 | 
	
		
			
				|  |  |      return `${window.location.origin}/customer-service/case-detail/${caseItem.id}?from=share&designer=${encodeURIComponent(caseItem.designer)}`;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  copyShareLink() {
 | 
	
		
			
				|  |  | -    if (this.selectedCase) {
 | 
	
		
			
				|  |  | -      const link = this.generateShareLink(this.selectedCase);
 | 
	
		
			
				|  |  | -      navigator.clipboard.writeText(link).then(() => {
 | 
	
		
			
				|  |  | +  async copyShareLink() {
 | 
	
		
			
				|  |  | +    if (this.selectedCaseForShare) {
 | 
	
		
			
				|  |  | +      try {
 | 
	
		
			
				|  |  | +        const shareUrl = this.generateShareLink(this.selectedCaseForShare);
 | 
	
		
			
				|  |  | +        await navigator.clipboard.writeText(shareUrl);
 | 
	
		
			
				|  |  |          this.showToast('链接已复制到剪贴板,可直接分享给客户!', 'success');
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | -        // 记录复制行为
 | 
	
		
			
				|  |  | -        this.recordBehavior('copy_link', this.selectedCase!.id, {
 | 
	
		
			
				|  |  | -          link: link
 | 
	
		
			
				|  |  | -        });
 | 
	
		
			
				|  |  | -      }).catch(err => {
 | 
	
		
			
				|  |  | +      } catch (err) {
 | 
	
		
			
				|  |  |          this.showToast('复制失败,请手动复制链接', 'error');
 | 
	
		
			
				|  |  |          console.error('复制链接失败:', err);
 | 
	
		
			
				|  |  | -      });
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  shareToWeCom() {
 | 
	
		
			
				|  |  | -    if (this.selectedCase) {
 | 
	
		
			
				|  |  | -      // 实际项目中应集成企业微信分享SDK
 | 
	
		
			
				|  |  | -      const shareData = {
 | 
	
		
			
				|  |  | -        title: `${this.selectedCase.name} - ${this.selectedCase.designer}设计作品`,
 | 
	
		
			
				|  |  | -        description: `${this.selectedCase.projectType} | ${this.selectedCase.spaceType} | ${this.selectedCase.area}㎡`,
 | 
	
		
			
				|  |  | -        link: this.generateShareLink(this.selectedCase),
 | 
	
		
			
				|  |  | -        imgUrl: this.selectedCase.coverImage
 | 
	
		
			
				|  |  | -      };
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | -      // 模拟企业微信分享
 | 
	
		
			
				|  |  | -      console.log('分享到企业微信:', shareData);
 | 
	
		
			
				|  |  | -      this.showToast('已调用企业微信分享', 'success');
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | -      // 记录企业微信分享行为
 | 
	
		
			
				|  |  | -      this.recordBehavior('share_wecom', this.selectedCase.id, shareData);
 | 
	
		
			
				|  |  | -      
 | 
	
		
			
				|  |  | -      this.closeShareModal();
 | 
	
		
			
				|  |  | +  async shareToWeCom() {
 | 
	
		
			
				|  |  | +    if (this.selectedCaseForShare) {
 | 
	
		
			
				|  |  | +      try {
 | 
	
		
			
				|  |  | +        const shareUrl = this.generateShareLink(this.selectedCaseForShare);
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        // 实际项目中应集成企业微信分享SDK
 | 
	
		
			
				|  |  | +        const shareData = {
 | 
	
		
			
				|  |  | +          title: `${this.selectedCaseForShare.name} - ${this.selectedCaseForShare.designer}设计作品`,
 | 
	
		
			
				|  |  | +          description: `${this.selectedCaseForShare.projectType} | ${this.selectedCaseForShare.spaceType} | ${this.selectedCaseForShare.area}㎡`,
 | 
	
		
			
				|  |  | +          link: shareUrl,
 | 
	
		
			
				|  |  | +          imgUrl: this.selectedCaseForShare.coverImage
 | 
	
		
			
				|  |  | +        };
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        // 模拟企业微信分享
 | 
	
		
			
				|  |  | +        console.log('分享到企业微信:', shareData);
 | 
	
		
			
				|  |  | +        this.showToast('已调用企业微信分享', 'success');
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        this.closeShareModal();
 | 
	
		
			
				|  |  | +      } catch (error) {
 | 
	
		
			
				|  |  | +        console.error('分享失败:', error);
 | 
	
		
			
				|  |  | +        this.showToast('分享失败,请重试', 'error');
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // 新增:行为数据记录方法
 | 
	
		
			
				|  |  | -  private recordBehavior(action: string, caseId: string, data?: any) {
 | 
	
		
			
				|  |  | -    const behaviorData = {
 | 
	
		
			
				|  |  | -      action,
 | 
	
		
			
				|  |  | -      caseId,
 | 
	
		
			
				|  |  | -      timestamp: new Date().toISOString(),
 | 
	
		
			
				|  |  | -      userAgent: navigator.userAgent,
 | 
	
		
			
				|  |  | -      data: data || {}
 | 
	
		
			
				|  |  | -    };
 | 
	
		
			
				|  |  | +  showStatistics() {
 | 
	
		
			
				|  |  | +    this.showStatsPanel = !this.showStatsPanel;
 | 
	
		
			
				|  |  | +    if (this.showStatsPanel) {
 | 
	
		
			
				|  |  | +      this.loadStatistics();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  // ========== 案例管理功能 ==========
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 打开创建案例模态框
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  openCreateModal() {
 | 
	
		
			
				|  |  | +    this.editingCase = null;
 | 
	
		
			
				|  |  | +    this.showManagementModal = true;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 打开编辑案例模态框
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  openEditModal(caseItem: Case) {
 | 
	
		
			
				|  |  | +    this.editingCase = caseItem;
 | 
	
		
			
				|  |  | +    this.showManagementModal = true;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 关闭管理模态框
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  closeManagementModal() {
 | 
	
		
			
				|  |  | +    this.showManagementModal = false;
 | 
	
		
			
				|  |  | +    this.editingCase = null;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 管理操作成功回调
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  async handleManagementSuccess(result: any) {
 | 
	
		
			
				|  |  | +    console.log('案例操作成功:', result);
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    // 实际项目中应发送到后端API
 | 
	
		
			
				|  |  | -    console.log('记录用户行为:', behaviorData);
 | 
	
		
			
				|  |  | +    if (this.editingCase) {
 | 
	
		
			
				|  |  | +      this.showToast('案例更新成功', 'success');
 | 
	
		
			
				|  |  | +    } else {
 | 
	
		
			
				|  |  | +      this.showToast('案例创建成功', 'success');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      
 | 
	
		
			
				|  |  | -    // 模拟存储到本地(实际应发送到服务器)
 | 
	
		
			
				|  |  | -    const behaviors = JSON.parse(localStorage.getItem('caseBehaviors') || '[]');
 | 
	
		
			
				|  |  | -    behaviors.push(behaviorData);
 | 
	
		
			
				|  |  | -    localStorage.setItem('caseBehaviors', JSON.stringify(behaviors));
 | 
	
		
			
				|  |  | +    // 刷新列表
 | 
	
		
			
				|  |  | +    await this.loadCases();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  /**
 | 
	
		
			
				|  |  | +   * 删除案例
 | 
	
		
			
				|  |  | +   */
 | 
	
		
			
				|  |  | +  async deleteCase(caseItem: Case) {
 | 
	
		
			
				|  |  | +    if (!confirm(`确定要删除案例"${caseItem.name}"吗?此操作不可恢复。`)) {
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      const success = await this.caseService.deleteCase(caseItem.id);
 | 
	
		
			
				|  |  | +      
 | 
	
		
			
				|  |  | +      if (success) {
 | 
	
		
			
				|  |  | +        this.showToast('案例删除成功', 'success');
 | 
	
		
			
				|  |  | +        // 刷新列表
 | 
	
		
			
				|  |  | +        await this.loadCases();
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        this.showToast('案例删除失败', 'error');
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } catch (error) {
 | 
	
		
			
				|  |  | +      console.error('删除案例失败:', error);
 | 
	
		
			
				|  |  | +      this.showToast('删除案例失败: ' + (error as Error).message, 'error');
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // 新增:显示提示消息
 | 
	
		
			
				|  |  | +  // 显示提示消息
 | 
	
		
			
				|  |  |    private showToast(message: string, type: 'success' | 'error' | 'info' = 'info') {
 | 
	
		
			
				|  |  |      // 实际项目中应使用专业的Toast组件
 | 
	
		
			
				|  |  |      const toast = document.createElement('div');
 |