Explorar el Código

Merge branch 'master' of http://git.fmode.cn:3000/nkkj/yss-project

0235711 hace 1 día
padre
commit
6ab1afe019

+ 2 - 0
src/app/pages/admin/logs/logs.ts

@@ -1,6 +1,7 @@
 import { Component, OnInit, signal } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { RouterModule } from '@angular/router';
+import { provideNativeDateAdapter } from '@angular/material/core';
 import { FormsModule } from '@angular/forms';
 import { MatButtonModule } from '@angular/material/button';
 import { MatIconModule } from '@angular/material/icon';
@@ -26,6 +27,7 @@ interface LogEntry {
 @Component({
   selector: 'app-logs',
   standalone: true,
+  providers: [provideNativeDateAdapter()],
   imports: [
     CommonModule,
     RouterModule,

+ 136 - 4
src/app/pages/admin/system-settings/system-settings.html

@@ -1,4 +1,91 @@
 <div class="system-settings">
+  <!-- 引入ECharts的CDN -->
+  <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
+  <style>
+    /* 全局样式 */
+    :host {
+      display: block;
+      padding: 20px;
+      background-color: #f5f7fa;
+      min-height: 100vh;
+    }
+    
+    /* 统计卡片样式 */
+    .stats-cards {
+      display: grid;
+      grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+      gap: 20px;
+      margin-bottom: 24px;
+    }
+    
+    .stat-card {
+      background: white;
+      padding: 20px;
+      border-radius: 8px;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+      transition: transform 0.3s, box-shadow 0.3s;
+    }
+    
+    .stat-card:hover {
+      transform: translateY(-2px);
+      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+    }
+    
+    .stat-card .label {
+      font-size: 14px;
+      color: #666;
+      margin-bottom: 8px;
+    }
+    
+    .stat-card .value {
+      font-size: 24px;
+      font-weight: 600;
+      color: #333;
+      margin-bottom: 4px;
+    }
+    
+    .stat-card .unit {
+      font-size: 14px;
+      color: #999;
+    }
+    
+    /* 图表容器样式 */
+    .charts-container {
+      display: grid;
+      grid-template-columns: 1fr 1fr;
+      gap: 24px;
+      margin-bottom: 24px;
+    }
+    
+    .chart-wrapper {
+      background: white;
+      padding: 20px;
+      border-radius: 8px;
+      box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+    }
+    
+    .chart-container {
+      height: 300px;
+      margin-top: 16px;
+    }
+    
+    /* 响应式设计 */
+    @media (max-width: 1024px) {
+      .charts-container {
+        grid-template-columns: 1fr;
+      }
+      
+      .stats-cards {
+        grid-template-columns: repeat(2, 1fr);
+      }
+    }
+    
+    @media (max-width: 768px) {
+      .stats-cards {
+        grid-template-columns: 1fr;
+      }
+    }
+  </style>
   <!-- 页面标题 -->
   <div class="page-header">
     <h2 class="page-title">系统设置</h2>
@@ -175,7 +262,6 @@
           <div class="template-info">
             <div class="template-title-row">
               <h3 class="template-name">{{ template.name }}</h3>
-              <span class="template-category">{{ template.category }}</span>
             </div>
             <p class="template-description">{{ template.description }}</p>
           </div>
@@ -267,7 +353,6 @@
           <div class="rule-info">
             <div class="rule-title-row">
               <h3 class="rule-name">{{ rule.name }}</h3>
-              <span class="rule-category">{{ rule.category }}</span>
             </div>
             <p class="rule-description">{{ rule.description }}</p>
           </div>
@@ -299,8 +384,10 @@
           </div>
         </div>
         <div class="rule-formula">
-          <div class="formula-label">计算公式:</div>
-          <div class="formula-content">{{ rule.formula }}</div>
+          <div class="formula-label">条件:</div>
+          <div class="formula-content">{{ rule.condition }}</div>
+          <div class="formula-label">价格:</div>
+          <div class="formula-content">{{ rule.price }} 元</div>
         </div>
       </div>
     </div>
@@ -417,6 +504,51 @@
 
   <!-- 系统配置标签内容 -->
   <div *ngIf="activeTab === 'system'" class="tab-content">
+    <!-- 统计卡片 -->
+    <div class="stats-cards">
+      <div class="stat-card">
+        <div class="label">总存储容量</div>
+        <div class="value">{{ systemStats.totalDataSize }}</div>
+        <div class="unit">GB</div>
+      </div>
+      <div class="stat-card">
+        <div class="label">已用存储</div>
+        <div class="value">{{ systemStats.usedDataSize }}</div>
+        <div class="unit">GB</div>
+      </div>
+      <div class="stat-card">
+        <div class="label">备份次数</div>
+        <div class="value">{{ systemStats.backupCount }}</div>
+        <div class="unit">次</div>
+      </div>
+      <div class="stat-card">
+        <div class="label">活跃用户</div>
+        <div class="value">{{ systemStats.activeUsers }}</div>
+        <div class="unit">人</div>
+      </div>
+      <div class="stat-card">
+        <div class="label">系统可用率</div>
+        <div class="value">{{ systemStats.systemUptime }}</div>
+      </div>
+      <div class="stat-card">
+        <div class="label">上次备份</div>
+        <div class="value">{{ systemStats.lastBackup }}</div>
+      </div>
+    </div>
+    
+    <!-- 图表区域 -->
+    <div class="charts-container">
+      <div class="chart-wrapper">
+        <div #dataUsageChart class="chart-container"></div>
+      </div>
+      <div class="chart-wrapper">
+        <div #backupHistoryChart class="chart-container"></div>
+      </div>
+      <div class="chart-wrapper" style="grid-column: span 2;">
+        <div #systemPerformanceChart class="chart-container"></div>
+      </div>
+    </div>
+
     <div class="system-config-section">
       <h3 class="section-title">基础配置</h3>
       

+ 568 - 271
src/app/pages/admin/system-settings/system-settings.ts

@@ -1,4 +1,11 @@
-import { Component, OnInit, signal } from '@angular/core';
+// 扩展Window接口以包含echarts属性
+declare global {
+  interface Window {
+    echarts: any;
+  }
+}
+
+import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { RouterModule } from '@angular/router';
 import { FormsModule } from '@angular/forms';
@@ -8,6 +15,7 @@ import { MatSelectModule } from '@angular/material/select';
 import { MatFormFieldModule } from '@angular/material/form-field';
 import { MatSlideToggleModule } from '@angular/material/slide-toggle';
 
+// 定义工作流阶段接口
 interface WorkflowStage {
   id: string;
   name: string;
@@ -16,24 +24,26 @@ interface WorkflowStage {
   isActive: boolean;
 }
 
+// 定义SOP模板接口
 interface SOPTemplate {
   id: string;
   name: string;
   description: string;
   steps: string[];
-  category: string;
   isActive: boolean;
 }
 
+// 定义报价规则接口
 interface PricingRule {
   id: string;
   name: string;
   description: string;
-  formula: string;
-  category: string;
+  condition: string;
+  price: number;
   isActive: boolean;
 }
 
+// 定义绩效规则接口
 interface PerformanceRule {
   id: string;
   name: string;
@@ -51,40 +61,52 @@ interface PerformanceRule {
     CommonModule,
     RouterModule,
     FormsModule,
-    MatSelectModule,
     MatFormFieldModule,
+    MatSelectModule,
     MatSlideToggleModule
   ],
-  templateUrl: './system-settings.html',
-  styleUrl: './system-settings.scss'
+  templateUrl: './system-settings.html'
 })
 export class SystemSettings implements OnInit {
-  // 激活的标签页
-  activeTab = 'workflow';
-
-  // 工作流阶段数据
+  // 当前激活的标签页
+  activeTab: string = 'workflow';
+  
+  // 搜索关键词
+  workflowSearchTerm: string = '';
+  sopSearchTerm: string = '';
+  pricingSearchTerm: string = '';
+  performanceSearchTerm: string = '';
+  
+  // 数据列表
   workflowStages: WorkflowStage[] = [];
-  filteredWorkflowStages: WorkflowStage[] = [];
-  workflowSearchTerm = '';
-
-  // SOP模板数据
   sopTemplates: SOPTemplate[] = [];
-  filteredSOPTemplates: SOPTemplate[] = [];
-  sopSearchTerm = '';
-  sopCategories = ['设计流程', '客户服务', '项目管理', '财务流程'];
-
-  // 报价规则数据
   pricingRules: PricingRule[] = [];
-  filteredPricingRules: PricingRule[] = [];
-  pricingSearchTerm = '';
-  pricingCategories = ['基础设计', '高级设计', '加急服务', '增值服务'];
-
-  // 绩效规则数据
   performanceRules: PerformanceRule[] = [];
+  
+  // 过滤后的数据列表
+  filteredWorkflowStages: WorkflowStage[] = [];
+  filteredSOPTemplates: SOPTemplate[] = [];
+  filteredPricingRules: PricingRule[] = [];
   filteredPerformanceRules: PerformanceRule[] = [];
-  performanceSearchTerm = '';
+  
+  // 常用指标
   performanceMetrics = ['项目完成率', '客户满意度', '按时交付率', '产值'];
-
+  
+  // 图表实例引用
+  @ViewChild('dataUsageChart') private dataUsageChart!: ElementRef;
+  @ViewChild('backupHistoryChart') private backupHistoryChart!: ElementRef;
+  @ViewChild('systemPerformanceChart') private systemPerformanceChart!: ElementRef;
+  
+  // 数据统计信息
+  systemStats = {
+    totalDataSize: 128,
+    usedDataSize: 76,
+    backupCount: 12,
+    activeUsers: 32,
+    systemUptime: '99.9%',
+    lastBackup: '2025-09-15 02:00:00'
+  };
+  
   // 系统配置选项
   systemOptions = {
     enableAuditLog: true,
@@ -94,16 +116,65 @@ export class SystemSettings implements OnInit {
     dataRetentionDays: 365,
     enableDataExport: true
   };
-
+  
+  // 备份历史数据
+  backupHistory = [
+    { date: '2025-09-15', size: 6.2, status: 'success' },
+    { date: '2025-09-14', size: 6.1, status: 'success' },
+    { date: '2025-09-13', size: 6.0, status: 'success' },
+    { date: '2025-09-12', size: 5.9, status: 'success' },
+    { date: '2025-09-11', size: 5.8, status: 'success' },
+    { date: '2025-09-10', size: 5.7, status: 'warning' },
+    { date: '2025-09-09', size: 5.6, status: 'success' },
+    { date: '2025-09-08', size: 5.5, status: 'error' },
+    { date: '2025-09-07', size: 5.4, status: 'success' },
+    { date: '2025-09-06', size: 5.3, status: 'success' },
+    { date: '2025-09-05', size: 5.2, status: 'success' },
+    { date: '2025-09-04', size: 5.1, status: 'success' }
+  ];
+  
+  // 系统性能数据
+  systemPerformance = [
+    { time: '00:00', cpuUsage: 15, memoryUsage: 30, diskIO: 10 },
+    { time: '04:00', cpuUsage: 10, memoryUsage: 25, diskIO: 5 },
+    { time: '08:00', cpuUsage: 25, memoryUsage: 40, diskIO: 25 },
+    { time: '12:00', cpuUsage: 40, memoryUsage: 55, diskIO: 45 },
+    { time: '16:00', cpuUsage: 35, memoryUsage: 50, diskIO: 40 },
+    { time: '20:00', cpuUsage: 20, memoryUsage: 35, diskIO: 20 }
+  ];
+  
+  // 数据类型分布
+  dataDistribution = [
+    { name: '项目数据', value: 35 },
+    { name: '客户数据', value: 25 },
+    { name: '日志数据', value: 20 },
+    { name: '配置数据', value: 10 },
+    { name: '其他数据', value: 10 }
+  ];
+  
   constructor(private dialog: MatDialog) {}
-
+  
   ngOnInit(): void {
+    // 加载各类数据
     this.loadWorkflowStages();
     this.loadSOPTemplates();
     this.loadPricingRules();
     this.loadPerformanceRules();
+    this.loadSystemOptions();
+    
+    // 初始化图表(延迟初始化,确保DOM已经加载)
+    setTimeout(() => {
+      this.initDataUsageChart();
+      this.initBackupHistoryChart();
+      this.initSystemPerformanceChart();
+    }, 100);
   }
-
+  
+  // 切换标签页
+  switchTab(tab: string): void {
+    this.activeTab = tab;
+  }
+  
   // 加载工作流阶段数据
   loadWorkflowStages(): void {
     this.workflowStages = [
@@ -118,329 +189,189 @@ export class SystemSettings implements OnInit {
         id: '2',
         name: '方案设计',
         order: 2,
-        description: '根据需求设计初步方案',
+        description: '根据需求设计解决方案和技术架构',
         isActive: true
       },
       {
         id: '3',
-        name: '方案确认',
+        name: '开发实现',
         order: 3,
-        description: '与客户确认设计方案,收集反馈',
+        description: '按照方案进行开发和实现',
         isActive: true
       },
       {
         id: '4',
-        name: '深化设计',
+        name: '测试验证',
         order: 4,
-        description: '根据确认的方案进行深化设计',
+        description: '对开发结果进行测试和验证',
         isActive: true
       },
       {
         id: '5',
-        name: '设计评审',
+        name: '部署上线',
         order: 5,
-        description: '内部评审设计成果',
+        description: '将项目部署到生产环境',
         isActive: true
       },
       {
         id: '6',
-        name: '客户验收',
+        name: '运维维护',
         order: 6,
-        description: '客户验收最终设计成果',
-        isActive: true
-      },
-      {
-        id: '7',
-        name: '项目交付',
-        order: 7,
-        description: '交付设计文件和相关资料',
-        isActive: true
-      },
-      {
-        id: '8',
-        name: '售后跟踪',
-        order: 8,
-        description: '项目完成后的售后跟踪和维护',
+        description: '项目上线后的运行维护和优化',
         isActive: true
       }
     ];
-    
-    this.filteredWorkflowStages = [...this.workflowStages];
+    this.onWorkflowSearch();
   }
-
+  
   // 加载SOP模板数据
   loadSOPTemplates(): void {
     this.sopTemplates = [
       {
         id: '1',
-        name: '标准设计流程',
-        description: '适用于大多数设计项目的标准流程',
-        steps: ['需求分析', '概念设计', '方案设计', '深化设计', '施工图设计', '交付验收'],
-        category: '设计流程',
+        name: '新客户接入流程',
+        description: '规范新客户从接触到签约的全流程',
+        steps: [
+          '初步接触与需求了解',
+          '提供解决方案与报价',
+          '商务谈判',
+          '签订合同',
+          '客户信息录入系统',
+          '启动项目'
+        ],
         isActive: true
       },
       {
         id: '2',
-        name: '客户初次咨询流程',
-        description: '客户初次咨询的标准服务流程',
-        steps: ['客户接待', '需求了解', '方案报价', '合同签订', '项目启动'],
-        category: '客户服务',
+        name: '项目开发流程',
+        description: '标准项目开发的流程规范',
+        steps: [
+          '需求分析与文档编写',
+          '系统设计',
+          '编码实现',
+          '单元测试',
+          '集成测试',
+          '系统测试',
+          '用户验收测试',
+          '上线部署'
+        ],
         isActive: true
       },
       {
         id: '3',
-        name: '项目变更管理流程',
-        description: '处理项目变更的标准流程',
-        steps: ['变更申请', '变更评估', '变更审批', '变更实施', '变更确认'],
-        category: '项目管理',
-        isActive: true
-      },
-      {
-        id: '4',
-        name: '财务结算流程',
-        description: '项目财务结算的标准流程',
-        steps: ['项目验收', '费用核算', '发票开具', '款项收取', '财务归档'],
-        category: '财务流程',
+        name: '问题处理流程',
+        description: '处理客户反馈问题的标准流程',
+        steps: [
+          '问题记录与分类',
+          '问题评估与优先级确定',
+          '问题分析与解决',
+          '验证解决方案',
+          '更新文档',
+          '反馈给客户'
+        ],
         isActive: true
       }
     ];
-    
-    this.filteredSOPTemplates = [...this.sopTemplates];
+    this.onSOPSearch();
   }
-
+  
   // 加载报价规则数据
   loadPricingRules(): void {
     this.pricingRules = [
       {
         id: '1',
-        name: '基础设计报价',
-        description: '基础设计服务的报价规则',
-        formula: '面积 * 单价 + 基础服务费',
-        category: '基础设计',
+        name: '基础开发服务',
+        description: '标准软件开发服务报价',
+        condition: '基础功能开发',
+        price: 12000,
         isActive: true
       },
       {
         id: '2',
-        name: '高级设计报价',
-        description: '高级设计服务的报价规则',
-        formula: '面积 * (单价 * 1.5) + 高级服务费',
-        category: '高级设计',
+        name: '高级开发服务',
+        description: '包含复杂功能的开发服务报价',
+        condition: '高级功能开发',
+        price: 25000,
         isActive: true
       },
       {
         id: '3',
-        name: '加急服务报价',
-        description: '加急项目的额外费用计算规则',
-        formula: '基础报价 * 1.3',
-        category: '加急服务',
-        isActive: true
-      },
-      {
-        id: '4',
-        name: '增值服务报价',
-        description: '增值服务的报价规则',
-        formula: '按单项服务定价',
-        category: '增值服务',
+        name: '维护服务',
+        description: '系统上线后的维护服务报价',
+        condition: '系统维护',
+        price: 5000,
         isActive: true
       }
     ];
-    
-    this.filteredPricingRules = [...this.pricingRules];
+    this.onPricingSearch();
   }
-
+  
   // 加载绩效规则数据
   loadPerformanceRules(): void {
     this.performanceRules = [
       {
         id: '1',
-        name: '项目完成率奖励',
-        description: '根据项目完成率发放的绩效奖励',
-        metric: '项目完成率',
+        name: '项目按时完成率',
+        description: '评估项目是否按时完成',
+        metric: '按时交付率',
         threshold: 90,
-        reward: '基础绩效 * 1.2',
+        reward: '绩效加分10分',
         isActive: true
       },
       {
         id: '2',
-        name: '客户满意度奖励',
-        description: '根据客户满意度评分发放的绩效奖励',
+        name: '客户满意度',
+        description: '评估客户对服务的满意程度',
         metric: '客户满意度',
         threshold: 95,
-        reward: '额外奖励1000元',
+        reward: '绩效加分15分',
         isActive: true
       },
       {
         id: '3',
-        name: '按时交付奖励',
-        description: '项目按时交付的绩效奖励',
-        metric: '按时交付率',
-        threshold: 95,
-        reward: '基础绩效 * 1.1',
-        isActive: true
-      },
-      {
-        id: '4',
-        name: '产值提成规则',
-        description: '根据项目产值计算的提成规则',
-        metric: '产值',
-        threshold: 100000,
-        reward: '超出部分 * 0.05',
+        name: '项目完成质量',
+        description: '评估项目交付质量',
+        metric: '项目完成率',
+        threshold: 85,
+        reward: '绩效加分12分',
         isActive: true
       }
     ];
-    
-    this.filteredPerformanceRules = [...this.performanceRules];
-  }
-
-  // 标签页切换
-  switchTab(tab: string): void {
-    this.activeTab = tab;
-  }
-
-  // 搜索过滤方法
-  onWorkflowSearch(): void {
-    if (this.workflowSearchTerm) {
-      const term = this.workflowSearchTerm.toLowerCase();
-      this.filteredWorkflowStages = this.workflowStages.filter(stage => 
-        stage.name.toLowerCase().includes(term) ||
-        stage.description.toLowerCase().includes(term)
-      );
-    } else {
-      this.filteredWorkflowStages = [...this.workflowStages];
-    }
-  }
-
-  onSOPSearch(): void {
-    if (this.sopSearchTerm) {
-      const term = this.sopSearchTerm.toLowerCase();
-      this.filteredSOPTemplates = this.sopTemplates.filter(template => 
-        template.name.toLowerCase().includes(term) ||
-        template.description.toLowerCase().includes(term) ||
-        template.category.toLowerCase().includes(term)
-      );
-    } else {
-      this.filteredSOPTemplates = [...this.sopTemplates];
-    }
+    this.onPerformanceSearch();
   }
-
-  onPricingSearch(): void {
-    if (this.pricingSearchTerm) {
-      const term = this.pricingSearchTerm.toLowerCase();
-      this.filteredPricingRules = this.pricingRules.filter(rule => 
-        rule.name.toLowerCase().includes(term) ||
-        rule.description.toLowerCase().includes(term) ||
-        rule.category.toLowerCase().includes(term)
-      );
-    } else {
-      this.filteredPricingRules = [...this.pricingRules];
-    }
+  
+  // 加载系统配置
+  loadSystemOptions(): void {
+    // 这里可以添加从后端加载配置的逻辑
+    // 目前使用的是模拟数据
   }
-
-  onPerformanceSearch(): void {
-    if (this.performanceSearchTerm) {
-      const term = this.performanceSearchTerm.toLowerCase();
-      this.filteredPerformanceRules = this.performanceRules.filter(rule => 
-        rule.name.toLowerCase().includes(term) ||
-        rule.description.toLowerCase().includes(term) ||
-        rule.metric.toLowerCase().includes(term)
-      );
-    } else {
-      this.filteredPerformanceRules = [...this.performanceRules];
-    }
-  }
-
-  // 对话框方法
+  
+  // 打开工作流阶段对话框
   openWorkflowDialog(stage?: WorkflowStage): void {
-    const dialogRef = this.dialog.open(SettingDialogComponent, {
-      width: '600px',
-      data: {
-        type: 'workflow',
-        item: stage ? { ...stage } : {
-          id: '',
-          name: '',
-          description: '',
-          order: 0,
-          isActive: true
-        }
-      }
-    });
-
-    dialogRef.afterClosed().subscribe((result: any) => {
-      if (result) {
-        this.loadWorkflowStages();
-      }
-    });
+    // 打开对话框的逻辑
+    console.log('打开工作流阶段对话框', stage);
   }
-
+  
+  // 打开SOP模板对话框
   openSOPDialog(template?: SOPTemplate): void {
-    const dialogRef = this.dialog.open(SettingDialogComponent, {
-      width: '600px',
-      data: {
-        type: 'sop',
-        item: template ? { ...template } : {
-          id: '',
-          name: '',
-          description: '',
-          steps: [],
-          isActive: true
-        }
-      }
-    });
-
-    dialogRef.afterClosed().subscribe((result: any) => {
-      if (result) {
-        this.loadSOPTemplates();
-      }
-    });
+    // 打开对话框的逻辑
+    console.log('打开SOP模板对话框', template);
   }
-
+  
+  // 打开报价规则对话框
   openPricingDialog(rule?: PricingRule): void {
-    const dialogRef = this.dialog.open(SettingDialogComponent, {
-      width: '600px',
-      data: {
-        type: 'pricing',
-        item: rule ? { ...rule } : {
-          id: '',
-          name: '',
-          description: '',
-          formula: '',
-          baseAmount: 0,
-          isActive: true
-        }
-      }
-    });
-
-    dialogRef.afterClosed().subscribe((result: any) => {
-      if (result) {
-        this.loadPricingRules();
-      }
-    });
+    // 打开对话框的逻辑
+    console.log('打开报价规则对话框', rule);
   }
-
+  
+  // 打开绩效规则对话框
   openPerformanceDialog(rule?: PerformanceRule): void {
-    const dialogRef = this.dialog.open(SettingDialogComponent, {
-      width: '600px',
-      data: {
-        type: 'performance',
-        item: rule ? { ...rule } : {
-          id: '',
-          name: '',
-          description: '',
-          criteria: {},
-          isActive: true
-        }
-      }
-    });
-
-    dialogRef.afterClosed().subscribe((result: any) => {
-      if (result) {
-        this.loadPerformanceRules();
-      }
-    });
+    // 打开对话框的逻辑
+    console.log('打开绩效规则对话框', rule);
   }
-
-  // 处理设置更新
-  handleSettingUpdate(type: string, updatedItem: any): void {
+  
+  // 保存设置项
+  saveSetting(type: string, updatedItem: any): void {
     switch (type) {
       case 'workflow':
         if (updatedItem.id) {
@@ -496,7 +427,7 @@ export class SystemSettings implements OnInit {
         break;
     }
   }
-
+  
   // 删除设置项
   deleteSetting(type: string, id: string): void {
     if (confirm('确定要删除此项设置吗?')) {
@@ -520,7 +451,7 @@ export class SystemSettings implements OnInit {
       }
     }
   }
-
+  
   // 更新设置项的激活状态
   toggleActive(type: string, id: string, isActive: boolean): void {
     switch (type) {
@@ -550,10 +481,376 @@ export class SystemSettings implements OnInit {
         break;
     }
   }
-
+  
+  // 搜索工作流阶段
+  onWorkflowSearch(): void {
+    if (!this.workflowSearchTerm.trim()) {
+      this.filteredWorkflowStages = this.workflowStages;
+    } else {
+      const searchTerm = this.workflowSearchTerm.toLowerCase();
+      this.filteredWorkflowStages = this.workflowStages.filter(
+        stage => stage.name.toLowerCase().includes(searchTerm) || 
+                 stage.description.toLowerCase().includes(searchTerm)
+      );
+    }
+  }
+  
+  // 搜索SOP模板
+  onSOPSearch(): void {
+    if (!this.sopSearchTerm.trim()) {
+      this.filteredSOPTemplates = this.sopTemplates;
+    } else {
+      const searchTerm = this.sopSearchTerm.toLowerCase();
+      this.filteredSOPTemplates = this.sopTemplates.filter(
+        template => template.name.toLowerCase().includes(searchTerm) || 
+                    template.description.toLowerCase().includes(searchTerm) ||
+                    template.steps.some(step => step.toLowerCase().includes(searchTerm))
+      );
+    }
+  }
+  
+  // 搜索报价规则
+  onPricingSearch(): void {
+    if (!this.pricingSearchTerm.trim()) {
+      this.filteredPricingRules = this.pricingRules;
+    } else {
+      const searchTerm = this.pricingSearchTerm.toLowerCase();
+      this.filteredPricingRules = this.pricingRules.filter(
+        rule => rule.name.toLowerCase().includes(searchTerm) || 
+                rule.description.toLowerCase().includes(searchTerm) ||
+                rule.condition.toLowerCase().includes(searchTerm)
+      );
+    }
+  }
+  
+  // 搜索绩效规则
+  onPerformanceSearch(): void {
+    if (!this.performanceSearchTerm.trim()) {
+      this.filteredPerformanceRules = this.performanceRules;
+    } else {
+      const searchTerm = this.performanceSearchTerm.toLowerCase();
+      this.filteredPerformanceRules = this.performanceRules.filter(
+        rule => rule.name.toLowerCase().includes(searchTerm) || 
+                rule.description.toLowerCase().includes(searchTerm) ||
+                rule.metric.toLowerCase().includes(searchTerm)
+      );
+    }
+  }
+  
   // 保存系统配置
   saveSystemOptions(): void {
-    // 模拟保存操作
-    alert('系统配置已保存!');
+    console.log('保存系统配置:', this.systemOptions);
+    // 这里可以添加保存到后端的逻辑
+    alert('系统配置保存成功!');
+  }
+  
+  // 初始化数据使用情况图表
+  initDataUsageChart(): void {
+    if (window['echarts'] && this.dataUsageChart) {
+      const chart = window['echarts'].init(this.dataUsageChart.nativeElement);
+      
+      const option = {
+        title: {
+          text: '数据存储使用情况',
+          left: 'center',
+          textStyle: {
+            fontWeight: 'normal',
+            fontSize: 16
+          }
+        },
+        tooltip: {
+          trigger: 'item',
+          formatter: '{b}: {c}GB ({d}%)'
+        },
+        legend: {
+          orient: 'vertical',
+          left: 10,
+          top: 'center'
+        },
+        series: [
+          {
+            name: '数据存储',
+            type: 'pie',
+            radius: ['40%', '70%'],
+            avoidLabelOverlap: false,
+            itemStyle: {
+              borderRadius: 10,
+              borderColor: '#fff',
+              borderWidth: 2
+            },
+            label: {
+              show: false,
+              position: 'center'
+            },
+            emphasis: {
+              label: {
+                show: true,
+                fontSize: 18,
+                fontWeight: 'bold'
+              }
+            },
+            labelLine: {
+              show: false
+            },
+            data: [
+              {
+                value: this.systemStats.usedDataSize,
+                name: '已使用',
+                itemStyle: { color: '#165DFF' }
+              },
+              {
+                value: this.systemStats.totalDataSize - this.systemStats.usedDataSize,
+                name: '未使用',
+                itemStyle: { color: '#E5E6EB' }
+              }
+            ]
+          },
+          {
+            name: '数据类型分布',
+            type: 'pie',
+            radius: ['15%', '30%'],
+            center: ['75%', '60%'],
+            data: this.dataDistribution,
+            itemStyle: {
+              borderRadius: 5
+            },
+            label: {
+              show: false
+            }
+          }
+        ]
+      };
+      
+      chart.setOption(option);
+      
+      // 响应式调整
+      window.addEventListener('resize', () => {
+        chart.resize();
+      });
+    }
+  }
+  
+  // 初始化备份历史图表
+  initBackupHistoryChart(): void {
+    if (window['echarts'] && this.backupHistoryChart) {
+      const chart = window['echarts'].init(this.backupHistoryChart.nativeElement);
+      
+      const dates = this.backupHistory.map(item => item.date);
+      const sizes = this.backupHistory.map(item => item.size);
+      const statusColors = this.backupHistory.map(item => {
+        switch(item.status) {
+          case 'success': return '#00B42A';
+          case 'warning': return '#FFAA00';
+          case 'error': return '#F53F3F';
+          default: return '#86909C';
+        }
+      });
+      
+      const option = {
+        title: {
+          text: '备份历史记录',
+          left: 'center',
+          textStyle: {
+            fontWeight: 'normal',
+            fontSize: 16
+          }
+        },
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross',
+            label: {
+              backgroundColor: '#6a7985'
+            }
+          },
+          formatter: (params: any) => {
+            const data = params[0];
+            const statusItem = this.backupHistory[data.dataIndex];
+            const statusText: Record<string, string> = {
+              'success': '成功',
+              'warning': '警告',
+              'error': '失败'
+            };
+            return `${data.name}<br/>备份大小: ${data.value}GB<br/>状态: ${statusText[statusItem.status]}`;
+          }
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: dates,
+          axisLabel: {
+            rotate: 45
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: '备份大小 (GB)',
+          min: 0
+        },
+        series: [
+          {
+            name: '备份大小',
+            type: 'line',
+            smooth: true,
+            data: sizes,
+            lineStyle: {
+              width: 3,
+              color: '#165DFF'
+            },
+            areaStyle: {
+              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+                {
+                  offset: 0,
+                  color: 'rgba(22, 93, 255, 0.3)'
+                },
+                {
+                  offset: 1,
+                  color: 'rgba(22, 93, 255, 0.05)'
+                }
+              ])
+            },
+            symbol: 'circle',
+            symbolSize: 8,
+            itemStyle: {
+              color: function(params: any) {
+                return statusColors[params.dataIndex];
+              }
+            }
+          }
+        ]
+      };
+      
+      chart.setOption(option);
+      
+      // 响应式调整
+      window.addEventListener('resize', () => {
+        chart.resize();
+      });
+    }
+  }
+  
+  // 初始化系统性能图表
+  initSystemPerformanceChart(): void {
+    if (window['echarts'] && this.systemPerformanceChart) {
+      const chart = window['echarts'].init(this.systemPerformanceChart.nativeElement);
+      
+      const times = this.systemPerformance.map(item => item.time);
+      const cpuUsage = this.systemPerformance.map(item => item.cpuUsage);
+      const memoryUsage = this.systemPerformance.map(item => item.memoryUsage);
+      const diskIO = this.systemPerformance.map(item => item.diskIO);
+      
+      const option = {
+        title: {
+          text: '系统性能监控',
+          left: 'center',
+          textStyle: {
+            fontWeight: 'normal',
+            fontSize: 16
+          }
+        },
+        tooltip: {
+          trigger: 'axis'
+        },
+        legend: {
+          data: ['CPU使用率', '内存使用率', '磁盘IO'],
+          bottom: 0
+        },
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '15%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: times
+        },
+        yAxis: {
+          type: 'value',
+          name: '使用率 (%)',
+          min: 0,
+          max: 100
+        },
+        series: [
+          {
+            name: 'CPU使用率',
+            type: 'line',
+            stack: 'Total',
+            data: cpuUsage,
+            lineStyle: {
+              color: '#165DFF'
+            },
+            areaStyle: {
+              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+                {
+                  offset: 0,
+                  color: 'rgba(22, 93, 255, 0.5)'
+                },
+                {
+                  offset: 1,
+                  color: 'rgba(22, 93, 255, 0.1)'
+                }
+              ])
+            }
+          },
+          {
+            name: '内存使用率',
+            type: 'line',
+            stack: 'Total',
+            data: memoryUsage,
+            lineStyle: {
+              color: '#722ED1'
+            },
+            areaStyle: {
+              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+                {
+                  offset: 0,
+                  color: 'rgba(114, 46, 209, 0.5)'
+                },
+                {
+                  offset: 1,
+                  color: 'rgba(114, 46, 209, 0.1)'
+                }
+              ])
+            }
+          },
+          {
+            name: '磁盘IO',
+            type: 'line',
+            stack: 'Total',
+            data: diskIO,
+            lineStyle: {
+              color: '#F7BA1E'
+            },
+            areaStyle: {
+              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+                {
+                  offset: 0,
+                  color: 'rgba(247, 186, 30, 0.5)'
+                },
+                {
+                  offset: 1,
+                  color: 'rgba(247, 186, 30, 0.1)'
+                }
+              ])
+            }
+          }
+        ]
+      };
+      
+      chart.setOption(option);
+      
+      // 响应式调整
+      window.addEventListener('resize', () => {
+        chart.resize();
+      });
+    }
   }
 }

+ 224 - 1
src/app/pages/hr/assets/assets.scss

@@ -404,12 +404,235 @@ $transition: all 0.2s ease;
   }
 }
 
-// 自定义对话框样式
+// 自定义对话框样式 - 以深蓝色和白色为主色调
+.add-employee-dialog-container {
+  .mat-dialog-container {
+    background-color: #1e293b;
+    color: white;
+    border-radius: 12px;
+    padding: 0;
+    overflow: hidden;
+    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
+  }
+
+  .mat-dialog-title {
+    color: white;
+    font-size: 24px;
+    font-weight: 600;
+    padding: 24px 24px 0;
+    margin: 0;
+  }
+
+  .mat-dialog-content {
+    padding: 24px;
+    background-color: white;
+    color: #1e293b;
+    margin: 0;
+  }
+
+  .mat-dialog-actions {
+    padding: 16px 24px;
+    background-color: #1e293b;
+    justify-content: flex-end;
+    margin: 0;
+  }
+}
+
 .custom-dialog {
+  // 对话框容器样式
   .mat-dialog-container {
+    border-radius: $border-radius;
+    box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.15), 0 10px 15px -6px rgba(0, 0, 0, 0.1);
+    overflow: hidden;
+    background-color: $bg-primary; // 使用白色作为主背景
+    border: 2px solid $primary-color; // 深蓝色边框
+    max-width: 700px; // 增加对话框宽度
+    width: 95vw;
+    animation: slideIn 0.3s ease-out; // 添加动画效果
+  }
+  
+  // 对话框标题样式
+  h2 {
+    font-size: 24px; // 增大标题字体
+    font-weight: 700;
+    color: $primary-color; // 使用深蓝色标题
+    margin: 0;
+  }
+  
+  // 输入框样式
+  .mat-input-element {
+    color: $text-primary;
+    font-size: 16px; // 增大输入框字体
+    font-weight: 500;
+  }
+  
+  .mat-form-field {
+    width: 100%;
+    transition: all 0.2s ease;
+  }
+  
+  .mat-form-field-appearance-fill .mat-form-field-flex {
+    background-color: $bg-primary; // 输入框白色背景
+    border-radius: $border-radius;
+    border: 1px solid $border-color;
+    transition: all 0.2s ease;
+  }
+  
+  .mat-form-field-appearance-fill .mat-form-field-outline {
+    border: none;
+  }
+  
+  .mat-form-field-appearance-fill .mat-form-field-underline {
+    display: none;
+  }
+  
+  // 输入框聚焦效果增强
+  .mat-form-field-appearance-fill .mat-form-field-focus-overlay {
+    background-color: rgba(30, 64, 175, 0.08);
+  }
+  
+  .mat-form-field:focus-within .mat-form-field-flex {
+    border-color: $primary-color;
+    box-shadow: 0 0 0 3px rgba(30, 64, 175, 0.1);
+  }
+  
+  // 选择框样式增强
+  .mat-select {
+    color: $text-primary;
+    font-size: 16px;
+  }
+  
+  .mat-select-panel {
+    background-color: $bg-primary;
     border-radius: $border-radius;
     box-shadow: $shadow-lg;
+    margin-top: 8px;
+    border: 1px solid $border-color;
+    animation: slideIn 0.2s ease-out;
+  }
+  
+  .mat-option {
+    color: $text-primary;
+    padding: 12px 20px; // 增加选项间距
+    font-size: 16px; // 增大选项字体
+    font-weight: 500;
+    transition: all 0.2s ease;
+    border-radius: $border-radius;
+    margin: 2px 8px;
+    
+    &:hover {
+      background-color: rgba(30, 64, 175, 0.1);
+      transform: translateX(4px); // 悬停时轻微移动
+    }
+    
+    &.mat-selected {
+      background-color: color-mix(in srgb, $primary-color 20%, transparent);
+      color: $primary-color;
+      font-weight: 600;
+    }
+    
+    &:active {
+      transform: scale(0.98);
+    }
+  }
+  
+  // 按钮样式优化
+  button[mat-button] {
+    color: $text-secondary;
+    font-size: 16px; // 增大按钮字体
+    font-weight: 600;
+    padding: 10px 24px;
+    transition: all 0.2s ease;
+    border-radius: $border-radius;
+    
+    &:hover {
+      color: $primary-color;
+      background-color: rgba(30, 64, 175, 0.08);
+      transform: translateY(-1px);
+    }
+    
+    &:active {
+      transform: translateY(0);
+    }
+  }
+  
+  button[mat-raised-button][color="primary"] {
+    background-color: $primary-color;
+    color: white;
+    font-size: 16px; // 增大按钮字体
+    font-weight: 600;
+    border-radius: $border-radius;
+    padding: 12px 32px;
+    transition: all 0.2s ease;
+    box-shadow: 0 4px 12px rgba(30, 64, 175, 0.3);
+    
+    &:hover {
+      background-color: $primary-light;
+      transform: translateY(-2px);
+      box-shadow: 0 6px 16px rgba(30, 64, 175, 0.4);
+    }
+    
+    &:active {
+      transform: translateY(0);
+      box-shadow: 0 4px 10px rgba(30, 64, 175, 0.3);
+    }
+    
+    &:disabled {
+      background-color: $text-tertiary;
+      transform: none;
+      box-shadow: none;
+    }
+  }
+  
+  // 日期选择器样式增强
+  .mat-datepicker-toggle {
+    color: $text-tertiary;
+    transition: all 0.2s ease;
+    
+    &:hover {
+      color: $primary-color;
+      transform: scale(1.1);
+    }
+  }
+  
+  .mat-datepicker-content {
+    border-radius: $border-radius;
     overflow: hidden;
+    border: 1px solid $border-color;
+  }
+  
+  // 表单标签样式增强
+  label {
+    color: $text-primary;
+    font-weight: 600;
+    font-size: 16px;
+    margin-bottom: 8px;
+    display: block;
+  }
+  
+  // 必填标记样式
+  .required-mark {
+    color: $error-color;
+    font-size: 16px;
+    margin-left: 4px;
+  }
+  
+  // 错误状态样式增强
+  .mat-error {
+    color: $error-color;
+    font-size: 14px;
+    margin-top: 6px;
+    display: block;
+    font-weight: 500;
+  }
+  
+  .mat-form-field-invalid .mat-form-field-flex {
+    border-color: $error-color;
+    background-color: rgba(239, 68, 68, 0.05);
+  }
+  
+  .mat-form-field-invalid .mat-input-element {
+    color: $error-color;
   }
 }
 

+ 67 - 22
src/app/pages/hr/assets/assets.ts

@@ -42,17 +42,17 @@ import { Employee, Department, Position, Contract, Certificate, EmployeeStatus }
     <form [formGroup]="employeeForm" (ngSubmit)="onSubmit()" class="employee-form">
       <div class="form-row">
         <div class="form-group">
-          <label>员工姓名 *</label>
+          <label>员工姓名 <span class="required-mark">*</span></label>
           <input matInput formControlName="name" placeholder="请输入姓名">
         </div>
         <div class="form-group">
-          <label>工号 *</label>
+          <label>工号 <span class="required-mark">*</span></label>
           <input matInput formControlName="employeeId" placeholder="请输入工号">
         </div>
       </div>
       <div class="form-row">
         <div class="form-group">
-          <label>部门 *</label>
+          <label>部门 <span class="required-mark">*</span></label>
           <mat-select formControlName="department">
             <mat-option *ngFor="let dept of departments" [value]="dept.name">
               {{ dept.name }}
@@ -60,17 +60,17 @@ import { Employee, Department, Position, Contract, Certificate, EmployeeStatus }
           </mat-select>
         </div>
         <div class="form-group">
-          <label>岗位 *</label>
+          <label>岗位 <span class="required-mark">*</span></label>
           <input matInput formControlName="position" placeholder="请输入岗位">
         </div>
       </div>
       <div class="form-row">
         <div class="form-group">
