| 
					
				 | 
			
			
				@@ -1,18 +1,14 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { CommonModule } from '@angular/common'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { RouterModule } from '@angular/router'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { Subscription } from 'rxjs'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { signal } from '@angular/core'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { signal, Component, OnInit, AfterViewInit, OnDestroy, computed } from '@angular/core'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { AdminDashboardService } from './dashboard.service'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { WriteContentComponent } from './components/write-content/write-content.component'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 使用全局echarts变量,不导入模块 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 确保@Component装饰器存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 @Component({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   selector: 'app-admin-dashboard', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   standalone: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  imports: [CommonModule, RouterModule, WriteContentComponent], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  imports: [CommonModule, RouterModule], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   templateUrl: './dashboard.html', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   styleUrl: './dashboard.scss' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 })  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -27,12 +23,104 @@ export class AdminDashboard implements OnInit, AfterViewInit, OnDestroy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     totalRevenue: signal(1258000) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  // 模态框控制 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  showWriteModal = signal(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 图表周期切换 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  projectPeriod = signal<'6m' | '12m'>('6m'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  revenuePeriod = signal<'quarter' | 'year'>('quarter'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 详情面板 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  detailOpen = signal(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  detailType = signal<'totalProjects' | 'active' | 'completed' | 'designers' | 'customers' | 'revenue' | null>(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  detailTitle = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    switch (this.detailType()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case 'totalProjects': return '项目总览'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case 'active': return '进行中项目详情'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case 'completed': return '已完成项目详情'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case 'designers': return '设计师统计详情'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case 'customers': return '客户统计详情'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      case 'revenue': return '收入统计详情'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      default: return ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 明细数据与筛选/分页状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  detailData = signal<any[]>([]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  keyword = signal(''); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  statusFilter = signal('all'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  dateFrom = signal<string | null>(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  dateTo = signal<string | null>(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pageIndex = signal(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pageSize = signal(10); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 过滤后的数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  filteredData = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const type = this.detailType(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let data = this.detailData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const kw = this.keyword().trim().toLowerCase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const status = this.statusFilter(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const from = this.dateFrom() ? new Date(this.dateFrom() as string).getTime() : null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const to = this.dateTo() ? new Date(this.dateTo() as string).getTime() : null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 关键词过滤(对常见字段做并集匹配) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (kw) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      data = data.filter((it: any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const text = [it.name, it.projectName, it.customer, it.owner, it.status, it.level, it.invoiceNo] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .filter(Boolean) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .join(' ') 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          .toLowerCase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return text.includes(kw); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 状态过滤(不同类型对应不同字段) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (status && status !== 'all') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      data = data.filter((it: any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        switch (type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          case 'active': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          case 'completed': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          case 'totalProjects': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return (it.status || '').toLowerCase() === status.toLowerCase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          case 'designers': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return (it.level || '').toLowerCase() === status.toLowerCase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          case 'customers': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return (it.status || '').toLowerCase() === status.toLowerCase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          case 'revenue': 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return (it.type || '').toLowerCase() === status.toLowerCase(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 时间范围过滤:尝试使用 date/endDate/startDate 三者之一 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (from || to) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      data = data.filter((it: any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const d = it.date || it.endDate || it.startDate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!d) return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const t = new Date(d).getTime(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (from && t < from) return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (to && t > to) return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 分页后的数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pagedData = computed(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const size = this.pageSize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const idx = this.pageIndex(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const start = (idx - 1) * size; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return this.filteredData().slice(start, start + size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  totalItems = computed(() => this.filteredData().length); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  totalPagesComputed = computed(() => Math.max(1, Math.ceil(this.totalItems() / this.pageSize()))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private subscriptions: Subscription = new Subscription(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private projectChart: any | null = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private revenueChart: any | null = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private detailChart: any | null = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   constructor(private dashboardService: AdminDashboardService) {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -48,105 +136,406 @@ export class AdminDashboard implements OnInit, AfterViewInit, OnDestroy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   ngOnDestroy(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     this.subscriptions.unsubscribe(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     window.removeEventListener('resize', this.handleResize); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (this.projectChart) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.projectChart.dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (this.revenueChart) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.revenueChart.dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.disposeCharts(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private disposeCharts(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (this.projectChart) { this.projectChart.dispose(); this.projectChart = null; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (this.revenueChart) { this.revenueChart.dispose(); this.revenueChart = null; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (this.detailChart) { this.detailChart.dispose(); this.detailChart = null; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   loadDashboardData(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 在实际应用中,这里会从服务加载数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 由于是模拟环境,我们使用模拟数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 模拟调用服务 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     this.subscriptions.add( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.dashboardService.getDashboardStats().subscribe(data => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 更新统计数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // this.stats.totalProjects.set(data.totalProjects); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        // 其他数据更新... 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.dashboardService.getDashboardStats().subscribe(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 使用默认模拟数据,必要时可在此更新 signals 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // ====== 顶部两张主图表 ====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   initCharts(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 初始化项目趋势图 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const projectChartDom = document.getElementById('projectTrendChart'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (projectChartDom) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.projectChart = echarts.init(projectChartDom); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (this.projectChart) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.projectChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          title: { text: '项目数量趋势', left: 'center', textStyle: { fontSize: 16 } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          tooltip: { trigger: 'axis' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          xAxis: { type: 'category', data: ['1月', '2月', '3月', '4月', '5月', '6月'] }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          yAxis: { type: 'value' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          series: [{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            name: '新项目', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            type: 'line', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            data: [18, 25, 32, 28, 42, 38], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            lineStyle: { color: '#165DFF' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            itemStyle: { color: '#165DFF' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          }, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            name: '完成项目', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            type: 'line', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            data: [15, 20, 25, 22, 35, 30], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            lineStyle: { color: '#00B42A' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            itemStyle: { color: '#00B42A' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 初始化收入统计图 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const revenueChartDom = document.getElementById('revenueChart'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (revenueChartDom) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.revenueChart = echarts.init(revenueChartDom); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (this.revenueChart) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.revenueChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          title: { text: '季度收入统计', left: 'center', textStyle: { fontSize: 16 } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          tooltip: { trigger: 'item' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          series: [{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            name: '收入分布', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            type: 'pie', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            radius: '65%', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            data: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              { value: 350000, name: '第一季度' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              { value: 420000, name: '第二季度' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              { value: 488000, name: '第三季度' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            emphasis: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              itemStyle: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                shadowBlur: 10, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                shadowOffsetX: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                shadowColor: 'rgba(0, 0, 0, 0.5)' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.initProjectChart(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.initRevenueChart(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private initProjectChart(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const el = document.getElementById('projectTrendChart'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!el) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.projectChart?.dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.projectChart = echarts.init(el); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const { x, newProjects, completed } = this.prepareProjectSeries(this.projectPeriod()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.projectChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      title: { text: '项目数量趋势', left: 'center', textStyle: { fontSize: 16 } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tooltip: { trigger: 'axis' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      legend: { data: ['新项目', '完成项目'] }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      xAxis: { type: 'category', data: x }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      yAxis: { type: 'value' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      series: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { name: '新项目', type: 'line', data: newProjects, lineStyle: { color: '#165DFF' }, itemStyle: { color: '#165DFF' }, smooth: true }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { name: '完成项目', type: 'line', data: completed, lineStyle: { color: '#00B42A' }, itemStyle: { color: '#00B42A' }, smooth: true } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private initRevenueChart(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const el = document.getElementById('revenueChart'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!el) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.revenueChart?.dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.revenueChart = echarts.init(el); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (this.revenuePeriod() === 'quarter') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.revenueChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: { text: '季度收入统计', left: 'center', textStyle: { fontSize: 16 } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tooltip: { trigger: 'item' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        series: [{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          type: 'pie', radius: '65%', 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          data: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { value: 350000, name: '第一季度' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { value: 420000, name: '第二季度' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { value: 488000, name: '第三季度' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          ], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0,0,0,0.5)' } } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 全年:使用柱状图展示 12 个月收入 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const months = ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月']; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const revenue = [120, 140, 160, 155, 180, 210, 230, 220, 240, 260, 280, 300].map(v => v * 1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.revenueChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: { text: '全年收入统计', left: 'center', textStyle: { fontSize: 16 } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tooltip: { trigger: 'axis' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        xAxis: { type: 'category', data: months }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        yAxis: { type: 'value' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        series: [{ type: 'bar', data: revenue, itemStyle: { color: '#165DFF' } }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  private handleResize = (): void => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (this.projectChart) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.projectChart.resize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private prepareProjectSeries(period: '6m' | '12m') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (period === '6m') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        x: ['1月','2月','3月','4月','5月','6月'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        newProjects: [18, 25, 32, 28, 42, 38], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        completed:   [15, 20, 25, 22, 35, 30] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 12个月数据(构造平滑趋势) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      x: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      newProjects: [12,18,22,26,30,34,36,38,40,42,44,46], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      completed:   [10,14,18,20,24,28,30,31,33,35,37,39] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setProjectPeriod(p: '6m' | '12m') {  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (this.projectPeriod() !== p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.projectPeriod.set(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.initProjectChart(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setRevenuePeriod(p: 'quarter' | 'year') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (this.revenuePeriod() !== p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.revenuePeriod.set(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.initRevenueChart(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // ====== 详情面板 ====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  showPanel(type: 'totalProjects' | 'active' | 'completed' | 'designers' | 'customers' | 'revenue') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailType.set(type); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 重置筛选与分页 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.keyword.set(''); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.statusFilter.set('all'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.dateFrom.set(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.dateTo.set(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.pageIndex.set(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 加载本次类型的明细数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.loadDetailData(type); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 打开抽屉并初始化图表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailOpen.set(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    setTimeout(() => this.initDetailChart(), 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    document.body.style.overflow = 'hidden'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  closeDetailPanel() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailOpen.set(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailType.set(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailChart?.dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailChart = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    document.body.style.overflow = 'auto'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private initDetailChart() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const el = document.getElementById('detailChart'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!el) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailChart?.dispose(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailChart = echarts.init(el); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const type = this.detailType(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'totalProjects' || type === 'active' || type === 'completed') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const { x, newProjects, completed } = this.prepareProjectSeries('12m'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.detailChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: { text: '项目趋势详情(12个月)', left: 'center' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tooltip: { trigger: 'axis' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        legend: { data: ['新项目','完成项目'] }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        xAxis: { type: 'category', data: x }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        yAxis: { type: 'value' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        series: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { name: '新项目', type: 'line', data: newProjects, smooth: true, lineStyle: { color: '#165DFF' } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { name: '完成项目', type: 'line', data: completed, smooth: true, lineStyle: { color: '#00B42A' } } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (this.revenueChart) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.revenueChart.resize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'designers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.detailChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: { text: '设计师完成量对比', left: 'center' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tooltip: { trigger: 'axis' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        legend: { data: ['完成','进行中'] }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        xAxis: { type: 'category', data: ['张','李','王','赵','陈'] }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        yAxis: { type: 'value' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        series: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { name: '完成', type: 'bar', data: [18,15,12,10,9], itemStyle: { color: '#00B42A' } }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { name: '进行中', type: 'bar', data: [8,6,5,4,3], itemStyle: { color: '#165DFF' } } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'customers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.detailChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        title: { text: '客户增长趋势', left: 'center' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        tooltip: { trigger: 'axis' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        xAxis: { type: 'category', data: ['1月','2月','3月','4月','5月','6月','7月','8月','9月','10月','11月','12月'] }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        yAxis: { type: 'value' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        series: [{ name: '客户数', type: 'line', data: [280,300,310,320,330,340,345,350,355,360,368,380], itemStyle: { color: '#4E5BA6' }, smooth: true }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // revenue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailChart.setOption({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      title: { text: '收入构成(年度)', left: 'center' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      tooltip: { trigger: 'item' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      series: [{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        type: 'pie', radius: ['35%','65%'], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        data: [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { value: 520000, name: '设计服务' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { value: 360000, name: '材料供应' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { value: 180000, name: '售后与增值' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          { value: 198000, name: '其他' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private handleResize = (): void => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.projectChart?.resize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.revenueChart?.resize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailChart?.resize(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   formatCurrency(amount: number): string { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return '¥' + amount.toLocaleString('zh-CN'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  // 模态框控制方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  openWriteModal(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    this.showWriteModal.set(true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    document.body.style.overflow = 'hidden'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 兼容旧模板调用(已调整为 showPanel) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  showProjectDetails(status: 'active' | 'completed'): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.showPanel(status); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  showCustomersDetails(): void { this.showPanel('customers'); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  showFinanceDetails(): void { this.showPanel('revenue'); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  closeWriteModal(): void { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    this.showWriteModal.set(false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    document.body.style.overflow = 'auto'; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // ====== 明细数据:加载、列配置、导出与分页 ====== 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private loadDetailData(type: 'totalProjects' | 'active' | 'completed' | 'designers' | 'customers' | 'revenue') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 构造模拟数据(足量便于分页演示) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const now = new Date(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const addDays = (base: Date, days: number) => new Date(base.getTime() + days * 86400000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'totalProjects' || type === 'active' || type === 'completed') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const status = type === 'active' ? '进行中' : (type === 'completed' ? '已完成' : undefined); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const items = Array.from({ length: 42 }).map((_, i) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: 'P' + String(1000 + i), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        name: `项目 ${i + 1}`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        owner: ['张三','李四','王五','赵六'][i % 4], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        status: status || (i % 3 === 0 ? '进行中' : (i % 3 === 1 ? '已完成' : '待启动')), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        startDate: addDays(now, -60 + i).toISOString().slice(0,10), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        endDate: addDays(now, -30 + i).toISOString().slice(0,10) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.detailData.set(items); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'designers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const items = Array.from({ length: 36 }).map((_, i) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: 'D' + String(200 + i), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        name: ['张一','李二','王三','赵四','陈五','刘六'][i % 6], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        level: ['junior','mid','senior'][i % 3], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        completed: 10 + (i % 15), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        inProgress: 1 + (i % 6), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        avgCycle: 7 + (i % 10), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        date: addDays(now, -i).toISOString().slice(0,10) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.detailData.set(items); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'customers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const items = Array.from({ length: 28 }).map((_, i) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        id: 'C' + String(300 + i), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        name: ['王先生','李女士','赵先生','陈女士'][i % 4], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        projects: 1 + (i % 5), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        lastContact: addDays(now, -i * 2).toISOString().slice(0,10), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        status: ['潜在','跟进中','已签约'][i % 3], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        date: addDays(now, -i * 2).toISOString().slice(0,10) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.detailData.set(items); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // revenue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const items = Array.from({ length: 34 }).map((_, i) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      invoiceNo: 'INV-' + String(10000 + i), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      customer: ['华夏地产','远景家装','绿洲装饰','宏图设计'][i % 4], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      amount: 5000 + (i % 12) * 1500, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      type: ['service','material','addon'][i % 3], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      date: addDays(now, -i).toISOString().slice(0,10) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.detailData.set(items); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getColumns(): { label: string; field: string; formatter?: (v: any) => string }[] { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const type = this.detailType(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'totalProjects' || type === 'active' || type === 'completed') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '项目编号', field: 'id' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '项目名称', field: 'name' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '负责人', field: 'owner' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '状态', field: 'status' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '开始日期', field: 'startDate' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '结束日期', field: 'endDate' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'designers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '设计师', field: 'name' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '级别', field: 'level' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '完成量', field: 'completed' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '进行中', field: 'inProgress' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '平均周期(天)', field: 'avgCycle' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '统计日期', field: 'date' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'customers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '客户名', field: 'name' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '项目数', field: 'projects' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '最后联系', field: 'lastContact' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '状态', field: 'status' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // revenue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: '发票号', field: 'invoiceNo' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: '客户', field: 'customer' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: '金额', field: 'amount', formatter: (v: any) => this.formatCurrency(Number(v)) }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: '类型', field: 'type' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: '日期', field: 'date' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 状态选项(随类型变化) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getStatusOptions(): { label: string; value: string }[] { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const type = this.detailType(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'totalProjects' || type === 'active' || type === 'completed') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '全部状态', value: 'all' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '进行中', value: '进行中' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '已完成', value: '已完成' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '待启动', value: '待启动' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'designers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '全部级别', value: 'all' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: 'junior', value: 'junior' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: 'mid', value: 'mid' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: 'senior', value: 'senior' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (type === 'customers') { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '全部状态', value: 'all' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '潜在', value: '潜在' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '跟进中', value: '跟进中' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { label: '已签约', value: '已签约' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: '全部类型', value: 'all' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: 'service', value: 'service' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: 'material', value: 'material' }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      { label: 'addon', value: 'addon' } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 交互:筛选与分页 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setKeyword(v: string) { this.keyword.set(v); this.pageIndex.set(1); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setStatus(v: string) { this.statusFilter.set(v); this.pageIndex.set(1); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setDateFrom(v: string) { this.dateFrom.set(v || null); this.pageIndex.set(1); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  setDateTo(v: string) { this.dateTo.set(v || null); this.pageIndex.set(1); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  resetFilters() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.keyword.set(''); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.statusFilter.set('all'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.dateFrom.set(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.dateTo.set(null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.pageIndex.set(1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  get totalPages() { return this.totalPagesComputed(); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  goToPage(n: number) { const tp = this.totalPagesComputed(); if (n >= 1 && n <= tp) this.pageIndex.set(n); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  prevPage() { this.goToPage(this.pageIndex() - 1); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  nextPage() { this.goToPage(this.pageIndex() + 1); } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 生成页码列表(最多展示 5 个,居中当前页) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getPages(): number[] { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const total = this.totalPagesComputed(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const current = this.pageIndex(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const max = 5; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let start = Math.max(1, current - Math.floor(max / 2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let end = Math.min(total, start + max - 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    start = Math.max(1, end - max + 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const pages: number[] = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    for (let i = start; i <= end; i++) pages.push(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return pages; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // 导出当前过滤结果为 CSV 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  exportCSV() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const cols = this.getColumns(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const rows = this.filteredData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const header = cols.map(c => c.label).join(','); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const escape = (val: any) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (val === undefined || val === null) return ''; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const s = String(val).replace(/"/g, '""'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return /[",\n]/.test(s) ? `"${s}"` : s; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const lines = rows.map(r => cols.map(c => escape(c.formatter ? c.formatter((r as any)[c.field]) : (r as any)[c.field])).join(',')); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const csv = [header, ...lines].join('\n'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const blob = new Blob(["\ufeff" + csv], { type: 'text/csv;charset=utf-8;' }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const url = URL.createObjectURL(blob); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const a = document.createElement('a'); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    a.href = url; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const filenameMap: any = { totalProjects: '项目总览', active: '进行中项目', completed: '已完成项目', designers: '设计师统计', customers: '客户统计', revenue: '收入统计' }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    a.download = `${filenameMap[this.detailType() || 'totalProjects']}-明细.csv`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    a.click(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    URL.revokeObjectURL(url); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |