Prechádzať zdrojové kódy

feat:team-leader-demo01

0235711 1 deň pred
rodič
commit
e715794b07

+ 14 - 0
angular.json

@@ -91,8 +91,22 @@
               "src/styles.scss"
             ]
           }
+        },
+        "lint": {
+          "builder": "@angular-eslint/builder:lint",
+          "options": {
+            "lintFilePatterns": [
+              "src/**/*.ts",
+              "src/**/*.html"
+            ]
+          }
         }
       }
     }
+  },
+  "cli": {
+    "schematicCollections": [
+      "angular-eslint"
+    ]
   }
 }

+ 43 - 0
eslint.config.js

@@ -0,0 +1,43 @@
+// @ts-check
+const eslint = require("@eslint/js");
+const tseslint = require("typescript-eslint");
+const angular = require("angular-eslint");
+
+module.exports = tseslint.config(
+  {
+    files: ["**/*.ts"],
+    extends: [
+      eslint.configs.recommended,
+      ...tseslint.configs.recommended,
+      ...tseslint.configs.stylistic,
+      ...angular.configs.tsRecommended,
+    ],
+    processor: angular.processInlineTemplates,
+    rules: {
+      "@angular-eslint/directive-selector": [
+        "error",
+        {
+          type: "attribute",
+          prefix: "app",
+          style: "camelCase",
+        },
+      ],
+      "@angular-eslint/component-selector": [
+        "error",
+        {
+          type: "element",
+          prefix: "app",
+          style: "kebab-case",
+        },
+      ],
+    },
+  },
+  {
+    files: ["**/*.html"],
+    extends: [
+      ...angular.configs.templateRecommended,
+      ...angular.configs.templateAccessibility,
+    ],
+    rules: {},
+  }
+);

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1211 - 41
package-lock.json


+ 7 - 3
package.json

@@ -6,7 +6,8 @@
     "start": "ng serve",
     "build": "ng build",
     "watch": "ng build --watch --configuration development",
-    "test": "ng test"
+    "test": "ng test",
+    "lint": "ng lint"
   },
   "prettier": {
     "overrides": [
@@ -36,12 +37,15 @@
     "@angular/cli": "^20.1.5",
     "@angular/compiler-cli": "^20.1.0",
     "@types/jasmine": "~5.1.0",
+    "angular-eslint": "20.2.0",
+    "eslint": "^9.33.0",
     "jasmine-core": "~5.8.0",
     "karma": "~6.4.0",
     "karma-chrome-launcher": "~3.2.0",
     "karma-coverage": "~2.2.0",
     "karma-jasmine": "~5.1.0",
     "karma-jasmine-html-reporter": "~2.1.0",
-    "typescript": "~5.8.2"
+    "typescript": "~5.8.2",
+    "typescript-eslint": "8.40.0"
   }
-}
+}

+ 6 - 6
src/app/app.routes.ts

@@ -14,9 +14,9 @@ import { PersonalBoard } from './pages/designer/personal-board/personal-board';
 
 // 组长页面
 import { Dashboard as TeamLeaderDashboard } from './pages/team-leader/dashboard/dashboard';
-import { TeamManagement } from './pages/team-leader/team-management/team-management';
-import { ProjectReview } from './pages/team-leader/project-review/project-review';
-import { QualityManagement } from './pages/team-leader/quality-management/quality-management';
+import { TeamManagementComponent } from './pages/team-leader/team-management/team-management';
+import { ProjectReviewComponent } from './pages/team-leader/project-review/project-review';
+import { QualityManagementComponent } from './pages/team-leader/quality-management/quality-management';
 
 // 财务页面
 import { Dashboard as FinanceDashboard } from './pages/finance/dashboard/dashboard';
