|
|
@@ -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');
|