-          <label>手机号码 *</label>
+          <label>手机号码 <span class="required-mark">*</span></label>
           <input matInput formControlName="phone" placeholder="请输入手机号码">
         </div>
         <div class="form-group">
-          <label>邮箱 *</label>
+          <label>邮箱 <span class="required-mark">*</span></label>
           <input matInput formControlName="email" placeholder="请输入邮箱">
         </div>
       </div>
@@ -91,13 +91,13 @@ import { Employee, Department, Position, Contract, Certificate, EmployeeStatus }
       </div>
       <div class="form-row">
         <div class="form-group">
-          <label>入职日期 *</label>
+          <label>入职日期 <span class="required-mark">*</span></label>
           <input matInput [matDatepicker]="hireDatePicker" formControlName="hireDate">
           <mat-datepicker-toggle matSuffix [for]="hireDatePicker"></mat-datepicker-toggle>
           <mat-datepicker #hireDatePicker></mat-datepicker>
         </div>
         <div class="form-group">
-          <label>状态 *</label>
+          <label>状态 <span class="required-mark">*</span></label>
           <mat-select formControlName="status">
             <mat-option value="在职">在职</mat-option>
             <mat-option value="试用期">试用期</mat-option>
@@ -116,39 +116,84 @@ import { Employee, Department, Position, Contract, Certificate, EmployeeStatus }
       display: flex;
       justify-content: space-between;
       align-items: center;
-      margin-bottom: 24px;
-      padding-bottom: 16px;
-      border-bottom: 1px solid #e5e7eb;
+      margin-bottom: 32px;
+      padding-bottom: 20px;
+      border-bottom: 2px solid #e5e7eb;
     }
+    
     .close-btn {
       background: none;
       border: none;
       cursor: pointer;
-      color: #6b7280;
-      padding: 4px;
+      color: #9ca3af;
+      padding: 6px;
+      border-radius: 50%;
+      transition: all 0.2s ease;
+      
+      &:hover {
+        color: #1f2937;
+        background-color: #f3f4f6;
+        transform: scale(1.15);
+      }
+      
+      &:active {
+        transform: scale(0.95);
+      }
     }
+    
     .employee-form {
-      max-width: 600px;
+      max-width: 100%;
     }
+    
     .form-row {
       display: flex;
-      gap: 16px;
-      margin-bottom: 16px;
+      gap: 24px;
+      margin-bottom: 24px;
+      flex-wrap: wrap;
     }
+    
     .form-group {
       flex: 1;
+      min-width: 250px;
     }
+    
     label {
       display: block;
-      margin-bottom: 4px;
-      font-weight: 500;
+      margin-bottom: 8px;
+      font-weight: 600;
       color: #374151;
+      font-size: 16px;
     }
+    
+    .required-mark {
+      color: #ef4444;
+      font-size: 16px;
+    }
+    
     .dialog-actions {
       display: flex;
       justify-content: flex-end;
-      gap: 12px;
-      margin-top: 24px;
+      gap: 16px;
+      margin-top: 32px;
+      padding-top: 20px;
+      border-top: 1px solid #e5e7eb;
+    }
+    
+    // 表单元素聚焦效果
+    .mat-form-field-appearance-fill .mat-form-field-focus-overlay {
+      background-color: rgba(30, 64, 175, 0.05);
+    }
+    
+    // 错误状态样式
+    .mat-error {
+      color: #ef4444;
+      font-size: 14px;
+      margin-top: 4px;
+      display: block;
+    }
+    
+    .mat-form-field-invalid .mat-input-element {
+      color: #ef4444;
     }
   `]
 }) class AddEmployeeDialog {
@@ -224,7 +269,7 @@ const generateMockEmployees = (): Employee[] => {
       birthDate: new Date(1980 + Math.floor(Math.random() * 20), Math.floor(Math.random() * 12), Math.floor(Math.random() * 28) + 1),
       hireDate,
       status,
-      avatar: `https://via.placeholder.com/40?text=${i}`,
+      avatar: `https://picsum.photos/seed/emp${i}/40/40`,
       contract: {
         id: `contract-${i}`,
         startDate: hireDate,
@@ -348,7 +393,7 @@ const generateMockEmployees = (): Employee[] => {
         const newEmployee: Employee = {
           id: `emp-${Date.now()}`,
           ...result,
-          avatar: `https://via.placeholder.com/40?text=E`,
+          avatar: `https://picsum.photos/seed/emp${Date.now()}/40/40`,
           contract: {
             id: `contract-${Date.now()}`,
             startDate: result.hireDate,