@@ -63,9 +63,9 @@ export const routes: Routes = [
     children: [
       { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
       { path: 'dashboard', component: TeamLeaderDashboard, title: '组长工作台' },
-      { path: 'team-management', component: TeamManagement, title: '团队管理' },
-      { path: 'project-review/:id', component: ProjectReview, title: '项目审核' },
-      { path: 'quality-management', component: QualityManagement, title: '质量管理' }
+      { path: 'team-management', component: TeamManagementComponent, title: '团队管理' },
+      { path: 'project-review', component: ProjectReviewComponent, title: '项目审核' },
+      { path: 'quality-management', component: QualityManagementComponent, title: '质量管理' }
     ]
   },
 

+ 123 - 1
src/app/pages/team-leader/dashboard/dashboard.html

@@ -1 +1,123 @@
-<p>dashboard works!</p>
+<header class="dashboard-header">
+  <h1>设计组长工作台</h1>
+</header>
+
+<main class="dashboard-main">
+  <!-- 项目监控大盘 -->
+  <section class="monitoring-section">
+    <div class="section-header">
+      <h2>项目监控大盘</h2>
+      <div class="section-filters">
+        <select (change)="filterProjects($event)">
+          <option value="all">全部项目</option>
+          <option value="soft">软装项目</option>
+          <option value="hard">硬装项目</option>
+        </select>
+        <select (change)="filterByUrgency($event)">
+          <option value="all">全部紧急程度</option>
+          <option value="high">高</option>
+          <option value="medium">中</option>
+          <option value="low">低</option>
+        </select>
+      </div>
+    </div>
+    
+    <div class="project-gantt-chart">
+      <div *ngFor="let project of projects" class="project-bar">
+        <div class="project-info">
+          <h3 [routerLink]="['/team-leader/project-review', project.id]" class="project-name">{{ project.name }}</h3>
+          <p class="project-details">负责组员: {{ project.designerName }} | 状态: {{ project.status }}</p>
+          <p [class.overdue-warning]="project.isOverdue" class="project-deadline">
+            {{ project.isOverdue ? '⚠️ 已超期' : '预计完成: ' + (project.expectedEndDate | date:'yyyy-MM-dd') }}
+          </p>
+        </div>
+        <div class="gantt-bars">
+          <div *ngFor="let phase of project.phases" 
+               [style.width]="phase.percentage + '%'"
+               [style.left]="phase.startPercentage + '%'"
+               [class]="'phase-bar phase-' + phase.name.toLowerCase()"
+               [class.completed]="phase.isCompleted"
+               [class.current]="phase.isCurrent">
+            <span class="phase-label">{{ phase.name }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 工作量评估快捷入口 -->
+  <section class="workload-section">
+    <div class="section-header">
+      <h2>工作量评估</h2>
+    </div>
+    
+    <div class="workload-calculator">
+      <div class="calculator-form">
+        <div class="form-group">
+          <label>户型面积 (㎡)</label>
+          <input type="number" [(ngModel)]="workloadParams.area" placeholder="请输入面积">
+        </div>
+        <div class="form-group">
+          <label>风格复杂度</label>
+          <select [(ngModel)]="workloadParams.styleComplexity">
+            <option value="simple">简单</option>
+            <option value="medium">中等</option>
+            <option value="complex">复杂</option>
+          </select>
+        </div>
+        <div class="form-group">
+          <label>交付要求</label>
+          <select [(ngModel)]="workloadParams.deliveryRequirement">
+            <option value="standard">标准</option>
+            <option value="premium">优质</option>
+            <option value="vip">VIP</option>
+          </select>
+        </div>
+        <button (click)="calculateWorkload()" class="btn-calculate">一键评估</button>
+      </div>
+      
+      <div *ngIf="workloadResult" class="workload-result">
+        <h3>评估结果</h3>
+        <p><strong>周期建议:</strong> 建模 {{ workloadResult.modelingDays }}天 + 渲染 {{ workloadResult.renderingDays }}天</p>
+        <p><strong>基础报价:</strong> 建模 {{ workloadResult.modelingPrice }}元/㎡、渲染 {{ workloadResult.renderingPrice }}元/张</p>
+        <button (click)="syncToProjectReview()" class="btn-sync">同步至项目评审</button>
+      </div>
+    </div>
+  </section>
+
+  <!-- 待办任务优先级排序 -->
+  <section class="todo-section">
+    <div class="section-header">
+      <h2>待办任务</h2>
+    </div>
+    
+    <div class="todo-list">
+      <div *ngFor="let task of todoTasks" class="todo-item" [class.priority-high]="task.priority === 'high'" [class.priority-medium]="task.priority === 'medium'" [class.priority-low]="task.priority === 'low'">
+        <div class="todo-header">
+          <h3>{{ task.title }}</h3>
+          <span class="task-priority">{{ getPriorityLabel(task.priority) }}</span>
+        </div>
+        <div class="todo-info">
+          <p>{{ task.description }}</p>
+          <p class="task-deadline">截止时间: {{ task.deadline | date:'yyyy-MM-dd HH:mm' }}</p>
+        </div>
+        <div class="todo-actions">
+          <button (click)="navigateToTask(task)" class="btn-handle">处理任务</button>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 超期项目提醒 -->
+  <div *ngIf="showAlert && overdueProjects.length > 0" class="overdue-alert">
+    <div class="alert-content">
+      <h3>⚠️ 超期项目提醒</h3>
+      <ul>
+        <li *ngFor="let project of overdueProjects.slice(0, 3)">
+          {{ project.name }} ({{ project.designerName }} 负责) - 超期{{ project.overdueDays }}天
+        </li>
+      </ul>
+      <button (click)="closeAlert()" class="btn-close">关闭</button>
+    </div>
+  </div>
+</main>

+ 373 - 0
src/app/pages/team-leader/dashboard/dashboard.scss

@@ -0,0 +1,373 @@
+@import '../ios-theme.scss';
+
+:host {
+  display: block;
+  background-color: $ios-background-secondary;
+  min-height: 100vh;
+  padding: $ios-spacing-lg;
+}
+
+.dashboard-header {
+  margin-bottom: $ios-spacing-xxl;
+  h1 {
+    font-size: $ios-font-size-xl;
+    font-weight: $ios-font-weight-bold;
+    color: $ios-text-primary;
+    margin: 0;
+  }
+}
+
+.dashboard-main {
+  max-width: 1400px;
+  margin: 0 auto;
+}
+
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: $ios-spacing-lg;
+  h2 {
+    font-size: $ios-font-size-lg;
+    font-weight: $ios-font-weight-semibold;
+    color: $ios-text-primary;
+    margin: 0;
+  }
+}
+
+.section-filters {
+  display: flex;
+  gap: $ios-spacing-md;
+  select {
+    padding: $ios-spacing-sm $ios-spacing-md;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-md;
+    background-color: $ios-background;
+    font-size: $ios-font-size-sm;
+    color: $ios-text-primary;
+    cursor: pointer;
+    &:focus {
+      outline: none;
+      border-color: $ios-primary;
+    }
+  }
+}
+
+/* 项目监控大盘样式 */
+.monitoring-section {
+  background-color: $ios-card-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-xl;
+  margin-bottom: $ios-spacing-xl;
+  box-shadow: $ios-shadow-card;
+}
+
+.project-gantt-chart {
+  .project-bar {
+    display: flex;
+    gap: $ios-spacing-lg;
+    padding: $ios-spacing-lg 0;
+    border-bottom: 1px solid $ios-border;
+    &:last-child {
+      border-bottom: none;
+    }
+    .project-info {
+      flex: 0 0 300px;
+      .project-name {
+        font-size: $ios-font-size-base;
+        font-weight: $ios-font-weight-medium;
+        color: $ios-primary;
+        cursor: pointer;
+        margin: 0 0 $ios-spacing-xs 0;
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+      .project-details {
+        font-size: $ios-font-size-sm;
+        color: $ios-text-secondary;
+        margin: 0 0 $ios-spacing-xs 0;
+      }
+      .project-deadline {
+        font-size: $ios-font-size-sm;
+        color: $ios-text-secondary;
+        margin: 0;
+        &.overdue-warning {
+          color: $ios-danger;
+          font-weight: $ios-font-weight-medium;
+        }
+      }
+    }
+    .gantt-bars {
+      flex: 1;
+      position: relative;
+      height: 40px;
+      background-color: $ios-background-secondary;
+      border-radius: $ios-radius-md;
+      overflow: hidden;
+      .phase-bar {
+        position: absolute;
+        top: 50%;
+        transform: translateY(-50%);
+        height: 24px;
+        border-radius: $ios-radius-sm;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        transition: $ios-feedback-hover;
+        .phase-label {
+          font-size: $ios-font-size-xs;
+          color: $ios-background;
+          font-weight: $ios-font-weight-medium;
+          text-shadow: 0 1px 2px rgba(0,0,0,0.2);
+        }
+      }
+      .phase-建模 {
+        background-color: $ios-primary-light;
+      }
+      .phase-渲染 {
+        background-color: $ios-info;
+      }
+      .phase-后期 {
+        background-color: $ios-warning;
+      }
+      .phase-交付 {
+        background-color: $ios-success;
+      }
+      .phase-bar.current {
+        box-shadow: 0 0 0 2px $ios-primary;
+        transform: translateY(-50%) scale(1.05);
+      }
+      .phase-bar.completed {
+        opacity: 0.6;
+      }
+    }
+  }
+}
+
+/* 工作量评估样式 */
+.workload-section {
+  background-color: $ios-card-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-xl;
+  margin-bottom: $ios-spacing-xl;
+  box-shadow: $ios-shadow-card;
+}
+
+.workload-calculator {
+  display: flex;
+  gap: $ios-spacing-xl;
+  .calculator-form {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    gap: $ios-spacing-lg;
+    .form-group {
+      display: flex;
+      flex-direction: column;
+      gap: $ios-spacing-sm;
+      label {
+        font-size: $ios-font-size-sm;
+        font-weight: $ios-font-weight-medium;
+        color: $ios-text-primary;
+      }
+      input,
+      select {
+        padding: $ios-spacing-sm $ios-spacing-md;
+        border: 1px solid $ios-border;
+        border-radius: $ios-radius-md;
+        background-color: $ios-background;
+        font-size: $ios-font-size-base;
+        color: $ios-text-primary;
+        &:focus {
+          outline: none;
+          border-color: $ios-primary;
+        }
+      }
+    }
+    .btn-calculate {
+      background-color: $ios-primary;
+      color: $ios-background;
+      border: none;
+      border-radius: $ios-radius-md;
+      padding: $ios-spacing-md;
+      font-size: $ios-font-size-base;
+      font-weight: $ios-font-weight-medium;
+      cursor: pointer;
+      transition: $ios-feedback-tap;
+      &:hover {
+        background-color: $ios-primary-light;
+        transform: translateY(-1px);
+      }
+      &:active {
+        transform: translateY(0);
+      }
+    }
+  }
+  .workload-result {
+    flex: 1;
+    background-color: $ios-background-secondary;
+    border-radius: $ios-radius-md;
+    padding: $ios-spacing-lg;
+    h3 {
+      font-size: $ios-font-size-base;
+      font-weight: $ios-font-weight-medium;
+      color: $ios-text-primary;
+      margin: 0 0 $ios-spacing-lg 0;
+    }
+    p {
+      margin: 0 0 $ios-spacing-md 0;
+      font-size: $ios-font-size-base;
+      color: $ios-text-primary;
+      strong {
+        font-weight: $ios-font-weight-medium;
+      }
+    }
+    .btn-sync {
+      background-color: $ios-success;
+      color: $ios-background;
+      border: none;
+      border-radius: $ios-radius-md;
+      padding: $ios-spacing-sm $ios-spacing-lg;
+      font-size: $ios-font-size-sm;
+      font-weight: $ios-font-weight-medium;
+      cursor: pointer;
+      transition: $ios-feedback-tap;
+      &:hover {
+        background-color: #2AA049;
+        transform: translateY(-1px);
+      }
+    }
+  }
+}
+
+/* 待办任务样式 */
+.todo-section {
+  background-color: $ios-card-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-xl;
+  margin-bottom: $ios-spacing-xl;
+  box-shadow: $ios-shadow-card;
+}
+
+.todo-list {
+  .todo-item {
+    padding: $ios-spacing-lg;
+    border-radius: $ios-radius-md;
+    margin-bottom: $ios-spacing-md;
+    background-color: $ios-background;
+    border: 1px solid $ios-border;
+    transition: $ios-feedback-hover;
+    &:last-child {
+      margin-bottom: 0;
+    }
+    &.priority-high {
+      border-left: 4px solid $ios-danger;
+    }
+    &.priority-medium {
+      border-left: 4px solid $ios-warning;
+    }
+    &.priority-low {
+      border-left: 4px solid $ios-info;
+    }
+    &:hover {
+      transform: translateY(-1px);
+      box-shadow: $ios-shadow-sm;
+    }
+    .todo-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: $ios-spacing-md;
+      h3 {
+        font-size: $ios-font-size-base;
+        font-weight: $ios-font-weight-medium;
+        color: $ios-text-primary;
+        margin: 0;
+      }
+      .task-priority {
+        font-size: $ios-font-size-xs;
+        padding: $ios-spacing-xs $ios-spacing-sm;
+        border-radius: $ios-radius-full;
+        font-weight: $ios-font-weight-medium;
+      }
+    }
+    .todo-info {
+      margin-bottom: $ios-spacing-md;
+      p {
+        margin: 0 0 $ios-spacing-xs 0;
+        font-size: $ios-font-size-sm;
+        color: $ios-text-secondary;
+      }
+      .task-deadline {
+        font-size: $ios-font-size-xs;
+        color: $ios-text-tertiary;
+      }
+    }
+    .todo-actions {
+      .btn-handle {
+        background-color: $ios-primary;
+        color: $ios-background;
+        border: none;
+        border-radius: $ios-radius-md;
+        padding: $ios-spacing-sm $ios-spacing-lg;
+        font-size: $ios-font-size-sm;
+        font-weight: $ios-font-weight-medium;
+        cursor: pointer;
+        transition: $ios-feedback-tap;
+        &:hover {
+          background-color: $ios-primary-light;
+        }
+      }
+    }
+  }
+}
+
+/* 超期提醒样式 */
+.overdue-alert {
+  position: fixed;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  background-color: $ios-card-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-xl;
+  box-shadow: $ios-shadow-lg;
+  z-index: 1000;
+  min-width: 400px;
+  .alert-content {
+    h3 {
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-semibold;
+      color: $ios-danger;
+      margin: 0 0 $ios-spacing-lg 0;
+    }
+    ul {
+      margin: 0 0 $ios-spacing-lg 0;
+      padding-left: $ios-spacing-xl;
+      li {
+        font-size: $ios-font-size-base;
+        color: $ios-text-primary;
+        margin-bottom: $ios-spacing-sm;
+        &:last-child {
+          margin-bottom: 0;
+        }
+      }
+    }
+    .btn-close {
+      background-color: $ios-text-tertiary;
+      color: $ios-text-primary;
+      border: none;
+      border-radius: $ios-radius-md;
+      padding: $ios-spacing-sm $ios-spacing-lg;
+      font-size: $ios-font-size-sm;
+      font-weight: $ios-font-weight-medium;
+      cursor: pointer;
+      transition: $ios-feedback-tap;
+      &:hover {
+        background-color: $ios-text-secondary;
+        color: $ios-background;
+      }
+    }
+  }
+}

+ 336 - 3
src/app/pages/team-leader/dashboard/dashboard.ts

@@ -1,11 +1,344 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { Router, RouterModule } from '@angular/router';
+import { ProjectService } from '../../../services/project.service';
+
+interface ProjectPhase {
+  name: string;
+  percentage: number;
+  startPercentage: number;
+  isCompleted: boolean;
+  isCurrent: boolean;
+}
+
+interface Project {
+  id: string;
+  name: string;
+  type: 'soft' | 'hard';
+  designerName: string;
+  status: string;
+  expectedEndDate: Date;
+  isOverdue: boolean;
+  overdueDays: number;
+  urgency: 'high' | 'medium' | 'low';
+  phases: ProjectPhase[];
+}
+
+interface WorkloadParams {
+  area: number;
+  styleComplexity: 'simple' | 'medium' | 'complex';
+  deliveryRequirement: 'standard' | 'premium' | 'vip';
+}
+
+interface WorkloadResult {
+  modelingDays: number;
+  renderingDays: number;
+  modelingPrice: number;
+  renderingPrice: number;
+}
+
+interface TodoTask {
+  id: string;
+  title: string;
+  description: string;
+  deadline: Date;
+  priority: 'high' | 'medium' | 'low';
+  type: 'review' | 'assign' | 'performance';
+  targetId: string;
+}
 
 @Component({
   selector: 'app-dashboard',
-  imports: [],
+  imports: [CommonModule, FormsModule, RouterModule],
   templateUrl: './dashboard.html',
   styleUrl: './dashboard.scss'
 })
-export class Dashboard {
 
+export class Dashboard implements OnInit {
+  projects: Project[] = [];
+  filteredProjects: Project[] = [];
+  workloadParams: WorkloadParams = {
+    area: 0,
+    styleComplexity: 'medium',
+    deliveryRequirement: 'standard'
+  };
+  workloadResult: WorkloadResult | null = null;
+  todoTasks: TodoTask[] = [];
+  overdueProjects: Project[] = [];
+  showAlert: boolean = false;
+
+  constructor(private projectService: ProjectService, private router: Router) {}
+
+  ngOnInit(): void {
+    this.loadProjects();
+    this.loadTodoTasks();
+  }
+
+  loadProjects(): void {
+    // 模拟数据加载
+    this.projects = [
+      {
+        id: 'proj-001',
+        name: '现代风格客厅设计',
+        type: 'soft',
+        designerName: '张三',
+        status: '进行中',
+        expectedEndDate: new Date(2023, 9, 15),
+        isOverdue: true,
+        overdueDays: 2,
+        urgency: 'high',
+        phases: [
+          { name: '建模', percentage: 15, startPercentage: 0, isCompleted: true, isCurrent: false },
+          { name: '渲染', percentage: 20, startPercentage: 15, isCompleted: false, isCurrent: true },
+          { name: '后期', percentage: 15, startPercentage: 35, isCompleted: false, isCurrent: false },
+          { name: '交付', percentage: 50, startPercentage: 50, isCompleted: false, isCurrent: false }
+        ]
+      },
+      {
+        id: 'proj-002',
+        name: '北欧风格卧室设计',
+        type: 'soft',
+        designerName: '李四',
+        status: '进行中',
+        expectedEndDate: new Date(2023, 9, 20),
+        isOverdue: false,
+        overdueDays: 0,
+        urgency: 'medium',
+        phases: [
+          { name: '建模', percentage: 15, startPercentage: 0, isCompleted: true, isCurrent: false },
+          { name: '渲染', percentage: 20, startPercentage: 15, isCompleted: true, isCurrent: false },
+          { name: '后期', percentage: 15, startPercentage: 35, isCompleted: false, isCurrent: true },
+          { name: '交付', percentage: 50, startPercentage: 50, isCompleted: false, isCurrent: false }
+        ]
+      },
+      {
+        id: 'proj-003',
+        name: '新中式餐厅设计',
+        type: 'hard',
+        designerName: '王五',
+        status: '进行中',
+        expectedEndDate: new Date(2023, 9, 25),
+        isOverdue: false,
+        overdueDays: 0,
+        urgency: 'low',
+        phases: [
+          { name: '建模', percentage: 15, startPercentage: 0, isCompleted: false, isCurrent: true },
+          { name: '渲染', percentage: 20, startPercentage: 15, isCompleted: false, isCurrent: false },
+          { name: '后期', percentage: 15, startPercentage: 35, isCompleted: false, isCurrent: false },
+          { name: '交付', percentage: 50, startPercentage: 50, isCompleted: false, isCurrent: false }
+        ]
+      },
+      {
+        id: 'proj-004',
+        name: '工业风办公室设计',
+        type: 'hard',
+        designerName: '赵六',
+        status: '进行中',
+        expectedEndDate: new Date(2023, 9, 10),
+        isOverdue: true,
+        overdueDays: 7,
+        urgency: 'high',
+        phases: [
+          { name: '建模', percentage: 15, startPercentage: 0, isCompleted: true, isCurrent: false },
+          { name: '渲染', percentage: 20, startPercentage: 15, isCompleted: true, isCurrent: false },
+          { name: '后期', percentage: 15, startPercentage: 35, isCompleted: false, isCurrent: false },
+          { name: '交付', percentage: 50, startPercentage: 50, isCompleted: false, isCurrent: false }
+        ]
+      }
+    ];
+
+    // 筛选超期项目
+    this.overdueProjects = this.projects.filter(project => project.isOverdue);
+    this.filteredProjects = [...this.projects];
+
+    // 显示超期提醒
+    if (this.overdueProjects.length > 0) {
+      this.showAlert = true;
+    }
+  }
+
+  loadTodoTasks(): void {
+    // 模拟待办任务数据
+    this.todoTasks = [
+      {
+        id: 'todo-001',
+        title: '待评审效果图',
+        description: '现代风格客厅设计项目需要进行效果图评审',
+        deadline: new Date(2023, 9, 18, 15, 0),
+        priority: 'high',
+        type: 'review',
+        targetId: 'proj-001'
+      },
+      {
+        id: 'todo-002',
+        title: '待分配项目',
+        description: '新中式厨房设计项目需要分配给合适的设计师',
+        deadline: new Date(2023, 9, 19, 10, 0),
+        priority: 'high',
+        type: 'assign',
+        targetId: 'proj-new'
+      },
+      {
+        id: 'todo-003',
+        title: '待确认绩效',
+        description: '9月份团队绩效需要进行审核确认',
+        deadline: new Date(2023, 9, 22, 18, 0),
+        priority: 'medium',
+        type: 'performance',
+        targetId: 'sep-2023'
+      },
+      {
+        id: 'todo-004',
+        title: '待处理客户反馈',
+        description: '北欧风格卧室设计项目有客户反馈需要处理',
+        deadline: new Date(2023, 9, 20, 14, 0),
+        priority: 'medium',
+        type: 'review',
+        targetId: 'proj-002'
+      },
+      {
+        id: 'todo-005',
+        title: '团队会议',
+        description: '每周团队进度沟通会议',
+        deadline: new Date(2023, 9, 18, 10, 0),
+        priority: 'low',
+        type: 'performance',
+        targetId: 'weekly-meeting'
+      }
+    ];
+
+    // 按优先级排序:紧急且重要 > 重要不紧急 > 紧急不重要
+    this.todoTasks.sort((a, b) => {
+      const priorityOrder = {
+        'high': 3,
+        'medium': 2,
+        'low': 1
+      };
+      return priorityOrder[b.priority] - priorityOrder[a.priority];
+    });
+  }
+
+  filterProjects(event: Event): void {
+    const target = event.target as HTMLSelectElement;
+    const filterValue = target.value;
+    
+    if (filterValue === 'all') {
+      this.filteredProjects = [...this.projects];
+    } else {
+      this.filteredProjects = this.projects.filter(project => project.type === filterValue);
+    }
+  }
+
+  filterByUrgency(event: Event): void {
+    const target = event.target as HTMLSelectElement;
+    const filterValue = target.value;
+    
+    if (filterValue === 'all') {
+      this.filteredProjects = [...this.projects];
+    } else {
+      this.filteredProjects = this.projects.filter(project => project.urgency === filterValue);
+    }
+  }
+
+  calculateWorkload(): void {
+    if (!this.workloadParams.area || this.workloadParams.area <= 0) {
+      alert('请输入有效的户型面积');
+      return;
+    }
+
+    // 模拟工作量计算逻辑
+    let modelingDays = 1;
+    let renderingDays = 1;
+    let modelingPrice = 50;
+    let renderingPrice = 200;
+
+    // 根据面积调整
+    if (this.workloadParams.area > 100) {
+      modelingDays += 1;
+      renderingDays += 0.5;
+    }
+    if (this.workloadParams.area > 200) {
+      modelingDays += 1;
+      renderingDays += 0.5;
+    }
+
+    // 根据风格复杂度调整
+    if (this.workloadParams.styleComplexity === 'medium') {
+      modelingDays += 1;
+      renderingDays += 0.5;
+      modelingPrice += 20;
+      renderingPrice += 50;
+    } else if (this.workloadParams.styleComplexity === 'complex') {
+      modelingDays += 2;
+      renderingDays += 1;
+      modelingPrice += 40;
+      renderingPrice += 100;
+    }
+
+    // 根据交付要求调整
+    if (this.workloadParams.deliveryRequirement === 'premium') {
+      modelingDays += 0.5;
+      renderingDays += 0.5;
+      modelingPrice += 30;
+      renderingPrice += 100;
+    } else if (this.workloadParams.deliveryRequirement === 'vip') {
+      modelingDays += 1;
+      renderingDays += 1;
+      modelingPrice += 50;
+      renderingPrice += 200;
+    }
+
+    this.workloadResult = {
+      modelingDays,
+      renderingDays,
+      modelingPrice,
+      renderingPrice
+    };
+  }
+
+  syncToProjectReview(): void {
+    if (!this.workloadResult) return;
+
+    // 在实际应用中,这里会调用API将评估结果同步到project-review板块
+    // 这里我们直接跳转到project-review页面
+    this.router.navigate(['/team-leader/project-review'], {
+      queryParams: {
+        modelingDays: this.workloadResult.modelingDays,
+        renderingDays: this.workloadResult.renderingDays,
+        modelingPrice: this.workloadResult.modelingPrice,
+        renderingPrice: this.workloadResult.renderingPrice,
+        area: this.workloadParams.area,
+        style: this.workloadParams.styleComplexity,
+        delivery: this.workloadParams.deliveryRequirement
+      }
+    });
+  }
+
+  navigateToTask(task: TodoTask): void {
+    switch (task.type) {
+      case 'review':
+        this.router.navigate(['team-leader/quality-management', task.targetId]);
+        break;
+      case 'assign':
+        this.router.navigate(['team-leader/project-review']);
+        break;
+      case 'performance':
+        this.router.navigate(['team-leader/team-management']);
+        break;
+    }
+  }
+
+  getPriorityLabel(priority: 'high' | 'medium' | 'low'): string {
+    const labels: Record<'high' | 'medium' | 'low', string> = {
+      'high': '紧急且重要',
+      'medium': '重要不紧急',
+      'low': '紧急不重要'
+    };
+    return labels[priority];
+  }
+
+  closeAlert(): void {
+    this.showAlert = false;
+  }
 }

+ 66 - 0
src/app/pages/team-leader/ios-theme.scss

@@ -0,0 +1,66 @@
+// 颜色变量
+$ios-primary: #0047AB; // 克莱茵蓝 - iOS风格的蓝色
+$ios-primary-light: #4D91F7; // 较浅的蓝色
+$ios-background: #FFFFFF; // 白色背景
+$ios-background-secondary: #F2F2F7; // 浅灰色背景
+$ios-background-tertiary: #E5E5EA; // 三级背景色 - 浅灰色
+$ios-card-background: #FFFFFF; // 卡片背景色
+$ios-text-primary: #000000; // 主要文本色
+$ios-text-secondary: #8E8E93; // 次要文本色
+$ios-text-tertiary: #C7C7CC; // 三级文本色
+$ios-border: #E5E5EA; // 边框颜色
+$ios-success: #34C759; // 成功色
+$ios-warning: #FF9500; // 警告色
+$ios-danger: #FF3B30; // 危险色
+$ios-info: #5AC8FA; // 信息色
+
+// 字体变量
+$ios-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+$ios-font-size-xs: 12px;
+$ios-font-size-sm: 14px;
+$ios-font-size-base: 16px;
+$ios-font-size-lg: 18px;
+$ios-font-size-xl: 22px;
+$ios-font-weight-light: 300;
+$ios-font-weight-regular: 400;
+$ios-font-weight-medium: 500;
+$ios-font-weight-semibold: 600;
+$ios-font-weight-bold: 700;
+
+// 圆角变量
+$ios-radius-sm: 6px;
+$ios-radius-md: 8px;
+$ios-radius-lg: 12px;
+$ios-radius-xl: 16px;
+$ios-radius-full: 9999px;
+
+// 阴影变量
+$ios-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
+$ios-shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
+$ios-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.05), 0 4px 6px rgba(0, 0, 0, 0.05);
+$ios-shadow-card: 0 2px 8px rgba(0, 0, 0, 0.05);
+
+// 间距变量
+$ios-spacing-xs: 4px;
+$ios-spacing-sm: 8px;
+$ios-spacing-md: 12px;
+$ios-spacing-lg: 16px;
+$ios-spacing-xl: 20px;
+$ios-spacing-xxl: 24px;
+$ios-spacing-xxxl: 32px;
+
+// 动画变量
+$ios-animation-fast: 0.2s;
+$ios-animation-normal: 0.3s;
+$ios-animation-slow: 0.5s;
+$ios-animation-easing: cubic-bezier(0.25, 0.8, 0.25, 1);
+
+// 交互反馈
+$ios-feedback-tap: transform 0.2s ease, box-shadow 0.2s ease;
+$ios-feedback-hover: transform 0.2s ease, box-shadow 0.2s ease;
+
+// iOS风格的滚动条
+$ios-scrollbar-width: 8px;
+$ios-scrollbar-track: $ios-background-secondary;
+$ios-scrollbar-thumb: $ios-text-tertiary;
+$ios-scrollbar-thumb-hover: $ios-text-secondary;

+ 194 - 1
src/app/pages/team-leader/project-review/project-review.html

@@ -1 +1,194 @@
-<p>project-review works!</p>
+<header class="project-review-header">
+  <h1>项目评审</h1>
+</header>
+
+<main class="project-review-main">
+  <!-- 效果图可行性测试 -->
+  <section class="feasibility-section">
+    <div class="section-header">
+      <h2>效果图可行性测试</h2>
+    </div>
+    
+    <div class="test-form">
+      <div class="form-group">
+        <label>客户需求对图描述</label>
+        <textarea [(ngModel)]="testForm.description" placeholder="请输入客户需求描述..."></textarea>
+      </div>
+      
+      <div class="form-group">
+        <label>上传效果图</label>
+        <div class="file-upload">
+          <input type="file" (change)="onFileSelected($event)" accept="image/png, image/jpeg">
+          <div class="upload-placeholder">
+            <span class="upload-icon">+</span>
+            <p>点击或拖拽图片到此处上传</p>
+            <p class="upload-hint">支持 PNG、JPG 格式</p>
+          </div>
+        </div>
+        
+        <div *ngIf="selectedImage" class="image-preview">
+          <img [src]="selectedImage" alt="效果图预览">
+          <button (click)="removeImage()" class="btn-remove">移除</button>
+        </div>
+      </div>
+      
+      <button (click)="runFeasibilityTest()" class="btn-run-test" [disabled]="!testForm.description || !selectedImage">
+        运行可行性测试
+      </button>
+    </div>
+    
+    <!-- 测试结果 -->
+    <div *ngIf="testResult" class="test-result">
+      <div class="result-header">
+        <h3>测试结果分析</h3>
+        <div class="result-tags">
+          <span [class]="'tag ' + (testResult.overallStatus === 'pass' ? 'pass' : testResult.overallStatus === 'warning' ? 'warning' : 'fail')">
+            {{ testResult.overallStatus === 'pass' ? '通过' : testResult.overallStatus === 'warning' ? '需修改' : '不通过' }}
+          </span>
+        </div>
+      </div>
+      
+      <div class="result-content">
+        <div class="result-section">
+          <h4>技术角度评估</h4>
+          <ul class="evaluation-list">
+            <li *ngFor="let item of testResult.technicalEvaluation">
+              <span class="eval-label">{{ item.name }}:</span>
+              <span [class]="'eval-value ' + item.status">{{ item.value }}%</span>
+              <span class="eval-status">{{ getStatusLabel(item.status) }}</span>
+            </li>
+          </ul>
+        </div>
+        
+        <div class="result-section">
+          <h4>需求角度评估</h4>
+          <p class="requirement-match">{{ testResult.requirementMatch }}</p>
+          <div class="suggestions">
+            <h5>修改建议:</h5>
+            <ul>
+              <li *ngFor="let suggestion of testResult.modificationSuggestions">{{ suggestion }}</li>
+            </ul>
+          </div>
+        </div>
+        
+        <div class="reference-images">
+          <h4>参考案例</h4>
+          <div class="image-grid">
+            <div *ngFor="let ref of testResult.referenceImages" class="reference-item">
+              <img [src]="ref.url" alt="参考案例">
+              <p class="reference-hint">{{ ref.hint }}</p>
+            </div>
+          </div>
+        </div>
+        
+        <div class="result-actions">
+          <button (click)="submitToQualityManagement()" class="btn-submit">提交至质量管理</button>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 项目分配审核与执行 -->
+  <section class="assignment-section">
+    <div class="section-header">
+      <h2>项目分配审核与执行</h2>
+    </div>
+    
+    <div class="assignment-form">
+      <div class="form-group">
+        <label>项目名称</label>
+        <select [(ngModel)]="assignmentForm.projectId">
+          <option value="">请选择项目</option>
+          <option *ngFor="let project of availableProjects" [value]="project.id">{{ project.name }}</option>
+        </select>
+      </div>
+      
+      <div class="form-group">
+        <label>分配方式</label>
+        <select [(ngModel)]="assignmentForm.assignmentType" (change)="onAssignmentTypeChange()">
+          <option value="customer-service">客服指定</option>
+          <option value="system-recommend">系统推荐</option>
+        </select>
+      </div>
+      
+      <!-- 客服指定分配 -->
+      <div *ngIf="assignmentForm.assignmentType === 'customer-service'" class="specified-assignment">
+        <div class="form-group">
+          <label>客服指定设计师</label>
+          <select [(ngModel)]="assignmentForm.specifiedDesignerId" (change)="checkDesignerWorkload()">
+            <option value="">请选择设计师</option>
+            <option *ngFor="let designer of designers" [value]="designer.id">{{ designer.name }}</option>
+          </select>
+        </div>
+        
+        <div *ngIf="designerWorkloadStatus" class="workload-status">
+          <span [class]="'status ' + designerWorkloadStatus.status">
+            {{ designerWorkloadStatus.message }}
+          </span>
+          
+          <div *ngIf="designerWorkloadStatus.status === 'busy'" class="alternative-suggestions">
+            <p>推荐备选设计师:</p>
+            <div class="designer-suggestions">
+              <div *ngFor="let suggestion of alternativeDesigners" class="designer-card">
+                <p class="designer-name">{{ suggestion.name }}</p>
+                <p class="designer-skill">擅长: {{ suggestion.skills }}</p>
+                <p class="designer-workload">工作量: {{ suggestion.workload }}%</p>
+                <button (click)="selectAlternativeDesigner(suggestion.id)" class="btn-select">选择</button>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 系统推荐分配 -->
+      <div *ngIf="assignmentForm.assignmentType === 'system-recommend'" class="recommended-assignment">
+        <div *ngIf="recommendedDesigners.length > 0" class="designer-recommendations">
+          <p>系统推荐设计师 (按能力匹配度排序):</p>
+          <div class="designer-cards">
+            <div *ngFor="let designer of recommendedDesigners" class="designer-card">
+              <div class="card-header">
+                <p class="designer-name">{{ designer.name }}</p>
+                <p class="match-score">匹配度: {{ designer.matchScore }}%</p>
+              </div>
+              <div class="card-body">
+                <p class="designer-skill">擅长: {{ designer.skills }}</p>
+                <p class="designer-workload">工作量: {{ designer.workload }}%</p>
+                <div class="designer-stats">
+                  <div class="stat-item">
+                    <span class="stat-label">完成率</span>
+                    <span class="stat-value">{{ designer.completionRate }}%</span>
+                  </div>
+                  <div class="stat-item">
+                    <span class="stat-label">满意度</span>
+                    <span class="stat-value">{{ designer.satisfactionRate }}%</span>
+                  </div>
+                </div>
+              </div>
+              <div class="card-footer">
+                <button (click)="confirmAssignment(designer.id)" class="btn-assign">确认分配</button>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      
+      <button (click)="executeAssignment()" class="btn-execute" [disabled]="!canExecuteAssignment()">
+        执行分配
+      </button>
+    </div>
+    
+    <!-- 分配结果 -->
+    <div *ngIf="assignmentResult" class="assignment-result">
+      <div class="result-content">
+        <div class="result-icon success">✓</div>
+        <h3>分配成功</h3>
+        <p>{{ assignmentResult.message }}</p>
+        <div class="result-details">
+          <p><strong>项目:</strong> {{ assignmentResult.projectName }}</p>
+          <p><strong>分配给:</strong> {{ assignmentResult.designerName }}</p>
+                <p><strong>分配时间:</strong> {{ assignmentResult.assignTime | date:'yyyy-MM-dd HH:mm' }}</p>
+        </div>
+      </div>
+    </div>
+  </section>
+</main>

+ 573 - 0
src/app/pages/team-leader/project-review/project-review.scss

@@ -0,0 +1,573 @@
+@import '../ios-theme.scss';
+
+.project-review-header {
+  background-color: $ios-primary;
+  color: white;
+  padding: 20px;
+  text-align: center;
+  border-radius: $ios-radius-xl;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+.project-review-main {
+  padding: 20px;
+}
+
+.section-header {
+  margin-bottom: 20px;
+  h2 {
+    color: $ios-primary;
+    font-size: 18px;
+    font-weight: 600;
+  }
+}
+
+.feasibility-section,
+.assignment-section {
+  background-color: white;
+  border-radius: $ios-radius-lg;
+  padding: 20px;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+/* 效果图可行性测试样式 */
+.test-form {
+  .form-group {
+    margin-bottom: 15px;
+    label {
+      display: block;
+      margin-bottom: 5px;
+      color: $ios-text-primary;
+      font-weight: 500;
+    }
+    textarea {
+      width: 100%;
+      padding: 10px;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius-lg;
+      font-size: 14px;
+      resize: vertical;
+      min-height: 100px;
+      &:focus {
+        outline: none;
+        border-color: $ios-primary;
+        box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+      }
+    }
+  }
+  
+  .file-upload {
+    position: relative;
+    .upload-placeholder {
+      border: 2px dashed $ios-border;
+      border-radius: $ios-radius-lg;
+      padding: 30px;
+      text-align: center;
+      cursor: pointer;
+      background-color: $ios-background-secondary;
+      transition: all 0.3s ease;
+      &:hover {
+        border-color: $ios-primary;
+        background-color: rgba(0, 71, 171, 0.05);
+      }
+      .upload-icon {
+        display: block;
+        font-size: 40px;
+        color: $ios-primary;
+        margin-bottom: 10px;
+      }
+      p {
+        margin: 5px 0;
+        color: $ios-text-secondary;
+      }
+      .upload-hint {
+        font-size: 12px;
+        color: $ios-text-tertiary;
+      }
+    }
+    input[type="file"] {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      opacity: 0;
+      cursor: pointer;
+    }
+  }
+  
+  .image-preview {
+    margin-top: 15px;
+    position: relative;
+    img {
+      max-width: 100%;
+      max-height: 300px;
+      border-radius: $ios-radius-lg;
+      display: block;
+      margin: 0 auto;
+    }
+    .btn-remove {
+      position: absolute;
+      top: 10px;
+      right: 10px;
+      background-color: red;
+      color: white;
+      border: none;
+      border-radius: 50%;
+      width: 30px;
+      height: 30px;
+      cursor: pointer;
+      font-size: 16px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+    }
+  }
+  
+  .btn-run-test {
+    background-color: $ios-primary;
+    color: white;
+    border: none;
+    border-radius: $ios-radius-lg;
+    padding: 12px 20px;
+    font-size: 16px;
+    font-weight: 500;
+    cursor: pointer;
+    width: 100%;
+    margin-top: 10px;
+    transition: background-color 0.3s ease;
+    &:hover:not(:disabled) {
+      background-color: $ios-primary-light;
+    }
+    &:disabled {
+      background-color: $ios-text-tertiary;
+      cursor: not-allowed;
+    }
+  }
+}
+
+/* 测试结果样式 */
+.test-result {
+  margin-top: 20px;
+  padding: 15px;
+  background-color: $ios-background-secondary;
+  border-radius: $ios-radius-lg;
+  
+  .result-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 15px;
+    h3 {
+      color: $ios-text-primary;
+      font-size: 16px;
+    }
+    .result-tags {
+      .tag {
+        padding: 5px 10px;
+        border-radius: 15px;
+        font-size: 12px;
+        font-weight: 500;
+        &.pass {
+          background-color: #d4edda;
+          color: #155724;
+        }
+        &.warning {
+          background-color: #fff3cd;
+          color: #856404;
+        }
+        &.fail {
+          background-color: #f8d7da;
+          color: #721c24;
+        }
+      }
+    }
+  }
+  
+  .result-content {
+    .result-section {
+      margin-bottom: 15px;
+      h4 {
+        color: $ios-text-primary;
+        font-size: 14px;
+        margin-bottom: 10px;
+        font-weight: 600;
+      }
+    }
+    
+    .evaluation-list {
+      list-style: none;
+      padding: 0;
+      li {
+        display: flex;
+        align-items: center;
+        margin-bottom: 8px;
+        .eval-label {
+          flex: 1;
+          color: $ios-text-primary;
+          font-size: 14px;
+        }
+        .eval-value {
+          margin: 0 10px;
+          font-weight: 600;
+          &.high {
+            color: #28a745;
+          }
+          &.medium {
+            color: #ffc107;
+          }
+          &.low {
+            color: #dc3545;
+          }
+        }
+        .eval-status {
+          font-size: 12px;
+          color: $ios-text-secondary;
+        }
+      }
+    }
+    
+    .requirement-match {
+      color: $ios-text-primary;
+      font-size: 14px;
+      margin-bottom: 10px;
+      line-height: 1.5;
+    }
+    
+    .suggestions {
+      h5 {
+        color: $ios-text-primary;
+        font-size: 13px;
+        margin-bottom: 5px;
+        font-weight: 600;
+      }
+      ul {
+        list-style: none;
+        padding: 0;
+        li {
+          color: $ios-text-secondary;
+          font-size: 13px;
+          margin-bottom: 5px;
+          padding-left: 15px;
+          position: relative;
+          &::before {
+            content: "•";
+            color: $ios-primary;
+            position: absolute;
+            left: 0;
+            font-weight: bold;
+          }
+        }
+      }
+    }
+    
+    .reference-images {
+      h4 {
+        color: $ios-text-primary;
+        font-size: 14px;
+        margin-bottom: 10px;
+        font-weight: 600;
+      }
+      .image-grid {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
+        gap: 10px;
+        .reference-item {
+          text-align: center;
+          img {
+            width: 100%;
+            height: 80px;
+            object-fit: cover;
+            border-radius: $ios-radius-lg;
+            margin-bottom: 5px;
+          }
+          .reference-hint {
+            font-size: 11px;
+            color: $ios-text-secondary;
+            text-align: left;
+          }
+        }
+      }
+    }
+    
+    .result-actions {
+      margin-top: 20px;
+      .btn-submit {
+        background-color: $ios-primary;
+        color: white;
+        border: none;
+        border-radius: $ios-radius-lg;
+        padding: 10px 20px;
+        font-size: 14px;
+        cursor: pointer;
+        transition: background-color 0.3s ease;
+        &:hover {
+          background-color: $ios-primary-light;
+        }
+      }
+    }
+  }
+}
+
+/* 项目分配审核与执行样式 */
+.assignment-form {
+  .form-group {
+    margin-bottom: 15px;
+    label {
+      display: block;
+      margin-bottom: 5px;
+      color: $ios-text-primary;
+      font-weight: 500;
+    }
+    select {
+      width: 100%;
+      padding: 10px;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius-lg;
+      font-size: 14px;
+      background-color: white;
+      &:focus {
+        outline: none;
+        border-color: $ios-primary;
+        box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+      }
+    }
+  }
+  
+  .specified-assignment,
+  .recommended-assignment {
+    margin-top: 15px;
+  }
+  
+  .workload-status {
+    margin-top: 10px;
+    .status {
+      padding: 8px 12px;
+      border-radius: $ios-radius-lg;
+      font-size: 14px;
+      display: inline-block;
+      &.idle {
+        background-color: #e3f2fd;
+        color: $ios-primary;
+      }
+      &.medium {
+        background-color: #fff3cd;
+        color: #856404;
+      }
+      &.busy {
+        background-color: #ffebee;
+        color: #c62828;
+      }
+    }
+    
+    .alternative-suggestions {
+      margin-top: 15px;
+      p {
+        color: $ios-text-primary;
+        font-weight: 500;
+        margin-bottom: 10px;
+        font-size: 14px;
+      }
+      .designer-suggestions {
+        display: grid;
+        grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+        gap: 10px;
+        .designer-card {
+          background-color: white;
+          padding: 12px;
+          border-radius: $ios-radius-lg;
+          border: 1px solid $ios-border;
+          .designer-name {
+            color: $ios-text-primary;
+            font-weight: 600;
+            margin-bottom: 5px;
+          }
+          .designer-skill,
+          .designer-workload {
+            font-size: 13px;
+            color: $ios-text-secondary;
+            margin: 3px 0;
+          }
+          .btn-select {
+            background-color: $ios-primary;
+            color: white;
+            border: none;
+            border-radius: $ios-radius-lg;
+            padding: 6px 12px;
+            font-size: 12px;
+            cursor: pointer;
+            margin-top: 8px;
+            &:hover {
+              background-color: $ios-primary-light;
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  .designer-recommendations {
+    p {
+      color: $ios-text-primary;
+      font-weight: 500;
+      margin-bottom: 15px;
+      font-size: 14px;
+    }
+    .designer-cards {
+      display: grid;
+      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+      gap: 15px;
+      .designer-card {
+        background-color: white;
+        border-radius: $ios-radius-lg;
+        border: 1px solid $ios-border;
+        overflow: hidden;
+        .card-header {
+          background-color: $ios-background-secondary;
+          padding: 12px;
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          .designer-name {
+            color: $ios-text-primary;
+            font-weight: 600;
+            margin: 0;
+          }
+          .match-score {
+            color: $ios-primary;
+            font-weight: 600;
+            font-size: 13px;
+            margin: 0;
+          }
+        }
+        .card-body {
+          padding: 12px;
+          .designer-skill,
+          .designer-workload {
+            font-size: 13px;
+            color: $ios-text-secondary;
+            margin: 5px 0;
+          }
+          .designer-stats {
+            display: flex;
+            margin-top: 10px;
+            .stat-item {
+              flex: 1;
+              .stat-label {
+                font-size: 12px;
+                color: $ios-text-tertiary;
+              }
+              .stat-value {
+                font-size: 14px;
+                font-weight: 600;
+                color: $ios-text-primary;
+              }
+            }
+          }
+        }
+        .card-footer {
+          padding: 12px;
+          border-top: 1px solid $ios-border;
+          .btn-assign {
+            background-color: $ios-primary;
+            color: white;
+            border: none;
+            border-radius: $ios-radius-lg;
+            padding: 8px 16px;
+            font-size: 14px;
+            cursor: pointer;
+            width: 100%;
+            &:hover {
+              background-color: $ios-primary-light;
+            }
+          }
+        }
+      }
+    }
+  }
+  
+  .btn-execute {
+    background-color: $ios-primary;
+    color: white;
+    border: none;
+    border-radius: $ios-radius-lg;
+    padding: 12px 20px;
+    font-size: 16px;
+    font-weight: 500;
+    cursor: pointer;
+    width: 100%;
+    margin-top: 20px;
+    transition: background-color 0.3s ease;
+    &:hover:not(:disabled) {
+      background-color: $ios-primary-light;
+    }
+    &:disabled {
+      background-color: $ios-text-tertiary;
+      cursor: not-allowed;
+    }
+  }
+}
+
+/* 分配结果样式 */
+.assignment-result {
+  margin-top: 20px;
+  background-color: $ios-background-secondary;
+  border-radius: $ios-radius-lg;
+  padding: 20px;
+  text-align: center;
+  
+  .result-content {
+    .result-icon {
+      width: 50px;
+      height: 50px;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin: 0 auto 15px;
+      font-size: 24px;
+      font-weight: bold;
+      &.success {
+        background-color: #d4edda;
+        color: #155724;
+      }
+    }
+    h3 {
+      color: $ios-text-primary;
+      margin-bottom: 10px;
+    }
+    p {
+      color: $ios-text-secondary;
+      margin-bottom: 15px;
+    }
+    .result-details {
+      background-color: white;
+      border-radius: $ios-radius-lg;
+      padding: 15px;
+      text-align: left;
+      p {
+        margin: 5px 0;
+        color: $ios-text-primary;
+      }
+    }
+  }
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .project-review-main {
+    padding: 10px;
+  }
+  
+  .feasibility-section,
+  .assignment-section {
+    padding: 15px;
+  }
+  
+  .designer-suggestions,
+  .designer-cards {
+    grid-template-columns: 1fr !important;
+  }
+}

+ 374 - 5
src/app/pages/team-leader/project-review/project-review.ts

@@ -1,11 +1,380 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+
+// 定义接口
+interface TestForm {
+  description: string;
+}
+
+interface TechnicalEvaluationItem {
+  name: string;
+  value: number;
+  status: 'high' | 'medium' | 'low';
+}
+
+interface ReferenceImage {
+  url: string;
+  hint: string;
+}
+
+interface TestResult {
+  overallStatus: 'pass' | 'warning' | 'fail';
+  technicalEvaluation: TechnicalEvaluationItem[];
+  requirementMatch: string;
+  modificationSuggestions: string[];
+  referenceImages: ReferenceImage[];
+}
+
+interface AssignmentForm {
+  projectId: string;
+  assignmentType: 'customer-service' | 'system-recommend';
+  specifiedDesignerId: string;
+}
+
+interface Designer {
+  id: string;
+  name: string;
+  skills: string;
+  workload: number;
+  completionRate: number;
+  satisfactionRate: number;
+  matchScore?: number;
+}
+
+interface DesignerWorkloadStatus {
+  status: 'idle' | 'medium' | 'busy';
+  message: string;
+}
+
+interface Project {
+  id: string;
+  name: string;
+  type: string;
+  complexity: string;
+  deadline: string;
+}
+
+interface AssignmentResult {
+  message: string;
+  projectName: string;
+  designerName: string;
+  assignTime: Date;
+}
 
 @Component({
   selector: 'app-project-review',
-  imports: [],
   templateUrl: './project-review.html',
-  styleUrl: './project-review.scss'
+  styleUrls: ['./project-review.scss'],
+  standalone: true,
+  imports: [FormsModule, CommonModule]
 })
-export class ProjectReview {
-
+export class ProjectReviewComponent implements OnInit {
+  // 表单数据
+  testForm: TestForm = {
+    description: ''
+  };
+  
+  assignmentForm: AssignmentForm = {
+    projectId: '',
+    assignmentType: 'customer-service',
+    specifiedDesignerId: ''
+  };
+  
+  // 状态数据
+  selectedImage: string | null = null;
+  testResult: TestResult | null = null;
+  designerWorkloadStatus: DesignerWorkloadStatus | null = null;
+  assignmentResult: AssignmentResult | null = null;
+  
+  // 模拟数据
+  availableProjects: Project[] = [];
+  designers: Designer[] = [];
+  alternativeDesigners: Designer[] = [];
+  recommendedDesigners: Designer[] = [];
+  
+  constructor(private route: ActivatedRoute, private router: Router) {}
+  
+  ngOnInit(): void {
+    this.loadMockData();
+  }
+  
+  // 加载模拟数据
+  loadMockData(): void {
+    // 模拟项目数据
+    this.availableProjects = [
+      { id: '1', name: '现代风格80㎡软装设计', type: '软装', complexity: '中等', deadline: '2024-11-15' },
+      { id: '2', name: '新中式客厅效果图', type: '硬装', complexity: '高', deadline: '2024-11-20' },
+      { id: '3', name: '北欧风格卧室改造', type: '软装', complexity: '低', deadline: '2024-11-10' },
+      { id: '4', name: '宋式风格别墅客厅', type: '硬装', complexity: '高', deadline: '2024-12-05' }
+    ];
+    
+    // 模拟设计师数据
+    this.designers = [
+      { id: '101', name: '张三', skills: '现代风格、北欧风格', workload: 90, completionRate: 95, satisfactionRate: 92 },
+      { id: '102', name: '李四', skills: '新中式、宋式风格', workload: 45, completionRate: 90, satisfactionRate: 88 },
+      { id: '103', name: '王五', skills: '北欧风格、日式风格', workload: 60, completionRate: 85, satisfactionRate: 90 },
+      { id: '104', name: '赵六', skills: '现代风格、轻奢风格', workload: 30, completionRate: 88, satisfactionRate: 94 }
+    ];
+  }
+  
+  // 文件选择处理
+  onFileSelected(event: Event): void {
+    const input = event.target as HTMLInputElement;
+    if (input.files && input.files[0]) {
+      const reader = new FileReader();
+      reader.onload = (e) => {
+        this.selectedImage = e.target?.result as string;
+      };
+      reader.readAsDataURL(input.files[0]);
+    }
+  }
+  
+  // 移除图片
+  removeImage(): void {
+    this.selectedImage = null;
+  }
+  
+  // 运行可行性测试
+  runFeasibilityTest(): void {
+    // 模拟测试过程
+    // 在实际应用中,这里应该调用后端API进行真实的可行性测试
+    
+    // 模拟加载效果
+    setTimeout(() => {
+      // 生成模拟测试结果
+      const technicalEvaluation: TechnicalEvaluationItem[] = [
+        { name: '氛围匹配度', value: Math.floor(Math.random() * 30) + 70, status: 'high' },
+        { name: '美感达标率', value: Math.floor(Math.random() * 40) + 60, status: 'medium' },
+        { name: '渲染真实度', value: Math.floor(Math.random() * 30) + 70, status: 'high' }
+      ];
+      
+      // 根据技术评估计算总体状态
+      const avgScore = technicalEvaluation.reduce((sum, item) => sum + item.value, 0) / technicalEvaluation.length;
+      let overallStatus: 'pass' | 'warning' | 'fail';
+      if (avgScore >= 80) {
+        overallStatus = 'pass';
+      } else if (avgScore >= 60) {
+        overallStatus = 'warning';
+      } else {
+        overallStatus = 'fail';
+      }
+      
+      // 模拟参考图片(使用国内CDN)
+      const referenceImages: ReferenceImage[] = [
+        { url: 'https://img.alicdn.com/imgextra/i3/1111111111/O1CN01abcdefg_1234567890.jpg_220x220xz.jpg', hint: '宋式风格软装布局参考' },
+        { url: 'https://img.alicdn.com/imgextra/i4/2222222222/O1CN01hijklmn_1234567890.jpg_220x220xz.jpg', hint: '暖色调灯光效果参考' },
+        { url: 'https://img.alicdn.com/imgextra/i5/3333333333/O1CN01opqrstu_1234567890.jpg_220x220xz.jpg', hint: '客厅空间划分参考' }
+      ];
+      
+      // 模拟修改建议
+      const modificationSuggestions = [
+        '调整灯光色温,使其更符合暖色调要求',
+        '增加一些宋式风格的装饰元素',
+        '优化空间层次感,增强视觉深度'
+      ];
+      
+      this.testResult = {
+        overallStatus,
+        technicalEvaluation,
+        requirementMatch: '整体符合客户需求,但在风格细节和色彩匹配上还有优化空间',
+        modificationSuggestions,
+        referenceImages
+      };
+    }, 1500);
+  }
+  
+  // 获取状态标签
+  getStatusLabel(status: string): string {
+    switch (status) {
+      case 'high':
+        return '优秀';
+      case 'medium':
+        return '一般';
+      case 'low':
+        return '较差';
+      default:
+        return '';
+    }
+  }
+  
+  // 提交至质量管理
+  submitToQualityManagement(): void {
+    // 在实际应用中,这里应该调用API将测试结果提交到质量管理模块
+    alert('测试结果已提交至质量管理模块!');
+    // 跳转到质量管理页面
+    this.router.navigate(['team-leader/quality-management']);
+  }
+  
+  // 分配类型变更处理
+  onAssignmentTypeChange(): void {
+    this.assignmentForm.specifiedDesignerId = '';
+    this.designerWorkloadStatus = null;
+    this.alternativeDesigners = [];
+    this.recommendedDesigners = [];
+    
+    // 如果选择系统推荐,自动获取推荐设计师
+    if (this.assignmentForm.assignmentType === 'system-recommend' && this.assignmentForm.projectId) {
+      this.getRecommendedDesigners();
+    }
+  }
+  
+  // 检查设计师工作量
+  checkDesignerWorkload(): void {
+    if (!this.assignmentForm.specifiedDesignerId) {
+      this.designerWorkloadStatus = null;
+      return;
+    }
+    
+    const designer = this.designers.find(d => d.id === this.assignmentForm.specifiedDesignerId);
+    if (designer) {
+      let status: 'idle' | 'medium' | 'busy';
+      let message: string;
+      
+      if (designer.workload <= 50) {
+        status = 'idle';
+        message = `${designer.name} 当前工作量充足(${designer.workload}%)`;
+      } else if (designer.workload <= 80) {
+        status = 'medium';
+        message = `${designer.name} 当前工作量适中(${designer.workload}%)`;
+      } else {
+        status = 'busy';
+        message = `${designer.name} 当前工作量较高(${designer.workload}%)`;
+        // 生成备选设计师
+        this.generateAlternativeDesigners();
+      }
+      
+      this.designerWorkloadStatus = { status, message };
+    }
+  }
+  
+  // 生成备选设计师
+  generateAlternativeDesigners(): void {
+    // 筛选工作量≤60%的设计师
+    this.alternativeDesigners = this.designers
+      .filter(d => d.id !== this.assignmentForm.specifiedDesignerId && d.workload <= 60)
+      .slice(0, 3);
+  }
+  
+  // 选择备选设计师
+  selectAlternativeDesigner(designerId: string): void {
+    this.assignmentForm.specifiedDesignerId = designerId;
+    this.checkDesignerWorkload();
+  }
+  
+  // 获取推荐设计师
+  getRecommendedDesigners(): void {
+    // 在实际应用中,这里应该根据项目需求和设计师能力进行智能推荐
+    // 这里使用模拟数据生成推荐
+    if (!this.assignmentForm.projectId) {
+      this.recommendedDesigners = [];
+      return;
+    }
+    
+    const selectedProject = this.availableProjects.find(p => p.id === this.assignmentForm.projectId);
+    if (!selectedProject) {
+      return;
+    }
+    
+    // 根据项目类型和复杂度生成推荐分数
+    this.recommendedDesigners = this.designers
+      .map(designer => {
+        let matchScore = 50; // 基础分数
+        
+        // 根据项目类型调整匹配分数
+        if (selectedProject.type === '软装' && designer.skills.includes('现代风格')) {
+          matchScore += 20;
+        } else if (selectedProject.type === '硬装' && designer.skills.includes('中式')) {
+          matchScore += 25;
+        }
+        
+        // 根据工作量调整匹配分数
+        if (designer.workload <= 30) {
+          matchScore += 20;
+        } else if (designer.workload <= 60) {
+          matchScore += 10;
+        }
+        
+        // 根据完成率和满意度调整分数
+        matchScore += (designer.completionRate - 80) / 5;
+        matchScore += (designer.satisfactionRate - 85) / 5;
+        
+        return { ...designer, matchScore: Math.min(Math.max(Math.round(matchScore), 0), 100) };
+      })
+      .filter(designer => designer.workload <= 60) // 只推荐工作量≤60%的设计师
+      .sort((a, b) => b.matchScore! - a.matchScore!)
+      .slice(0, 3);
+  }
+  
+  // 确认推荐设计师分配
+  confirmAssignment(designerId: string): void {
+    this.assignmentForm.specifiedDesignerId = designerId;
+  }
+  
+  // 检查是否可以执行分配
+  canExecuteAssignment(): boolean {
+    if (!this.assignmentForm.projectId || !this.assignmentForm.specifiedDesignerId) {
+      return false;
+    }
+    
+    // 如果是客服指定分配,需要检查工作量状态是否为idle或medium
+    if (this.assignmentForm.assignmentType === 'customer-service' && 
+        this.designerWorkloadStatus && 
+        this.designerWorkloadStatus.status === 'busy') {
+      return false;
+    }
+    
+    return true;
+  }
+  
+  // 执行分配
+  executeAssignment(): void {
+    if (!this.canExecuteAssignment()) {
+      return;
+    }
+    
+    const selectedProject = this.availableProjects.find(p => p.id === this.assignmentForm.projectId);
+    const selectedDesigner = this.designers.find(d => d.id === this.assignmentForm.specifiedDesignerId);
+    
+    if (selectedProject && selectedDesigner) {
+      // 模拟分配过程
+      setTimeout(() => {
+        this.assignmentResult = {
+          message: `项目已成功分配给设计师 ${selectedDesigner.name}`,
+          projectName: selectedProject.name,
+          designerName: selectedDesigner.name,
+          assignTime: new Date()
+        };
+        
+        // 在实际应用中,这里应该调用API更新项目分配状态
+        // 并同步到dashboard和设计师工作台
+        
+        // 显示成功消息后,重置表单
+        setTimeout(() => {
+          this.resetAssignmentForm();
+        }, 3000);
+      }, 1000);
+    }
+  }
+  
+  // 重置分配表单
+  resetAssignmentForm(): void {
+    this.assignmentForm = {
+      projectId: '',
+      assignmentType: 'customer-service',
+      specifiedDesignerId: ''
+    };
+    this.designerWorkloadStatus = null;
+    this.alternativeDesigners = [];
+    this.recommendedDesigners = [];
+    this.assignmentResult = null;
+  }
+  
+  // 项目选择变更处理
+  onProjectChange(): void {
+    if (this.assignmentForm.assignmentType === 'system-recommend') {
+      this.getRecommendedDesigners();
+    }
+  }
 }

+ 305 - 1
src/app/pages/team-leader/quality-management/quality-management.html

@@ -1 +1,305 @@
-<p>quality-management works!</p>
+<header class="quality-management-header">
+  <h1>质量管理</h1>
+</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>
+    
+    <div class="sop-tabs">
+      <div class="tab-buttons">
+        <button (click)="activeTab = 'modeling'" [class.active]="activeTab === 'modeling'">建模阶段</button>
+        <button (click)="activeTab = 'rendering'" [class.active]="activeTab === 'rendering'">渲染阶段</button>
+        <button (click)="activeTab = 'postProduction'" [class.active]="activeTab === 'postProduction'">后期阶段</button>
+      </div>
+      
+      <div class="tab-content">
+        <!-- 建模阶段标准 -->
+        <div *ngIf="activeTab === 'modeling'" class="phase-content">
+          <div class="sop-section">
+            <h3>交付物要求</h3>
+            <ul class="requirement-list">
+              <li>提交完整的3D模型文件</li>
+              <li>提供户型匹配度检查报告,误差≤2%</li>
+              <li>材质贴图完整且正确命名</li>
+              <li>灯光方案初步设置</li>
+            </ul>
+          </div>
+          
+          <div class="sop-section">
+            <h3>质量验收指标</h3>
+            <table class="quality-table">
+              <thead>
+                <tr>
+                  <th>指标项</th>
+                  <th>普通客户</th>
+                  <th>优质客户</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td>模型精度</td>
+                  <td>≥95%</td>
+                  <td>≥98%</td>
+                </tr>
+                <tr>
+                  <td>户型匹配度</td>
+                  <td>≥98%</td>
+                  <td>≥99%</td>
+                </tr>
+                <tr>
+                  <td>材质还原度</td>
+                  <td>≥90%</td>
+                  <td>≥95%</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          
+          <div class="sop-section">
+            <h3>整改规则</h3>
+            <ul class="rule-list">
+              <li>质量不达标项需24小时内修改</li>
+              <li>修改超2次需组长复核</li>
+              <li>重大错误(如户型严重不符)需重新建模</li>
+            </ul>
+          </div>
+        </div>
+        
+        <!-- 渲染阶段标准 -->
+        <div *ngIf="activeTab === 'rendering'" class="phase-content">
+          <div class="sop-section">
+            <h3>交付物要求</h3>
+            <ul class="requirement-list">
+              <li>提交高清渲染图(PSD+JPG)</li>
+              <li>提供多角度渲染预览(至少3个角度)</li>
+              <li>保留渲染参数文件</li>
+            </ul>
+          </div>
+          
+          <div class="sop-section">
+            <h3>质量验收指标</h3>
+            <table class="quality-table">
+              <thead>
+                <tr>
+                  <th>指标项</th>
+                  <th>普通客户</th>
+                  <th>优质客户</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td>像素要求</td>
+                  <td>≥800px</td>
+                  <td>≥1200px</td>
+                </tr>
+                <tr>
+                  <td>真实度</td>
+                  <td>≥90%</td>
+                  <td>≥95%</td>
+                </tr>
+                <tr>
+                  <td>光影效果</td>
+                  <td>自然流畅</td>
+                  <td>专业级光影处理</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          
+          <div class="sop-section">
+            <h3>整改规则</h3>
+            <ul class="rule-list">
+              <li>渲染效果不满意项需18小时内修改</li>
+              <li>修改超3次需重新设计灯光方案</li>
+              <li>客户特殊要求需单独确认</li>
+            </ul>
+          </div>
+        </div>
+        
+        <!-- 后期阶段标准 -->
+        <div *ngIf="activeTab === 'postProduction'" class="phase-content">
+          <div class="sop-section">
+            <h3>交付物要求</h3>
+            <ul class="requirement-list">
+              <li>提交最终效果图(JPG+PNG透明底)</li>
+              <li>提供颜色校正前后对比图</li>
+              <li>保留PSD源文件</li>
+            </ul>
+          </div>
+          
+          <div class="sop-section">
+            <h3>质量验收指标</h3>
+            <table class="quality-table">
+              <thead>
+                <tr>
+                  <th>指标项</th>
+                  <th>普通客户</th>
+                  <th>优质客户</th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td>色彩准确度</td>
+                  <td>符合设计稿</td>
+                  <td>专业级色彩管理</td>
+                </tr>
+                <tr>
+                  <td>细节处理</td>
+                  <td>无明显瑕疵</td>
+                  <td>精细处理每一处细节</td>
+                </tr>
+                <tr>
+                  <td>文件格式</td>
+                  <td>JPG (300dpi)</td>
+                  <td>JPG+PNG (350dpi)</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+          
+          <div class="sop-section">
+            <h3>整改规则</h3>
+            <ul class="rule-list">
+              <li>后期处理不满意项需12小时内修改</li>
+              <li>颜色偏差需重新进行色彩校正</li>
+              <li>最终交付需客户确认签字</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 效果图质量整改跟踪 -->
+  <section class="rectification-section">
+    <div class="section-header">
+      <h2>质量整改跟踪</h2>
+      <div class="search-filter">
+        <input type="text" placeholder="搜索项目名称..." [(ngModel)]="searchTerm">
+        <select [(ngModel)]="filterStatus">
+          <option value="all">全部状态</option>
+          <option value="pending">待处理</option>
+          <option value="processing">处理中</option>
+          <option value="review">待审核</option>
+          <option value="completed">已完成</option>
+        </select>
+      </div>
+    </div>
+    
+    <div class="rectification-list">
+      <div *ngFor="let task of filteredTasks" class="rectification-task" [class.priority-high]="task.priority === 'high'">
+        <div class="task-header">
+          <h3>{{ task.projectName }}</h3>
+          <span [class]="'status ' + task.status">{{ getStatusText(task.status) }}</span>
+        </div>
+        
+        <div class="task-details">
+          <div class="detail-item">
+            <span class="label">负责组员:</span>
+            <span class="value">{{ task.designerName }}</span>
+          </div>
+          <div class="detail-item">
+            <span class="label">问题描述:</span>
+            <span class="value">{{ task.issueDescription }}</span>
+          </div>
+          <div class="detail-item">
+            <span class="label">优先级:</span>
+            <span [class]="'priority ' + task.priority">{{ getPriorityText(task.priority) }}</span>
+          </div>
+          <div class="detail-item">
+            <span class="label">建议完成时间:</span>
+            <span class="value">{{ task.suggestedDeadline | date:'yyyy-MM-dd' }}</span>
+          </div>
+          
+          <div *ngIf="task.sopComplianceScore !== null" class="detail-item">
+            <span class="label">SOP符合度评分:</span>
+            <span class="value score">{{ task.sopComplianceScore }}/100</span>
+          </div>
+          
+          <div *ngIf="task.managerComment" class="detail-item comment">
+            <span class="label">组长评语:</span>
+            <span class="value">{{ task.managerComment }}</span>
+          </div>
+        </div>
+        
+        <div class="task-actions">
+          <button (click)="viewTaskDetails(task.id)" class="btn-view">查看详情</button>
+          
+          <div *ngIf="task.status === 'review'">
+            <button (click)="approveTask(task.id)" class="btn-approve">通过</button>
+            <button (click)="rejectTask(task.id)" class="btn-reject">驳回</button>
+          </div>
+          
+          <div *ngIf="task.status === 'completed'">
+            <button (click)="syncToProjectReview(task.id)" class="btn-sync">同步至项目评审</button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 能力提升工具集成 -->
+  <section class="training-section">
+    <div class="section-header">
+      <h2>能力提升工具</h2>
+    </div>
+    
+    <div class="training-content">
+      <div class="video-tutorials">
+        <h3>视频教程</h3>
+        <div class="video-list">
+          <div *ngFor="let video of videoTutorials" class="video-item">
+            <div class="video-thumbnail">
+              <img [src]="video.thumbnailUrl" alt="视频缩略图">
+              <div class="video-duration">{{ video.duration }}</div>
+            </div>
+            <div class="video-info">
+              <h4>{{ video.title }}</h4>
+              <p class="video-description">{{ video.description }}</p>
+              <div class="video-meta">
+                <span class="category">{{ video.category }}</span>
+                <span class="views">{{ video.views }} 次观看</span>
+              </div>
+              <button (click)="playVideo(video.id)" class="btn-play">播放</button>
+            </div>
+          </div>
+        </div>
+      </div>
+      
+      <div class="practice-assignments">
+        <h3>实践作业</h3>
+        <div class="assignment-list">
+          <div *ngFor="let assignment of practiceAssignments" class="assignment-item">
+            <div class="assignment-header">
+              <h4>{{ assignment.title }}</h4>
+              <span [class]="'status ' + assignment.status">{{ getAssignmentStatusText(assignment.status) }}</span>
+            </div>
+            <div class="assignment-details">
+              <p class="description">{{ assignment.description }}</p>
+              <div class="detail-item">
+                <span class="label">关联SOP:</span>
+                <span class="value">{{ assignment.relatedSOP }}</span>
+              </div>
+              <div class="detail-item">
+                <span class="label">截止日期:</span>
+                <span class="value">{{ assignment.deadline | date:'yyyy-MM-dd' }}</span>
+              </div>
+              <div *ngIf="assignment.score !== null" class="detail-item">
+                <span class="label">得分:</span>
+                <span class="value score">{{ assignment.score }}/100</span>
+              </div>
+            </div>
+            <div class="assignment-actions">
+              <button (click)="reviewAssignment(assignment.id)" class="btn-review">评审作业</button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+</main>

+ 523 - 0
src/app/pages/team-leader/quality-management/quality-management.scss

@@ -0,0 +1,523 @@
+@import '../ios-theme.scss';
+
+// 质量管理页面容器
+.quality-management-main {
+  padding: $ios-spacing-lg;
+  max-width: 1200px;
+  margin: 0 auto;
+}
+
+// 页面标题
+.quality-management-header {
+  padding: $ios-spacing-lg $ios-spacing-lg $ios-spacing-md;
+  border-bottom: 1px solid $ios-border;
+  h1 {
+    font-size: $ios-font-size-xl;
+    font-weight: $ios-font-weight-semibold;
+    color: $ios-text-primary;
+    margin: 0;
+  }
+}
+
+// 内容区域
+.quality-management-content {
+  padding: $ios-spacing-lg 0;
+}
+
+// 筛选区域
+.filter-section {
+  margin-bottom: $ios-spacing-xl;
+  .filter-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: $ios-spacing-md;
+    h2 {
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      color: $ios-text-primary;
+      margin: 0;
+    }
+  }
+  .filter-controls {
+    display: flex;
+    flex-wrap: wrap;
+    gap: $ios-spacing-md;
+    align-items: flex-end;
+  }
+  .filter-item {
+    flex: 1;
+    min-width: 200px;
+    .label {
+      display: block;
+      font-size: $ios-font-size-sm;
+      font-weight: $ios-font-weight-medium;
+      color: $ios-text-secondary;
+      margin-bottom: $ios-spacing-xs;
+    }
+    input,
+    select {
+      width: 100%;
+      padding: $ios-spacing-sm $ios-spacing-md;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius-md;
+      background-color: $ios-background;
+      color: $ios-text-primary;
+      font-size: $ios-font-size-base;
+      &:focus {
+        outline: none;
+        border-color: $ios-primary;
+        box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+      }
+    }
+  }
+  .search-button {
+    padding: $ios-spacing-sm $ios-spacing-xl;
+    background-color: $ios-primary;
+    color: white;
+    border: none;
+    border-radius: $ios-radius-md;
+    font-size: $ios-font-size-base;
+    font-weight: $ios-font-weight-medium;
+    cursor: pointer;
+    transition: background-color 0.2s ease;
+    &:hover {
+      background-color: $ios-primary-light;
+    }
+    &:disabled {
+      background-color: $ios-text-tertiary;
+      cursor: not-allowed;
+    }
+  }
+}
+
+// 评分区间筛选
+.score-range-filter {
+  display: flex;
+  align-items: center;
+  gap: $ios-spacing-sm;
+  .score-input {
+    width: 80px;
+  }
+  .score-separator {
+    color: $ios-text-secondary;
+  }
+}
+
+// 检查任务列表
+.task-list {
+  margin-bottom: $ios-spacing-xl;
+  .task-list-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: $ios-spacing-md;
+    h2 {
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      color: $ios-text-primary;
+      margin: 0;
+    }
+    .view-toggle {
+      display: flex;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius-md;
+      overflow: hidden;
+      .toggle-button {
+        padding: $ios-spacing-xs $ios-spacing-md;
+        background-color: $ios-background;
+        border: none;
+        color: $ios-text-secondary;
+        cursor: pointer;
+        transition: all 0.2s ease;
+        &.active {
+          background-color: $ios-primary;
+          color: white;
+        }
+        &:hover:not(.active) {
+          background-color: $ios-background-secondary;
+        }
+      }
+    }
+  }
+}
+
+// 任务卡片
+.task-card {
+  background-color: $ios-background;
+  border: 1px solid $ios-border;
+  border-radius: $ios-radius-md;
+  padding: $ios-spacing-lg;
+  margin-bottom: $ios-spacing-md;
+  transition: all 0.3s ease;
+  &:hover {
+    box-shadow: $ios-shadow-md;
+    transform: translateY(-1px);
+  }
+  .task-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    margin-bottom: $ios-spacing-md;
+    .task-info {
+      flex: 1;
+      h3 {
+        font-size: $ios-font-size-lg;
+        font-weight: $ios-font-weight-medium;
+        color: $ios-text-primary;
+        margin: 0 0 $ios-spacing-xs 0;
+      }
+      .task-meta {
+        display: flex;
+        gap: $ios-spacing-md;
+        font-size: $ios-font-size-sm;
+        color: $ios-text-secondary;
+        .task-status {
+          padding: $ios-spacing-xs $ios-spacing-sm;
+          border-radius: $ios-radius-full;
+          background-color: $ios-background-secondary;
+          font-weight: $ios-font-weight-medium;
+        }
+      }
+    }
+    .task-actions {
+      display: flex;
+      gap: $ios-spacing-sm;
+    }
+  }
+  .task-body {
+    margin-bottom: $ios-spacing-md;
+    .task-description {
+      font-size: $ios-font-size-base;
+      color: $ios-text-primary;
+      margin: 0 0 $ios-spacing-sm 0;
+      line-height: 1.5;
+    }
+    .task-details {
+      display: flex;
+      flex-wrap: wrap;
+      gap: $ios-spacing-md;
+      margin-bottom: $ios-spacing-sm;
+      .detail-item {
+        display: flex;
+        align-items: center;
+        font-size: $ios-font-size-sm;
+        .label {
+          font-weight: $ios-font-weight-medium;
+          color: $ios-text-secondary;
+          margin-right: $ios-spacing-xs;
+        }
+        .value {
+          color: $ios-text-primary;
+        }
+      }
+    }
+  }
+  .task-footer {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    .task-assignee {
+      display: flex;
+      align-items: center;
+      font-size: $ios-font-size-sm;
+      color: $ios-text-secondary;
+      .avatar {
+        width: 32px;
+        height: 32px;
+        border-radius: $ios-radius-full;
+        margin-right: $ios-spacing-xs;
+      }
+    }
+    .task-deadline {
+      font-size: $ios-font-size-sm;
+      color: $ios-text-secondary;
+    }
+  }
+}
+
+// 操作按钮
+.action-button {
+  padding: $ios-spacing-xs $ios-spacing-md;
+  border: 1px solid $ios-border;
+  border-radius: $ios-radius-md;
+  background-color: $ios-background;
+  color: $ios-text-primary;
+  font-size: $ios-font-size-sm;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  &:hover {
+    background-color: $ios-background-secondary;
+  }
+  &.primary {
+    background-color: $ios-primary;
+    border-color: $ios-primary;
+    color: white;
+    &:hover {
+      background-color: $ios-primary-light;
+    }
+  }
+  &.danger {
+    background-color: $ios-danger;
+    border-color: $ios-danger;
+    color: white;
+    &:hover {
+      background-color: #FF453A;
+    }
+  }
+}
+
+// 分页控件
+.pagination {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  gap: $ios-spacing-xs;
+  margin-top: $ios-spacing-xl;
+  .page-button {
+    width: 36px;
+    height: 36px;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-md;
+    background-color: $ios-background;
+    color: $ios-text-primary;
+    font-size: $ios-font-size-sm;
+    cursor: pointer;
+    transition: all 0.2s ease;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    &:hover:not(:disabled) {
+      background-color: $ios-background-secondary;
+    }
+    &.active {
+      background-color: $ios-primary;
+      border-color: $ios-primary;
+      color: white;
+    }
+    &:disabled {
+      color: $ios-text-tertiary;
+      cursor: not-allowed;
+    }
+  }
+  .page-info {
+    font-size: $ios-font-size-sm;
+    color: $ios-text-secondary;
+    margin: 0 $ios-spacing-md;
+  }
+}
+
+// 培训资源区域
+.training-section {
+  margin-bottom: $ios-spacing-xl;
+  .section-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: $ios-spacing-md;
+    h2 {
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      color: $ios-text-primary;
+      margin: 0;
+    }
+  }
+}
+
+// SOP标签页
+.sop-tabs {
+  margin-bottom: $ios-spacing-lg;
+  .tab-buttons {
+    display: flex;
+    border-bottom: 1px solid $ios-border;
+    margin-bottom: $ios-spacing-lg;
+    .tab-button {
+      padding: $ios-spacing-md $ios-spacing-xl;
+      background-color: transparent;
+      border: none;
+      border-bottom: 2px solid transparent;
+      color: $ios-text-secondary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      &.active {
+        color: $ios-primary;
+        border-bottom-color: $ios-primary;
+      }
+      &:hover:not(.active) {
+        color: $ios-text-primary;
+      }
+    }
+  }
+}
+
+// 视频列表
+.video-list {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: $ios-spacing-lg;
+  .video-item {
+    background-color: $ios-background;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-md;
+    overflow: hidden;
+    transition: all 0.3s ease;
+    &:hover {
+      box-shadow: $ios-shadow-md;
+      transform: translateY(-1px);
+    }
+    .video-thumbnail {
+      position: relative;
+      img {
+        width: 100%;
+        height: auto;
+        display: block;
+      }
+      .video-duration {
+        position: absolute;
+        bottom: $ios-spacing-xs;
+        right: $ios-spacing-xs;
+        background-color: rgba(0, 0, 0, 0.7);
+        color: white;
+        padding: 2px $ios-spacing-xs;
+        border-radius: $ios-radius-sm;
+        font-size: $ios-font-size-xs;
+      }
+    }
+    .video-info {
+      padding: $ios-spacing-md;
+      h4 {
+        font-size: $ios-font-size-base;
+        font-weight: $ios-font-weight-medium;
+        color: $ios-text-primary;
+        margin: 0 0 $ios-spacing-xs 0;
+      }
+      .video-description {
+        font-size: $ios-font-size-sm;
+        color: $ios-text-secondary;
+        margin: 0 0 $ios-spacing-xs 0;
+        line-height: 1.4;
+      }
+      .video-meta {
+        display: flex;
+        gap: $ios-spacing-md;
+        font-size: $ios-font-size-xs;
+        color: $ios-text-tertiary;
+        margin-bottom: $ios-spacing-sm;
+      }
+    }
+  }
+}
+
+// 审核任务列表
+.assignment-list {
+  display: flex;
+  flex-direction: column;
+  gap: $ios-spacing-md;
+}
+
+// 审核任务项
+.assignment-item {
+  padding: $ios-spacing-md;
+  border: 1px solid $ios-border;
+  border-radius: $ios-radius-md;
+  background-color: $ios-background-secondary;
+  transition: all 0.3s ease;
+  &:hover {
+    box-shadow: $ios-shadow-md;
+    transform: translateY(-1px);
+  }
+  .assignment-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: $ios-spacing-sm;
+    h4 {
+      font-size: $ios-font-size-base;
+      font-weight: $ios-font-weight-medium;
+      color: $ios-text-primary;
+      margin: 0;
+    }
+  }
+  .assignment-details {
+    margin-bottom: $ios-spacing-md;
+    .description {
+      font-size: $ios-font-size-sm;
+      color: $ios-text-secondary;
+      margin: 0 0 $ios-spacing-sm 0;
+      line-height: 1.4;
+    }
+    .detail-item {
+      display: flex;
+      margin-bottom: $ios-spacing-xs;
+      .label {
+        font-weight: $ios-font-weight-medium;
+        color: $ios-text-secondary;
+        width: 100px;
+      }
+      .value {
+        color: $ios-text-primary;
+        flex: 1;
+      }
+      .score {
+        font-weight: $ios-font-weight-semibold;
+        color: $ios-primary;
+      }
+    }
+  }
+  .assignment-actions {
+    margin-top: $ios-spacing-sm;
+  }
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .quality-management-main {
+    padding: $ios-spacing-md;
+  }
+  
+  .section-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: $ios-spacing-md;
+  }
+  
+  .search-filter {
+    width: 100%;
+    input,
+    select {
+      flex: 1;
+      width: auto;
+    }
+  }
+  
+  .sop-tabs .tab-buttons {
+    overflow-x: auto;
+    -webkit-overflow-scrolling: touch;
+    scrollbar-width: none;
+    &::-webkit-scrollbar {
+      display: none;
+    }
+  }
+  
+  .task-details .detail-item {
+    flex-direction: column;
+    .label {
+      width: auto;
+      margin-bottom: $ios-spacing-xs;
+    }
+  }
+  
+  .training-content {
+    flex-direction: column;
+  }
+  
+  .video-item {
+    flex-direction: column;
+    .video-thumbnail {
+      width: 100%;
+      height: auto;
+      aspect-ratio: 16/9;
+    }
+  }
+}

+ 342 - 5
src/app/pages/team-leader/quality-management/quality-management.ts

@@ -1,11 +1,348 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+
+// 定义质量整改任务接口
+interface RectificationTask {
+  id: string;
+  projectName: string;
+  designerName: string;
+  issueDescription: string;
+  priority: 'high' | 'medium' | 'low';
+  status: 'pending' | 'processing' | 'review' | 'completed';
+  suggestedDeadline: Date;
+  sopComplianceScore: number | null;
+  managerComment: string | null;
+  relatedSOP: string;
+}
+
+// 定义视频教程接口
+interface VideoTutorial {
+  id: string;
+  title: string;
+  description: string;
+  thumbnailUrl: string;
+  duration: string;
+  category: string;
+  views: number;
+  relatedSOP: string;
+}
+
+// 定义实践作业接口
+interface PracticeAssignment {
+  id: string;
+  title: string;
+  description: string;
+  relatedSOP: string;
+  deadline: Date;
+  status: 'pending' | 'submitted' | 'reviewed';
+  score: number | null;
+  designerName: string;
+}
 
 @Component({
   selector: 'app-quality-management',
-  imports: [],
   templateUrl: './quality-management.html',
-  styleUrl: './quality-management.scss'
+  styleUrl: './quality-management.scss',
+  standalone: true,
+  imports: [FormsModule, CommonModule]
 })
-export class QualityManagement {
-
+export class QualityManagementComponent implements OnInit {
+  // 活动标签页
+  activeTab: 'modeling' | 'rendering' | 'postProduction' = 'modeling';
+  
+  // 搜索和筛选条件
+  searchTerm: string = '';
+  filterStatus: string = 'all';
+  
+  // 质量整改任务列表
+  rectificationTasks: RectificationTask[] = [];
+  
+  // 视频教程列表
+  videoTutorials: VideoTutorial[] = [];
+  
+  // 实践作业列表
+  practiceAssignments: PracticeAssignment[] = [];
+  
+  constructor(private router: Router) {}
+  
+  ngOnInit() {
+    // 初始化模拟数据
+    this.initializeMockData();
+  }
+  
+  // 初始化模拟数据
+  initializeMockData(): void {
+    // 初始化质量整改任务
+    this.rectificationTasks = [
+      {
+        id: 'task-1',
+        projectName: '现代风格客厅效果图',
+        designerName: '张三',
+        issueDescription: '渲染真实度不足,光影效果不自然',
+        priority: 'high',
+        status: 'review',
+        suggestedDeadline: new Date('2023-12-15'),
+        sopComplianceScore: 82,
+        managerComment: null,
+        relatedSOP: '渲染阶段'
+      },
+      {
+        id: 'task-2',
+        projectName: '新中式卧室设计',
+        designerName: '李四',
+        issueDescription: '材质贴图不符合要求,颜色偏差较大',
+        priority: 'medium',
+        status: 'processing',
+        suggestedDeadline: new Date('2023-12-18'),
+        sopComplianceScore: null,
+        managerComment: null,
+        relatedSOP: '建模阶段'
+      },
+      {
+        id: 'task-3',
+        projectName: '北欧风格厨房',
+        designerName: '王五',
+        issueDescription: '后期处理细节不到位,色彩不够明亮',
+        priority: 'low',
+        status: 'pending',
+        suggestedDeadline: new Date('2023-12-20'),
+        sopComplianceScore: null,
+        managerComment: null,
+        relatedSOP: '后期阶段'
+      },
+      {
+        id: 'task-4',
+        projectName: '工业风办公室',
+        designerName: '赵六',
+        issueDescription: '户型匹配度误差超过2%,需要重新建模',
+        priority: 'high',
+        status: 'completed',
+        suggestedDeadline: new Date('2023-12-10'),
+        sopComplianceScore: 95,
+        managerComment: '整改效果良好,符合SOP标准',
+        relatedSOP: '建模阶段'
+      }
+    ];
+    
+    // 初始化视频教程
+    this.videoTutorials = [
+      {
+        id: 'video-1',
+        title: '渲染真实度提升技巧',
+        description: '学习如何调整灯光和材质参数,提升效果图的真实感',
+        thumbnailUrl: 'https://img.alicdn.com/imgextra/i3/O1CN01V9V6wF1u0l7zIeVYB_!!6000000006001-2-tps-1200-675.jpg',
+        duration: '15:30',
+        category: '渲染技巧',
+        views: 1256,
+        relatedSOP: '渲染阶段'
+      },
+      {
+        id: 'video-2',
+        title: '宋式风格建模规范',
+        description: '详细讲解宋式风格的建模要点和注意事项',
+        thumbnailUrl: 'https://img.alicdn.com/imgextra/i1/O1CN01y8z30s1L7c8w9X83G_!!6000000001323-2-tps-1200-675.jpg',
+        duration: '22:15',
+        category: '建模技巧',
+        views: 892,
+        relatedSOP: '建模阶段'
+      },
+      {
+        id: 'video-3',
+        title: '色彩校正与后期处理',
+        description: '掌握专业的后期处理流程,提升效果图的视觉效果',
+        thumbnailUrl: 'https://img.alicdn.com/imgextra/i4/O1CN012bQ5Z11j1D5P7XQr1_!!6000000004666-2-tps-1200-675.jpg',
+        duration: '18:45',
+        category: '后期处理',
+        views: 1053,
+        relatedSOP: '后期阶段'
+      }
+    ];
+    
+    // 初始化实践作业
+    this.practiceAssignments = [
+      {
+        id: 'assignment-1',
+        title: '现代风格客厅渲染练习',
+        description: '根据提供的3D模型,完成现代风格客厅的渲染,要求真实度达到90%以上',
+        relatedSOP: '渲染阶段',
+        deadline: new Date('2023-12-25'),
+        status: 'submitted',
+        score: null,
+        designerName: '张三'
+      },
+      {
+        id: 'assignment-2',
+        title: '新中式卧室建模练习',
+        description: '根据户型图,完成新中式卧室的建模,要求户型匹配度误差≤2%',
+        relatedSOP: '建模阶段',
+        deadline: new Date('2024-01-05'),
+        status: 'pending',
+        score: null,
+        designerName: '李四'
+      },
+      {
+        id: 'assignment-3',
+        title: '北欧风格厨房后期处理',
+        description: '对提供的渲染图进行后期处理,重点优化色彩和细节',
+        relatedSOP: '后期阶段',
+        deadline: new Date('2023-12-30'),
+        status: 'reviewed',
+        score: 92,
+        designerName: '王五'
+      }
+    ];
+  }
+  
+  // 获取筛选后的任务列表
+  get filteredTasks(): RectificationTask[] {
+    return this.rectificationTasks.filter(task => {
+      const matchesSearch = this.searchTerm === '' || 
+        task.projectName.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
+        task.designerName.toLowerCase().includes(this.searchTerm.toLowerCase());
+      
+      const matchesStatus = this.filterStatus === 'all' || task.status === this.filterStatus;
+      
+      return matchesSearch && matchesStatus;
+    });
+  }
+  
+  // 获取状态文本
+  getStatusText(status: string): string {
+    const statusMap: { [key: string]: string } = {
+      'pending': '待处理',
+      'processing': '处理中',
+      'review': '待审核',
+      'completed': '已完成'
+    };
+    return statusMap[status] || status;
+  }
+  
+  // 获取优先级文本
+  getPriorityText(priority: string): string {
+    const priorityMap: { [key: string]: string } = {
+      'high': '高',
+      'medium': '中',
+      'low': '低'
+    };
+    return priorityMap[priority] || priority;
+  }
+  
+  // 获取作业状态文本
+  getAssignmentStatusText(status: string): string {
+    const statusMap: { [key: string]: string } = {
+      'pending': '待提交',
+      'submitted': '已提交',
+      'reviewed': '已评审'
+    };
+    return statusMap[status] || status;
+  }
+  
+  // 导出SOP为PDF
+  exportSOP(): void {
+    // 模拟导出PDF功能
+    alert(`已导出${this.getPhaseName(this.activeTab)}的SOP标准为PDF文件`);
+    // 实际项目中,这里应该调用PDF生成库或API
+  }
+  
+  // 获取阶段名称
+  getPhaseName(phase: string): string {
+    const phaseMap: { [key: string]: string } = {
+      'modeling': '建模阶段',
+      'rendering': '渲染阶段',
+      'postProduction': '后期阶段'
+    };
+    return phaseMap[phase] || phase;
+  }
+  
+  // 查看任务详情
+  viewTaskDetails(taskId: string): void {
+    // 模拟查看任务详情
+    console.log(`查看任务详情: ${taskId}`);
+    // 实际项目中,这里应该跳转到任务详情页面或打开任务详情模态框
+  }
+  
+  // 批准任务
+  approveTask(taskId: string): void {
+    const task = this.rectificationTasks.find(t => t.id === taskId);
+    if (task) {
+      task.status = 'completed';
+      // 自动同步至项目评审板块
+      this.syncToProjectReview(taskId);
+      alert(`已批准任务: ${task.projectName}`);
+    }
+  }
+  
+  // 拒绝任务
+  rejectTask(taskId: string): void {
+    const task = this.rectificationTasks.find(t => t.id === taskId);
+    if (task) {
+      task.status = 'pending';
+      // 可以添加拒绝原因输入框
+      const reason = prompt('请输入拒绝原因:');
+      if (reason) {
+        task.managerComment = reason;
+      }
+      alert(`已拒绝任务: ${task.projectName}`);
+    }
+  }
+  
+  // 同步至项目评审板块
+  syncToProjectReview(taskId: string): void {
+    const task = this.rectificationTasks.find(t => t.id === taskId);
+    if (task) {
+      // 模拟同步数据到项目评审板块
+      console.log(`同步任务${taskId}至项目评审板块`);
+      // 实际项目中,这里应该调用API同步数据
+    }
+  }
+  
+  // 播放视频
+  playVideo(videoId: string): void {
+    const video = this.videoTutorials.find(v => v.id === videoId);
+    if (video) {
+      // 模拟播放视频
+      alert(`正在播放视频: ${video.title}`);
+      // 实际项目中,这里应该打开视频播放器或跳转到视频播放页面
+    }
+  }
+  
+  // 评审作业
+  reviewAssignment(assignmentId: string): void {
+    const assignment = this.practiceAssignments.find(a => a.id === assignmentId);
+    if (assignment) {
+      // 模拟评审作业
+      if (assignment.status === 'submitted') {
+        const score = prompt('请输入评分 (0-100):');
+        if (score && !isNaN(Number(score)) && Number(score) >= 0 && Number(score) <= 100) {
+          assignment.score = Number(score);
+          assignment.status = 'reviewed';
+          // 同步成绩到team-management板块的能力看板
+          this.syncScoreToTeamManagement(assignmentId, Number(score));
+          alert(`已完成作业评审,评分: ${score}`);
+        }
+      }
+    }
+  }
+  
+  // 同步成绩到team-management板块
+  syncScoreToTeamManagement(assignmentId: string, score: number): void {
+    const assignment = this.practiceAssignments.find(a => a.id === assignmentId);
+    if (assignment) {
+      // 模拟同步成绩数据
+      console.log(`同步作业${assignmentId}的成绩${score}至team-management板块`);
+      // 实际项目中,这里应该调用API同步数据
+    }
+  }
+  
+  // 跳转到团队管理页面
+  navigateToTeamManagement(): void {
+    this.router.navigate(['/team-leader/team-management']);
+  }
+  
+  // 跳转到项目评审页面
+  navigateToProjectReview(): void {
+    this.router.navigate(['/team-leader/project-review']);
+  }
 }

+ 333 - 1
src/app/pages/team-leader/team-management/team-management.html

@@ -1 +1,333 @@
-<p>team-management works!</p>
+<header class="team-management-header">
+  <h1>团队管理</h1>
+</header>
+
+<main class="team-management-main">
+  <!-- 组员项目进度与排期 -->
+  <section class="team-schedule-section">
+    <div class="section-header">
+      <h2>组员项目进度与排期</h2>
+      <div class="search-filter">
+        <input type="text" placeholder="搜索组员姓名..." [(ngModel)]="searchTerm">
+        <select [(ngModel)]="filterProjectType">
+          <option value="all">全部项目类型</option>
+          <option value="soft">软装</option>
+          <option value="hard">硬装</option>
+        </select>
+      </div>
+    </div>
+    
+    <div class="team-schedule-tabs">
+      <div class="tab-buttons">
+        <button (click)="activeScheduleTab = 'all'" [class.active]="activeScheduleTab === 'all'">整体排期</button>
+        <button (click)="activeScheduleTab = 'overdue'" [class.active]="activeScheduleTab === 'overdue'">超期任务</button>
+      </div>
+      
+      <div class="tab-content">
+        <div *ngIf="activeScheduleTab === 'all'" class="schedule-content">
+          <div *ngFor="let designer of filteredDesigners" class="designer-schedule">
+            <div class="designer-header">
+              <h3>{{ designer.name }}</h3>
+              <span [class]="'workload ' + getWorkloadClass(designer.workload)">{{ getWorkloadText(designer.workload) }}</span>
+            </div>
+            
+            <div class="task-list">
+              <div *ngFor="let task of getDesignerTasks(designer.id)" class="task-item" [class.overdue]="isTaskOverdue(task)">
+                <div class="task-info">
+                  <h4>{{ task.projectName }}</h4>
+                  <div class="task-meta">
+                    <span class="phase">{{ task.phase }}</span>
+                    <span class="deadline">截止: {{ task.deadline | date:'yyyy-MM-dd' }}</span>
+                  </div>
+                </div>
+                <div class="task-actions">
+                  <button (click)="viewProjectDetails(task.projectId)" class="btn-view">查看详情</button>
+                  <button (click)="adjustTaskPriority(task.id)" class="btn-adjust">调整优先级</button>
+                </div>
+              </div>
+              
+              <div *ngIf="getDesignerTasks(designer.id).length === 0" class="no-tasks">
+                暂无任务
+              </div>
+            </div>
+          </div>
+        </div>
+        
+        <div *ngIf="activeScheduleTab === 'overdue'" class="overdue-content">
+          <div class="overdue-list">
+            <div *ngFor="let task of getOverdueTasks()" class="overdue-task">
+              <div class="task-header">
+                <h3>{{ task.projectName }}</h3>
+                <span class="overdue-badge">超期 {{ getOverdueDays(task) }} 天</span>
+              </div>
+              
+              <div class="task-details">
+                <div class="detail-item">
+                  <span class="label">负责组员:</span>
+                  <span class="value">{{ getDesignerName(task.designerId) }}</span>
+                </div>
+                <div class="detail-item">
+                  <span class="label">当前阶段:</span>
+                  <span class="value">{{ task.phase }}</span>
+                </div>
+                <div class="detail-item">
+                  <span class="label">原截止日期:</span>
+                  <span class="value">{{ task.deadline | date:'yyyy-MM-dd' }}</span>
+                </div>
+              </div>
+              
+              <div class="task-actions">
+                <button (click)="viewProjectDetails(task.projectId)" class="btn-view">查看详情</button>
+                <button (click)="adjustTaskDeadline(task.id)" class="btn-adjust">调整截止日期</button>
+              </div>
+            </div>
+            
+            <div *ngIf="getOverdueTasks().length === 0" class="no-overdue">
+              暂无超期任务
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 组员能力看板 -->
+  <section class="capability-board-section">
+    <div class="section-header">
+      <h2>组员能力看板</h2>
+    </div>
+    
+    <div class="capability-tabs">
+      <div class="tab-buttons">
+        <button (click)="activeCapabilityTab = 'ranking'" [class.active]="activeCapabilityTab === 'ranking'">整体排行</button>
+        <button (click)="activeCapabilityTab = 'detail'" [class.active]="activeCapabilityTab === 'detail'">单人看板</button>
+      </div>
+      
+      <div class="tab-content">
+        <!-- 整体排行 -->
+        <div *ngIf="activeCapabilityTab === 'ranking'" class="ranking-content">
+          <div class="ranking-section">
+            <h3>能力分值排行</h3>
+            <div class="ranking-list">
+              <div *ngFor="let designer of getDesignersByCapability()" class="ranking-item">
+                <div class="ranking-info">
+                  <span class="rank">{{ getRank(designer.id) }}</span>
+                  <span class="name">{{ designer.name }}</span>
+                </div>
+                <div class="capability-score">
+                  <div class="score-bar">
+                    <div class="score-fill" [style.width.px]="designer.capabilityScore * 2"></div>
+                  </div>
+                  <span class="score-value">{{ designer.capabilityScore }}分</span>
+                </div>
+              </div>
+            </div>
+          </div>
+          
+          <div class="ranking-section">
+            <h3>作品满意度排行</h3>
+            <div class="ranking-list">
+              <div *ngFor="let designer of getDesignersBySatisfaction()" class="ranking-item">
+                <div class="ranking-info">
+                  <span class="rank">{{ getSatisfactionRank(designer.id) }}</span>
+                  <span class="name">{{ designer.name }}</span>
+                </div>
+                <div class="satisfaction-score">
+                  <div class="score-bar">
+                    <div class="score-fill satisfaction" [style.width.px]="designer.satisfactionScore * 2"></div>
+                  </div>
+                  <span class="score-value">{{ designer.satisfactionScore }}分</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        
+        <!-- 单人看板 -->
+        <div *ngIf="activeCapabilityTab === 'detail'" class="detail-content">
+          <div class="designer-selector">
+            <select [(ngModel)]="selectedDesignerId" (change)="onDesignerChange()">
+              <option value="">选择组员</option>
+              <option *ngFor="let designer of designers" [value]="designer.id">{{ designer.name }}</option>
+            </select>
+          </div>
+          
+          <div *ngIf="selectedDesigner" class="designer-detail">
+            <!-- 雷达图 -->
+            <div class="radar-chart-section">
+              <h3>能力维度</h3>
+              <div class="radar-chart">
+                <!-- 这里应该是雷达图的实现,为了简化,使用模拟的雷达图 -->
+                <svg width="300" height="300" viewBox="0 0 300 300">
+                  <!-- 雷达图背景 -->
+                  <circle cx="150" cy="150" r="120" fill="none" stroke="#e0e0e0" stroke-width="1"></circle>
+                  <circle cx="150" cy="150" r="90" fill="none" stroke="#e0e0e0" stroke-width="1"></circle>
+                  <circle cx="150" cy="150" r="60" fill="none" stroke="#e0e0e0" stroke-width="1"></circle>
+                  <circle cx="150" cy="150" r="30" fill="none" stroke="#e0e0e0" stroke-width="1"></circle>
+                  
+                  <!-- 坐标轴 -->
+                  <line x1="150" y1="30" x2="150" y2="270" stroke="#e0e0e0" stroke-width="1"></line>
+                  <line x1="30" y1="150" x2="270" y2="150" stroke="#e0e0e0" stroke-width="1"></line>
+                  <line x1="77" y1="77" x2="223" y2="223" stroke="#e0e0e0" stroke-width="1"></line>
+                  <line x1="223" y1="77" x2="77" y2="223" stroke="#e0e0e0" stroke-width="1"></line>
+                  
+                  <!-- 能力点 -->
+                  <polygon 
+                    [attr.points]="selectedDesigner ? getRadarPoints(selectedDesigner) : ''" 
+                    fill="rgba(0, 71, 171, 0.2)" 
+                    stroke="#0047AB" 
+                    stroke-width="2"
+                  ></polygon>
+                  
+                  <!-- 能力标签 -->
+                  <text x="150" y="20" text-anchor="middle" fill="#666">建模</text>
+                  <text x="280" y="150" text-anchor="middle" fill="#666">渲染</text>
+                  <text x="150" y="280" text-anchor="middle" fill="#666">软装</text>
+                  <text x="20" y="150" text-anchor="middle" fill="#666">沟通</text>
+                </svg>
+              </div>
+            </div>
+            
+            <!-- 项目经验 -->
+            <div class="experience-section">
+              <h3>项目经验</h3>
+              <div class="experience-details">
+                <div class="detail-item">
+                    <span class="label">完成项目数量:</span>
+                    <span class="value">{{ selectedDesigner.completedProjects }}个</span>
+                  </div>
+                <div class="detail-item">
+                  <span class="label">擅长类型:</span>
+                  <span class="value">{{ selectedDesigner ? getDesignerSkills(selectedDesigner) : '' }}</span>
+                </div>
+                <div class="detail-item">
+                  <span class="label">难点项目经验:</span>
+                  <span class="value">{{ selectedDesigner.difficultProjects }}个</span>
+                </div>
+              </div>
+            </div>
+            
+            <!-- 接单少原因分析 -->
+            <div *ngIf="selectedDesigner?.lowOrderReason" class="reason-analysis">
+              <h3>接单少原因分析</h3>
+              <p>{{ selectedDesigner.lowOrderReason }}</p>
+            </div>
+          </div>
+          
+          <div *ngIf="!selectedDesignerId" class="select-prompt">
+            请选择一个组员查看详细信息
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+
+  <!-- 绩效管理与721考核 -->
+  <section class="performance-section">
+    <div class="section-header">
+      <h2>绩效管理与721考核</h2>
+      <div class="quarter-selector">
+        <select [(ngModel)]="selectedQuarter" (change)="onQuarterChange()">
+          <option value="2023-Q4">2023年第四季度</option>
+          <option value="2023-Q3">2023年第三季度</option>
+          <option value="2023-Q2">2023年第二季度</option>
+          <option value="2023-Q1">2023年第一季度</option>
+        </select>
+        <button (click)="generateReport()" class="btn-generate">生成考核报告</button>
+      </div>
+    </div>
+    
+    <div class="performance-content">
+      <!-- 721分布 -->
+      <div class="distribution-section">
+        <h3>721考核分布</h3>
+        <div class="distribution-chart">
+          <div class="distribution-item top">
+            <div class="distribution-header">
+              <h4>头部 20%</h4>
+              <span class="count">{{ getTopPerformers().length }}人</span>
+            </div>
+            <div class="distribution-list">
+              <div *ngFor="let designer of getTopPerformers()" class="performer-item top">
+                <span class="name">{{ designer.name }}</span>
+                <span class="score">{{ designer.performanceScore }}分</span>
+              </div>
+            </div>
+            <div class="distribution-actions">
+              <button (click)="showPromotionCriteria()" class="btn-info">查看晋级条件</button>
+            </div>
+          </div>
+          
+          <div class="distribution-item middle">
+            <div class="distribution-header">
+              <h4>中部 70%</h4>
+              <span class="count">{{ getMiddlePerformers().length }}人</span>
+            </div>
+            <div class="distribution-list">
+              <div *ngFor="let designer of getMiddlePerformers()" class="performer-item middle">
+                <span class="name">{{ designer.name }}</span>
+                <span class="score">{{ designer.performanceScore }}分</span>
+              </div>
+            </div>
+            <div class="distribution-actions">
+              <button (click)="showImprovementSuggestions()" class="btn-info">查看提升建议</button>
+            </div>
+          </div>
+          
+          <div class="distribution-item bottom">
+            <div class="distribution-header">
+              <h4>尾部 10%</h4>
+              <span class="count">{{ getBottomPerformers().length }}人</span>
+            </div>
+            <div class="distribution-list">
+              <div *ngFor="let designer of getBottomPerformers()" class="performer-item bottom">
+                <div class="bottom-item">
+                  <span class="name">{{ designer.name }}</span>
+                  <span class="score">{{ designer.performanceScore }}分</span>
+                </div>
+              </div>
+            </div>
+            <div class="distribution-actions">
+              <button (click)="showRectificationPlan()" class="btn-info">查看整改计划</button>
+            </div>
+          </div>
+        </div>
+      </div>
+      
+      <!-- 绩效详情 -->
+      <div class="performance-detail-section">
+        <h3>绩效详情</h3>
+        <div class="performance-detail-list">
+          <div *ngFor="let designer of designers" class="performance-detail-item">
+            <div class="detail-header">
+              <span class="name">{{ designer.name }}</span>
+              <span class="total-score">{{ designer.performanceScore }}分</span>
+            </div>
+            <div class="score-breakdown">
+              <div class="score-item">
+                <span class="label">交付准时率 (30%):</span>
+                <span class="value">{{ designer.onTimeRateScore }}分</span>
+              </div>
+              <div class="score-item">
+                <span class="label">客户满意度 (40%):</span>
+                <span class="value">{{ designer.satisfactionScore }}分</span>
+              </div>
+              <div class="score-item">
+                <span class="label">作品优秀率 (40%):</span>
+                <span class="value">{{ designer.excellentRateScore }}分</span>
+              </div>
+              <div class="score-item deduction">
+                <span class="label">扣分项:</span>
+                <span class="value">{{ designer.deductions }}分</span>
+              </div>
+            </div>
+            <div class="performance-actions">
+              <button (click)="viewPerformanceReport(designer.id)" class="btn-view">查看报告</button>
+              <button (click)="syncToHR(designer.id)" class="btn-sync">同步至人事</button>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+</main>

+ 729 - 0
src/app/pages/team-leader/team-management/team-management.scss

@@ -0,0 +1,729 @@
+@import '../ios-theme.scss';
+
+.team-management-header {
+  background-color: $ios-background;
+  padding: $ios-spacing-xl;
+  border-bottom: 1px solid $ios-border;
+  h1 {
+    color: $ios-text-primary;
+    font-size: $ios-font-size-xl;
+    font-weight: 600;
+    margin: 0;
+  }
+}
+
+.team-management-main {
+  padding: $ios-spacing-xl;
+  background-color: $ios-background-secondary;
+}
+
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  h2 {
+    color: $ios-text-primary;
+    font-size: $ios-font-size-lg;
+    font-weight: 600;
+    margin: 0;
+  }
+}
+
+.search-filter {
+  display: flex;
+  gap: 10px;
+  input,
+  select {
+    padding: 8px 12px;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-lg;
+    background-color: $ios-background;
+    color: $ios-text-primary;
+    font-size: $ios-font-size-base;
+    &:focus {
+      outline: none;
+      border-color: $ios-primary;
+      box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+    }
+  }
+  input {
+    width: 200px;
+  }
+  select {
+    width: 150px;
+    cursor: pointer;
+  }
+}
+
+/* 组员项目进度与排期 */
+.team-schedule-section {
+  background-color: $ios-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-lg;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+.team-schedule-tabs {
+  .tab-buttons {
+    display: flex;
+    border-bottom: 1px solid $ios-border;
+    margin-bottom: 20px;
+    button {
+      padding: 10px 20px;
+      background-color: transparent;
+      border: none;
+      border-bottom: 2px solid transparent;
+      color: $ios-text-secondary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      &.active {
+        color: $ios-primary;
+        border-bottom-color: $ios-primary;
+        font-weight: 500;
+      }
+      &:hover {
+        color: $ios-primary;
+      }
+    }
+  }
+}
+
+.schedule-content {
+  .designer-schedule {
+    margin-bottom: 20px;
+    padding-bottom: 20px;
+    border-bottom: 1px solid $ios-border;
+    &:last-child {
+      border-bottom: none;
+      margin-bottom: 0;
+      padding-bottom: 0;
+    }
+    .designer-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        font-weight: 500;
+        margin: 0;
+      }
+      .workload {
+        padding: 4px 8px;
+        border-radius: $ios-radius-lg;
+        font-size: $ios-font-size-sm;
+        font-weight: 500;
+        &.light {
+          background-color: rgba(52, 199, 89, 0.1);
+          color: #34c759;
+        }
+        &.medium {
+          background-color: rgba(255, 149, 0, 0.1);
+          color: #ff9500;
+        }
+        &.heavy {
+          background-color: rgba(255, 59, 48, 0.1);
+          color: #ff3b30;
+        }
+      }
+    }
+  }
+}
+
+.task-list {
+  .task-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 12px;
+    background-color: $ios-background-secondary;
+    border-radius: $ios-radius-lg;
+    margin-bottom: 8px;
+    transition: all 0.2s ease;
+    &:hover {
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+    }
+    &.overdue {
+      border-left: 4px solid $ios-danger;
+      background-color: rgba(255, 59, 48, 0.05);
+    }
+    .task-info {
+      flex: 1;
+      h4 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        font-weight: 500;
+        margin: 0 0 5px 0;
+      }
+      .task-meta {
+        display: flex;
+        gap: 15px;
+        .phase {
+          color: $ios-primary;
+          font-size: $ios-font-size-sm;
+          font-weight: 500;
+        }
+        .deadline {
+          color: $ios-text-secondary;
+          font-size: $ios-font-size-sm;
+        }
+      }
+    }
+    .task-actions {
+      display: flex;
+      gap: 8px;
+    }
+  }
+  .no-tasks {
+    text-align: center;
+    color: $ios-text-secondary;
+    padding: 20px;
+    font-size: $ios-font-size-base;
+  }
+}
+
+.overdue-content {
+  .overdue-list {
+    .overdue-task {
+      background-color: $ios-background-secondary;
+      border-radius: $ios-radius-lg;
+      padding: 15px;
+      margin-bottom: 10px;
+      border-left: 4px solid $ios-danger;
+      .task-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+        h3 {
+          color: $ios-text-primary;
+          font-size: $ios-font-size-base;
+          font-weight: 500;
+          margin: 0;
+        }
+        .overdue-badge {
+          background-color: $ios-danger;
+          color: white;
+          padding: 4px 8px;
+          border-radius: $ios-radius-full;
+          font-size: $ios-font-size-sm;
+          font-weight: 500;
+        }
+      }
+      .task-details {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 15px;
+        margin-bottom: 10px;
+        .detail-item {
+          .label {
+            color: $ios-text-secondary;
+            font-size: $ios-font-size-sm;
+            margin-right: 5px;
+          }
+          .value {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+            font-weight: 500;
+          }
+        }
+      }
+      .task-actions {
+        display: flex;
+        gap: 8px;
+      }
+    }
+    .no-overdue {
+      text-align: center;
+      color: $ios-text-secondary;
+      padding: 20px;
+      font-size: $ios-font-size-base;
+    }
+  }
+}
+
+/* 组员能力看板 */
+.capability-board-section {
+  background-color: $ios-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-lg;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+.capability-tabs {
+  .tab-buttons {
+    display: flex;
+    border-bottom: 1px solid $ios-border;
+    margin-bottom: 20px;
+    button {
+      padding: 10px 20px;
+      background-color: transparent;
+      border: none;
+      border-bottom: 2px solid transparent;
+      color: $ios-text-secondary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      &.active {
+        color: $ios-primary;
+        border-bottom-color: $ios-primary;
+        font-weight: 500;
+      }
+      &:hover {
+        color: $ios-primary;
+      }
+    }
+  }
+}
+
+.ranking-content {
+  .ranking-section {
+    margin-bottom: 30px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+    h3 {
+      color: $ios-text-primary;
+      font-size: $ios-font-size-base;
+      font-weight: 500;
+      margin: 0 0 15px 0;
+    }
+    .ranking-list {
+      .ranking-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+        padding: 10px;
+        background-color: $ios-background-secondary;
+        border-radius: $ios-radius-md;
+        .ranking-info {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+          .rank {
+            background-color: $ios-primary;
+            color: white;
+            width: 24px;
+            height: 24px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: $ios-font-size-sm;
+            font-weight: 600;
+          }
+          .name {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+          }
+        }
+        .capability-score,
+        .satisfaction-score {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+          .score-bar {
+            width: 150px;
+            height: 8px;
+            background-color: $ios-border;
+            border-radius: 4px;
+            overflow: hidden;
+            .score-fill {
+              height: 100%;
+              background-color: $ios-primary;
+              border-radius: 4px;
+            }
+            .score-fill.satisfaction {
+              background-color: #34c759;
+            }
+          }
+          .score-value {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-sm;
+            font-weight: 500;
+          }
+        }
+      }
+    }
+  }
+}
+
+.detail-content {
+  .designer-selector {
+    margin-bottom: 20px;
+    select {
+      width: 200px;
+      padding: 8px 12px;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius-md;
+      background-color: $ios-background;
+      color: $ios-text-primary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      &:focus {
+        outline: none;
+        border-color: $ios-primary;
+        box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+      }
+    }
+  }
+  .designer-detail {
+    .radar-chart-section {
+      margin-bottom: 30px;
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        font-weight: 500;
+        margin: 0 0 15px 0;
+      }
+      .radar-chart {
+        display: flex;
+        justify-content: center;
+        margin-bottom: 20px;
+      }
+    }
+    .experience-section {
+      margin-bottom: 30px;
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-lg;
+        font-weight: 500;
+        margin: 0 0 15px 0;
+      }
+      .experience-details {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 20px;
+        .detail-item {
+          .label {
+            color: $ios-text-secondary;
+            font-size: $ios-font-size-sm;
+            margin-right: 5px;
+          }
+          .value {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+            font-weight: 500;
+          }
+        }
+      }
+    }
+    .reason-analysis {
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-lg;
+        font-weight: 500;
+        margin: 0 0 15px 0;
+      }
+      p {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        line-height: 1.6;
+        margin: 0;
+        padding: 10px;
+        background-color: $ios-background-secondary;
+        border-radius: $ios-radius-md;
+      }
+    }
+  }
+  .select-prompt {
+    text-align: center;
+    color: $ios-text-secondary;
+    padding: 20px;
+    font-size: $ios-font-size-base;
+  }
+}
+
+/* 绩效管理与721考核 */
+.performance-section {
+  background-color: $ios-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-lg;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+.quarter-selector {
+  display: flex;
+  gap: 10px;
+  select {
+    padding: 8px 12px;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-md;
+    background-color: $ios-background;
+    color: $ios-text-primary;
+    font-size: $ios-font-size-base;
+    cursor: pointer;
+    &:focus {
+      outline: none;
+      border-color: $ios-primary;
+      box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+    }
+  }
+}
+
+.performance-content {
+  .distribution-section {
+    margin-bottom: 30px;
+    h3 {
+      color: $ios-text-primary;
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      margin: 0 0 15px 0;
+    }
+    .distribution-chart {
+      display: flex;
+      gap: 20px;
+      .distribution-item {
+        flex: 1;
+        padding: 15px;
+        border-radius: $ios-radius-md;
+        .distribution-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 10px;
+          h4 {
+            color: white;
+            font-size: $ios-font-size-base;
+            font-weight: $ios-font-weight-medium;
+            margin: 0;
+          }
+          .count {
+            color: white;
+            font-size: $ios-font-size-xs;
+            background-color: rgba(255, 255, 255, 0.2);
+            padding: 2px 6px;
+            border-radius: $ios-radius-full;
+          }
+        }
+        .distribution-list {
+          margin-bottom: 10px;
+          .performer-item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 5px;
+            margin-bottom: 5px;
+            border-radius: $ios-radius-md;
+            .name {
+              color: white;
+              font-size: $ios-font-size-xs;
+            }
+            .score {
+              color: white;
+              font-size: $ios-font-size-xs;
+              font-weight: $ios-font-weight-medium;
+            }
+          }
+        }
+        .distribution-actions {
+          text-align: center;
+        }
+        &.top {
+          background-color: #34c759;
+          .performer-item.top {
+            background-color: rgba(255, 255, 255, 0.1);
+          }
+        }
+        &.middle {
+          background-color: #ff9500;
+          .performer-item.middle {
+            background-color: rgba(255, 255, 255, 0.1);
+          }
+        }
+        &.bottom {
+          background-color: #ff3b30;
+          .performer-item.bottom {
+            background-color: rgba(255, 255, 255, 0.1);
+          }
+        }
+      }
+    }
+  }
+  .performance-detail-section {
+    h3 {
+      color: $ios-text-primary;
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      margin: 0 0 15px 0;
+    }
+    .performance-detail-list {
+      .performance-detail-item {
+        background-color: $ios-background-secondary;
+        border-radius: $ios-radius-md;
+        padding: 15px;
+        margin-bottom: 10px;
+        .detail-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 10px;
+          .name {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+            font-weight: $ios-font-weight-medium;
+          }
+          .total-score {
+            color: $ios-primary;
+            font-size: $ios-font-size-base;
+            font-weight: $ios-font-weight-semibold;
+          }
+        }
+        .score-breakdown {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 15px;
+          margin-bottom: 10px;
+          .score-item {
+            .label {
+              color: $ios-text-secondary;
+              font-size: $ios-font-size-xs;
+              margin-right: 5px;
+            }
+            .value {
+              color: $ios-text-primary;
+              font-size: $ios-font-size-base;
+              font-weight: $ios-font-weight-medium;
+            }
+            &.deduction {
+              .value {
+                color: $ios-danger;
+              }
+            }
+          }
+        }
+        .performance-actions {
+          display: flex;
+          gap: 8px;
+        }
+      }
+    }
+  }
+}
+
+/* 按钮样式 */
+.btn-view,
+.btn-adjust,
+.btn-info,
+.btn-generate,
+.btn-sync {
+  padding: 6px 12px;
+  border: none;
+  border-radius: $ios-radius-md;
+  font-size: $ios-font-size-xs;
+  font-weight: $ios-font-weight-medium;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  &:hover {
+    opacity: 0.9;
+  }
+  &:disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+  }
+}
+
+.btn-view {
+  background-color: $ios-primary;
+  color: white;
+}
+
+.btn-adjust {
+  background-color: #ff9500;
+  color: white;
+}
+
+.btn-info {
+  background-color: white;
+  color: $ios-primary;
+  border: 1px solid $ios-primary;
+}
+
+.btn-generate {
+  background-color: $ios-primary;
+  color: white;
+  padding: 8px 16px;
+}
+
+.btn-sync {
+  background-color: #34c759;
+  color: white;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .team-management-main {
+    padding: 10px;
+  }
+  
+  .section-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+  }
+  
+  .search-filter {
+    flex-direction: column;
+    width: 100%;
+    input,
+    select {
+      width: 100%;
+    }
+  }
+  
+  .task-item {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+    .task-actions {
+      width: 100%;
+      justify-content: flex-end;
+    }
+  }
+  
+  .distribution-chart {
+    flex-direction: column;
+  }
+  
+  .score-breakdown {
+    flex-direction: column;
+    gap: 5px !important;
+  }
+  
+  .quarter-selector {
+    flex-direction: column;
+    width: 100%;
+    select {
+      width: 100%;
+    }
+  }
+  
+  .radar-chart svg {
+    width: 250px;
+    height: 250px;
+  }
+}
+
+@media (max-width: 480px) {
+  .task-meta {
+    flex-direction: column;
+    gap: 5px !important;
+  }
+  
+  .experience-details {
+    flex-direction: column;
+    gap: 5px !important;
+  }
+  
+  .radar-chart svg {
+    width: 200px;
+    height: 200px;
+  }
+}

+ 728 - 0
src/app/pages/team-leader/team-management/team-management.scss.bak

@@ -0,0 +1,728 @@
+@import '../ios-theme.scss';
+
+.team-management-header {
+  background-color: $ios-background;
+  padding: $ios-spacing-xl;
+  border-bottom: 1px solid $ios-border;
+  h1 {
+    color: $ios-text-primary;
+    font-size: $ios-font-size-xl;
+    font-weight: 600;
+    margin: 0;
+  
+}
+}
+
+.team-management-main {
+  padding: $ios-spacing-xl;
+  background-color: $ios-background-secondary;
+}
+
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 20px;
+  h2 {
+    color: $ios-text-primary;
+    font-size: $ios-font-size-lg;
+    font-weight: 600;
+    margin: 0;
+  }
+}
+
+.search-filter {
+  display: flex;
+  gap: 10px;
+  input,
+  select {
+    padding: 8px 12px;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-lg;
+    background-color: $ios-background;
+    color: $ios-text-primary;
+    font-size: $ios-font-size-base;
+    &:focus {
+      outline: none;
+      border-color: $ios-primary;
+      box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+    }
+  }
+  input {
+    width: 200px;
+  }
+  select {
+    width: 150px;
+    cursor: pointer;
+  }
+}
+
+/* 组员项目进度与排期 */
+.team-schedule-section {
+  background-color: $ios-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-lg;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+.team-schedule-tabs {
+  .tab-buttons {
+    display: flex;
+    border-bottom: 1px solid $ios-border;
+    margin-bottom: 20px;
+    button {
+      padding: 10px 20px;
+      background-color: transparent;
+      border: none;
+      border-bottom: 2px solid transparent;
+      color: $ios-text-secondary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      &.active {
+        color: $ios-primary;
+        border-bottom-color: $ios-primary;
+        font-weight: 500;
+      }
+      &:hover {
+        color: $ios-primary;
+      }
+    }
+  }
+}
+
+.schedule-content {
+  .designer-schedule {
+    margin-bottom: 20px;
+    padding-bottom: 20px;
+    border-bottom: 1px solid $ios-border;
+    &:last-child {
+      border-bottom: none;
+      margin-bottom: 0;
+      padding-bottom: 0;
+    }
+    .designer-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        font-weight: 500;
+        margin: 0;
+      }
+      .workload {
+        padding: 4px 8px;
+        border-radius: $ios-radius-lg;
+        font-size: $ios-font-size-sm;
+        font-weight: 500;
+        &.light {
+          background-color: rgba(52, 199, 89, 0.1);
+          color: #34c759;
+        }
+        &.medium {
+          background-color: rgba(255, 149, 0, 0.1);
+          color: #ff9500;
+        }
+        &.heavy {
+          background-color: rgba(255, 59, 48, 0.1);
+          color: #ff3b30;
+        }
+      }
+    }
+  }
+}
+
+.task-list {
+  .task-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 12px;
+    background-color: $ios-background-secondary;
+    border-radius: $ios-radius-lg;
+    margin-bottom: 8px;
+    transition: all 0.2s ease;
+    &:hover {
+      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+    }
+    &.overdue {
+      border-left: 4px solid $ios-danger;
+      background-color: rgba(255, 59, 48, 0.05);
+    }
+    .task-info {
+      flex: 1;
+      h4 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        font-weight: 500;
+        margin: 0 0 5px 0;
+      }
+      .task-meta {
+        display: flex;
+        gap: 15px;
+        .phase {
+          color: $ios-primary;
+          font-size: $ios-font-size-sm;
+          font-weight: 500;
+        }
+        .deadline {
+          color: $ios-text-secondary;
+          font-size: $ios-font-size-sm;
+        }
+      }
+    }
+    .task-actions {
+      display: flex;
+      gap: 8px;
+    }
+  }
+  .no-tasks {
+    text-align: center;
+    color: $ios-text-secondary;
+    padding: 20px;
+    font-size: $ios-font-size-base;
+  }
+}
+
+.overdue-content {
+  .overdue-list {
+    .overdue-task {
+      background-color: $ios-background-secondary;
+      border-radius: $ios-radius-lg;
+      padding: 15px;
+      margin-bottom: 10px;
+      border-left: 4px solid $ios-danger;
+      .task-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+        h3 {
+          color: $ios-text-primary;
+          font-size: $ios-font-size-base;
+          font-weight: 500;
+          margin: 0;
+        }
+        .overdue-badge {
+          background-color: $ios-danger;
+          color: white;
+          padding: 4px 8px;
+          border-radius: $ios-radius-full;
+          font-size: $ios-font-size-sm;
+          font-weight: 500;
+        }
+      }
+      .task-details {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 15px;
+        margin-bottom: 10px;
+        .detail-item {
+          .label {
+            color: $ios-text-secondary;
+            font-size: $ios-font-size-sm;
+            margin-right: 5px;
+          }
+          .value {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+            font-weight: 500;
+          }
+        }
+      }
+      .task-actions {
+        display: flex;
+        gap: 8px;
+      }
+    }
+    .no-overdue {
+      text-align: center;
+      color: $ios-text-secondary;
+      padding: 20px;
+      font-size: $ios-font-size-base;
+    }
+  }
+}
+
+/* 组员能力看板 */
+.capability-board-section {
+  background-color: $ios-background;
+  border-radius: $ios-radius-lg;
+  padding: $ios-spacing-lg;
+  margin-bottom: 20px;
+  box-shadow: $ios-shadow-card;
+}
+
+.capability-tabs {
+  .tab-buttons {
+    display: flex;
+    border-bottom: 1px solid $ios-border;
+    margin-bottom: 20px;
+    button {
+      padding: 10px 20px;
+      background-color: transparent;
+      border: none;
+      border-bottom: 2px solid transparent;
+      color: $ios-text-secondary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      transition: all 0.2s ease;
+      &.active {
+        color: $ios-primary;
+        border-bottom-color: $ios-primary;
+        font-weight: 500;
+      }
+      &:hover {
+        color: $ios-primary;
+      }
+    }
+  }
+}
+
+.ranking-content {
+  .ranking-section {
+    margin-bottom: 30px;
+    &:last-child {
+      margin-bottom: 0;
+    }
+    h3 {
+          color: $ios-text-primary;
+          font-size: $ios-font-size-base;
+          font-weight: 500;
+          margin: 0 0 15px 0;
+        }
+    .ranking-list {
+      .ranking-item {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 10px;
+        padding: 10px;
+        background-color: $ios-background-secondary;
+        border-radius: $ios-radius-md;
+        .ranking-info {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+          .rank {
+            background-color: $ios-primary;
+            color: white;
+            width: 24px;
+            height: 24px;
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            font-size: $ios-font-size-sm;
+            font-weight: 600;
+          }
+          .name {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+          }
+        }
+        .capability-score,
+        .satisfaction-score {
+          display: flex;
+          align-items: center;
+          gap: 10px;
+          .score-bar {
+            width: 150px;
+            height: 8px;
+            background-color: $ios-border;
+            border-radius: 4px;
+            overflow: hidden;
+            .score-fill {
+              height: 100%;
+              background-color: $ios-primary;
+              border-radius: 4px;
+            }
+            .score-fill.satisfaction {
+              background-color: #34c759;
+            }
+          }
+          .score-value {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-sm;
+            font-weight: 500;
+          }
+        }
+      }
+    }
+  }
+}
+
+.detail-content {
+  .designer-selector {
+    margin-bottom: 20px;
+    select {
+      width: 200px;
+      padding: 8px 12px;
+      border: 1px solid $ios-border;
+      border-radius: $ios-radius-md;
+      background-color: $ios-background;
+      color: $ios-text-primary;
+      font-size: $ios-font-size-base;
+      cursor: pointer;
+      &:focus {
+        outline: none;
+        border-color: $ios-primary;
+        box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+      }
+    }
+  }
+  .designer-detail {
+    .radar-chart-section {
+      margin-bottom: 30px;
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        font-weight: 500;
+        margin: 0 0 15px 0;
+      }
+      .radar-chart {
+        display: flex;
+        justify-content: center;
+        margin-bottom: 20px;
+      }
+    }
+    .experience-section {
+      margin-bottom: 30px;
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-lg;
+        font-weight: 500;
+        margin: 0 0 15px 0;
+      }
+      .experience-details {
+        display: flex;
+        flex-wrap: wrap;
+        gap: 20px;
+        .detail-item {
+          .label {
+            color: $ios-text-secondary;
+            font-size: $ios-font-size-sm;
+            margin-right: 5px;
+          }
+          .value {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+            font-weight: 500;
+          }
+        }
+      }
+    }
+    .reason-analysis {
+      h3 {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-lg;
+        font-weight: 500;
+        margin: 0 0 15px 0;
+      }
+      p {
+        color: $ios-text-primary;
+        font-size: $ios-font-size-base;
+        line-height: 1.6;
+        margin: 0;
+        padding: 10px;
+        background-color: $ios-background-secondary;
+        border-radius: $ios-radius-md;
+      }
+    }
+  }
+  .select-prompt {
+    text-align: center;
+    color: $ios-text-secondary;
+    padding: 20px;
+    font-size: $ios-font-size-base;
+  }
+
+/* 绩效管理与721考核 */
+.performance-section {
+  background-color: $ios-background-secondary;
+  border-radius: $ios-radius-md;
+  padding: $ios-spacing-lg;
+  box-shadow: $ios-shadow-card;
+}
+
+.quarter-selector {
+  display: flex;
+  gap: 10px;
+  select {
+    padding: 8px 12px;
+    border: 1px solid $ios-border;
+    border-radius: $ios-radius-md;
+    background-color: $ios-background-secondary;
+    color: $ios-text-primary;
+    font-size: $ios-font-size-base;
+    cursor: pointer;
+    &:focus {
+      outline: none;
+      border-color: $ios-primary;
+      box-shadow: 0 0 0 2px rgba(0, 71, 171, 0.1);
+    }
+  }
+}
+
+.performance-content {
+  .distribution-section {
+    margin-bottom: 30px;
+    h3 {
+      color: $ios-text-primary;
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      margin: 0 0 15px 0;
+    }
+    .distribution-chart {
+      display: flex;
+      gap: 20px;
+      .distribution-item {
+        flex: 1;
+        padding: 15px;
+        border-radius: $ios-radius-md;
+        .distribution-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 10px;
+          h4 {
+            color: white;
+            font-size: $ios-font-size-base;
+            font-weight: $ios-font-weight-medium;
+            margin: 0;
+          }
+          .count {
+            color: white;
+            font-size: $ios-font-size-xs;
+            background-color: rgba(255, 255, 255, 0.2);
+            padding: 2px 6px;
+            border-radius: $ios-radius-full;
+          }
+        }
+        .distribution-list {
+          margin-bottom: 10px;
+          .performer-item {
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+            padding: 5px;
+            margin-bottom: 5px;
+            border-radius: $ios-radius-md;
+            .name {
+              color: white;
+              font-size: $ios-font-size-xs;
+            }
+            .score {
+              color: white;
+              font-size: $ios-font-size-xs;
+              font-weight: $ios-font-weight-medium;
+            }
+          }
+        }
+        .distribution-actions {
+          text-align: center;
+        }
+        &.top {
+          background-color: #34c759;
+          .performer-item.top {
+            background-color: rgba(255, 255, 255, 0.1);
+          }
+        }
+        &.middle {
+          background-color: #ff9500;
+          .performer-item.middle {
+            background-color: rgba(255, 255, 255, 0.1);
+          }
+        }
+        &.bottom {
+          background-color: #ff3b30;
+          .performer-item.bottom {
+            background-color: rgba(255, 255, 255, 0.1);
+          }
+        }
+      }
+    }
+  }
+  .performance-detail-section {
+    h3 {
+      color: $ios-text-primary;
+      font-size: $ios-font-size-lg;
+      font-weight: $ios-font-weight-medium;
+      margin: 0 0 15px 0;
+    }
+    .performance-detail-list {
+      .performance-detail-item {
+        background-color: $ios-background-secondary;
+        border-radius: $ios-radius-md;
+        padding: 15px;
+        margin-bottom: 10px;
+        .detail-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          margin-bottom: 10px;
+          .name {
+            color: $ios-text-primary;
+            font-size: $ios-font-size-base;
+            font-weight: $ios-font-weight-medium;
+          }
+          .total-score {
+            color: $ios-primary;
+            font-size: $ios-font-size-base;
+            font-weight: $ios-font-weight-semibold;
+          }
+        }
+        .score-breakdown {
+          display: flex;
+          flex-wrap: wrap;
+          gap: 15px;
+          margin-bottom: 10px;
+          .score-item {
+            .label {
+              color: $ios-text-secondary;
+              font-size: $ios-font-size-xs;
+              margin-right: 5px;
+            }
+            .value {
+              color: $ios-text-primary;
+              font-size: $ios-font-size-base;
+              font-weight: $ios-font-weight-medium;
+            }
+            &.deduction {
+              .value {
+                color: $ios-danger;
+              }
+            }
+          }
+        }
+        .performance-actions {
+          display: flex;
+          gap: 8px;
+        }
+      }
+    }
+  }
+}
+
+/* 按钮样式 */
+.btn-view,
+.btn-adjust,
+.btn-info,
+.btn-generate,
+.btn-sync {
+  padding: 6px 12px;
+  border: none;
+  border-radius: $ios-radius-md;
+  font-size: $ios-font-size-xs;
+  font-weight: $ios-font-weight-medium;
+  cursor: pointer;
+  transition: all 0.2s ease;
+  &:hover {
+    opacity: 0.9;
+  }
+  &:disabled {
+    opacity: 0.5;
+    cursor: not-allowed;
+  }
+}
+
+.btn-view {
+  background-color: $ios-primary;
+  color: white;
+}
+
+.btn-adjust {
+  background-color: #ff9500;
+  color: white;
+}
+
+.btn-info {
+  background-color: white;
+  color: $ios-primary;
+  border: 1px solid $ios-primary;
+}
+
+.btn-generate {
+  background-color: $ios-primary;
+  color: white;
+  padding: 8px 16px;
+}
+
+.btn-sync {
+  background-color: #34c759;
+  color: white;
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .team-management-main {
+    padding: 10px;
+  }
+  
+  .section-header {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+  }
+  
+  .search-filter {
+    flex-direction: column;
+    width: 100%;
+    input,
+    select {
+      width: 100%;
+    }
+  }
+  
+  .task-item {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 10px;
+    .task-actions {
+      width: 100%;
+      justify-content: flex-end;
+    }
+  }
+  
+  .distribution-chart {
+    flex-direction: column;
+  }
+  
+  .score-breakdown {
+    flex-direction: column;
+    gap: 5px !important;
+  }
+  
+  .quarter-selector {
+    flex-direction: column;
+    width: 100%;
+    select {
+      width: 100%;
+    }
+  }
+  
+  .radar-chart svg {
+    width: 250px;
+    height: 250px;
+  }
+}
+
+@media (max-width: 480px) {
+  .task-meta {
+    flex-direction: column;
+    gap: 5px !important;
+  }
+  
+  .experience-details {
+    flex-direction: column;
+    gap: 5px !important;
+  }
+  
+  .radar-chart svg {
+    width: 200px;
+    height: 200px;
+  }
+}

