0235711 пре 1 дан
родитељ
комит
b5b975782a

+ 2 - 0
.trae/rules/project_rules.md

@@ -0,0 +1,2 @@
+
+模板页面显示的条件和循环if和for统一用控制流的@if和@for

+ 112 - 82
src/app/pages/team-leader/dashboard/dashboard.html

@@ -9,6 +9,13 @@
         <div class="metric-label">已延期项目</div>
       </div>
     </div>
+    <div class="metric-card" (click)="filterByStatus('dueSoon')">
+      <div class="metric-icon info">⏳</div>
+      <div class="metric-content">
+        <div class="metric-count">{{ dueSoonProjects.length }}</div>
+        <div class="metric-label">临期项目(3天内)</div>
+      </div>
+    </div>
     <div class="metric-card" (click)="filterByStatus('pendingApproval')">
       <div class="metric-icon info">📋</div>
       <div class="metric-content">
@@ -48,14 +55,35 @@
           <option value="progress">进行中</option>
           <option value="completed">已完成</option>
           <option value="overdue">已延期</option>
+          <option value="dueSoon">临期(3天内)</option>
           <option value="pendingApproval">待确认</option>
           <option value="pendingAssignment">待分配</option>
         </select>
+        <select (change)="onDesignerChange($event)" class="custom-select">
+          <option value="all">全部设计师</option>
+          @for (d of designers; track d) {
+            <option [value]="d">{{ d }}</option>
+          }
+        </select>
+        <select (change)="onMemberTypeChange($event)" class="custom-select">
+          <option value="all">全部会员</option>
+          <option value="vip">VIP会员</option>
+          <option value="normal">普通会员</option>
+        </select>
         <!-- 支持数百项目的下拉筛选 -->
         <select [(ngModel)]="selectedProjectId" (change)="selectProject()" class="custom-select project-selector">
           <option value="">选择项目</option>
-          <option *ngFor="let project of projects" [value]="project.id">{{ project.name }}</option>
+          @for (project of projects; track project.id) {
+            <option [value]="project.id">{{ project.name }}</option>
+          }
         </select>
+        <!-- 新增:时间窗快捷筛选按钮组 -->
+        <div class="time-window-buttons">
+          <button [class.active]="selectedTimeWindow === 'all'" (click)="filterByTimeWindow('all')">全部</button>
+          <button [class.active]="selectedTimeWindow === 'today'" (click)="filterByTimeWindow('today')">今天到期</button>
+          <button [class.active]="selectedTimeWindow === 'threeDays'" (click)="filterByTimeWindow('threeDays')">3天内</button>
+          <button [class.active]="selectedTimeWindow === 'sevenDays'" (click)="filterByTimeWindow('sevenDays')">7天内</button>
+        </div>
       </div>
     </div>
     
@@ -65,37 +93,58 @@
       <div class="kanban-scroll">
         <!-- 阶段标题 -->
         <div class="kanban-header">
-          <div class="kanban-column-header" *ngFor="let stage of projectStages">
-            <h3>{{ stage.name }}</h3>
-            <span class="stage-count">{{ getProjectCountByStage(stage.id) }}</span>
-          </div>
+          @for (core of corePhases; track core.id) {
+            <div class="kanban-column-header">
+              <h3>{{ core.name }}</h3>
+              <span class="stage-count">{{ getProjectCountByCorePhase(core.id) }}</span>
+            </div>
+          }
         </div>
         <!-- 项目卡片 -->
         <div class="kanban-body">
-          <div class="kanban-column" *ngFor="let stage of projectStages">
-            <div *ngFor="let project of getProjectsByStage(stage.id)" 
-                 class="project-card" 
-                 [class.overdue]="project.isOverdue" 
-                 [class.high-urgency]="project.urgency === 'high'">
-              <div class="project-card-header">
-                <h4 [routerLink]="['/team-leader/project-review', project.id]">{{ project.name }}</h4>
-                <span class="project-urgency" [class]="'urgency-' + project.urgency">{{ getUrgencyLabel(project.urgency) }}</span>
-              </div>
-              <div class="project-card-content">
-                <p>负责人: {{ project.designerName }}</p>
-                <p class="deadline">{{ project.isOverdue ? '超期' + project.overdueDays + '天' : '截止: ' + (project.expectedEndDate | date:'MM-dd') }}</p>
-              </div>
-              <div class="project-card-footer">
-                <button (click)="viewProjectDetails(project.id)" class="btn-view">查看详情</button>
-                <button (click)="quickAssignProject(project.id)" *ngIf="stage.id === 'pendingAssignment'" class="btn-assign">分配</button>
-              </div>
+          @for (core of corePhases; track core.id) {
+            <div class="kanban-column">
+              @for (project of getProjectsByCorePhase(core.id); track project.id) {
+                <div class="project-card" 
+                     (click)="viewProjectDetails(project.id)"
+                     [class.overdue]="project.isOverdue" 
+                     [class.high-urgency]="project.urgency === 'high'"
+                     [class.due-soon]="project.dueSoon && !project.isOverdue">
+                  <div class="project-card-header">
+                    <h4 [routerLink]="['/team-leader/project-review', project.id]" (click)="$event.stopPropagation()">{{ project.name }}</h4>
+                    <div class="right-badges">
+                      <span class="member-badge" [class.vip]="project.memberType === 'vip'">{{ project.memberType === 'vip' ? 'VIP' : '普通' }}</span>
+                      <span class="project-urgency" [class]="'urgency-' + project.urgency">{{ getUrgencyLabel(project.urgency) }}</span>
+                    </div>
+                  </div>
+                  <div class="project-card-content">
+                    <p>负责人: {{ project.designerName || '未分配' }}</p>
+                    <p class="deadline">{{ project.isOverdue ? '超期' + project.overdueDays + '天' : (project.dueSoon ? '临期: ' + (project.expectedEndDate | date:'MM-dd') : '截止: ' + (project.expectedEndDate | date:'MM-dd')) }}</p>
+                  </div>
+                  <div class="project-card-footer">
+                    <button (click)="viewProjectDetails(project.id); $event.stopPropagation()" class="btn-view">查看详情</button>
+                    @if (project.currentStage === 'pendingAssignment') {
+                      <button (click)="quickAssignProject(project.id); $event.stopPropagation()" class="btn-assign">分配</button>
+                    }
+                    <!-- 新增:质量评审快捷操作 -->
+                    @if (project.currentStage === 'review' || project.currentStage === 'delivery') {
+                      <div class="inline-actions">
+                        <button class="btn-secondary" (click)="$event.stopPropagation(); reviewProjectQuality(project.id, 'excellent')">评为优秀</button>
+                        <button class="btn-secondary" (click)="$event.stopPropagation(); reviewProjectQuality(project.id, 'qualified')">评为合格</button>
+                        <button class="btn-secondary" (click)="$event.stopPropagation(); reviewProjectQuality(project.id, 'unqualified')">评为不合格</button>
+                      </div>
+                    }
+                  </div>
+                </div>
+              }
+              @if (getProjectsByCorePhase(core.id).length === 0) {
+                <div class="empty-column">
+                  <span class="empty-icon">📦</span>
+                  <p>暂无项目</p>
+                </div>
+              }
             </div>
-            <!-- 空状态 -->
-            <div *ngIf="getProjectsByStage(stage.id).length === 0" class="empty-column">
-              <span class="empty-icon">📦</span>
-              <p>暂无项目</p>
-            </div>
-          </div>
+          }
         </div>
       </div>
     </div>
