工业检测 1 өдөр өмнө
parent
commit
a16683245e

+ 42 - 68
industry-monitor-web/src/app/pages/device-monitor/device-monitor.component.html

@@ -1,37 +1,41 @@
-
 <!-- device-monitor.component.html -->
 <div class="monitor-container">
   <div class="monitor-header">
     <h2><i class="fa fa-microchip"></i> 单设备监测面板</h2>
-    <div class="device-info">
-      <div><strong>设备名称:</strong> CNC 铣床 #01</div>
-      <div><strong>设备编号:</strong> DEV-2023-001</div>
-      <div><strong>位置:</strong> 车间A - 产线3</div>
-      <div><strong>设备类型:</strong> CNC加工中心</div>
+    <div class="header-info">
+      <div class="device-info">
+        <div><strong>设备名称:</strong> CNC 铣床 #01</div>
+        <div><strong>设备编号:</strong> DEV-2023-001</div>
+        <div><strong>位置:</strong> 车间A - 产线3</div>
+        <div><strong>设备类型:</strong> CNC加工中心</div>
+      </div>
+      <div class="current-time">
+        <strong>当前时间:</strong> {{ currentTime | date: 'yyyy-MM-dd HH:mm:ss' }}
+      </div>
     </div>
   </div>
 
   <div class="monitor-row">
     <div class="waveform-card">
       <h3><i class="fa fa-wave-square"></i> 振动波形图 (40秒周期)</h3>
-      <div class="waveform-container">
-        <div class="waveform-grid">
-          <div class="grid-line"></div>
-          <div class="grid-line"></div>
-          <div class="grid-line"></div>
-          <div class="waveform-line"></div>
-          <div class="threshold upper"></div>
-          <div class="threshold lower"></div>
-        </div>
+      <!-- 修改1: 使用 appEchart 指令和 echartOptions 绑定 -->
+      <div class="waveform-container"
+           appEchart
+           [echartOptions]="chartOptions">
       </div>
       <div class="waveform-controls">
         <div class="threshold-control">
-          <label>阈值上限: <span id="upperValue">0.8</span> mm/s</label>
-          <input type="range" min="0" max="1.5" step="0.1" value="0.8" id="upperThreshold">
+          <label>阈值上限: {{ upperThreshold }} mm/s</label>
+          <!-- 修改2: 更新滑块绑定 -->
+          <input type="range" min="0.1" max="1.5" step="0.05"
+                 [(ngModel)]="upperThreshold"
+                 (input)="updateThreshold()">
         </div>
         <div class="threshold-control">
-          <label>阈值下限: <span id="lowerValue">0.2</span> mm/s</label>
-          <input type="range" min="0" max="1.5" step="0.1" value="0.2" id="lowerThreshold">
+          <label>阈值下限: {{ lowerThreshold }} mm/s</label>
+          <input type="range" min="0.1" max="1.5" step="0.05"
+                 [(ngModel)]="lowerThreshold"
+                 (input)="updateThreshold()">
         </div>
       </div>
     </div>
@@ -39,44 +43,18 @@
     <div class="status-panel">
       <h3><i class="fa fa-heartbeat"></i> 实时状态</h3>
       <div class="status-grid">
-        <div class="status-card">
-          <div class="status-icon blue">
-            <i class="fa fa-wave-square"></i>
+        <!-- 修改3: 修复 ngClass 绑定 -->
+        <div class="status-card" *ngFor="let status of statusValues">
+          <div class="status-icon" [ngClass]="status.color">
+            <i class="fa" [ngClass]="status.icon"></i>
           </div>
           <div class="status-data">
-            <div class="status-label">当前振幅</div>
-            <div class="status-value">0.58 mm/s</div>
-          </div>
-        </div>
-        <div class="status-card">
-          <div class="status-icon green">
-            <i class="fa fa-heartbeat"></i>
-          </div>
-          <div class="status-data">
-            <div class="status-label">健康指数</div>
-            <div class="status-value">89%</div>
-          </div>
-        </div>
-        <div class="status-card">
-          <div class="status-icon orange">
-            <i class="fa fa-thermometer-half"></i>
-          </div>
-          <div class="status-data">
-            <div class="status-label">温度</div>
-            <div class="status-value">68°C</div>
-          </div>
-        </div>
-        <div class="status-card">
-          <div class="status-icon purple">
-            <i class="fa fa-tachometer-alt"></i>
-          </div>
-          <div class="status-data">
-            <div class="status-label">转速</div>
-            <div class="status-value">1420 RPM</div>
+            <div class="status-label">{{ status.label }}</div>
+            <div class="status-value">{{ status.value }} {{ status.unit }}</div>
           </div>
         </div>
       </div>
-      
+
       <div class="progress-container">
         <h4>工序进度</h4>
         <div class="progress-steps">
@@ -100,23 +78,19 @@
         <button class="btn"><i class="fa fa-download"></i> 数据导出</button>
       </div>
     </div>
-    
+
     <div class="alert-history">
-      <div class="history-item">
-        <div class="alert-time">14:30:22</div>
-        <div class="alert-desc">振动超标 (0.92 mm/s)</div>
-        <div class="alert-level warning">警告</div>
-      </div>
-      <div class="history-item">
-        <div class="alert-time">11:45:10</div>
-        <div class="alert-desc">温度异常 (78°C)</div>
-        <div class="alert-level critical">严重</div>
-      </div>
-      <div class="history-item">
-        <div class="alert-time">09:15:33</div>
-        <div class="alert-desc">转速波动超出范围</div>
-        <div class="alert-level info">注意</div>
+      <!-- 修改4: 修复 ngClass 绑定 -->
+      <div class="history-item" *ngFor="let alert of alertHistory">
+        <div class="alert-time">{{ alert.time }}</div>
+        <div class="alert-desc">{{ alert.desc }}</div>
+        <div class="alert-level" [ngClass]="alert.level">
+          {{
+            alert.level === 'warning' ? '警告' :
+            alert.level === 'critical' ? '严重' : '注意'
+          }}
+        </div>
       </div>
     </div>
   </div>
-</div>
+</div>

+ 151 - 8
industry-monitor-web/src/app/pages/device-monitor/device-monitor.component.ts

@@ -1,21 +1,164 @@
-import { Component, ViewEncapsulation } from '@angular/core';
+import { Component, ViewEncapsulation, OnInit } from '@angular/core';
 import { DatePipe } from '@angular/common';
+import * as echarts from 'echarts';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { EchartDirective } from '../../shared/directives/echarts.directive';
 
 @Component({
   standalone: true,
   selector: 'app-device-monitor',
-  styleUrls: ['./device-monitor.css'],
-  imports: [DatePipe],
   templateUrl: './device-monitor.component.html',
+  styleUrls: ['./device-monitor.css'],
+  imports: [
+    DatePipe,
+    CommonModule,
+    FormsModule,
+    EchartDirective
+  ],
   encapsulation: ViewEncapsulation.None
 })