+ 467 - 4
src/app/pages/team-leader/team-management/team-management.ts

@@ -1,11 +1,474 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';
+
+// 定义设计师接口
+interface Designer {
+  id: string;
+  name: string;
+  workload: 'light' | 'medium' | 'heavy';
+  capabilityScore: number;
+  satisfactionScore: number;
+  completedProjects: number;
+  difficultProjects: number;
+  skills: string[];
+  performanceScore: number;
+  onTimeRateScore: number;
+  excellentRateScore: number;
+  deductions: number;
+  lowOrderReason?: string;
+}
+
+// 定义任务接口
+interface Task {
+  id: string;
+  projectId: string;
+  projectName: string;
+  designerId: string;
+  phase: string;
+  deadline: Date;
+  projectType: 'soft' | 'hard';
+  priority: number;
+}
+
+// 定义721考核分布接口
+interface PerformanceDistribution {
+  top: Designer[];
+  middle: Designer[];
+  bottom: Designer[];
+}
 
 @Component({
   selector: 'app-team-management',
-  imports: [],
   templateUrl: './team-management.html',
-  styleUrl: './team-management.scss'
+  styleUrl: './team-management.scss',
+  standalone: true,
+  imports: [FormsModule, CommonModule]
 })
-export class TeamManagement {
+export class TeamManagementComponent implements OnInit {
+  // 数据
+  designers: Designer[] = [];
+  tasks: Task[] = [];
+  searchTerm = '';
+  filterProjectType = 'all';
+  selectedQuarter = '2023-Q4';
+  selectedDesignerId = '';
+  selectedDesigner: Designer | null = null;
+  activeScheduleTab = 'all';
+  activeCapabilityTab = 'ranking';
+  performanceDistribution: PerformanceDistribution = {
+    top: [],
+    middle: [],
+    bottom: []
+  };
+
+  constructor(private router: Router) {}
+
+  ngOnInit() {
+    this.initializeMockData();
+    this.calculatePerformanceDistribution();
+  }
+
+  // 初始化模拟数据
+  initializeMockData() {
+    // 初始化设计师数据
+    this.designers = [
+      {
+        id: 'd1',
+        name: '张三',
+        workload: 'heavy',
+        capabilityScore: 92,
+        satisfactionScore: 95,
+        completedProjects: 48,
+        difficultProjects: 12,
+        skills: ['现代风格', '渲染', '后期'],
+        performanceScore: 91,
+        onTimeRateScore: 90,
+        excellentRateScore: 95,
+        deductions: 0
+      },
+      {
+        id: 'd2',
+        name: '李四',
+        workload: 'medium',
+        capabilityScore: 88,
+        satisfactionScore: 92,
+        completedProjects: 35,
+        difficultProjects: 8,
+        skills: ['中式风格', '建模', '软装'],
+        performanceScore: 87,
+        onTimeRateScore: 85,
+        excellentRateScore: 90,
+        deductions: 2
+      },
+      {
+        id: 'd3',
+        name: '王五',
+        workload: 'light',
+        capabilityScore: 76,
+        satisfactionScore: 85,
+        completedProjects: 20,
+        difficultProjects: 3,
+        skills: ['北欧风格', '建模'],
+        performanceScore: 78,
+        onTimeRateScore: 82,
+        excellentRateScore: 80,
+        deductions: 1,
+        lowOrderReason: '能力匹配度低,近1个月软装需求占比80%,组员擅长硬装'
+      },
+      {
+        id: 'd4',
+        name: '赵六',
+        workload: 'medium',
+        capabilityScore: 82,
+        satisfactionScore: 88,
+        completedProjects: 30,
+        difficultProjects: 5,
+        skills: ['工业风格', '后期', '渲染'],
+        performanceScore: 84,
+        onTimeRateScore: 88,
+        excellentRateScore: 85,
+        deductions: 3
+      },
+      {
+        id: 'd5',
+        name: '钱七',
+        workload: 'heavy',
+        capabilityScore: 90,
+        satisfactionScore: 94,
+        completedProjects: 42,
+        difficultProjects: 10,
+        skills: ['新中式', '渲染', '软装'],
+        performanceScore: 89,
+        onTimeRateScore: 92,
+        excellentRateScore: 93,
+        deductions: 0
+      }
+    ];
+
+    // 初始化任务数据
+    const today = new Date();
+    this.tasks = [
+      {
+        id: 't1',
+        projectId: 'p1',
+        projectName: '现代简约客厅',
+        designerId: 'd1',
+        phase: '渲染',
+        deadline: new Date(today.getTime() - 2 * 24 * 60 * 60 * 1000), // 2天前
+        projectType: 'soft',
+        priority: 1
+      },
+      {
+        id: 't2',
+        projectId: 'p2',
+        projectName: '新中式卧室',
+        designerId: 'd5',
+        phase: '建模',
+        deadline: new Date(today.getTime() + 3 * 24 * 60 * 60 * 1000), // 3天后
+        projectType: 'hard',
+        priority: 2
+      },
+      {
+        id: 't3',
+        projectId: 'p3',
+        projectName: '北欧风格厨房',
+        designerId: 'd3',
+        phase: '后期',
+        deadline: new Date(today.getTime() + 5 * 24 * 60 * 60 * 1000), // 5天后
+        projectType: 'soft',
+        priority: 3
+      },
+      {
+        id: 't4',
+        projectId: 'p4',
+        projectName: '工业风办公室',
+        designerId: 'd4',
+        phase: '渲染',
+        deadline: new Date(today.getTime() + 1 * 24 * 60 * 60 * 1000), // 1天后
+        projectType: 'hard',
+        priority: 1
+      },
+      {
+        id: 't5',
+        projectId: 'p5',
+        projectName: '中式餐厅',
+        designerId: 'd2',
+        phase: '软装',
+        deadline: new Date(today.getTime() - 1 * 24 * 60 * 60 * 1000), // 1天前
+        projectType: 'soft',
+        priority: 2
+      },
+      {
+        id: 't6',
+        projectId: 'p6',
+        projectName: '现代轻奢卫生间',
+        designerId: 'd1',
+        phase: '建模',
+        deadline: new Date(today.getTime() + 4 * 24 * 60 * 60 * 1000), // 4天后
+        projectType: 'hard',
+        priority: 3
+      }
+    ];
+  }
+
+  // 计算721绩效分布
+  calculatePerformanceDistribution() {
+    // 按绩效分数排序
+    const sortedDesigners = [...this.designers].sort((a, b) => b.performanceScore - a.performanceScore);
+    const total = sortedDesigners.length;
+    const topCount = Math.ceil(total * 0.2);
+    const bottomCount = Math.floor(total * 0.1);
+
+    this.performanceDistribution = {
+      top: sortedDesigners.slice(0, topCount),
+      middle: sortedDesigners.slice(topCount, total - bottomCount),
+      bottom: sortedDesigners.slice(total - bottomCount)
+    };
+  }
+
+  // 获取筛选后的设计师
+  get filteredDesigners() {
+    return this.designers.filter(designer => 
+      designer.name.toLowerCase().includes(this.searchTerm.toLowerCase())
+    );
+  }
+
+  // 获取设计师的任务
+  getDesignerTasks(designerId: string): Task[] {
+    let filtered = this.tasks.filter(task => task.designerId === designerId);
+    
+    // 根据项目类型筛选
+    if (this.filterProjectType !== 'all') {
+      filtered = filtered.filter(task => task.projectType === this.filterProjectType);
+    }
+    
+    // 按优先级和截止日期排序
+    return filtered.sort((a, b) => {
+      if (a.priority !== b.priority) {
+        return a.priority - b.priority;
+      }
+      return a.deadline.getTime() - b.deadline.getTime();
+    });
+  }
+
+  // 获取超期任务
+  getOverdueTasks(): Task[] {
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    
+    let overdueTasks = this.tasks.filter(task => {
+      const taskDate = new Date(task.deadline);
+      taskDate.setHours(0, 0, 0, 0);
+      return taskDate < today;
+    });
+    
+    // 根据项目类型筛选
+    if (this.filterProjectType !== 'all') {
+      overdueTasks = overdueTasks.filter(task => task.projectType === this.filterProjectType);
+    }
+    
+    // 按超期天数排序
+    return overdueTasks.sort((a, b) => this.getOverdueDays(a) - this.getOverdueDays(b));
+  }
+
+  // 获取超期天数
+  getOverdueDays(task: Task): number {
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    const taskDate = new Date(task.deadline);
+    taskDate.setHours(0, 0, 0, 0);
+    
+    const diffTime = Math.abs(today.getTime() - taskDate.getTime());
+    const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
+    
+    return diffDays;
+  }
+
+  // 判断任务是否超期
+  isTaskOverdue(task: Task): boolean {
+    const today = new Date();
+    today.setHours(0, 0, 0, 0);
+    const taskDate = new Date(task.deadline);
+    taskDate.setHours(0, 0, 0, 0);
+    
+    return taskDate < today;
+  }
+
+  // 获取工作量等级的CSS类名
+  getWorkloadClass(workload: string): string {
+    return workload;
+  }
+
+  // 获取工作量等级的文本
+  getWorkloadText(workload: string): string {
+    switch (workload) {
+      case 'light': return '空闲';
+      case 'medium': return '中等';
+      case 'heavy': return '繁忙';
+      default: return '未知';
+    }
+  }
+
+  // 根据能力分值排序设计师
+  getDesignersByCapability(): Designer[] {
+    return [...this.designers].sort((a, b) => b.capabilityScore - a.capabilityScore);
+  }
+
+  // 根据满意度排序设计师
+  getDesignersBySatisfaction(): Designer[] {
+    return [...this.designers].sort((a, b) => b.satisfactionScore - a.satisfactionScore);
+  }
+
+  // 获取排名
+  getRank(designerId: string): number {
+    const sorted = this.getDesignersByCapability();
+    return sorted.findIndex(d => d.id === designerId) + 1;
+  }
+
+  // 获取满意度排名
+  getSatisfactionRank(designerId: string): number {
+    const sorted = this.getDesignersBySatisfaction();
+    return sorted.findIndex(d => d.id === designerId) + 1;
+  }
+
+  // 获取设计师姓名
+  getDesignerName(designerId: string): string {
+    const designer = this.designers.find(d => d.id === designerId);
+    return designer ? designer.name : '未知';
+  }
+
+  // 获取设计师技能
+  getDesignerSkills(designer: Designer): string {
+    return designer.skills.join(', ');
+  }
+
+  // 获取雷达图点坐标
+  getRadarPoints(designer: Designer): string {
+    // 简化实现,实际项目中应使用专业的图表库
+    const centerX = 150;
+    const centerY = 150;
+    const maxRadius = 120;
+    
+    // 假设设计师各能力维度得分
+    const modelingScore = 85; // 建模能力
+    const renderingScore = 90; // 渲染能力
+    const softDecorationScore = 75; // 软装能力
+    const communicationScore = 88; // 沟通能力
+    
+    // 计算各点坐标
+    const modelingX = centerX + (modelingScore / 100) * maxRadius;
+    const modelingY = centerY - (modelingScore / 100) * maxRadius;
+    
+    const renderingX = centerX + (renderingScore / 100) * maxRadius;
+    const renderingY = centerY;
+    
+    const softDecorationX = centerX;
+    const softDecorationY = centerY + (softDecorationScore / 100) * maxRadius;
+    
+    const communicationX = centerX - (communicationScore / 100) * maxRadius;
+    const communicationY = centerY;
+    
+    return `${modelingX},${modelingY} ${renderingX},${renderingY} ${softDecorationX},${softDecorationY} ${communicationX},${communicationY}`;
+  }
+
+  // 获取头部绩效人员
+  getTopPerformers(): Designer[] {
+    return this.performanceDistribution.top;
+  }
+
+  // 获取中部绩效人员
+  getMiddlePerformers(): Designer[] {
+    return this.performanceDistribution.middle;
+  }
+
+  // 获取尾部绩效人员
+  getBottomPerformers(): Designer[] {
+    return this.performanceDistribution.bottom;
+  }
+
+  // 查看项目详情
+  viewProjectDetails(projectId: string): void {
+    this.router.navigate(['/team-leader/project-review'], { queryParams: { projectId } });
+  }
+
+  // 调整任务优先级
+  adjustTaskPriority(taskId: string): void {
+    const task = this.tasks.find(t => t.id === taskId);
+    if (task) {
+      // 在实际项目中,这里应该弹出一个对话框让用户选择新的优先级
+      // 这里简单地循环切换优先级
+      task.priority = task.priority % 3 + 1;
+      alert(`任务优先级已调整为: ${task.priority}`);
+    }
+  }
+
+  // 调整任务截止日期
+  adjustTaskDeadline(taskId: string): void {
+    const task = this.tasks.find(t => t.id === taskId);
+    if (task) {
+      // 在实际项目中,这里应该弹出一个日期选择器让用户选择新的截止日期
+      // 这里简单地将截止日期延长3天
+      const newDeadline = new Date(task.deadline);
+      newDeadline.setDate(newDeadline.getDate() + 3);
+      task.deadline = newDeadline;
+      alert(`任务截止日期已调整为: ${newDeadline.toLocaleDateString()}`);
+    }
+  }
+
+  // 设计师选择变更
+  onDesignerChange(): void {
+    if (this.selectedDesignerId) {
+      this.selectedDesigner = this.designers.find(d => d.id === this.selectedDesignerId) || null;
+    } else {
+      this.selectedDesigner = null;
+    }
+  }
+
+  // 季度选择变更
+  onQuarterChange(): void {
+    // 在实际项目中,这里应该根据选择的季度加载对应的绩效数据
+    // 这里简单地重新计算绩效分布
+    this.calculatePerformanceDistribution();
+  }
+
+  // 生成考核报告
+  generateReport(): void {
+    // 在实际项目中,这里应该生成并下载考核报告
+    alert(`已生成${this.selectedQuarter}考核报告`);
+  }
+
+  // 查看绩效报告
+  viewPerformanceReport(designerId: string): void {
+    // 在实际项目中,这里应该显示该设计师的详细绩效报告
+    const designer = this.designers.find(d => d.id === designerId);
+    if (designer) {
+      alert(`查看${designer.name}的绩效报告`);
+    }
+  }
+
+  // 同步至人事系统
+  syncToHR(designerId: string): void {
+    // 在实际项目中,这里应该调用API将绩效数据同步至人事系统
+    const designer = this.designers.find(d => d.id === designerId);
+    if (designer) {
+      alert(`${designer.name}的绩效数据已同步至人事系统`);
+    }
+  }
+
+  // 查看晋级条件
+  showPromotionCriteria(): void {
+    alert('头部20%员工可获得晋级机会,具体条件:\n1. 绩效分数≥90分\n2. 无重大客户投诉\n3. 连续2个季度保持头部20%');
+  }
+
+  // 查看提升建议
+  showImprovementSuggestions(): void {
+    alert('中部70%员工提升建议:\n1. 参加技能培训课程\n2. 多与优秀员工交流学习\n3. 针对薄弱环节进行专项练习');
+  }
 
+  // 查看整改计划
+  showRectificationPlan(): void {
+    alert('尾部10%员工整改计划:\n1. 制定个性化提升计划\n2. 每周提交学习进度\n3. 1个月后进行重新评估,仍未达标者将进行转岗或其他处理');
+  }
 }

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov