소스 검색

feat:new-001

0235711 3 일 전
부모
커밋
a0319763a8

+ 0 - 3
angular.json

@@ -23,9 +23,6 @@
             ],
             "tsConfig": "tsconfig.app.json",
             "inlineStyleLanguage": "scss",
-            "externalDependencies": [
-              "echarts"
-            ],
             "assets": [
               {
                 "glob": "**/*",

+ 1 - 1
src/app/pages/admin/dashboard/dashboard.ts

@@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router';
 import { Subscription } from 'rxjs';
 import { signal } from '@angular/core';
 import { AdminDashboardService } from './dashboard.service';
-// 使用全局echarts变量,不导入模块
+import * as echarts from 'echarts';
 
 // 确保@Component装饰器存在
 import { Component, OnInit, AfterViewInit, OnDestroy } from '@angular/core';

+ 0 - 2
src/app/pages/admin/system-settings/system-settings.html

@@ -1,6 +1,4 @@
 <div class="system-settings">
-  <!-- 引入ECharts的CDN -->
-  <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
   <style>
     /* 全局样式 */
     :host {

+ 11 - 17
src/app/pages/admin/system-settings/system-settings.ts

@@ -1,11 +1,5 @@
-// 扩展Window接口以包含echarts属性
-declare global {
-  interface Window {
-    echarts: any;
-  }
-}
-
 import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
+import * as echarts from 'echarts';
 import { CommonModule } from '@angular/common';
 import { RouterModule } from '@angular/router';
 import { FormsModule } from '@angular/forms';
@@ -546,8 +540,8 @@ export class SystemSettings implements OnInit {
   
   // 初始化数据使用情况图表
   initDataUsageChart(): void {
-    if (window['echarts'] && this.dataUsageChart) {
-      const chart = window['echarts'].init(this.dataUsageChart.nativeElement);
+    if (echarts && this.dataUsageChart) {
+      const chart = echarts.init(this.dataUsageChart.nativeElement);
       
       const option = {
         title: {
@@ -632,8 +626,8 @@ export class SystemSettings implements OnInit {
   
   // 初始化备份历史图表
   initBackupHistoryChart(): void {
-    if (window['echarts'] && this.backupHistoryChart) {
-      const chart = window['echarts'].init(this.backupHistoryChart.nativeElement);
+    if (echarts && this.backupHistoryChart) {
+      const chart = echarts.init(this.backupHistoryChart.nativeElement);
       
       const dates = this.backupHistory.map(item => item.date);
       const sizes = this.backupHistory.map(item => item.size);
@@ -704,7 +698,7 @@ export class SystemSettings implements OnInit {
               color: '#165DFF'
             },
             areaStyle: {
-              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                 {
                   offset: 0,
                   color: 'rgba(22, 93, 255, 0.3)'
@@ -737,8 +731,8 @@ export class SystemSettings implements OnInit {
   
   // 初始化系统性能图表
   initSystemPerformanceChart(): void {
-    if (window['echarts'] && this.systemPerformanceChart) {
-      const chart = window['echarts'].init(this.systemPerformanceChart.nativeElement);
+    if (echarts && this.systemPerformanceChart) {
+      const chart = echarts.init(this.systemPerformanceChart.nativeElement);
       
       const times = this.systemPerformance.map(item => item.time);
       const cpuUsage = this.systemPerformance.map(item => item.cpuUsage);
@@ -788,7 +782,7 @@ export class SystemSettings implements OnInit {
               color: '#165DFF'
             },
             areaStyle: {
-              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                 {
                   offset: 0,
                   color: 'rgba(22, 93, 255, 0.5)'
@@ -809,7 +803,7 @@ export class SystemSettings implements OnInit {
               color: '#722ED1'
             },
             areaStyle: {
-              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                 {
                   offset: 0,
                   color: 'rgba(114, 46, 209, 0.5)'
@@ -830,7 +824,7 @@ export class SystemSettings implements OnInit {
               color: '#F7BA1E'
             },
             areaStyle: {
-              color: new window['echarts'].graphic.LinearGradient(0, 0, 0, 1, [
+              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                 {
                   offset: 0,
                   color: 'rgba(247, 186, 30, 0.5)'

+ 1 - 1
src/app/pages/designer/dashboard/skill-radar/skill-radar.component.html

@@ -9,7 +9,7 @@
   
   <div class="skill-radar-content">
     <div class="radar-chart-wrapper">
-      <canvas #radarChart></canvas>
+      <div #radarChart style="width: 100%; height: 400px;"></div>
     </div>
     
     <div class="skill-legend">

+ 73 - 65
src/app/pages/designer/dashboard/skill-radar/skill-radar.component.ts

@@ -1,6 +1,6 @@
 import { Component, OnInit, AfterViewInit, OnDestroy, ViewChild, ElementRef } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { Chart } from 'chart.js';
+import * as echarts from 'echarts';
 
 interface SkillData {
   label: string;
@@ -22,8 +22,8 @@ interface SkillAnalysisItem {
   styleUrl: './skill-radar.component.scss'
 })
 export class SkillRadarComponent implements OnInit, AfterViewInit, OnDestroy {
-  @ViewChild('radarChart') radarChartRef!: ElementRef<HTMLCanvasElement>;
-  private radarChart: Chart | null = null;
+  @ViewChild('radarChart') radarChartRef!: ElementRef<HTMLDivElement>;
+  private radarChart: any = null;
   
   viewMode: 'self' | 'comparison' = 'self';
   
@@ -74,20 +74,11 @@ export class SkillRadarComponent implements OnInit, AfterViewInit, OnDestroy {
 
   // 初始化雷达图
   private initRadarChart(): void {
-    const ctx = this.radarChartRef.nativeElement.getContext('2d');
-    if (!ctx) return;
-
-    const labels = this.skillDimensions.map(dim => dim.label);
-    const data = this.prepareChartData();
-
-    this.radarChart = new Chart(ctx, {
-      type: 'radar',
-      data: {
-        labels: labels,
-        datasets: data
-      },
-      options: this.getChartOptions()
-    });
+    const chartDom = this.radarChartRef.nativeElement;
+    this.radarChart = echarts.init(chartDom);
+    
+    const option = this.getEChartsOption();
+    this.radarChart.setOption(option);
 
     // 窗口调整大小时重绘图表
     window.addEventListener('resize', () => {
@@ -97,75 +88,92 @@ export class SkillRadarComponent implements OnInit, AfterViewInit, OnDestroy {
     });
   }
 
-  // 准备图表数据
-  private prepareChartData() {
-    const datasets = [
+  // 获取ECharts配置选项
+  private getEChartsOption() {
+    const indicators = this.skillDimensions.map(dim => ({
+      name: dim.label,
+      max: 100
+    }));
+
+    const series = [
       {
-        label: '个人能力',
-        data: this.skillDimensions.map(dim => dim.current),
-        backgroundColor: 'rgba(255, 99, 132, 0.2)',
-        borderColor: 'rgba(255, 99, 132, 1)',
-        pointBackgroundColor: 'rgba(255, 99, 132, 1)',
-        pointBorderColor: '#fff',
-        pointHoverBackgroundColor: '#fff',
-        pointHoverBorderColor: 'rgba(255, 99, 132, 1)'
+        name: '个人能力',
+        type: 'radar',
+        data: [
+          {
+            value: this.skillDimensions.map(dim => dim.current),
+            name: '个人能力',
+            itemStyle: {
+              color: '#ff6384'
+            },
+            areaStyle: {
+              color: 'rgba(255, 99, 132, 0.2)'
+            }
+          }
+        ]
       }
     ];
 
     if (this.viewMode === 'comparison') {
-      datasets.push({
-        label: '团队平均',
-        data: this.skillDimensions.map(dim => dim.teamAvg),
-        backgroundColor: 'rgba(54, 162, 235, 0.2)',
-        borderColor: 'rgba(54, 162, 235, 1)',
-        pointBackgroundColor: 'rgba(54, 162, 235, 1)',
-        pointBorderColor: '#fff',
-        pointHoverBackgroundColor: '#fff',
-        pointHoverBorderColor: 'rgba(54, 162, 235, 1)'
+      series[0].data.push({
+        value: this.skillDimensions.map(dim => dim.teamAvg),
+        name: '团队平均',
+        itemStyle: {
+          color: '#36a2eb'
+        },
+        areaStyle: {
+          color: 'rgba(54, 162, 235, 0.2)'
+        }
       });
     }
 
-    return datasets;
-  }
-
-  // 获取图表配置
-  private getChartOptions() {
     return {
-      scales: {
-        r: {
-          angleLines: {
-            display: true,
-            color: 'rgba(200, 200, 200, 0.3)'
-          },
-          suggestedMin: 0,
-          suggestedMax: 100,
-          ticks: {
-            stepSize: 20,
-            backdropColor: 'transparent'
-          }
+      title: {
+        text: '能力雷达图',
+        left: 'center',
+        textStyle: {
+          fontSize: 16,
+          color: '#333'
         }
       },
-      plugins: {
-        legend: {
-          display: false
+      legend: {
+        data: this.viewMode === 'comparison' ? ['个人能力', '团队平均'] : ['个人能力'],
+        bottom: 10
+      },
+      radar: {
+        indicator: indicators,
+        radius: '60%',
+        axisLine: {
+          lineStyle: {
+            color: 'rgba(200, 200, 200, 0.3)'
+          }
         },
-        tooltip: {
-          callbacks: {
-            label: function(context: any) {
-              return `${context.dataset.label}: ${context.parsed.r}/100`;
-            }
+        splitLine: {
+          lineStyle: {
+            color: 'rgba(200, 200, 200, 0.3)'
           }
+        },
+        splitArea: {
+          show: false
         }
       },
-      maintainAspectRatio: false
+      series: series,
+      tooltip: {
+        trigger: 'item',
+        formatter: function(params: any) {
+          return `${params.seriesName}<br/>${params.name}: ${params.value}`;
+        }
+      }
     };
   }
 
+
+
   // 更新雷达图
   private updateRadarChart(): void {
     if (this.radarChart) {
-      this.radarChart.data.datasets = this.prepareChartData();
-      this.radarChart.update();
+      const option = this.getEChartsOption();
+      this.radarChart.setOption(option);
     }
   }
 

+ 1 - 1
src/app/pages/finance/reports/reports.ts

@@ -3,7 +3,7 @@ import { FormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 import { Component, signal, ElementRef, ViewChild, OnInit, AfterViewInit, effect } from '@angular/core';
 import { AuthService } from '../../../services/auth.service';
-// 使用全局echarts变量,不导入模块
+import * as echarts from 'echarts';
 
 // 报表类型定义
 export type ReportType = 

+ 254 - 66
src/app/pages/team-leader/quality-management/quality-management.html

@@ -1,24 +1,135 @@
-<header>
-  <h1>质量管理</h1>
+<header class="quality-management-header">
+  <div class="header-content">
+    <div class="header-left">
+      <div class="header-icon">
+        <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M9 12L11 14L15 10M21 12C21 16.9706 16.9706 21 12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+      </div>
+      <div class="header-text">
+        <h1>质量管理</h1>
+        <p class="header-subtitle">确保项目质量标准,提升团队专业能力</p>
+      </div>
+    </div>
+    <div class="header-actions">
+      <button class="btn-secondary header-btn">
+        <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M14 2L8 8L2 2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+        导出报告
+      </button>
+      <button class="btn-primary header-btn">
+        <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M8 2V14M2 8H14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+        新建任务
+      </button>
+    </div>
+  </div>
+  
+  <!-- 统计卡片 -->
+  <div class="stats-cards">
+    <div class="stat-card">
+      <div class="stat-icon pending">
+        <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <circle cx="10" cy="10" r="8" stroke="currentColor" stroke-width="2"/>
+          <path d="M10 6V10L13 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+      </div>
+      <div class="stat-content">
+        <div class="stat-number">12</div>
+        <div class="stat-label">待处理任务</div>
+      </div>
+    </div>
+    
+    <div class="stat-card">
+      <div class="stat-icon processing">
+        <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M10 2V6M10 14V18M18 10H14M6 10H2M15.5 4.5L12.5 7.5M7.5 12.5L4.5 15.5M15.5 15.5L12.5 12.5M7.5 7.5L4.5 4.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+      </div>
+      <div class="stat-content">
+        <div class="stat-number">8</div>
+        <div class="stat-label">处理中</div>
+      </div>
+    </div>
+    
+    <div class="stat-card">
+      <div class="stat-icon completed">
+        <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M6 10L8.5 12.5L14 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+          <circle cx="10" cy="10" r="8" stroke="currentColor" stroke-width="2"/>
+        </svg>
+      </div>
+      <div class="stat-content">
+        <div class="stat-number">24</div>
+        <div class="stat-label">已完成</div>
+      </div>
+    </div>
+    
+    <div class="stat-card">
+      <div class="stat-icon quality">
+        <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M10 2L12.5 7L18 7.5L14 11L15 17L10 14.5L5 17L6 11L2 7.5L7.5 7L10 2Z" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
+        </svg>
+      </div>
+      <div class="stat-content">
+        <div class="stat-number">96%</div>
+        <div class="stat-label">质量达标率</div>
+      </div>
+    </div>
+  </div>
 </header>
 
 <main class="quality-management-main">
   <!-- 质量验收标准(SOP落地) -->
   <section class="sop-section">
     <div class="section-header">
-      <h2>质量验收标准 (SOP)</h2>
-      <button (click)="exportSOP()" class="btn-export">导出 PDF</button>
+      <div class="section-title">
+        <div class="section-icon">
+          <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path d="M9 12L11 14L15 10M19 10C19 14.9706 14.9706 19 10 19C5.02944 19 1 14.9706 1 10C1 5.02944 5.02944 1 10 1C14.9706 1 19 5.02944 19 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+          </svg>
+        </div>
+        <div>
+          <h2>质量验收标准 (SOP)</h2>
+          <p class="section-description">确保每个阶段的交付质量符合标准要求</p>
+        </div>
+      </div>
+      <button (click)="exportSOP()" class="btn-export">
+        <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="M14 10V12.6667C14 13.0203 13.8595 13.3594 13.6095 13.6095C13.3594 13.8595 13.0203 14 12.6667 14H3.33333C2.97971 14 2.64057 13.8595 2.39052 13.6095C2.14048 13.3594 2 13.0203 2 12.6667V10M11.3333 6.66667L8 3.33333M8 3.33333L4.66667 6.66667M8 3.33333V10" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+        导出 PDF
+      </button>
     </div>
     
     <div class="sop-tabs">
       <div class="tab-buttons">
-          <button (click)="activeTab = 'modeling'" [class.active]="activeTab === 'modeling'">
+          <button (click)="activeTab = 'modeling'" [class.active]="activeTab === 'modeling'" class="tab-button">
+            <div class="tab-icon">
+              <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M2 2L16 2V16L2 16V2Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M6 6L12 6M6 9L12 9M6 12L9 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+              </svg>
+            </div>
             <span>建模阶段</span>
           </button>
-          <button (click)="activeTab = 'rendering'" [class.active]="activeTab === 'rendering'">
+          <button (click)="activeTab = 'rendering'" [class.active]="activeTab === 'rendering'" class="tab-button">
+            <div class="tab-icon">
+              <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M9 1L11.5 6L17 6.5L13 10L14 16L9 13.5L4 16L5 10L1 6.5L6.5 6L9 1Z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
+              </svg>
+            </div>
             <span>渲染阶段</span>
           </button>
-          <button (click)="activeTab = 'postProduction'" [class.active]="activeTab === 'postProduction'">
+          <button (click)="activeTab = 'postProduction'" [class.active]="activeTab === 'postProduction'" class="tab-button">
+            <div class="tab-icon">
+              <svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M9 2V9L13 13" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
+                <circle cx="9" cy="9" r="7" stroke="currentColor" stroke-width="1.5"/>
+              </svg>
+            </div>
             <span>后期阶段</span>
           </button>
         </div>
@@ -188,12 +299,39 @@
     </div>
   </section>
   
-  <!-- 效果图质量整改跟踪 -->
+  <!-- 质量整改跟踪 -->
   <section class="rectification-section">
     <div class="section-header">
-      <h2>质量整改跟踪</h2>
-      <div class="search-filter">
-        <input type="text" placeholder="搜索项目名称..." [(ngModel)]="searchTerm">
+      <div class="section-title">
+        <div class="title-icon">
+          <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+          </svg>
+        </div>
+        <div class="title-content">
+          <h2>质量整改跟踪</h2>
+          <p>实时监控项目质量问题的整改进度和完成情况</p>
+        </div>
+      </div>
+      <div class="section-actions">
+        <button class="export-btn">
+          <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4m4-5l5-5 5 5m-5-5v12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+          </svg>
+          导出报告
+        </button>
+      </div>
+    </div>
+    
+    <div class="search-filter-modern">
+      <div class="search-input-wrapper">
+        <svg class="search-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2"/>
+          <path d="m21 21-4.35-4.35" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
+        <input type="text" placeholder="搜索项目名称或负责人..." [(ngModel)]="searchTerm">
+      </div>
+      <div class="filter-dropdown">
         <select [(ngModel)]="filterStatus">
           <option value="all">全部状态</option>
           <option value="pending">待处理</option>
@@ -201,15 +339,31 @@
           <option value="review">待审核</option>
           <option value="completed">已完成</option>
         </select>
+        <svg class="dropdown-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+          <path d="m6 9 6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+        </svg>
       </div>
     </div>
     
-    <div class="rectification-list">
+    <div class="rectification-grid">
       @for (task of filteredTasks; track task.id) {
-      <div class="rectification-item" [class.priority-high]="task.priority === 'high'" [class.priority-medium]="task.priority === 'medium'" [class.priority-low]="task.priority === 'low'">
-        <div class="rectification-header">
-          <h4>{{ task.projectName }}</h4>
-          <span [class]="'rectification-status status-' + task.status">{{ getStatusText(task.status) }}</span>
+      <div class="rectification-card" [class.priority-high]="task.priority === 'high'" [class.priority-medium]="task.priority === 'medium'" [class.priority-low]="task.priority === 'low'">
+        <div class="card-header">
+          <div class="project-info">
+            <div class="project-avatar">
+              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10M9 1v6m6-6v6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+              </svg>
+            </div>
+            <div class="project-details">
+              <h4>{{ task.projectName }}</h4>
+              <p class="project-designer">{{ task.designerName }}</p>
+            </div>
+          </div>
+          <div class="status-badge" [class]="'status-' + task.status">
+            <div class="status-indicator"></div>
+            <span>{{ getStatusText(task.status) }}</span>
+          </div>
         </div>
         
         <div class="rectification-details">
@@ -269,41 +423,70 @@
   <!-- 能力提升工具集成 -->
   <section class="training-section">
     <div class="section-header">
-      <h2>能力提升工具</h2>
-      <p class="section-description">通过视频教程和实践作业提升团队技能,确保SOP标准执行</p>
+      <div class="section-title">
+        <div class="title-icon">
+          <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+          </svg>
+        </div>
+        <div class="title-content">
+          <h2>能力提升工具</h2>
+          <p>通过视频教程和实践作业提升团队技能,确保SOP标准执行</p>
+        </div>
+      </div>
+      <div class="section-actions">
+        <button class="progress-btn">
+          <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+            <path d="M9 19c-5 0-8-3-8-8s3-8 8-8 8 3 8 8-3 8-8 8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            <path d="M9 9h.01M9 13h.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+          </svg>
+          学习进度
+        </button>
+      </div>
     </div>
     
     <div class="training-content">
       <!-- 视频教程区域 -->
       <div class="video-tutorials">
-        <div class="section-subheader">
-          <h3>视频教程</h3>
-          <button class="btn-view-all">查看全部</button>
+        <div class="subsection-header">
+          <div class="subsection-title">
+            <div class="subsection-icon">
+              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+              </svg>
+            </div>
+            <h3>视频教程</h3>
+          </div>
+          <button class="view-all-btn">
+            <span>查看全部</span>
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path d="m9 18 6-6-6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+          </button>
         </div>
         <div class="video-grid">
           @for (video of videoTutorials; track video.id) {
-          <div class="video-card" (mouseenter)="video.isHovered = true" (mouseleave)="video.isHovered = false">
+          <div class="video-card" (click)="playVideo(video)" (mouseenter)="video.isHovered = true" (mouseleave)="video.isHovered = false">
             <div class="video-thumbnail-container">
               <div class="video-thumbnail">
-                <img [src]="video.thumbnailUrl" alt="视频缩略图" class="thumbnail-img">
+                <img [src]="video.thumbnailUrl" [alt]="video.title" class="thumbnail-img">
                 <div class="video-duration">{{ video.duration }}</div>
-                <div class="play-overlay" [class.visible]="video.isHovered">
-                  <button (click)="playVideo(video.id)" class="play-button">
-                    <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
-                      <circle cx="20" cy="20" r="20" fill="rgba(0,0,0,0.6)"/>
-                      <path d="M15 13L28 20L15 27V13Z" fill="white"/>
+                <div class="play-overlay" [class.visible]="true">
+                  <button class="play-button">
+                    <svg viewBox="0 0 24 24">
+                      <path d="M8 5v14l11-7z"/>
                     </svg>
                   </button>
                 </div>
               </div>
             </div>
             <div class="video-info">
-              <div class="category-badge">{{ video.category }}</div>
+              <span class="category-badge">{{ video.category }}</span>
               <h4 class="video-title">{{ video.title }}</h4>
               <p class="video-description">{{ video.description }}</p>
               <div class="video-meta">
                 <span class="views">{{ video.views }} 次观看</span>
-                <span class="date">2天前</span>
+                <span class="date">{{ video.date }}</span>
               </div>
             </div>
           </div>
@@ -313,53 +496,58 @@
       
       <!-- 实践作业区域 -->
       <div class="practice-assignments">
-        <div class="section-subheader">
-          <h3>实践作业</h3>
-          <div class="assignment-stats">
-            <span class="stat">待评审: 2</span>
-            <span class="stat">进行中: 3</span>
+        <div class="subsection-header">
+          <div class="subsection-title">
+            <div class="subsection-icon">
+              <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                <path d="M14 2v6h6M16 13H8M16 17H8M10 9H8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+              </svg>
+            </div>
+            <h3>实践作业</h3>
           </div>
+          <button class="view-all-btn">
+            <span>查看全部</span>
+            <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+              <path d="m9 18 6-6-6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+            </svg>
+          </button>
         </div>
-        <div class="assignment-list">
+        <div class="assignment-grid">
           @for (assignment of practiceAssignments; track assignment.id) {
-          <div class="assignment-card">
+          <div class="assignment-card" (click)="openAssignment(assignment)">
             <div class="assignment-header">
-              <div class="assignment-title-section">
-                <h4>{{ assignment.title }}</h4>
-                <div class="assignment-badges">
-                  <span class="badge related-sop">关联SOP: {{ assignment.relatedSOP }}</span>
-                </div>
+              <div class="assignment-icon">
+                <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                  <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8l-6-6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
+                </svg>
               </div>
-              <span [class]="'status-badge status-' + assignment.status">{{ getAssignmentStatusText(assignment.status) }}</span>
-            </div>
-            <div class="assignment-details">
-              <p class="description">{{ assignment.description }}</p>
               <div class="assignment-meta">
-                <div class="meta-item">
-                  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-                    <path d="M8 2V3M8 13V14M1 8H2M14 8H15M12.5 3.5L13.5 2.5M3.5 13.5L2.5 12.5M12.5 12.5L13.5 13.5M3.5 3.5L2.5 2.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
-                    <circle cx="8" cy="8" r="5" stroke="currentColor" stroke-width="2"/>
-                  </svg>
-                  <span>截止日期: {{ assignment.deadline | date:'yyyy-MM-dd' }}</span>
-                </div>
-                @if (assignment.score !== null) {
-                <div class="meta-item score-item">
-                  <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-                    <path d="M8 1L10.5 5.5L16 6L12 9L13 14L8 12L3 14L4 9L0 6L5.5 5.5L8 1Z" stroke="currentColor" stroke-width="2" fill="none"/>
-                  </svg>
-                  <span>得分: {{ assignment.score }}/100</span>
+                <span class="difficulty-badge" [class]="'difficulty-' + assignment.difficulty">{{ assignment.difficulty }}</span>
+                <span class="assignment-type">{{ assignment.type }}</span>
+              </div>
+            </div>
+            <div class="assignment-content">
+              <h4 class="assignment-title">{{ assignment.title }}</h4>
+              <p class="assignment-description">{{ assignment.description }}</p>
+              <div class="assignment-progress">
+                <div class="progress-bar">
+                  <div class="progress-fill" [style.width.%]="assignment.progress"></div>
                 </div>
-                }
+                <span class="progress-text">{{ assignment.progress }}%</span>
               </div>
             </div>
-            <div class="assignment-actions">
-              <button (click)="reviewAssignment(assignment.id)" class="btn-review btn-primary">
-                <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-                  <path d="M8 1L10.5 5.5L16 6L12 9L13 14L8 12L3 14L4 9L0 6L5.5 5.5L8 1Z" stroke="white" stroke-width="2" fill="none"/>
+            <div class="assignment-footer">
+              <div class="assignment-stats">
+                <span class="deadline">{{ assignment.deadline | date:'yyyy-MM-dd' }}</span>
+                <span class="points">{{ assignment.points }} 积分</span>
+              </div>
+              <button class="start-btn" [class.completed]="assignment.progress === 100">
+                <span>{{ assignment.progress === 100 ? '已完成' : '开始练习' }}</span>
+                <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+                  <path d="M8 5v14l11-7z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
                 </svg>
-                评审作业
               </button>
-              <button class="btn-secondary">下载资料</button>
             </div>
           </div>
           }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 872 - 196
src/app/pages/team-leader/quality-management/quality-management.scss


+ 36 - 13
src/app/pages/team-leader/quality-management/quality-management.ts

@@ -28,6 +28,7 @@ interface VideoTutorial {
   views: number;
   relatedSOP: string;
   isHovered: boolean;
+  date: string;
 }
 
 // 定义实践作业接口
@@ -40,6 +41,10 @@ interface PracticeAssignment {
   status: 'pending' | 'submitted' | 'reviewed';
   score: number | null;
   designerName: string;
+  points: number;
+  progress: number;
+  difficulty: 'easy' | 'medium' | 'hard';
+  type: string;
 }
 
 @Component({
@@ -138,7 +143,8 @@ export class QualityManagementComponent implements OnInit {
         category: '渲染技巧',
         views: 1256,
         relatedSOP: '渲染阶段',
-        isHovered: false
+        isHovered: false,
+        date: '2023-12-01'
       },
       {
         id: 'video-2',
@@ -149,7 +155,8 @@ export class QualityManagementComponent implements OnInit {
         category: '建模技巧',
         views: 892,
         relatedSOP: '建模阶段',
-        isHovered: false
+        isHovered: false,
+        date: '2023-11-28'
       },
       {
         id: 'video-3',
@@ -160,7 +167,8 @@ export class QualityManagementComponent implements OnInit {
         category: '后期处理',
         views: 1053,
         relatedSOP: '后期阶段',
-        isHovered: false
+        isHovered: false,
+        date: '2023-12-05'
       }
     ];
     
@@ -174,7 +182,11 @@ export class QualityManagementComponent implements OnInit {
         deadline: new Date('2023-12-25'),
         status: 'submitted',
         score: null,
-        designerName: '张三'
+        designerName: '张三',
+        points: 85,
+        progress: 100,
+        difficulty: 'medium',
+        type: '渲染练习'
       },
       {
         id: 'assignment-2',
@@ -184,7 +196,11 @@ export class QualityManagementComponent implements OnInit {
         deadline: new Date('2024-01-05'),
         status: 'pending',
         score: null,
-        designerName: '李四'
+        designerName: '李四',
+        points: 75,
+        progress: 30,
+        difficulty: 'hard',
+        type: '建模练习'
       },
       {
         id: 'assignment-3',
@@ -194,7 +210,11 @@ export class QualityManagementComponent implements OnInit {
         deadline: new Date('2023-12-30'),
         status: 'reviewed',
         score: 92,
-        designerName: '王五'
+        designerName: '王五',
+        points: 90,
+        progress: 100,
+        difficulty: 'easy',
+        type: '后期处理'
       }
     ];
   }
@@ -303,13 +323,10 @@ export class QualityManagementComponent implements OnInit {
   }
   
   // 播放视频
-  playVideo(videoId: string): void {
-    const video = this.videoTutorials.find(v => v.id === videoId);
-    if (video) {
-      // 模拟播放视频
-      alert(`正在播放视频: ${video.title}`);
-      // 实际项目中,这里应该打开视频播放器或跳转到视频播放页面
-    }
+  playVideo(video: VideoTutorial): void {
+    // 模拟播放视频
+    alert(`正在播放视频: ${video.title}`);
+    // 实际项目中,这里应该打开视频播放器或跳转到视频播放页面
   }
   
   // 评审作业
@@ -349,4 +366,10 @@ export class QualityManagementComponent implements OnInit {
   navigateToProjectReview(): void {
     this.router.navigate(['/team-leader/project-review']);
   }
+
+  // 打开作业详情
+  openAssignment(assignment: PracticeAssignment): void {
+    console.log('打开作业详情:', assignment);
+    // 这里可以实现打开作业详情的逻辑,比如导航到详情页面或打开模态框
+  }
 }

+ 2 - 6
src/index.html

@@ -10,12 +10,8 @@
     <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
     
     <!-- 使用国内CDN引入echarts -->
-    <script src="https://unpkg.com/echarts@6.0.0/dist/echarts.min.js"></script>
-    <!-- 声明全局变量告知Angular使用外部的echarts -->
-    <script>
-      // 全局变量,供Angular应用使用
-      window.echarts = echarts;
-    </script>
+    <!-- ECharts will be imported in components as needed -->
+    <!-- ECharts will be imported locally in components -->
   </head>
 <body>
   <app-root></app-root>

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.