@@ -105,68 +154,49 @@
   <section class="todo-section">
     <div class="section-header">
       <h2>待办任务</h2>
+      <!-- 新增:绩效与负载入口 -->
+      <div class="section-actions">
+        <button class="btn-link" (click)="viewPerformanceDetails()">查看绩效预警</button>
+        <button class="btn-link" (click)="navigateToWorkloadCalendar()">打开负载日历</button>
+      </div>
     </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>
+      @for (task of todoTasks; track task.id) {
+        <div 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>
-    </div>
-  </section>
-
-  <!-- 快速操作面板 -->
-  <section class="quick-actions-section">
-    <div class="section-header">
-      <h2>快速操作</h2>
-    </div>
-    
-    <div class="quick-actions-grid">
-      <div class="action-card" (click)="navigateToTeamManagement()">
-        <div class="action-icon">👥</div>
-        <h3>团队管理</h3>
-        <p>查看组员能力和绩效</p>
-      </div>
-      <div class="action-card" (click)="navigateToProjectReview()">
-        <div class="action-icon">📊</div>
-        <h3>项目评审</h3>
-        <p>审核和分配新项目</p>
-      </div>
-      <div class="action-card" (click)="navigateToQualityManagement()">
-        <div class="action-icon">✅</div>
-        <h3>质量管理</h3>
-        <p>查看整改任务和标准</p>
-      </div>
-      <div class="action-card" (click)="openWorkloadEstimator()">
-        <div class="action-icon">⏱️</div>
-        <h3>工作量预估</h3>
-        <p>前往项目详情页使用</p>
-      </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>
-      <div class="alert-actions">
-        <button (click)="viewAllOverdueProjects()" class="btn-view-all">查看全部</button>
-        <button (click)="closeAlert()" class="btn-close">关闭</button>
+  @if (showAlert && overdueProjects.length > 0) {
+    <div class="overdue-alert">
+      <div class="alert-content">
+        <h3>⚠️ 超期项目提醒</h3>
+        <ul>
+          @for (project of overdueProjects.slice(0, 3); track $index) {
+            <li>
+              {{ project.name }} ({{ project.designerName }} 负责) - 超期{{ project.overdueDays }}天
+            </li>
+          }
+        </ul>
+        <div class="alert-actions">
+          <button (click)="viewAllOverdueProjects()" class="btn-view-all">查看全部</button>
+          <button (click)="closeAlert()" class="btn-close">关闭</button>
+        </div>
       </div>
     </div>
-  </div>
+  }
 </main>

+ 88 - 12
src/app/pages/team-leader/dashboard/dashboard.scss

@@ -132,8 +132,8 @@
 .section-filters {
   display: flex;
   gap: $ios-spacing-md;
+  flex-wrap: wrap; // 小屏换行
   
-  // 自定义选择框样式
   .custom-select {
     padding: $ios-spacing-sm $ios-spacing-md;
     border: 1px solid $ios-border;
@@ -143,17 +143,36 @@
     color: $ios-text-primary;
     cursor: pointer;
     transition: all 0.2s ease;
-    
-    &:focus {
-      outline: none;
-      border-color: $ios-primary;
-      box-shadow: 0 0 0 2px rgba(124, 58, 237, 0.1);
-    }
-    
-    // 支持数百项目的下拉筛选器
-    &.project-selector {
-      min-width: 200px;
-      max-height: 40px;
+    min-width: 140px;
+  }
+}
+
+// 项目卡片补充样式
+.project-kanban {
+  .kanban-body {
+    .kanban-column {
+      .project-card {
+        &.due-soon {
+          border-left: 4px solid $ios-warning; // 黄色标识临期
+        }
+        .right-badges {
+          display: flex;
+          align-items: center;
+          gap: 6px;
+        }
+        .member-badge {
+          font-size: 10px;
+          padding: 2px 6px;
+          border-radius: $ios-radius-full;
+          background-color: rgba(59, 130, 246, 0.08);
+          color: $ios-info;
+          &.vip {
+            background-color: rgba(124, 58, 237, 0.12);
+            color: $ios-primary;
+            font-weight: $ios-font-weight-semibold;
+          }
+        }
+      }
     }
   }
 }
@@ -303,12 +322,19 @@
         border: 1px solid $ios-border;
         box-shadow: $ios-shadow-sm;
         transition: all 0.2s ease;
+        cursor: pointer; // 整卡可点击指针
+        user-select: none; // 避免误选中文字
         
         &:hover {
           transform: translateY(-2px);
           box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
         }
         
+        &:active {
+          transform: translateY(-1px);
+          opacity: 0.98;
+        }
+        
         &.overdue {
           border-left: 4px solid $ios-danger;
         }
@@ -661,4 +687,54 @@
       }
     }
   }
+}
+.time-window-buttons {
+  display: inline-flex;
+  gap: 8px;
+  margin-left: 8px;
+  button {
+    padding: 6px 10px;
+    border: 1px solid #d0d7de;
+    border-radius: 6px;
+    background: #fff;
+    color: #24292f;
+    cursor: pointer;
+    transition: all .15s ease;
+    &:hover { background: #f6f8fa; }
+    &.active { background: #0969da; color: #fff; border-color: #0969da; }
+  }
+}
+
+.inline-actions {
+  display: inline-flex;
+  gap: 6px;
+  margin-left: 8px;
+  .btn-secondary {
+    padding: 4px 8px;
+    font-size: 12px;
+    border: 1px solid #d0d7de;
+    border-radius: 6px;
+    background: #fff;
+    color: #24292f;
+    cursor: pointer;
+    &:hover { background: #f3f4f6; }
+  }
+}
+
+.section-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  .section-actions {
+    display: inline-flex;
+    gap: 12px;
+    .btn-link {
+      background: transparent;
+      border: none;
+      color: #0969da;
+      cursor: pointer;
+      padding: 4px 6px;
+      &:hover { text-decoration: underline; }
+    }
+  }
 }

+ 233 - 33
src/app/pages/team-leader/dashboard/dashboard.ts

@@ -23,14 +23,19 @@ interface Project {
   id: string;
   name: string;
   type: 'soft' | 'hard';
+  memberType: 'vip' | 'normal';
   designerName: string;
   status: string;
   expectedEndDate: Date;
   isOverdue: boolean;
   overdueDays: number;
+  dueSoon: boolean;
   urgency: 'high' | 'medium' | 'low';
   phases: ProjectPhase[];
   currentStage: string; // 新增:当前项目阶段
+  // 新增:质量评级
+  qualityRating?: 'excellent' | 'qualified' | 'unqualified' | 'pending';
+  lastCustomerFeedback?: string;
 }
 
 interface TodoTask {
@@ -58,6 +63,25 @@ export class Dashboard implements OnInit {
   showAlert: boolean = false;
   selectedProjectId: string = '';
   
+  // 新增:临期项目与筛选状态
+  dueSoonProjects: Project[] = [];
+  selectedType: 'all' | 'soft' | 'hard' = 'all';
+  selectedUrgency: 'all' | 'high' | 'medium' | 'low' = 'all';
+  selectedStatus: 'all' | 'progress' | 'completed' | 'overdue' | 'pendingApproval' | 'pendingAssignment' | 'dueSoon' = 'all';
+  selectedDesigner: string = 'all';
+  selectedMemberType: 'all' | 'vip' | 'normal' = 'all';
+  // 新增:时间窗筛选
+  selectedTimeWindow: 'all' | 'today' | 'threeDays' | 'sevenDays' = 'all';
+  designers: string[] = [];
+  
+  // 新增:智能推荐设计师配置
+  designerProfiles: any[] = [
+    { id: 'zhang', name: '张三', skills: ['现代风格', '北欧风格'], workload: 70, avgRating: 4.5, experience: 3 },
+    { id: 'li', name: '李四', skills: ['新中式', '宋式风格'], workload: 45, avgRating: 4.8, experience: 5 },
+    { id: 'wang', name: '王五', skills: ['北欧风格', '日式风格'], workload: 85, avgRating: 4.2, experience: 2 },
+    { id: 'zhao', name: '赵六', skills: ['现代风格', '轻奢风格'], workload: 30, avgRating: 4.6, experience: 4 }
+  ];
+  
   // 定义10个项目阶段
   projectStages: ProjectStage[] = [
     { id: 'pendingApproval', name: '待确认', order: 1 },
@@ -72,6 +96,14 @@ export class Dashboard implements OnInit {
     { id: 'delivery', name: '交付完成', order: 10 }
   ];
 
+  // 新增:5大核心阶段
+  corePhases: ProjectStage[] = [
+    { id: 'preparation', name: '前期准备', order: 1 }, // 待确认、待分配
+    { id: 'design', name: '方案设计', order: 2 },     // 需求沟通、方案规划
+    { id: 'production', name: '制作执行', order: 3 }, // 建模、渲染、后期
+    { id: 'review', name: '评审修订', order: 4 },    // 评审、修改
+    { id: 'delivery', name: '交付完成', order: 5 }    // 交付
+  ];
   constructor(private projectService: ProjectService, private router: Router) {}
 
   ngOnInit(): void {
@@ -86,11 +118,13 @@ export class Dashboard implements OnInit {
         id: 'proj-001',
         name: '现代风格客厅设计',
         type: 'soft',
+        memberType: 'vip',
         designerName: '张三',
         status: '进行中',
         expectedEndDate: new Date(2023, 9, 15),
         isOverdue: true,
         overdueDays: 2,
+        dueSoon: false,
         urgency: 'high',
         currentStage: 'rendering',
         phases: [
@@ -104,11 +138,13 @@ export class Dashboard implements OnInit {
         id: 'proj-002',
         name: '北欧风格卧室设计',
         type: 'soft',
+        memberType: 'normal',
         designerName: '李四',
         status: '进行中',
         expectedEndDate: new Date(2023, 9, 20),
         isOverdue: false,
         overdueDays: 0,
+        dueSoon: false,
         urgency: 'medium',
         currentStage: 'postProduction',
         phases: [
@@ -122,11 +158,13 @@ export class Dashboard implements OnInit {
         id: 'proj-003',
         name: '新中式餐厅设计',
         type: 'hard',
+        memberType: 'normal',
         designerName: '王五',
         status: '进行中',
         expectedEndDate: new Date(2023, 9, 25),
         isOverdue: false,
         overdueDays: 0,
+        dueSoon: false,
         urgency: 'low',
         currentStage: 'modeling',
         phases: [
@@ -140,11 +178,13 @@ export class Dashboard implements OnInit {
         id: 'proj-004',
         name: '工业风办公室设计',
         type: 'hard',
+        memberType: 'normal',
         designerName: '赵六',
         status: '进行中',
         expectedEndDate: new Date(2023, 9, 10),
         isOverdue: true,
         overdueDays: 7,
+        dueSoon: false,
         urgency: 'high',
         currentStage: 'review',
         phases: [
@@ -159,11 +199,13 @@ export class Dashboard implements OnInit {
         id: 'proj-005',
         name: '现代简约厨房设计',
         type: 'soft',
+        memberType: 'normal',
         designerName: '',
         status: '待分配',
         expectedEndDate: new Date(2023, 10, 5),
         isOverdue: false,
         overdueDays: 0,
+        dueSoon: false,
         urgency: 'medium',
         currentStage: 'pendingAssignment',
         phases: []
@@ -172,11 +214,13 @@ export class Dashboard implements OnInit {
         id: 'proj-006',
         name: '日式风格书房设计',
         type: 'hard',
+        memberType: 'normal',
         designerName: '',
         status: '待确认',
         expectedEndDate: new Date(2023, 10, 10),
         isOverdue: false,
         overdueDays: 0,
+        dueSoon: false,
         urgency: 'low',
         currentStage: 'pendingApproval',
         phases: []
@@ -185,11 +229,13 @@ export class Dashboard implements OnInit {
         id: 'proj-007',
         name: '轻奢风格浴室设计',
         type: 'soft',
+        memberType: 'normal',
         designerName: '钱七',
         status: '已完成',
         expectedEndDate: new Date(2023, 9, 5),
         isOverdue: false,
         overdueDays: 0,
+        dueSoon: false,
         urgency: 'medium',
         currentStage: 'delivery',
         phases: []
@@ -225,16 +271,21 @@ export class Dashboard implements OnInit {
       const expectedEndDate = new Date();
       const daysOffset = isOverdue ? - (overdueDays + (i % 5)) : ((i % 20) + 3);
       expectedEndDate.setDate(expectedEndDate.getDate() + daysOffset);
+      const daysToDeadline = Math.ceil((expectedEndDate.getTime() - Date.now()) / (1000 * 60 * 60 * 24));
+      const dueSoon = !isOverdue && daysToDeadline >= 0 && daysToDeadline <= 3;
+      const memberType: 'vip' | 'normal' = i % 4 === 0 ? 'vip' : 'normal';
 
       this.projects.push({
         id: `proj-${String(i).padStart(3, '0')}`,
         name: `${type === 'soft' ? '软装' : '硬装'}示例项目 ${i}`,
         type,
+        memberType,
         designerName,
         status,
         expectedEndDate,
         isOverdue,
         overdueDays,
+        dueSoon,
         urgency,
         currentStage,
         phases: []
@@ -242,10 +293,14 @@ export class Dashboard implements OnInit {
     }
     // ===== 示例数据生成结束 =====
 
-    // 筛选超期项目
+    // 筛选超期与临期项目
     this.overdueProjects = this.projects.filter(project => project.isOverdue);
+    this.dueSoonProjects = this.projects.filter(project => project.dueSoon && !project.isOverdue);
     this.filteredProjects = [...this.projects];
 
+    // 供筛选用的设计师列表
+    this.designers = Array.from(new Set(this.projects.map(p => p.designerName).filter(n => !!n)));
+
     // 显示超期提醒
     if (this.overdueProjects.length > 0) {
       this.showAlert = true;
@@ -316,54 +371,118 @@ export class Dashboard implements OnInit {
   // 筛选项目类型
   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);
-    }
+    this.selectedType = (target && target.value ? target.value : 'all') as any;
+    this.applyFilters();
   }
 
   // 筛选紧急程度
   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);
-    }
+    this.selectedUrgency = (target && target.value ? target.value : 'all') as any;
+    this.applyFilters();
   }
 
   // 筛选项目状态
   filterByStatus(status: string): void {
-    if (status === 'all') {
-      this.filteredProjects = [...this.projects];
-    } else if (status === 'overdue') {
-      this.filteredProjects = this.overdueProjects;
-    } else if (status === 'pendingApproval') {
-      this.filteredProjects = this.projects.filter(project => project.currentStage === 'pendingApproval');
-    } else if (status === 'pendingAssignment') {
-      this.filteredProjects = this.projects.filter(project => project.currentStage === 'pendingAssignment');
-    } else if (status === 'progress') {
-      this.filteredProjects = this.projects.filter(project => 
-        ['requirement', 'planning', 'modeling', 'rendering', 'postProduction', 'review', 'revision'].includes(project.currentStage)
-      );
-    } else if (status === 'completed') {
-      this.filteredProjects = this.projects.filter(project => project.currentStage === 'delivery');
-    }
+    this.selectedStatus = (status && status.length ? status : 'all') as any;
+    this.applyFilters();
   }
   
   // 处理状态筛选下拉框变化
   onStatusChange(event: Event): void {
     const target = event.target as HTMLSelectElement;
-    if (target && target.value) {
-      this.filterByStatus(target.value);
+    this.selectedStatus = (target && target.value ? target.value : 'all') as any;
+    this.applyFilters();
+  }
+
+  // 时间窗快捷筛选(供UI按钮触发)
+  filterByTimeWindow(timeWindow: 'all' | 'today' | 'threeDays' | 'sevenDays'): void {
+    this.selectedTimeWindow = timeWindow;
+    this.applyFilters();
+  }
+
+  // 统一筛选
+  private applyFilters(): void {
+    let result = [...this.projects];
+
+    // 类型筛选
+    if (this.selectedType !== 'all') {
+      result = result.filter(p => p.type === this.selectedType);
     }
+
+    // 紧急程度筛选
+    if (this.selectedUrgency !== 'all') {
+      result = result.filter(p => p.urgency === this.selectedUrgency);
+    }
+
+    // 项目状态筛选
+    if (this.selectedStatus !== 'all') {
+      if (this.selectedStatus === 'overdue') {
+        result = result.filter(p => p.isOverdue);
+      } else if (this.selectedStatus === 'dueSoon') {
+        result = result.filter(p => p.dueSoon && !p.isOverdue);
+      } else if (this.selectedStatus === 'pendingApproval') {
+        result = result.filter(p => p.currentStage === 'pendingApproval');
+      } else if (this.selectedStatus === 'pendingAssignment') {
+        result = result.filter(p => p.currentStage === 'pendingAssignment');
+      } else if (this.selectedStatus === 'progress') {
+        const progressStages = ['requirement','planning','modeling','rendering','postProduction','review','revision'];
+        result = result.filter(p => progressStages.includes(p.currentStage));
+      } else if (this.selectedStatus === 'completed') {
+        result = result.filter(p => p.currentStage === 'delivery');
+      }
+    }
+
+    // 设计师筛选
+    if (this.selectedDesigner !== 'all') {
+      result = result.filter(p => p.designerName === this.selectedDesigner);
+    }
+
+    // 会员类型筛选
+    if (this.selectedMemberType !== 'all') {
+      result = result.filter(p => p.memberType === this.selectedMemberType);
+    }
+
+    // 新增:时间窗筛选
+    if (this.selectedTimeWindow !== 'all') {
+      const now = new Date();
+      const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+      
+      result = result.filter(p => {
+        const projectDeadline = new Date(p.expectedEndDate);
+        const timeDiff = projectDeadline.getTime() - today.getTime();
+        const daysDiff = Math.ceil(timeDiff / (1000 * 60 * 60 * 24));
+        
+        switch (this.selectedTimeWindow) {
+          case 'today':
+            return daysDiff <= 1 && daysDiff >= 0;
+          case 'threeDays':
+            return daysDiff <= 3 && daysDiff >= 0;
+          case 'sevenDays':
+            return daysDiff <= 7 && daysDiff >= 0;
+          default:
+            return true;
+        }
+      });
+    }
+
+    this.filteredProjects = result;
+  }
+
+  // 新增:设计师筛选
+  onDesignerChange(event: Event): void {
+    const target = event.target as HTMLSelectElement;
+    this.selectedDesigner = target && target.value ? target.value : 'all';
+    this.applyFilters();
   }
 
+  // 新增:会员类型筛选
+  onMemberTypeChange(event: Event): void {
+    const target = event.target as HTMLSelectElement;
+    this.selectedMemberType = (target && target.value ? target.value : 'all') as any;
+    this.applyFilters();
+  }
+  
   // 选择单个项目
   selectProject(): void {
     if (this.selectedProjectId) {
@@ -376,6 +495,25 @@ export class Dashboard implements OnInit {
     return this.filteredProjects.filter(project => project.currentStage === stageId);
   }
 
+  // 新增:阶段到核心阶段的映射
+  private mapStageToCorePhase(stageId: string): 'preparation' | 'design' | 'production' | 'review' | 'delivery' {
+    if (stageId === 'pendingApproval' || stageId === 'pendingAssignment') return 'preparation';
+    if (stageId === 'requirement' || stageId === 'planning') return 'design';
+    if (stageId === 'modeling' || stageId === 'rendering' || stageId === 'postProduction') return 'production';
+    if (stageId === 'review' || stageId === 'revision') return 'review';
+    return 'delivery';
+  }
+
+  // 新增:获取核心阶段的项目
+  getProjectsByCorePhase(coreId: string): Project[] {
+    return this.filteredProjects.filter(p => this.mapStageToCorePhase(p.currentStage) === coreId);
+  }
+
+  // 新增:获取核心阶段的项目数量
+  getProjectCountByCorePhase(coreId: string): number {
+    return this.getProjectsByCorePhase(coreId).length;
+  }
+
   // 获取特定阶段的项目数量
   getProjectCountByStage(stageId: string): number {
     return this.getProjectsByStage(stageId).length;
@@ -391,13 +529,75 @@ export class Dashboard implements OnInit {
     return labels[urgency as keyof typeof labels] || urgency;
   }
 
+  // 智能推荐设计师
+  private getRecommendedDesigner(projectType: 'soft' | 'hard') {
+    if (!this.designerProfiles || !this.designerProfiles.length) return null;
+    const scoreOf = (p: any) => {
+      const workloadScore = 100 - (p.workload ?? 0); // 负载越低越好
+      const ratingScore = (p.avgRating ?? 0) * 10;   // 评分越高越好
+      const expScore = (p.experience ?? 0) * 5;      // 经验越高越好
+      return workloadScore * 0.5 + ratingScore * 0.3 + expScore * 0.2;
+    };
+    const sorted = [...this.designerProfiles].sort((a, b) => scoreOf(b) - scoreOf(a));
+    return sorted[0] || null;
+  }
+
+  // 质量评审
+  reviewProjectQuality(projectId: string, rating: 'excellent' | 'qualified' | 'unqualified'): void {
+    const project = this.projects.find(p => p.id === projectId);
+    if (!project) return;
+    project.qualityRating = rating;
+    if (rating === 'unqualified') {
+      // 不合格:回退到修改阶段
+      project.currentStage = 'revision';
+    }
+    this.applyFilters();
+    alert('质量评审已提交');
+  }
+
+  // 查看绩效预警(占位:跳转到团队管理)
+  viewPerformanceDetails(): void {
+    this.router.navigate(['/team-leader/team-management']);
+  }
+
+  // 打开负载日历(占位:跳转到团队管理)
+  navigateToWorkloadCalendar(): void {
+    this.router.navigate(['/team-leader/team-management']);
+  }
+
   // 查看项目详情
   viewProjectDetails(projectId: string): void {
     this.router.navigate(['/team-leader/project-review', projectId]);
   }
 
-  // 快速分配项目
+  // 快速分配项目(增强:加入智能推荐)
   quickAssignProject(projectId: string): void {
+    const project = this.projects.find(p => p.id === projectId);
+    if (!project) {
+      alert('未找到对应项目');
+      return;
+    }
+
+    const recommended = this.getRecommendedDesigner(project.type);
+    if (recommended) {
+      const reassigning = !!project.designerName;
+      const message = `推荐设计师:${recommended.name}(工作负载:${recommended.workload}%,评分:${recommended.avgRating}分)`
+        + (reassigning ? `\n\n该项目当前已由「${project.designerName}」负责,是否改为分配给「${recommended.name}」?` : '\n\n是否确认分配?');
+      const confirmAssign = confirm(message);
+      if (confirmAssign) {
+        project.designerName = recommended.name;
+        if (project.currentStage === 'pendingAssignment' || project.currentStage === 'pendingApproval') {
+          project.currentStage = 'requirement';
+        }
+        project.status = '进行中';
+        // 更新设计师筛选列表
+        this.designers = Array.from(new Set(this.projects.map(p => p.designerName).filter(n => !!n)));
+        this.applyFilters();
+        alert(`项目已${reassigning ? '重新' : ''}分配给 ${recommended.name}`);
+        return;
+      }
+    }
+    // 无推荐或用户取消,跳转到详细分配页面
     this.router.navigate(['/team-leader/project-review', projectId, 'assign']);
   }
 

+ 119 - 0
src/app/pages/team-leader/performance/performance.html

@@ -0,0 +1,119 @@
+<div class="container">
+  <header class="page-header">
+    <h1>绩效考核</h1>
+    <p class="subtitle">基于7-2-1原则,评估并展示团队成员的周期绩效</p>
+  </header>
+
+  <main class="main-content">
+    <div class="toolbar">
+      <div class="filters">
+        <div class="filter-group">
+          <i class="icon-calendar"></i>
+          <select (change)="onFilterChange('quarter', $event)">
+            <option value="2024-Q2">2024年第二季度</option>
+            <option value="2024-Q1">2024年第一季度</option>
+            <option value="2023-Q4">2023年第四季度</option>
+          </select>
+        </div>
+      </div>
+      <button class="btn-icon" (click)="exportReport()">
+        <i class="icon-export"></i>
+        <span>导出报告</span>
+      </button>
+    </div>
+
+    <!-- 7-2-1 分布概览 -->
+    <section class="distribution-overview">
+      <div class="dist-card top-20">
+        <div class="card-header">
+          <h2>头部 20%</h2>
+          <span class="count">{{ distribution.top.length }}人</span>
+        </div>
+        <div class="card-body">
+          @for (designer of distribution.top; track designer.id) {
+            <div class="designer-item">
+              <span class="name">{{ designer.name }}</span>
+              <span class="score">{{ designer.performanceScore }}分</span>
+            </div>
+          }
+        </div>
+        <div class="card-footer">
+          <p>激励与晋升机会</p>
+        </div>
+      </div>
+
+      <div class="dist-card middle-70">
+        <div class="card-header">
+          <h2>中部 70%</h2>
+          <span class="count">{{ distribution.middle.length }}人</span>
+        </div>
+        <div class="card-body">
+          @for (designer of distribution.middle; track designer.id) {
+            <div class="designer-item">
+              <span class="name">{{ designer.name }}</span>
+              <span class="score">{{ designer.performanceScore }}分</span>
+            </div>
+          }
+        </div>
+        <div class="card-footer">
+          <p>稳步发展与赋能</p>
+        </div>
+      </div>
+
+      <div class="dist-card bottom-10">
+        <div class="card-header">
+          <h2>尾部 10%</h2>
+          <span class="count">{{ distribution.bottom.length }}人</span>
+        </div>
+        <div class="card-body">
+          @for (designer of distribution.bottom; track designer.id) {
+            <div class="designer-item">
+              <span class="name">{{ designer.name }}</span>
+              <span class="score">{{ designer.performanceScore }}分</span>
+            </div>
+          }
+        </div>
+        <div class="card-footer">
+          <p>辅导与改进计划</p>
+        </div>
+      </div>
+    </section>
+
+    <!-- 绩效详情列表 -->
+    <section class="performance-details">
+      <h2 class="section-title">绩效详情</h2>
+      <div class="details-table">
+        <div class="table-header">
+          <div class="col-rank">排名</div>
+          <div class="col-name">姓名</div>
+          <div class="col-score">总分</div>
+          <div class="col-delivery">交付准时率</div>
+          <div class="col-quality">作品优秀率</div>
+          <div class="col-satisfaction">客户满意度</div>
+          <div class="col-actions">操作</div>
+        </div>
+        @if (sortedDesigners.length > 0) {
+          <div class="table-body">
+            @for (designer of sortedDesigners; track designer.id; let i = $index) {
+              <div class="table-row">
+                <div class="col-rank">{{ i + 1 }}</div>
+                <div class="col-name">{{ designer.name }}</div>
+                <div class="col-score">{{ designer.performanceScore }}</div>
+                <div class="col-delivery">{{ designer.metrics.deliveryRate }}%</div>
+                <div class="col-quality">{{ designer.metrics.qualityRate }}%</div>
+                <div class="col-satisfaction">{{ designer.metrics.satisfactionRate }}%</div>
+                <div class="col-actions">
+                  <button class="btn-link" (click)="viewDetailReport(designer.id)">查看报告</button>
+                </div>
+              </div>
+            }
+          </div>
+        } @else {
+          <div class="empty-state">
+            <p>当前季度暂无绩效数据</p>
+          </div>
+        }
+      </div>
+    </section>
+  </main>
+</div>

+ 275 - 0
src/app/pages/team-leader/performance/performance.scss

@@ -0,0 +1,275 @@
+@use '../ios-theme' as ios;
+
+.container {
+  padding: 20px;
+  background-color: ios.$ios-background-secondary;
+  min-height: 100vh;
+}
+
+.page-header {
+  margin-bottom: 30px;
+  h1 {
+    font-size: 28px;
+    font-weight: 600;
+    color: ios.$ios-text-primary;
+    margin-bottom: 4px;
+  }
+  .subtitle {
+    font-size: 16px;
+    color: ios.$ios-text-secondary;
+  }
+}
+
+.main-content {
+  display: flex;
+  flex-direction: column;
+  gap: 30px;
+}
+
+.toolbar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  background-color: ios.$ios-background;
+  padding: 15px;
+  border-radius: ios.$ios-radius-lg;
+  box-shadow: ios.$ios-shadow-sm;
+
+  .filters {
+    display: flex;
+    align-items: center;
+    gap: 20px;
+
+    .filter-group {
+      display: flex;
+      align-items: center;
+      gap: 8px;
+
+      i {
+        color: ios.$ios-text-secondary;
+      }
+
+      select {
+        background-color: transparent;
+        border: none;
+        font-size: 16px;
+        font-weight: 500;
+        color: ios.$ios-text-primary;
+        cursor: pointer;
+
+        &:focus {
+          outline: none;
+        }
+      }
+    }
+  }
+
+  .btn-icon {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    background-color: ios.$ios-primary;
+    color: white;
+    padding: 10px 15px;
+    border-radius: ios.$ios-radius-md;
+    font-size: 15px;
+    font-weight: 500;
+    border: none;
+    cursor: pointer;
+    transition: background-color 0.3s ease;
+
+    &:hover {
+      opacity: 0.9;
+    }
+
+    i {
+      font-size: 18px;
+    }
+  }
+}
+
+.distribution-overview {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 20px;
+
+  .dist-card {
+    background-color: ios.$ios-background;
+    border-radius: ios.$ios-radius-lg;
+    box-shadow: ios.$ios-shadow-sm;
+    padding: 20px;
+    display: flex;
+    flex-direction: column;
+
+    .card-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: baseline;
+      margin-bottom: 15px;
+      padding-bottom: 10px;
+      border-bottom: 1px solid ios.$ios-border;
+
+      h2 {
+        font-size: 20px;
+        font-weight: 600;
+      }
+
+      .count {
+        font-size: 16px;
+        font-weight: 500;
+        color: ios.$ios-text-secondary;
+      }
+    }
+
+    .card-body {
+      flex-grow: 1;
+      display: flex;
+      flex-direction: column;
+      gap: 12px;
+
+      .designer-item {
+        display: flex;
+        justify-content: space-between;
+        padding: 8px 0;
+
+        .name {
+          font-weight: 500;
+          color: ios.$ios-text-primary;
+        }
+
+        .score {
+          font-weight: 600;
+        }
+      }
+    }
+
+    .card-footer {
+      margin-top: 15px;
+      padding-top: 10px;
+      border-top: 1px solid ios.$ios-border;
+      p {
+        font-size: 14px;
+        color: ios.$ios-text-secondary;
+        font-style: italic;
+      }
+    }
+
+    &.top-20 {
+      h2 { color: ios.$ios-success; }
+      .score { color: ios.$ios-success; }
+    }
+    &.middle-70 {
+      h2 { color: ios.$ios-info; }
+      .score { color: ios.$ios-info; }
+    }
+    &.bottom-10 {
+      h2 { color: ios.$ios-danger; }
+      .score { color: ios.$ios-danger; }
+    }
+  }
+}
+
+.performance-details {
+  background-color: ios.$ios-background;
+  border-radius: ios.$ios-radius-lg;
+  box-shadow: ios.$ios-shadow-sm;
+  padding: 20px;
+
+  .section-title {
+    font-size: 22px;
+    font-weight: 600;
+    margin-bottom: 20px;
+  }
+
+  .details-table {
+    .table-header, .table-row {
+      display: grid;
+      grid-template-columns: 50px 1fr 1fr 1fr 1fr 1fr 100px;
+      gap: 15px;
+      align-items: center;
+      padding: 12px 15px;
+      border-bottom: 1px solid ios.$ios-border;
+    }
+
+    .table-header {
+      font-weight: 600;
+      color: ios.$ios-text-secondary;
+      font-size: 14px;
+      text-transform: uppercase;
+    }
+
+    .table-body {
+      .table-row {
+        transition: background-color 0.3s ease;
+
+        &:hover {
+          background-color: ios.$ios-background-secondary;
+        }
+
+        .col-rank {
+          font-weight: 700;
+          font-size: 18px;
+          color: ios.$ios-primary;
+        }
+
+        .col-name {
+        }
+
+        .col-score {
+          font-weight: 600;
+        }
+
+        .btn-link {
+          color: ios.$ios-primary;
+          font-weight: 500;
+          cursor: pointer;
+          background: none;
+          border: none;
+          &:hover { text-decoration: underline; }
+        }
+      }
+    }
+
+    .empty-state {
+      text-align: center;
+      padding: 40px;
+      color: ios.$ios-text-secondary;
+    }
+  }
+}
+
+// Responsive Design
+@media (max-width: 1200px) {
+  .distribution-overview {
+    grid-template-columns: 1fr;
+  }
+}
+
+@media (max-width: 768px) {
+  .container { padding: 15px; }
+  .page-header h1 { font-size: 24px; }
+  .toolbar { flex-direction: column; gap: 15px; align-items: stretch; }
+  .details-table {
+    .table-header { display: none; }
+    .table-row {
+      grid-template-columns: 1fr 1fr;
+      gap: 10px;
+      padding: 15px;
+      margin-bottom: 10px;
+      border-radius: ios.$ios-radius-md;
+      border: 1px solid ios.$ios-border;
+      position: relative;
+
+      div[class^="col-"]::before {
+        content: attr(data-label);
+        font-weight: 600;
+        color: ios.$ios-text-secondary;
+        margin-right: 10px;
+      }
+
+      .col-rank { position: absolute; top: 15px; right: 15px; font-size: 20px; }
+      .col-name { grid-column: 1 / -1; font-size: 18px; margin-bottom: 5px; }
+      .col-actions { grid-column: 1 / -1; margin-top: 10px; }
+    }
+  }
+}

+ 91 - 0
src/app/pages/team-leader/performance/performance.ts

@@ -0,0 +1,91 @@
+import { Component, OnInit } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+interface DesignerPerformance {
+  id: string;
+  name: string;
+  performanceScore: number;
+  metrics: {
+    deliveryRate: number;
+    qualityRate: number;
+    satisfactionRate: number;
+  };
+}
+
+@Component({
+  selector: 'app-performance',
+  standalone: true,
+  imports: [CommonModule],
+  templateUrl: './performance.html',
+  styleUrls: ['./performance.scss']
+})
+export class PerformanceComponent implements OnInit {
+
+  allDesigners: DesignerPerformance[] = [];
+  sortedDesigners: DesignerPerformance[] = [];
+  distribution = {
+    top: [] as DesignerPerformance[],
+    middle: [] as DesignerPerformance[],
+    bottom: [] as DesignerPerformance[],
+  };
+
+  ngOnInit(): void {
+    this.loadPerformanceData();
+  }
+
+  loadPerformanceData(): void {
+    // 模拟数据
+    this.allDesigners = this.generateMockData(20);
+    this.sortAndDistributeDesigners();
+  }
+
+  generateMockData(count: number): DesignerPerformance[] {
+    const names = ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', 'Grace', 'Heidi', 'Ivan', 'Judy', 'Mallory', 'Niaj', 'Olivia', 'Peggy', 'Rupert', 'Sybil', 'Trent', 'Victor', 'Walter', 'Wendy'];
+    const data: DesignerPerformance[] = [];
+    for (let i = 0; i < count; i++) {
+      const score = Math.floor(Math.random() * 41) + 60; // 60-100
+      data.push({
+        id: `d${i + 1}`,
+        name: names[i % names.length],
+        performanceScore: score,
+        metrics: {
+          deliveryRate: Math.floor(Math.random() * 11) + 90, // 90-100
+          qualityRate: Math.floor(Math.random() * 21) + 80, // 80-100
+          satisfactionRate: Math.floor(Math.random() * 21) + 80, // 80-100
+        }
+      });
+    }
+    return data;
+  }
+
+  sortAndDistributeDesigners(): void {
+    this.sortedDesigners = [...this.allDesigners].sort((a, b) => b.performanceScore - a.performanceScore);
+
+    const total = this.sortedDesigners.length;
+    const topCount = Math.ceil(total * 0.2);
+    const bottomCount = Math.floor(total * 0.1);
+
+    this.distribution.top = this.sortedDesigners.slice(0, topCount);
+    this.distribution.bottom = this.sortedDesigners.slice(total - bottomCount);
+    this.distribution.middle = this.sortedDesigners.slice(topCount, total - bottomCount);
+  }
+
+  onFilterChange(type: string, event: Event): void {
+    const value = (event.target as HTMLSelectElement).value;
+    console.log(`Filter changed: ${type} = ${value}`);
+    // 重新加载模拟数据以体现变化
+    this.loadPerformanceData();
+  }
+
+  exportReport(): void {
+    console.log('Exporting performance report...');
+    // 实际的导出逻辑
+    alert('报告已开始导出!');
+  }
+
+  viewDetailReport(designerId: string): void {
+    console.log(`Viewing detail report for designer: ${designerId}`);
+    // 导航到详细报告页面的逻辑
+    alert(`正在查看 ${this.allDesigners.find(d => d.id === designerId)?.name} 的详细报告`);
+  }
+}

+ 170 - 0
src/app/shared/styles/_ios-theme.scss

@@ -0,0 +1,170 @@
+// ==========================================================================
+// iOS Design Theme - Variables
+// ==========================================================================
+//
+// Purpose:
+// --------
+// This file establishes a design system based on Apple's Human Interface Guidelines (HIG).
+// It provides a comprehensive set of SCSS variables for colors, typography, spacing,
+// and other properties to ensure a consistent and native iOS look and feel across
+// the application.
+//
+// Sections:
+// ---------
+// 1.  **System Colors**: Standard iOS system colors for backgrounds, text, and UI elements.
+// 2.  **UI Colors**: Colors for specific UI components like buttons, switches, and notifications.
+// 3.  **Typography**: Font families, sizes, and weights for different text styles.
+// 4.  **Spacing & Layout**: Standardized spacing units for margins, padding, and grid systems.
+// 5.  **Effects & Materials**: Variables for shadows, blurs, and other visual effects.
+// 6.  **Component-Specific**: Variables tailored for specific components like lists, forms, etc.
+//
+// ==========================================================================
+
+// --------------------------------------------------------------------------
+// 1. System Colors
+//    - Based on Apple's Human Interface Guidelines (HIG) color palette.
+//    - Includes light and dark mode variants.
+// --------------------------------------------------------------------------
+
+// Light Mode System Colors
+$ios-color-system-blue-light: #007AFF;
+$ios-color-system-green-light: #34C759;
+$ios-color-system-indigo-light: #5856D6;
+$ios-color-system-orange-light: #FF9500;
+$ios-color-system-pink-light: #FF2D55;
+$ios-color-system-purple-light: #AF52DE;
+$ios-color-system-red-light: #FF3B30;
+$ios-color-system-teal-light: #5AC8FA;
+$ios-color-system-yellow-light: #FFCC00;
+
+// Light Mode Grays
+$ios-color-system-gray-1-light: #8E8E93;
+$ios-color-system-gray-2-light: #AEAEB2;
+$ios-color-system-gray-3-light: #C7C7CC;
+$ios-color-system-gray-4-light: #D1D1D6;
+$ios-color-system-gray-5-light: #E5E5EA;
+$ios-color-system-gray-6-light: #F2F2F7;
+
+// Light Mode UI Elements
+$ios-color-label-light: #000000;
+$ios-color-secondary-label-light: rgba(60, 60, 67, 0.6);
+$ios-color-tertiary-label-light: rgba(60, 60, 67, 0.3);
+$ios-color-quaternary-label-light: rgba(60, 60, 67, 0.18);
+
+$ios-color-system-background-light: #FFFFFF;
+$ios-color-secondary-system-background-light: #F2F2F7;
+$ios-color-tertiary-system-background-light: #FFFFFF;
+
+$ios-color-separator-light: rgba(60, 60, 67, 0.29);
+$ios-color-opaque-separator-light: #C6C6C8;
+
+// Dark Mode will be defined here if needed in the future
+
+// --------------------------------------------------------------------------
+// 2. UI Colors
+//    - Colors for specific UI components.
+// --------------------------------------------------------------------------
+$ios-primary: $ios-color-system-blue-light;
+$ios-color-link: $ios-color-system-blue-light;
+$ios-color-button-primary-background: $ios-color-system-blue-light;
+$ios-card-background: $ios-color-system-background-light;
+$ios-background: $ios-color-system-background-light;
+$ios-background-secondary: $ios-color-secondary-system-background-light;
+$ios-background-tertiary: $ios-color-tertiary-system-background-light;
+$ios-border: $ios-color-separator-light;
+
+// Text Colors
+$ios-text-primary: $ios-color-label-light;
+$ios-text-secondary: $ios-color-secondary-label-light;
+$ios-text-tertiary: $ios-color-tertiary-label-light;
+
+// Semantic Colors
+$ios-success: $ios-color-system-green-light;
+$ios-warning: $ios-color-system-orange-light;
+$ios-error: $ios-color-system-red-light;
+$ios-danger: $ios-color-system-red-light;
+$ios-info: $ios-color-system-teal-light;
+
+// --------------------------------------------------------------------------
+// 3. Typography
+//    - Font families, sizes, and weights based on SF Pro.
+// --------------------------------------------------------------------------
+$ios-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+
+// Dynamic Type Sizes (Large is default)
+$ios-font-size-large-title: 34px;
+$ios-font-size-title-1: 28px;
+$ios-font-size-title-2: 22px;
+$ios-font-size-title-3: 20px;
+$ios-font-size-headline: 17px;
+$ios-font-size-body: 17px;
+$ios-font-size-callout: 16px;
+$ios-font-size-subhead: 15px;
+$ios-font-size-footnote: 13px;
+$ios-font-size-caption-1: 12px;
+$ios-font-size-caption-2: 11px;
+
+// Custom sizes
+$ios-font-size-xl: 24px;
+$ios-font-size-lg: 18px;
+$ios-font-size-md: 16px;
+$ios-font-size-sm: 14px;
+$ios-font-size-xs: 12px;
+$ios-font-size-base: $ios-font-size-md;
+
+// Font Weights
+$ios-font-weight-regular: 400;
+$ios-font-weight-medium: 500;
+$ios-font-weight-semibold: 600;
+$ios-font-weight-bold: 700;
+
+// --------------------------------------------------------------------------
+// 4. Spacing & Layout
+//    - Standardized spacing units for consistent layout.
+// --------------------------------------------------------------------------
+$ios-spacing-base-unit: 8px;
+$ios-spacing-xxs: $ios-spacing-base-unit * 0.25; // 2px
+$ios-spacing-xs: $ios-spacing-base-unit * 0.5;   // 4px
+$ios-spacing-sm: $ios-spacing-base-unit;         // 8px
+$ios-spacing-md: $ios-spacing-base-unit * 2;     // 16px
+$ios-spacing-lg: $ios-spacing-base-unit * 3;     // 24px
+$ios-spacing-xl: $ios-spacing-base-unit * 4;     // 32px
+$ios-spacing-xxl: $ios-spacing-base-unit * 6;    // 48px
+
+// --------------------------------------------------------------------------
+// 5. Effects & Materials
+//    - Shadows, corner radii, and other visual effects.
+// --------------------------------------------------------------------------
+$ios-corner-radius-sm: 6px;
+$ios-corner-radius-md: 10px;
+$ios-corner-radius-lg: 14px;
+$ios-corner-radius-xl: 20px;
+$ios-corner-radius-continuous: 9999px;
+
+$ios-radius-sm: $ios-corner-radius-sm;
+$ios-radius-md: $ios-corner-radius-md;
+$ios-radius-lg: $ios-corner-radius-lg;
+$ios-radius-xl: $ios-corner-radius-xl;
+$ios-radius-full: $ios-corner-radius-continuous;
+
+$ios-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
+$ios-shadow-md: 0 2px 4px rgba(0, 0, 0, 0.08);
+$ios-shadow-subtle: 0 1px 2px rgba(0, 0, 0, 0.05);
+$ios-shadow-standard: 0 3px 8px rgba(0, 0, 0, 0.12);
+$ios-shadow-strong: 0 6px 16px rgba(0, 0, 0, 0.15);
+$ios-shadow-card: $ios-shadow-standard;
+$ios-shadow-lg: $ios-shadow-strong;
+
+// --------------------------------------------------------------------------
+// 6. Component-Specific Variables
+// --------------------------------------------------------------------------
+
+$ios-list-item-height: 44px;
+$ios-form-input-height: 44px;
+$ios-navbar-height: 44px;
+$ios-tabbar-height: 50px;
+
+// Transitions
+$ios-transition-duration: 0.3s;
+$ios-transition-timing-function: ease-in-out;
+$ios-feedback-tap: transform 0.1s ease-out;