-export class DeviceMonitorComponent {
-currentTime: Date = new Date();
-   ngOnInit(): void {
-    // 更新时间,每秒更新一次
+export class DeviceMonitorComponent implements OnInit {
+  currentTime: Date = new Date();
+  vibrationData: number[] = [];
+  upperThreshold = 0.8;
+  lowerThreshold = 0.2;
+  currentAmplitude = 0.58;
+  healthIndex = 89;
+  temperature = 68;
+  rotationSpeed = 1420;
+  chartOptions: any;
+
+  statusValues = [
+    { label: '当前振幅', value: 0.58, unit: 'mm/s', icon: 'fa-wave-square', color: 'blue' },
+    { label: '健康指数', value: 89, unit: '%', icon: 'fa-heartbeat', color: 'green' },
+    { label: '温度', value: 68, unit: '°C', icon: 'fa-thermometer-half', color: 'orange' },
+    { label: '转速', value: 1420, unit: 'RPM', icon: 'fa-tachometer-alt', color: 'purple' }
+  ];
+
+  alertHistory = [
+    { time: '14:30:22', desc: '振动超标 (0.92 mm/s)', level: 'warning' },
+    { time: '11:45:10', desc: '温度异常 (78°C)', level: 'critical' },
+    { time: '09:15:33', desc: '转速波动超出范围', level: 'info' }
+  ];
+
+  ngOnInit(): void {
     setInterval(() => {
       this.currentTime = new Date();
     }, 1000);
 
-   }
+    this.generateVibrationData();
+    this.updateChartOptions();
+
+    setInterval(() => {
+      this.updateSensorData();
+    }, 3000);
+  }
+
+  generateVibrationData(): void {
+    for (let i = 0; i < 200; i++) {
+      const baseValue = Math.sin(i * 0.2) * 0.5;
+      const noise = (Math.random() - 0.5) * 0.2;
+      this.vibrationData.push(baseValue + noise + 0.5);
+    }
+  }
+
+  updateSensorData(): void {
+    this.currentAmplitude = 0.4 + Math.random() * 0.5;
+    this.healthIndex = Math.max(70, Math.min(95, this.healthIndex + (Math.random() - 0.5) * 5));
+    this.temperature = Math.max(60, Math.min(75, this.temperature + (Math.random() - 0.5) * 2));
+    this.rotationSpeed = 1400 + Math.floor(Math.random() * 50);
+
+    this.statusValues[0].value = parseFloat(this.currentAmplitude.toFixed(2));
+    this.statusValues[1].value = Math.round(this.healthIndex);
+    this.statusValues[2].value = Math.round(this.temperature);
+    this.statusValues[3].value = this.rotationSpeed;
+
+    // 更新振动数据
+    this.vibrationData.shift();
+    const newValue = 0.4 + Math.random() * 0.6;
+    this.vibrationData.push(newValue);
+
+    // 更新图表
+    this.updateChartOptions();
+  }
+
+  updateChartOptions(): void {
+    this.chartOptions = {
+      tooltip: {
+        trigger: 'axis',
+        formatter: (params: any) => {
+          const value = params[0].value;
+          let status = '正常';
+          if (value > this.upperThreshold) status = '超标';
+          if (value < this.lowerThreshold) status = '过低';
+
+          return `时间: ${params[0].name}<br/>振幅: ${value.toFixed(2)} mm/s<br/>状态: ${status}`;
+        }
+      },
+      grid: {
+        left: '3%',
+        right: '4%',
+        bottom: '12%',
+        top: '10%',
+        containLabel: true
+      },
+      xAxis: {
+        type: 'category',
+        boundaryGap: false,
+        data: Array.from({length: 200}, (_, i) => `${i*0.2}s`),
+        axisLine: { show: false },
+        axisTick: { show: false },
+        axisLabel: { show: false }
+      },
+      yAxis: {
+        type: 'value',
+        min: 0,
+        max: 1.5,
+        splitLine: {
+          lineStyle: { color: 'rgba(0, 0, 0, 0.05)' }
+        },
+        axisLabel: { formatter: '{value} mm/s' }
+      },
+      series: [
+        {
+          name: '振动波形',
+          type: 'line',
+          smooth: true,
+          symbol: 'none',
+          sampling: 'average',
+          data: this.vibrationData,
+          lineStyle: { width: 2, color: '#3498db' },
+          areaStyle: {
+            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+              { offset: 0, color: 'rgba(52, 152, 219, 0.3)' },
+              { offset: 1, color: 'rgba(52, 152, 219, 0.1)' }
+            ])
+          },
+          markLine: {
+            silent: true,
+            symbol: 'none',
+            lineStyle: { color: '#e74c3c', width: 1, type: 'dashed' },
+            data: [
+              {
+                name: '阈值上限',
+                yAxis: this.upperThreshold,
+                label: { formatter: '上限: {c} mm/s', position: 'end' }
+              },
+              {
+                name: '阈值下限',
+                yAxis: this.lowerThreshold,
+                label: { formatter: '下限: {c} mm/s', position: 'end' }
+              }
+            ]
+          }
+        }
+      ],
+      animation: false
+    };
+  }
+
+  updateThreshold(): void {
+    this.updateChartOptions();
+  }
 }

+ 116 - 52
industry-monitor-web/src/app/pages/device-monitor/device-monitor.css

@@ -1,8 +1,9 @@
-/* device-monitor.component.css */
+device-monitor.component.css
 :host {
   display: block;
   width: 100%;
   padding: 15px;
+  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 }
 
 .monitor-container {
@@ -31,6 +32,12 @@
   color: #2c3e50;
 }
 
+.header-info {
+  display: flex;
+  flex-direction: column;
+  align-items: flex-end;
+}
+
 .device-info {
   display: grid;
   grid-template-columns: repeat(2, 1fr);
@@ -39,6 +46,15 @@
   background: #f8fafc;
   padding: 15px;
   border-radius: 6px;
+  margin-bottom: 10px;
+}
+
+.current-time {
+  font-size: 14px;
+  background: #f8fafc;
+  padding: 8px 15px;
+  border-radius: 4px;
+  font-weight: 500;
 }
 
 .monitor-row {
@@ -47,12 +63,20 @@
   margin-bottom: 20px;
 }
 
+@media (max-width: 1200px) {
+  .monitor-row {
+    flex-direction: column;
+  }
+}
+
 .waveform-card {
   flex: 2;
   background: white;
   border-radius: 8px;
   padding: 20px;
   box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+  display: flex;
+  flex-direction: column;
 }
 
 .status-panel {
@@ -61,66 +85,24 @@
   border-radius: 8px;
   padding: 20px;
   box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+  display: flex;
+  flex-direction: column;
 }
 
 .waveform-container {
   height: 250px;
-  background: #f1f8ff;
+  background: #f8fafc;
   border-radius: 6px;
-  margin: 20px 0;
+  margin: 15px 0;
   position: relative;
   overflow: hidden;
+  border: 1px solid #eee;
 }
 
-.waveform-grid {
-  position: absolute;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-}
-
-.grid-line {
-  position: absolute;
-  height: 1px;
-  background: rgba(0, 0, 0, 0.05);
-  left: 0;
-  right: 0;
-}
-
-.grid-line:nth-child(1) { top: 25%; }
-.grid-line:nth-child(2) { top: 50%; }
-.grid-line:nth-child(3) { top: 75%; }
-
-.waveform-line {
-  position: absolute;
-  top: 50%;
-  left: 0;
-  right: 0;
-  height: 3px;
-  background: #3498db;
-  animation: waveform 8s infinite linear;
-}
-
-@keyframes waveform {
-  0% { transform: translateX(0); }
-  100% { transform: translateX(-100%); }
-}
-
-.threshold {
-  position: absolute;
-  left: 0;
-  right: 0;
-  height: 2px;
-  background: #e74c3c;
-}
-
-.threshold.upper { top: 25%; }
-.threshold.lower { top: 75%; }
-
 .waveform-controls {
   display: flex;
   gap: 20px;
+  margin-top: 15px;
 }
 
 .threshold-control {
@@ -131,10 +113,26 @@
   display: block;
   margin-bottom: 8px;
   font-size: 14px;
+  font-weight: 500;
 }
 
 .threshold-control input {
   width: 100%;
+  height: 6px;
+  border-radius: 3px;
+  background: #e0e7ff;
+  outline: none;
+  -webkit-appearance: none;
+}
+
+.threshold-control input::-webkit-slider-thumb {
+  -webkit-appearance: none;
+  width: 18px;
+  height: 18px;
+  border-radius: 50%;
+  background: #3498db;
+  cursor: pointer;
+  box-shadow: 0 2px 4px rgba(0,0,0,0.2);
 }
 
 .status-grid {
@@ -150,8 +148,14 @@
   gap: 15px;
   padding: 15px;
   background: #f8fafc;
-  border-radius: 6px;
-  border-left: 3px solid #3498db;
+  border-radius: 8px;
+  transition: all 0.3s ease;
+  box-shadow: 0 1px 3px rgba(0,0,0,0.05);
+}
+
+.status-card:hover {
+  transform: translateY(-3px);
+  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
 }
 
 .status-icon {
@@ -163,6 +167,7 @@
   justify-content: center;
   font-size: 18px;
   color: white;
+  flex-shrink: 0;
 }
 
 .status-icon.blue { background: #3498db; }
@@ -186,6 +191,10 @@
   color: #2c3e50;
 }
 
+.progress-container {
+  margin-top: auto;
+}
+
 .progress-steps {
   display: flex;
   justify-content: space-between;
@@ -202,6 +211,23 @@
   justify-content: center;
   font-weight: 700;
   color: #95a5a6;
+  position: relative;
+  transition: all 0.3s ease;
+}
+
+.step::after {
+  content: '';
+  position: absolute;
+  top: 50%;
+  left: 100%;
+  width: 20px;
+  height: 2px;
+  background: #ecf0f1;
+  z-index: 1;
+}
+
+.step:last-child::after {
+  display: none;
 }
 
 .step.active {
@@ -209,10 +235,15 @@
   color: white;
 }
 
+.step.active::after {
+  background: #3498db;
+}
+
 .step.current {
   background: #27ae60;
   color: white;
   transform: scale(1.2);
+  box-shadow: 0 0 0 4px rgba(39, 174, 96, 0.3);
 }
 
 .history-panel {
@@ -229,6 +260,30 @@
   margin-bottom: 15px;
 }
 
+.controls {
+  display: flex;
+  gap: 10px;
+}
+
+.btn {
+  padding: 8px 15px;
+  border-radius: 4px;
+  border: none;
+  background: #3498db;
+  color: white;
+  font-weight: 500;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap: 5px;
+  transition: all 0.2s;
+}
+
+.btn:hover {
+  background: #2980b9;
+  transform: translateY(-2px);
+}
+
 .alert-history {
   border: 1px solid #eee;
   border-radius: 6px;
@@ -240,6 +295,11 @@
   align-items: center;
   padding: 12px 15px;
   border-bottom: 1px solid #eee;
+  transition: background 0.2s;
+}
+
+.history-item:hover {
+  background: #f9f9f9;
 }
 
 .history-item:last-child {
@@ -250,6 +310,7 @@
   width: 90px;
   font-weight: 500;
   color: #2c3e50;
+  flex-shrink: 0;
 }
 
 .alert-desc {
@@ -261,6 +322,9 @@
   border-radius: 4px;
   font-size: 13px;
   font-weight: 500;
+  width: 60px;
+  text-align: center;
+  flex-shrink: 0;
 }
 
 .alert-level.warning {
@@ -279,4 +343,4 @@
   background: #ebf5fb;
   color: #3498db;
   border: 1px solid #3498db;
-}
+}

+ 160 - 45
industry-monitor-web/src/app/pages/factory-overview/factory-overview.component.html

@@ -1,14 +1,32 @@
-
+<!-- factory-overview.component.html -->
 <div class="dashboard">
   <div class="dashboard-header">
-    <h2><i class="fa fa-industry"></i> 工厂总览看板</h2>
-    <div class="time-display">
-      <i class="fa fa-clock"></i> {{ currentTime | date:'yyyy-MM-dd HH:mm:ss' }}
+    <div class="header-left">
+      <h2><i class="fa fa-industry"></i> 工厂总览看板</h2>
+      <div class="quick-nav">
+        <button class="nav-btn active">总览</button>
+        <button class="nav-btn">设备管理</button>
+        <button class="nav-btn">生产监控</button>
+        <button class="nav-btn">数据分析</button>
+      </div>
+    </div>
+
+    <div class="header-right">
+      <div class="user-info">
+        <i class="fa fa-user-circle"></i>
+        <span>管理员</span>
+      </div>
+      <div class="time-display">
+        <i class="fa fa-clock"></i> {{ currentTime | date:'yyyy-MM-dd HH:mm:ss' }}
+      </div>
+      <button class="refresh-btn" (click)="refreshData()">
+        <i class="fa fa-sync-alt"></i> 刷新数据
+      </button>
     </div>
   </div>
 
   <div class="metric-grid">
-    <div class="metric-card">
+    <div class="metric-card" (mouseenter)="cardHover(0)" [class.hover]="hoverIndex === 0">
       <div class="metric-icon blue">
         <i class="fa fa-cogs"></i>
       </div>
@@ -16,10 +34,16 @@
         <h3>设备运行状态</h3>
         <p class="metric-value">45/50</p>
         <p class="metric-label">运行设备数/总设备数</p>
+        <div class="metric-progress">
+          <div class="progress-bar" [style.width.%]="90"></div>
+        </div>
+      </div>
+      <div class="metric-hover">
+        <i class="fa fa-arrow-right"></i> 查看详情
       </div>
     </div>
-    
-    <div class="metric-card">
+
+    <div class="metric-card" (mouseenter)="cardHover(1)" [class.hover]="hoverIndex === 1">
       <div class="metric-icon orange">
         <i class="fa fa-exclamation-triangle"></i>
       </div>
@@ -27,10 +51,16 @@
         <h3>今日预警</h3>
         <p class="metric-value">12</p>
         <p class="metric-label">预警总数</p>
+        <div class="metric-progress">
+          <div class="progress-bar" [style.width.%]="24"></div>
+        </div>
+      </div>
+      <div class="metric-hover">
+        <i class="fa fa-arrow-right"></i> 查看详情
       </div>
     </div>
-    
-    <div class="metric-card">
+
+    <div class="metric-card" (mouseenter)="cardHover(2)" [class.hover]="hoverIndex === 2">
       <div class="metric-icon green">
         <i class="fa fa-heartbeat"></i>
       </div>
@@ -38,10 +68,16 @@
         <h3>设备健康指数</h3>
         <p class="metric-value">92%</p>
         <p class="metric-label">整体设备健康</p>
+        <div class="metric-progress">
+          <div class="progress-bar" [style.width.%]="92"></div>
+        </div>
+      </div>
+      <div class="metric-hover">
+        <i class="fa fa-arrow-right"></i> 查看详情
       </div>
     </div>
-    
-    <div class="metric-card">
+
+    <div class="metric-card" (mouseenter)="cardHover(3)" [class.hover]="hoverIndex === 3">
       <div class="metric-icon purple">
         <i class="fa fa-tachometer-alt"></i>
       </div>
@@ -49,74 +85,153 @@
         <h3>运行参数</h3>
         <p class="metric-value">65°C / 1450 RPM</p>
         <p class="metric-label">平均温度/转速</p>
+        <div class="metric-progress">
+          <div class="progress-bar" [style.width.%]="75"></div>
+        </div>
+      </div>
+      <div class="metric-hover">
+        <i class="fa fa-arrow-right"></i> 查看详情
       </div>
     </div>
   </div>
 
   <div class="dashboard-row">
-    <div class="chart-card">
-      <h3><i class="fa fa-chart-pie"></i> 设备状态分布</h3>
-      <div class="pie-chart">
-        <div class="chart-container">
-          <div class="chart-slice normal" style="--value: 80;"></div>
-          <div class="chart-slice warning" style="--value: 15;"></div>
-          <div class="chart-slice danger" style="--value: 5;"></div>
-          <div class="chart-center"></div>
+    <div class="chart-card with-tabs">
+      <div class="chart-header">
+        <h3><i class="fa fa-chart-pie"></i> 设备状态分析</h3>
+        <div class="chart-tabs">
+          <button class="tab-btn active">实时状态</button>
+          <button class="tab-btn">历史趋势</button>
+          <button class="tab-btn">对比分析</button>
         </div>
-        <div class="chart-legend">
-          <div><span class="dot normal"></span> 正常 80%</div>
-          <div><span class="dot warning"></span> 警告 15%</div>
-          <div><span class="dot danger"></span> 危险 5%</div>
+      </div>
+
+      <div class="chart-container-wrapper">
+        <div class="pie-chart">
+          <div class="chart-container">
+            <div class="chart-slice normal" style="--value: 80;"></div>
+            <div class="chart-slice warning" style="--value: 15;"></div>
+            <div class="chart-slice danger" style="--value: 5;"></div>
+            <div class="chart-center">
+              <div class="chart-center-text">92%</div>
+            </div>
+          </div>
+          <div class="chart-legend">
+            <div><span class="dot normal"></span> 正常 80%</div>
+            <div><span class="dot warning"></span> 警告 15%</div>
+            <div><span class="dot danger"></span> 危险 5%</div>
+          </div>
+        </div>
+        <div class="chart-details">
+          <div class="detail-item">
+            <div class="detail-label">设备总数</div>
+            <div class="detail-value">50台</div>
+          </div>
+          <div class="detail-item">
+            <div class="detail-label">在线设备</div>
+            <div class="detail-value">45台</div>
+          </div>
+          <div class="detail-item">
+            <div class="detail-label">离线设备</div>
+            <div class="detail-value">5台</div>
+          </div>
+          <div class="detail-item">
+            <div class="detail-label">平均在线率</div>
+            <div class="detail-value">92.5%</div>
+          </div>
         </div>
       </div>
     </div>
-    
-    <div class="alert-card">
-      <h3><i class="fa fa-bell"></i> 实时警报</h3>
+
+    <div class="alert-card with-filter">
+      <div class="alert-header">
+        <h3><i class="fa fa-bell"></i> 实时警报 (12)</h3>
+        <div class="alert-filter">
+          <select>
+            <option>全部警报</option>
+            <option>严重警报</option>
+            <option>警告</option>
+            <option>通知</option>
+          </select>
+        </div>
+      </div>
+
       <div class="alert-list">
         <div class="alert-item critical">
           <i class="fa fa-exclamation-circle"></i>
           <div class="alert-content">
             <strong>设备 #A23 温度过高</strong>
             <span>车间B - 产线2 | 15:23:45</span>
-            <comp-star-rating 
-              [star]="rating" 
-              (onStarChange)="ratingChange($event)"
-            ></comp-star-rating>
-            <p>当前评分: {{rating}}</p>
           </div>
+          <div class="alert-status">未处理</div>
         </div>
         <div class="alert-item warning">
           <i class="fa fa-exclamation-triangle"></i>
           <div class="alert-content">
             <strong>设备 #B07 振动异常</strong>
             <span>车间A - 产线4 | 15:20:12</span>
-            <p>{{ 125006 | tok}}</p>
-            <p>{{ 100 | tok}}</p>
-            <p>{{ 99987565 | tok}}</p>
           </div>
+          <div class="alert-status">处理中</div>
         </div>
         <div class="alert-item info">
           <i class="fa fa-info-circle"></i>
-            <div class="alert-content">
+          <div class="alert-content">
             <strong>设备 #C15 转速过低</strong>
             <span>车间C - 产线1 | 14:58:33</span>
           </div>
+          <div class="alert-status">已处理</div>
+        </div>
+        <div class="alert-item critical">
+          <i class="fa fa-exclamation-circle"></i>
+          <div class="alert-content">
+            <strong>设备 #D42 电压异常</strong>
+            <span>车间A - 产线3 | 14:45:21</span>
+          </div>
+          <div class="alert-status">未处理</div>
         </div>
       </div>
+      <div class="alert-footer">
+        <button class="view-all-btn">
+          <i class="fa fa-list"></i> 查看所有警报
+        </button>
+      </div>
     </div>
   </div>
-  
+
   <div class="trend-card">
-    <h3><i class="fa fa-chart-line"></i> 健康指数趋势 (24小时)</h3>
+    <div class="trend-header">
+      <h3><i class="fa fa-chart-line"></i> 健康指数趋势</h3>
+
+      <div class="time-range-selector">
+        <button class="time-btn active">24小时</button>
+        <button class="time-btn">7天</button>
+        <button class="time-btn">30天</button>
+        <button class="time-btn">自定义</button>
+      </div>
+
+    </div>
+
+
+
     <div class="trend-graph">
-      <div class="graph-bar" style="--height: 60;"></div>
-      <div class="graph-bar" style="--height: 65;"></div>
-      <div class="graph-bar" style="--height: 70;"></div>
-      <div class="graph-bar" style="--height: 82;"></div>
-      <div class="graph-bar" style="--height: 88;"></div>
-      <div class="graph-bar" style="--height: 92;"></div>
-      <div class="graph-bar" style="--height: 90;"></div>
+      <div class="graph-labels">
+        <span>04:00</span>
+        <span>08:00</span>
+        <span>12:00</span>
+        <span>16:00</span>
+        <span>20:00</span>
+        <span>00:00</span>
+        <span>当前</span>
+      </div>
+      <div class="graph-bars">
+        <div class="graph-bar" [style.height.%]="60"></div>
+        <div class="graph-bar" [style.height.%]="65"></div>
+        <div class="graph-bar" [style.height.%]="70"></div>
+        <div class="graph-bar" [style.height.%]="82"></div>
+        <div class="graph-bar" [style.height.%]="88"></div>
+        <div class="graph-bar" [style.height.%]="92"></div>
+        <div class="graph-bar" [style.height.%]="90"></div>
+      </div>
     </div>
   </div>
-</div>
+</div>

+ 15 - 25
industry-monitor-web/src/app/pages/factory-overview/factory-overview.component.ts

@@ -1,8 +1,6 @@
-
+// factory-overview.component.ts
 import { DatePipe } from '@angular/common';
 import { Component, ViewEncapsulation } from '@angular/core';
-import { CompStarRatingComponent } from '../../componets/star-rating/comp-star-rating.component';
-import { TokPipe } from '../../pipes/tok-pipe/tok.pipe';
 
 @Component({
   standalone: true,
@@ -10,36 +8,28 @@ import { TokPipe } from '../../pipes/tok-pipe/tok.pipe';
   styleUrls: ['./factory-overview.css'],
   templateUrl: './factory-overview.component.html',
   encapsulation: ViewEncapsulation.None,
-  imports: [
-    DatePipe,TokPipe,
-    CompStarRatingComponent
-  ]
-  
+  imports: [DatePipe]
 })
 export class FactoryOverviewComponent {
-  rating:number = 0
-  ratingChange(rating: number) {
-    this.rating = rating;
-  }
   currentTime: Date = new Date();
-   ngOnInit(): void {
+  hoverIndex: number = -1;
+
+  constructor() {
     // 更新时间,每秒更新一次
     setInterval(() => {
       this.currentTime = new Date();
     }, 1000);
+  }
 
+  // 修复:添加 cardHover 方法
+  cardHover(index: number) {
+    this.hoverIndex = index;
   }
 
-    tok(value:number){
-      if(value<=1000){
-        return value
-      }
-      if(value<=999999){
-        return (value/1000).toFixed(0) + 'k'
-      }
-      if(value<=999999999){
-        return (value/10000).toFixed(0) + '万'
-      }
-      return value
-    }
+  // 添加刷新数据方法
+  refreshData() {
+    // 这里可以添加实际的数据刷新逻辑
+    console.log('刷新数据...');
+    this.currentTime = new Date();
+  }
 }

+ 369 - 22
industry-monitor-web/src/app/pages/factory-overview/factory-overview.css

@@ -1,8 +1,9 @@
-/* 组件容器样式 */
+/* factory-overview.css */
 :host {
   display: block;
   width: 100%;
   padding: 15px;
+  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
 }
 
 .dashboard {
@@ -24,12 +25,53 @@
   border-bottom: 1px solid #eee;
 }
 
+.header-left {
+  display: flex;
+  align-items: center;
+  gap: 30px;
+}
+
 .dashboard-header h2 {
   display: flex;
   align-items: center;
   gap: 10px;
   font-size: 24px;
   color: #2c3e50;
+  margin: 0;
+}
+
+.quick-nav {
+  display: flex;
+  gap: 10px;
+}
+
+.nav-btn {
+  padding: 8px 16px;
+  background: #f1f2f6;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 14px;
+  transition: all 0.3s ease;
+}
+
+.nav-btn.active, .nav-btn:hover {
+  background: #2c3e50;
+  color: white;
+}
+
+.header-right {
+  display: flex;
+  align-items: center;
+  gap: 20px;
+}
+
+.user-info {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  font-size: 14px;
+  color: #2c3e50;
 }
 
 .time-display {
@@ -43,6 +85,24 @@
   gap: 8px;
 }
 
+.refresh-btn {
+  background: #27ae60;
+  color: white;
+  border: none;
+  padding: 8px 15px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  transition: background 0.3s ease;
+}
+
+.refresh-btn:hover {
+  background: #219653;
+}
+
 /* 指标网格样式 */
 .metric-grid {
   display: grid;
@@ -59,6 +119,15 @@
   display: flex;
   align-items: center;
   gap: 15px;
+  position: relative;
+  overflow: hidden;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.metric-card:hover {
+  transform: translateY(-5px);
+  box-shadow: 0 12px 20px rgba(0,0,0,0.15);
 }
 
 .metric-icon {
@@ -77,6 +146,10 @@
 .metric-icon.orange { background: #f39c12; }
 .metric-icon.purple { background: #9b59b6; }
 
+.metric-data {
+  flex: 1;
+}
+
 .metric-data h3 {
   font-size: 16px;
   font-weight: 600;
@@ -88,19 +161,115 @@
   font-size: 24px;
   font-weight: 700;
   color: #2c3e50;
+  margin: 5px 0;
 }
 
 .metric-label {
   font-size: 14px;
   color: #95a5a6;
+  margin: 0;
+}
+
+/* 进度条样式 */
+.metric-progress {
+  height: 6px;
+  background: #e0e0e0;
+  border-radius: 3px;
+  margin-top: 10px;
+  overflow: hidden;
+}
+
+.progress-bar {
+  height: 100%;
+  border-radius: 3px;
+  transition: width 0.5s ease;
+}
+
+.metric-card:nth-child(1) .progress-bar { background: #3498db; }
+.metric-card:nth-child(2) .progress-bar { background: #f39c12; }
+.metric-card:nth-child(3) .progress-bar { background: #27ae60; }
+.metric-card:nth-child(4) .progress-bar { background: #9b59b6; }
+
+/* 悬停效果 */
+.metric-hover {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: rgba(0,0,0,0.8);
+  color: white;
+  padding: 10px;
+  text-align: center;
+  opacity: 0;
+  transform: translateY(100%);
+  transition: all 0.3s ease;
+}
+
+.metric-card.hover .metric-hover {
+  opacity: 1;
+  transform: translateY(0);
+}
+
+/* 仪表板行布局 */
+.dashboard-row {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+.chart-card, .alert-card {
+  flex: 1;
+  background: white;
+  border-radius: 8px;
+  padding: 20px;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+}
+
+.trend-card {
+  background: white;
+  border-radius: 8px;
+  padding: 20px;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
 }
 
 /* 饼图样式 */
+.chart-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 15px;
+}
+
+.chart-tabs {
+  display: flex;
+  gap: 8px;
+}
+
+.tab-btn {
+  padding: 6px 12px;
+  border: none;
+  border-radius: 15px;
+  background: #f1f1f1;
+  font-size: 12px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.tab-btn.active, .tab-btn:hover {
+  background: #2c3e50;
+  color: white;
+}
+
+.chart-container-wrapper {
+  display: flex;
+  gap: 30px;
+}
+
 .pie-chart {
   display: flex;
   align-items: center;
   gap: 30px;
-  padding: 20px 0;
+  padding: 10px 0;
 }
 
 .chart-container {
@@ -124,6 +293,15 @@
   top: 50%;
   left: 50%;
   transform: translate(-50%, -50%);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.chart-center-text {
+  font-size: 20px;
+  font-weight: bold;
+  color: #2c3e50;
 }
 
 .chart-legend div {
@@ -145,9 +323,58 @@
 .dot.warning { background: #f39c12; }
 .dot.danger { background: #e74c3c; }
 
+/* 图表详情 */
+.chart-details {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 15px;
+  flex: 1;
+}
+
+.detail-item {
+  background: #f8fafc;
+  border-radius: 6px;
+  padding: 12px;
+  transition: transform 0.3s ease;
+}
+
+.detail-item:hover {
+  transform: translateY(-3px);
+  box-shadow: 0 2px 6px rgba(0,0,0,0.1);
+}
+
+.detail-label {
+  font-size: 13px;
+  color: #7f8c8d;
+  margin-bottom: 5px;
+}
+
+.detail-value {
+  font-size: 18px;
+  font-weight: 700;
+  color: #2c3e50;
+}
+
 /* 警报样式 */
+.alert-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 10px;
+}
+
+.alert-filter select {
+  padding: 6px 12px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  background: white;
+  font-size: 14px;
+}
+
 .alert-list {
   margin-top: 15px;
+  max-height: 300px;
+  overflow-y: auto;
 }
 
 .alert-item {
@@ -159,6 +386,12 @@
   margin-bottom: 10px;
   background: #f9f9f9;
   border-left: 4px solid;
+  transition: all 0.3s ease;
+}
+
+.alert-item:hover {
+  transform: translateX(5px);
+  box-shadow: 0 3px 8px rgba(0,0,0,0.1);
 }
 
 .alert-item.critical {
@@ -199,44 +432,158 @@
   color: #95a5a6;
 }
 
+.alert-status {
+  padding: 4px 10px;
+  border-radius: 12px;
+  font-size: 12px;
+  font-weight: bold;
+}
+
+.alert-item.critical .alert-status {
+  background: #e74c3c;
+  color: white;
+}
+
+.alert-item.warning .alert-status {
+  background: #f39c12;
+  color: white;
+}
+
+.alert-item.info .alert-status {
+  background: #3498db;
+  color: white;
+}
+
+.alert-footer {
+  margin-top: 15px;
+  text-align: center;
+}
+
+.view-all-btn {
+  background: #3498db;
+  color: white;
+  border: none;
+  padding: 8px 15px;
+  border-radius: 4px;
+  cursor: pointer;
+  font-size: 14px;
+  display: inline-flex;
+  align-items: center;
+  gap: 8px;
+  transition: background 0.3s ease;
+}
+
+.view-all-btn:hover {
+  background: #2980b9;
+}
+
 /* 趋势图样式 */
+.trend-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 15px;
+}
+
+.time-range-selector {
+  display: flex;
+  gap: 8px;
+}
+
+.time-btn {
+  padding: 6px 12px;
+  border: 1px solid #ddd;
+  border-radius: 15px;
+  background: white;
+  font-size: 12px;
+  cursor: pointer;
+  transition: all 0.3s ease;
+}
+
+.time-btn.active, .time-btn:hover {
+  border-color: #3498db;
+  background: #3498db;
+  color: white;
+}
+
 .trend-graph {
   display: flex;
-  align-items: flex-end;
-  gap: 10px;
+  flex-direction: column;
   height: 200px;
   padding: 20px;
   background: #f8fafc;
   border-radius: 6px;
   margin-top: 15px;
+  position: relative;
+}
+
+.graph-labels {
+  display: flex;
+  justify-content: space-between;
+  margin-top: auto;
+  color: #7f8c8d;
+  font-size: 12px;
+}
+
+.graph-bars {
+  display: flex;
+  align-items: flex-end;
+  gap: 10px;
+  height: 100%;
+  width: 100%;
 }
 
 .graph-bar {
   flex: 1;
   background: #3498db;
-  height: calc(var(--height) * 2px);
   border-radius: 4px 4px 0 0;
   position: relative;
+  transition: height 0.5s ease;
 }
 
-/* 仪表板行布局 */
-.dashboard-row {
-  display: flex;
-  gap: 20px;
-  margin-bottom: 20px;
+.graph-bar::after {
+  content: attr(style);
+  position: absolute;
+  top: -25px;
+  left: 50%;
+  transform: translateX(-50%);
+  background: rgba(0,0,0,0.7);
+  color: white;
+  padding: 3px 8px;
+  border-radius: 4px;
+  font-size: 12px;
+  opacity: 0;
+  transition: opacity 0.3s ease;
 }
 
-.chart-card, .alert-card {
-  flex: 1;
-  background: white;
-  border-radius: 8px;
-  padding: 20px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+.graph-bar:hover::after {
+  opacity: 1;
 }
 
-.trend-card {
-  background: white;
-  border-radius: 8px;
-  padding: 20px;
-  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
-}
+/* 响应式调整 */
+@media (max-width: 1200px) {
+  .dashboard-row {
+    flex-direction: column;
+  }
+}
+
+@media (max-width: 768px) {
+  .dashboard-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+  }
+
+  .header-left, .header-right {
+    width: 100%;
+  }
+
+  .quick-nav {
+    overflow-x: auto;
+    padding-bottom: 10px;
+  }
+
+  .chart-container-wrapper {
+    flex-direction: column;
+  }
+}

+ 68 - 64
industry-monitor-web/src/app/pages/system-settings/system-settings.component.html

@@ -14,37 +14,41 @@
             </button>
         </div>
     </div>
-    
+
+     <!-- 顶部导航标签 -->
+  <div class="settings-tabs-container">
+    <div class="settings-tabs">
+      <div class="settings-tab active" (click)="setActiveTab('users')" [class.active]="activeTab === 'users'">
+        <i class="fas fa-users"></i> 用户管理
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('alerts')" [class.active]="activeTab === 'alerts'">
+        <i class="fas fa-bell"></i> 警报设置
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('templates')" [class.active]="activeTab === 'templates'">
+        <i class="fas fa-cubes"></i> 设备模板
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('system')" [class.active]="activeTab === 'system'">
+        <i class="fas fa-server"></i> 系统参数
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('roles')" [class.active]="activeTab === 'roles'">
+        <i class="fas fa-key"></i> 权限管理
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('logs')" [class.active]="activeTab === 'logs'">
+        <i class="fas fa-clipboard-list"></i> 系统日志
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('license')" [class.active]="activeTab === 'license'">
+        <i class="fas fa-id-card"></i> 许可证信息
+      </div>
+      <div class="settings-tab" (click)="setActiveTab('backup')" [class.active]="activeTab === 'backup'">
+        <i class="fas fa-cloud-download-alt"></i> 备份与恢复
+      </div>
+    </div>
+  </div>
+
     <!-- 主体内容区域 -->
     <div class="settings-body">
-        <!-- 左侧导航菜单 -->
-        <div class="settings-sidebar">
-            <div class="settings-tab active" data-tab="users">
-                <i class="fas fa-users"></i> 用户管理
-            </div>
-            <div class="settings-tab" data-tab="alerts">
-                <i class="fas fa-bell"></i> 警报设置
-            </div>
-            <div class="settings-tab" data-tab="templates">
-                <i class="fas fa-cubes"></i> 设备模板
-            </div>
-            <div class="settings-tab" data-tab="system">
-                <i class="fas fa-server"></i> 系统参数
-            </div>
-            <div class="settings-tab" data-tab="roles">
-                <i class="fas fa-key"></i> 权限管理
-            </div>
-            <div class="settings-tab" data-tab="logs">
-                <i class="fas fa-clipboard-list"></i> 系统日志
-            </div>
-            <div class="settings-tab" data-tab="license">
-                <i class="fas fa-id-card"></i> 许可证信息
-            </div>
-            <div class="settings-tab" data-tab="backup">
-                <i class="fas fa-cloud-download-alt"></i> 备份与恢复
-            </div>
-        </div>
-        
+
+
         <!-- 右侧设置内容 -->
         <div class="settings-content">
             <!-- 用户管理 -->
@@ -55,7 +59,7 @@
                         <i class="fas fa-user-plus"></i> 添加新用户
                     </button>
                 </div>
-                
+
                 <div class="users-grid">
                     <!-- 管理员用户 -->
                     <div class="user-card">
@@ -71,7 +75,7 @@
                                 <strong>用户名:</strong> admin&#64;factory.com
                             </div>
                             <div class="user-detail">
-                                <strong>角色:</strong> 
+                                <strong>角色:</strong>
                                 <span class="role-badge badge-admin">管理员</span>
                             </div>
                             <div class="user-detail">
@@ -90,7 +94,7 @@
                             </div>
                         </div>
                     </div>
-                    
+
                     <!-- 工程师用户 -->
                     <div class="user-card">
                         <div class="user-header">
@@ -105,7 +109,7 @@
                                 <strong>用户名:</strong> liqiang&#64;factory.com
                             </div>
                             <div class="user-detail">
-                                <strong>角色:</strong> 
+                                <strong>角色:</strong>
                                 <span class="role-badge badge-engineer">工程师</span>
                             </div>
                             <div class="user-detail">
@@ -124,7 +128,7 @@
                             </div>
                         </div>
                     </div>
-                    
+
                     <!-- 操作员用户 -->
                     <div class="user-card">
                         <div class="user-header">
@@ -139,7 +143,7 @@
                                 <strong>用户名:</strong> wangfang&#64;factory.com
                             </div>
                             <div class="user-detail">
-                                <strong>角色:</strong> 
+                                <strong>角色:</strong>
                                 <span class="role-badge badge-operator">操作员</span>
                             </div>
                             <div class="user-detail">
@@ -158,7 +162,7 @@
                             </div>
                         </div>
                     </div>
-                    
+
                     <!-- 只读用户 -->
                     <div class="user-card">
                         <div class="user-header">
@@ -173,7 +177,7 @@
                                 <strong>用户名:</strong> zhaoyu&#64;factory.com
                             </div>
                             <div class="user-detail">
-                                <strong>角色:</strong> 
+                                <strong>角色:</strong>
                                 <span class="role-badge badge-viewer">主管</span>
                             </div>
                             <div class="user-detail">
@@ -194,14 +198,14 @@
                     </div>
                 </div>
             </div>
-            
+
             <!-- 警报设置 -->
             <div id="alerts" class="tab-content">
                 <div class="section-header">
                     <h2><i class="fas fa-bell"></i> 警报设置</h2>
                     <p>自定义系统警报阈值和通知方式</p>
                 </div>
-                
+
                 <div class="settings-card">
                     <div class="form-group">
                         <label>振动警报阈值 (mm/s)</label>
@@ -210,7 +214,7 @@
                             <div class="slider-value">0.8 mm/s</div>
                         </div>
                     </div>
-                    
+
                     <div class="form-group">
                         <label>温度警报阈值 (°C)</label>
                         <div class="slider-container">
@@ -218,7 +222,7 @@
                             <div class="slider-value">75°C</div>
                         </div>
                     </div>
-                    
+
                     <div class="form-group">
                         <label>转速偏差阈值 (%)</label>
                         <div class="slider-container">
@@ -226,11 +230,11 @@
                             <div class="slider-value">15%</div>
                         </div>
                     </div>
-                    
+
                     <h3 class="section-subheader">
                         <i class="fas fa-envelope"></i> 通知设置
                     </h3>
-                    
+
                     <div class="notification-item">
                         <div class="notification-icon">
                             <i class="fas fa-envelope"></i>
@@ -244,7 +248,7 @@
                             <span class="slider"></span>
                         </label>
                     </div>
-                    
+
                     <div class="notification-item">
                         <div class="notification-icon">
                             <i class="fas fa-mobile-alt"></i>
@@ -258,7 +262,7 @@
                             <span class="slider"></span>
                         </label>
                     </div>
-                    
+
                     <div class="notification-item">
                         <div class="notification-icon">
                             <i class="fas fa-bell"></i>
@@ -272,21 +276,21 @@
                             <span class="slider"></span>
                         </label>
                     </div>
-                    
+
                     <div class="form-footer">
                         <button class="btn btn-outline">取消</button>
                         <button class="btn btn-primary">保存设置</button>
                     </div>
                 </div>
             </div>
-            
+
             <!-- 系统参数 -->
             <div id="system" class="tab-content">
                 <div class="section-header">
                     <h2><i class="fas fa-server"></i> 系统参数配置</h2>
                     <p>调整系统核心参数和配置选项</p>
                 </div>
-                
+
                 <div class="system-status">
                     <div class="status-card">
                         <div class="status-icon system">
@@ -298,7 +302,7 @@
                             <div class="status-value">98.7%</div>
                         </div>
                     </div>
-                    
+
                     <div class="status-card">
                         <div class="status-icon database">
                             <i class="fas fa-database"></i>
@@ -309,7 +313,7 @@
                             <div class="status-value">64%</div>
                         </div>
                     </div>
-                    
+
                     <div class="status-card">
                         <div class="status-icon security">
                             <i class="fas fa-shield-alt"></i>
@@ -320,7 +324,7 @@
                             <div class="status-value">无威胁</div>
                         </div>
                     </div>
-                    
+
                     <div class="status-card">
                         <div class="status-icon analytics">
                             <i class="fas fa-chart-line"></i>
@@ -332,12 +336,12 @@
                         </div>
                     </div>
                 </div>
-                
+
                 <div class="settings-card">
                     <h3 class="section-subheader">
                         <i class="fas fa-cogs"></i> 高级配置
                     </h3>
-                    
+
                     <div class="form-row">
                         <div class="form-group">
                             <label>数据采集频率</label>
@@ -348,7 +352,7 @@
                                 <option>每分钟</option>
                             </select>
                         </div>
-                        
+
                         <div class="form-group">
                             <label>数据保留策略</label>
                             <select class="form-control">
@@ -359,7 +363,7 @@
                             </select>
                         </div>
                     </div>
-                    
+
                     <div class="form-group">
                         <label>系统API密钥</label>
                         <div class="api-key-container">
@@ -372,7 +376,7 @@
                             </button>
                         </div>
                     </div>
-                    
+
                     <div class="form-group">
                         <label>系统维护模式</label>
                         <div class="toggle-container">
@@ -385,26 +389,26 @@
                             </div>
                         </div>
                     </div>
-                    
+
                     <div class="form-footer">
                         <button class="btn btn-outline">取消</button>
                         <button class="btn btn-primary">保存配置</button>
                     </div>
                 </div>
             </div>
-            
+
             <!-- 备份与恢复 -->
             <div id="backup" class="tab-content">
                 <div class="section-header">
                     <h2><i class="fas fa-cloud-download-alt"></i> 备份与恢复</h2>
                     <p>管理您的系统备份和数据恢复</p>
                 </div>
-                
+
                 <div class="settings-card">
                     <h3 class="section-subheader">
                         <i class="fas fa-history"></i> 最近备份
                     </h3>
-                    
+
                     <div class="backup-list">
                         <div class="backup-item">
                             <div class="backup-icon">
@@ -423,7 +427,7 @@
                                 </button>
                             </div>
                         </div>
-                        
+
                         <div class="backup-item">
                             <div class="backup-icon">
                                 <i class="fas fa-file-alt"></i>
@@ -441,7 +445,7 @@
                                 </button>
                             </div>
                         </div>
-                        
+
                         <div class="backup-item">
                             <div class="backup-icon">
                                 <i class="fas fa-users"></i>
@@ -460,7 +464,7 @@
                             </div>
                         </div>
                     </div>
-                    
+
                     <div class="form-footer">
                         <button class="btn btn-primary">
                             <i class="fas fa-plus"></i> 创建新备份
@@ -470,4 +474,4 @@
             </div>
         </div>
     </div>
-</div>
+</div>

+ 4 - 0
industry-monitor-web/src/app/pages/system-settings/system-settings.component.ts

@@ -11,6 +11,7 @@ import { DatePipe } from '@angular/common';
 })
 export class SystemSettingsComponent {
 currentTime: Date = new Date();
+activeTab: string = 'users';
    ngOnInit(): void {
     // 更新时间,每秒更新一次
     setInterval(() => {
@@ -18,4 +19,7 @@ currentTime: Date = new Date();
     }, 1000);
 
    }
+   setActiveTab(tab: string): void {
+    this.activeTab = tab;
+  }
 }

+ 143 - 386
industry-monitor-web/src/app/pages/system-settings/system-settings.css

@@ -1,6 +1,6 @@
-/* 系统设置中心页面CSS样式 */
+/* 系统设置中心页面CSS样式 - 优化版 */
 
-/* 基础变量 - 与整体应用保持一致 */
+/* 基础变量 */
 :root {
   --primary: #3498db;
   --primary-dark: #2980b9;
@@ -65,114 +65,49 @@
   gap: 10px;
 }
 
-/* 按钮样式 */
-.btn {
-  padding: 8px 18px;
-  border-radius: 30px;
-  border: none;
-  font-weight: 600;
-  cursor: pointer;
-  display: flex;
-  align-items: center;
-  gap: 8px;
-  transition: var(--transition);
-  font-size: 14px;
-}
-
-.btn-sm {
-  padding: 6px 14px;
-  font-size: 13px;
-}
-
-.btn-primary {
-  background: var(--primary);
-  color: white;
-}
-
-.btn-primary:hover {
-  background: var(--primary-dark);
-  transform: translateY(-2px);
-  box-shadow: var(--shadow-hover);
-}
-
-.btn-outline {
-  background: transparent;
-  border: 1px solid var(--primary);
-  color: var(--primary);
-}
-
-.btn-outline:hover {
-  background: rgba(52, 152, 219, 0.1);
-}
-
-.btn-danger {
-  background: rgba(231, 76, 60, 0.1);
-  color: var(--danger);
-  border: 1px solid rgba(231, 76, 60, 0.3);
-}
-
-.btn-danger:hover {
-  background: rgba(231, 76, 60, 0.2);
-}
-
-.btn-edit {
-  background: rgba(243, 156, 18, 0.1);
-  color: var(--warning);
-  border: 1px solid rgba(243, 156, 18, 0.3);
-}
-
-.btn-delete {
-  background: rgba(231, 76, 60, 0.1);
-  color: var(--danger);
-  border: 1px solid rgba(231, 76, 60, 0.3);
+/* 顶部导航标签容器 */
+.settings-tabs-container {
+  background: white;
+  border-bottom: 1px solid var(--light-gray);
+  padding: 0 20px;
+  overflow-x: auto;
 }
 
-/* 主体内容区域 */
-.settings-body {
+.settings-tabs {
   display: flex;
-  min-height: 600px;
-}
-
-/* 左侧导航菜单 */
-.settings-sidebar {
-  width: 240px;
-  background: white;
-  border-right: 1px solid var(--light-gray);
-  padding: 20px 0;
+  min-width: max-content;
 }
 
 .settings-tab {
-  padding: 12px 24px;
+  padding: 14px 24px;
   display: flex;
   align-items: center;
   gap: 12px;
   cursor: pointer;
   transition: var(--transition);
-  border-left: 4px solid transparent;
+  border-bottom: 3px solid transparent;
   font-weight: 500;
   color: var(--dark);
   font-size: 15px;
-}
-
-.settings-tab.active {
-  background: rgba(52, 152, 219, 0.1);
-  border-left: 4px solid var(--primary);
-  color: var(--primary);
+  white-space: nowrap;
 }
 
 .settings-tab:hover:not(.active) {
   background: rgba(0, 0, 0, 0.03);
 }
 
+.settings-tab.active {
+  background: rgba(52, 152, 219, 0.05);
+  border-bottom: 3px solid var(--primary);
+  color: var(--primary);
+}
+
 .settings-tab i {
-  width: 24px;
-  text-align: center;
-  font-size: 18px;
+  font-size: 16px;
 }
 
-/* 右侧设置内容 */
-.settings-content {
-  flex: 1;
+/* 主体内容区域 */
+.settings-body {
   padding: 24px;
   background: #f9fbfd;
   min-height: 600px;
@@ -192,22 +127,68 @@
   to { opacity: 1; transform: translateY(0); }
 }
 
-/* 公共部分样式 */
-.section-header {
+/* 响应式设计 */
+@media (max-width: 992px) {
+  .settings-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 16px;
+  }
+
+  .setting-actions {
+    width: 100%;
+    justify-content: flex-end;
+  }
+}
+
+@media (max-width: 768px) {
+  .settings-tabs {
+    gap: 0;
+  }
+
+  .settings-tab {
+    padding: 12px 16px;
+    font-size: 14px;
+  }
+
+  .settings-tab i {
+    display: none;
+  }
+}
+
+@media (max-width: 480px) {
+  .settings-header h1 {
+    font-size: 18px;
+  }
+
+  .settings-tab {
+    padding: 10px 12px;
+    font-size: 13px;
+  }
+
+  .settings-body {
+    padding: 16px;
+  }
+}
+
+/* 用户管理卡片优化样式 */
+.users-header {
   display: flex;
   justify-content: space-between;
   align-items: center;
   margin-bottom: 24px;
+  padding-bottom: 16px;
+  border-bottom: 1px solid var(--light-gray);
 }
 
-.section-header h2 {
-  font-size: 20px;
+.users-header h2 {
   display: flex;
   align-items: center;
   gap: 12px;
+  font-size: 20px;
+  color: var(--dark);
 }
 
-/* 用户网格 */
 .users-grid {
   display: grid;
   grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
@@ -220,23 +201,25 @@
   box-shadow: var(--shadow);
   overflow: hidden;
   transition: var(--transition);
+  border: 1px solid var(--light-gray);
 }
 
 .user-card:hover {
+  transform: translateY(-5px);
   box-shadow: var(--shadow-hover);
-  transform: translateY(-4px);
 }
 
 .user-header {
   display: flex;
+  align-items: center;
   padding: 20px;
-  gap: 16px;
+  background: linear-gradient(135deg, #f5f7fa 0%, #e4e8eb 100%);
   border-bottom: 1px solid var(--light-gray);
 }
 
 .user-avatar {
-  width: 56px;
-  height: 56px;
+  width: 60px;
+  height: 60px;
   border-radius: 50%;
   background: var(--primary);
   color: white;
@@ -245,19 +228,18 @@
   justify-content: center;
   font-size: 24px;
   font-weight: bold;
+  margin-right: 16px;
+  box-shadow: 0 3px 6px rgba(0,0,0,0.1);
 }
 
-.badge-admin .user-avatar { background: #e74c3c; }
-.badge-engineer .user-avatar { background: #3498db; }
-.badge-operator .user-avatar { background: #27ae60; }
-.badge-viewer .user-avatar { background: #f39c12; }
-
 .user-info h3 {
+  margin: 0;
   font-size: 18px;
-  margin-bottom: 4px;
+  color: var(--dark);
 }
 
 .user-info p {
+  margin: 4px 0 0;
   color: var(--gray);
   font-size: 14px;
 }
@@ -269,10 +251,13 @@
 .user-detail {
   margin-bottom: 12px;
   font-size: 14px;
+  display: flex;
 }
 
 .user-detail strong {
-  color: var(--dark);
+  min-width: 80px;
+  color: var(--gray);
+  font-weight: 500;
 }
 
 .role-badge {
@@ -281,329 +266,101 @@
   border-radius: 20px;
   font-size: 12px;
   font-weight: 600;
+  text-transform: uppercase;
 }
 
-.badge-admin { background: rgba(231, 76, 60, 0.1); color: #e74c3c; }
-.badge-engineer { background: rgba(52, 152, 219, 0.1); color: #3498db; }
-.badge-operator { background: rgba(39, 174, 96, 0.1); color: #27ae60; }
-.badge-viewer { background: rgba(243, 156, 18, 0.1); color: #f39c12; }
-
-.user-actions {
-  display: flex;
-  gap: 10px;
-  margin-top: 16px;
-}
-
-/* 警报设置 */
-.settings-card {
-  background: white;
-  border-radius: var(--border-radius);
-  box-shadow: var(--shadow);
-  padding: 24px;
-  margin-bottom: 24px;
-}
-
-.form-group {
-  margin-bottom: 20px;
-}
-
-.form-group label {
-  display: block;
-  margin-bottom: 8px;
-  font-weight: 600;
-  color: var(--dark);
-}
-
-.slider-container {
-  display: flex;
-  align-items: center;
-  gap: 16px;
-}
-
-.slider-container input[type="range"] {
-  flex: 1;
-  height: 6px;
-  border-radius: 3px;
-  background: var(--light-gray);
-  outline: none;
-  -webkit-appearance: none;
-}
-
-.slider-container input[type="range"]::-webkit-slider-thumb {
-  -webkit-appearance: none;
-  width: 18px;
-  height: 18px;
-  border-radius: 50%;
-  background: var(--primary);
-  cursor: pointer;
-}
-
-.slider-value {
-  min-width: 80px;
-  text-align: right;
-  font-weight: 600;
-  color: var(--primary);
-}
-
-.section-subheader {
-  display: flex;
-  align-items: center;
-  gap: 10px;
-  margin: 24px 0 16px;
-  font-size: 18px;
-  color: var(--secondary);
-}
-
-.notification-item {
-  display: flex;
-  align-items: center;
-  padding: 16px;
-  border-radius: var(--border-radius);
-  background: var(--light);
-  margin-bottom: 12px;
+.badge-admin {
+  background: rgba(231, 76, 60, 0.1);
+  color: #e74c3c;
 }
 
-.notification-icon {
-  width: 40px;
-  height: 40px;
-  border-radius: 50%;
+.badge-engineer {
   background: rgba(52, 152, 219, 0.1);
-  display: flex;
-  align-items: center;
-  justify-content: center;
   color: var(--primary);
-  font-size: 18px;
-}
-
-.notification-info {
-  flex: 1;
-  padding: 0 16px;
-}
-
-.notification-info h4 {
-  margin-bottom: 4px;
-}
-
-.notification-info p {
-  color: var(--gray);
-  font-size: 14px;
-}
-
-.notification-switch {
-  position: relative;
-  display: inline-block;
-  width: 50px;
-  height: 24px;
 }
 
-.notification-switch input {
-  opacity: 0;
-  width: 0;
-  height: 0;
+.badge-operator {
+  background: rgba(46, 204, 113, 0.1);
+  color: #2ecc71;
 }
 
-.notification-switch .slider {
-  position: absolute;
-  cursor: pointer;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background-color: var(--light-gray);
-  transition: .4s;
-  border-radius: 34px;
-}
-
-.notification-switch .slider:before {
-  position: absolute;
-  content: "";
-  height: 16px;
-  width: 16px;
-  left: 4px;
-  bottom: 4px;
-  background-color: white;
-  transition: .4s;
-  border-radius: 50%;
+.badge-viewer {
+  background: rgba(155, 89, 182, 0.1);
+  color: #9b59b6;
 }
 
-.notification-switch input:checked + .slider {
-  background-color: var(--success);
-}
-
-.notification-switch input:checked + .slider:before {
-  transform: translateX(26px);
-}
-
-.form-footer {
+.user-actions {
   display: flex;
-  justify-content: flex-end;
-  gap: 12px;
-  margin-top: 24px;
+  gap: 8px;
+  margin-top: 16px;
   padding-top: 16px;
   border-top: 1px solid var(--light-gray);
 }
 
-/* 系统状态 */
-.system-status {
-  display: grid;
-  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
-  gap: 20px;
-  margin-bottom: 24px;
-}
-
-.status-card {
-  background: white;
+/* 优化按钮样式 */
+.btn {
+  padding: 8px 16px;
   border-radius: var(--border-radius);
-  box-shadow: var(--shadow);
-  padding: 20px;
-  display: flex;
-  gap: 16px;
-  align-items: center;
-}
-
-.status-icon {
-  width: 60px;
-  height: 60px;
-  border-radius: 50%;
-  display: flex;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: var(--transition);
+  display: inline-flex;
   align-items: center;
-  justify-content: center;
-  font-size: 24px;
-}
-
-.system .status-icon { background: rgba(52, 152, 219, 0.1); color: var(--primary); }
-.database .status-icon { background: rgba(46, 204, 113, 0.1); color: #2ecc71; }
-.security .status-icon { background: rgba(243, 156, 18, 0.1); color: var(--warning); }
-.analytics .status-icon { background: rgba(155, 89, 182, 0.1); color: #9b59b6; }
-
-.status-info h3 {
-  font-size: 17px;
-  margin-bottom: 4px;
-}
-
-.status-info p {
-  color: var(--gray);
-  font-size: 13px;
-  margin-bottom: 4px;
-}
-
-.status-value {
-  font-size: 20px;
-  font-weight: 700;
+  gap: 8px;
+  border: 1px solid transparent;
 }
 
-/* 备份列表 */
-.backup-list {
-  margin: 16px 0;
+.btn-primary {
+  background-color: var(--primary);
+  color: white;
+  box-shadow: 0 2px 5px rgba(52, 152, 219, 0.3);
 }
 
-.backup-item {
-  display: flex;
-  align-items: center;
-  padding: 16px;
-  border-radius: var(--border-radius);
-  background: var(--light);
-  margin-bottom: 12px;
+.btn-primary:hover {
+  background-color: var(--primary-dark);
+  transform: translateY(-3px);
+  box-shadow: 0 4px 8px rgba(52, 152, 219, 0.4);
 }
 
-.backup-icon {
-  width: 40px;
-  height: 40px;
-  border-radius: 50%;
-  background: rgba(52, 152, 219, 0.1);
-  display: flex;
-  align-items: center;
-  justify-content: center;
+.btn-outline {
+  background-color: transparent;
   color: var(--primary);
-  font-size: 18px;
-}
-
-.backup-info {
-  flex: 1;
-  padding: 0 16px;
+  border: 1px solid var(--primary);
 }
 
-.backup-info h4 {
-  margin-bottom: 4px;
+.btn-outline:hover {
+  background-color: rgba(52, 152, 219, 0.1);
+  transform: translateY(-3px);
+  box-shadow: 0 2px 5px rgba(52, 152, 219, 0.2);
 }
 
-.backup-info p {
-  color: var(--gray);
-  font-size: 14px;
+/* 添加新用户按钮特殊样式 */
+.users-header .btn-primary {
+  padding: 10px 18px;
+  font-size: 15px;
 }
 
-.backup-actions {
-  display: flex;
-  gap: 8px;
+.users-header .btn-primary:hover {
+  transform: translateY(-3px);
 }
 
-/* 响应式设计 */
-@media (max-width: 992px) {
-  .settings-sidebar {
-    width: 200px;
-  }
-  
-  .users-grid {
-    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
-  }
+/* 按钮图标样式 */
+.btn i {
+  font-size: 14px;
 }
 
+/* 响应式调整 */
 @media (max-width: 768px) {
-  .settings-body {
-    flex-direction: column;
-  }
-  
-  .settings-sidebar {
-    width: 100%;
-    display: flex;
-    overflow-x: auto;
-    padding: 10px 0;
-    border-right: none;
-    border-bottom: 1px solid var(--light-gray);
-  }
-  
-  .settings-tab {
-    padding: 10px 16px;
-    white-space: nowrap;
-  }
-  
   .users-grid {
     grid-template-columns: 1fr;
   }
-  
-  .system-status {
-    grid-template-columns: 1fr 1fr;
-  }
-  
-  .section-header {
-    flex-direction: column;
-    align-items: flex-start;
-    gap: 16px;
-  }
-}
 
-@media (max-width: 480px) {
-  .system-status {
-    grid-template-columns: 1fr;
-  }
-  
-  .settings-header {
-    flex-direction: column;
-    gap: 16px;
-    align-items: flex-start;
+  .user-header {
+    padding: 16px;
   }
-  
-  .setting-actions {
-    width: 100%;
-    flex-wrap: wrap;
-  }
-  
-  .form-footer {
-    flex-direction: column;
-  }
-  
-  .btn {
-    width: 100%;
-    justify-content: center;
+
+  .user-body {
+    padding: 16px;
   }
-}
+}

+ 36 - 0
industry-monitor-web/src/app/shared/directives/echarts.directive.ts

@@ -0,0 +1,36 @@
+// src/app/shared/directives/echarts.directive.ts
+import { Directive, ElementRef, Input, OnChanges, SimpleChanges } from '@angular/core';
+import * as echarts from 'echarts';
+
+@Directive({
+  selector: '[appEchart]',
+  standalone: true
+})
+export class EchartDirective implements OnChanges {
+  @Input() echartOptions: any;
+  private chart: any;
+
+  constructor(private el: ElementRef) {}
+
+  ngOnChanges(changes: SimpleChanges) {
+    if (changes['echartOptions']) {
+      this.renderChart();
+    }
+  }
+
+  private renderChart() {
+    if (!this.chart) {
+      this.chart = echarts.init(this.el.nativeElement);
+    }
+
+    if (this.echartOptions) {
+      this.chart.setOption(this.echartOptions);
+    }
+  }
+
+  ngOnDestroy() {
+    if (this.chart) {
+      this.chart.dispose();
+    }
+  }
+}