dashboard.html 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <header class="dashboard-header">
  2. <h1>设计组长工作台</h1>
  3. <!-- 核心数据指标卡片 -->
  4. <div class="dashboard-metrics">
  5. <div class="metric-card" (click)="filterByStatus('overdue')">
  6. <div class="metric-icon warning">⚠️</div>
  7. <div class="metric-content">
  8. <div class="metric-count">{{ overdueProjects.length }}</div>
  9. <div class="metric-label">已延期项目</div>
  10. </div>
  11. </div>
  12. <div class="metric-card" (click)="filterByStatus('dueSoon')">
  13. <div class="metric-icon info">⏳</div>
  14. <div class="metric-content">
  15. <div class="metric-count">{{ dueSoonProjects.length }}</div>
  16. <div class="metric-label">临期项目(3天内)</div>
  17. </div>
  18. </div>
  19. <div class="metric-card" (click)="filterByStatus('pendingApproval')">
  20. <div class="metric-icon info">📋</div>
  21. <div class="metric-content">
  22. <div class="metric-count">{{ pendingApprovalProjects.length }}</div>
  23. <div class="metric-label">待组长确认项目</div>
  24. </div>
  25. </div>
  26. <div class="metric-card" (click)="filterByStatus('pendingAssignment')">
  27. <div class="metric-icon primary">🎯</div>
  28. <div class="metric-content">
  29. <div class="metric-count">{{ pendingAssignmentProjects.length }}</div>
  30. <div class="metric-label">待分配方案项目</div>
  31. </div>
  32. </div>
  33. </div>
  34. </header>
  35. <main class="dashboard-main">
  36. <!-- 项目监控大盘 -->
  37. <section class="monitoring-section">
  38. <div class="section-header">
  39. <h2>项目监控大盘</h2>
  40. <div class="section-filters">
  41. <select (change)="filterProjects($event)" class="custom-select">
  42. <option value="all">全部项目</option>
  43. <option value="soft">软装项目</option>
  44. <option value="hard">硬装项目</option>
  45. </select>
  46. <select (change)="filterByUrgency($event)" class="custom-select">
  47. <option value="all">全部紧急程度</option>
  48. <option value="high">高</option>
  49. <option value="medium">中</option>
  50. <option value="low">低</option>
  51. </select>
  52. <select (change)="onStatusChange($event)" class="custom-select">
  53. <option value="all">全部状态</option>
  54. <option value="progress">进行中</option>
  55. <option value="completed">已完成</option>
  56. <option value="overdue">已延期</option>
  57. <option value="dueSoon">临期(3天内)</option>
  58. <option value="pendingApproval">待确认</option>
  59. <option value="pendingAssignment">待分配</option>
  60. </select>
  61. <select (change)="onDesignerChange($event)" class="custom-select">
  62. <option value="all">全部设计师</option>
  63. @for (d of designers; track d) {
  64. <option [value]="d">{{ d }}</option>
  65. }
  66. </select>
  67. <select (change)="onMemberTypeChange($event)" class="custom-select">
  68. <option value="all">全部会员</option>
  69. <option value="vip">VIP会员</option>
  70. <option value="normal">普通会员</option>
  71. </select>
  72. <!-- 支持数百项目的下拉筛选 -->
  73. <select [(ngModel)]="selectedProjectId" (change)="selectProject()" class="custom-select project-selector">
  74. <option value="">选择项目</option>
  75. @for (project of projects; track project.id) {
  76. <option [value]="project.id">{{ project.name }}</option>
  77. }
  78. </select>
  79. <!-- 新增:时间窗快捷筛选按钮组 -->
  80. <div class="time-window-buttons">
  81. <button [class.active]="selectedTimeWindow === 'all'" (click)="filterByTimeWindow('all')">全部</button>
  82. <button [class.active]="selectedTimeWindow === 'today'" (click)="filterByTimeWindow('today')">今天到期</button>
  83. <button [class.active]="selectedTimeWindow === 'threeDays'" (click)="filterByTimeWindow('threeDays')">3天内</button>
  84. <button [class.active]="selectedTimeWindow === 'sevenDays'" (click)="filterByTimeWindow('sevenDays')">7天内</button>
  85. </div>
  86. </div>
  87. </div>
  88. <!-- 项目看板 - 横向展开10个项目阶段 -->
  89. <div class="project-kanban">
  90. <!-- 新增:公共横向滚动容器,保证表头与表体同步滚动 -->
  91. <div class="kanban-scroll">
  92. <!-- 阶段标题 -->
  93. <div class="kanban-header">
  94. @for (core of corePhases; track core.id) {
  95. <div class="kanban-column-header">
  96. <h3>{{ core.name }}</h3>
  97. <span class="stage-count">{{ getProjectCountByCorePhase(core.id) }}</span>
  98. </div>
  99. }
  100. </div>
  101. <!-- 项目卡片 -->
  102. <div class="kanban-body">
  103. @for (core of corePhases; track core.id) {
  104. <div class="kanban-column">
  105. @for (project of getProjectsByCorePhase(core.id); track project.id) {
  106. <div class="project-card"
  107. (click)="viewProjectDetails(project.id)"
  108. [class.overdue]="project.isOverdue"
  109. [class.high-urgency]="project.urgency === 'high'"
  110. [class.due-soon]="project.dueSoon && !project.isOverdue">
  111. <div class="project-card-header">
  112. <h4 [routerLink]="['/team-leader/project-detail', project.id]" (click)="$event.stopPropagation()">{{ project.name }}</h4>
  113. <div class="right-badges">
  114. <span class="member-badge" [class.vip]="project.memberType === 'vip'">{{ project.memberType === 'vip' ? 'VIP' : '普通' }}</span>
  115. <span class="project-urgency" [class]="'urgency-' + project.urgency">{{ getUrgencyLabel(project.urgency) }}</span>
  116. </div>
  117. </div>
  118. <div class="project-card-content">
  119. <p>负责人: {{ project.designerName || '未分配' }}</p>
  120. <p class="deadline">{{ project.isOverdue ? '超期' + project.overdueDays + '天' : (project.dueSoon ? '临期: ' + (project.expectedEndDate | date:'MM-dd') : '截止: ' + (project.expectedEndDate | date:'MM-dd')) }}</p>
  121. </div>
  122. <div class="project-card-footer">
  123. <button (click)="viewProjectDetails(project.id); $event.stopPropagation()" class="btn-view">查看详情</button>
  124. @if (project.currentStage === 'pendingAssignment') {
  125. <button (click)="quickAssignProject(project.id); $event.stopPropagation()" class="btn-assign">分配</button>
  126. }
  127. <!-- 新增:质量评审快捷操作 -->
  128. @if (project.currentStage === 'review' || project.currentStage === 'delivery') {
  129. <div class="inline-actions">
  130. <button class="btn-secondary" (click)="$event.stopPropagation(); reviewProjectQuality(project.id, 'excellent')">评为优秀</button>
  131. <button class="btn-secondary" (click)="$event.stopPropagation(); reviewProjectQuality(project.id, 'qualified')">评为合格</button>
  132. <button class="btn-secondary" (click)="$event.stopPropagation(); reviewProjectQuality(project.id, 'unqualified')">评为不合格</button>
  133. </div>
  134. }
  135. </div>
  136. </div>
  137. }
  138. @if (getProjectsByCorePhase(core.id).length === 0) {
  139. <div class="empty-column">
  140. <span class="empty-icon">📦</span>
  141. <p>暂无项目</p>
  142. </div>
  143. }
  144. </div>
  145. }
  146. </div>
  147. </div>
  148. </div>
  149. </section>
  150. <!-- 待办任务优先级排序 -->
  151. <section class="todo-section">
  152. <div class="section-header">
  153. <h2>待办任务</h2>
  154. <!-- 新增:绩效与负载入口 -->
  155. <div class="section-actions">
  156. <button class="btn-link" (click)="viewPerformanceDetails()">查看绩效预警</button>
  157. <button class="btn-link" (click)="navigateToWorkloadCalendar()">打开负载日历</button>
  158. </div>
  159. </div>
  160. <div class="todo-list">
  161. @for (task of todoTasks; track task.id) {
  162. <div class="todo-item" [class.priority-high]="task.priority === 'high'" [class.priority-medium]="task.priority === 'medium'" [class.priority-low]="task.priority === 'low'">
  163. <div class="todo-header">
  164. <h3>{{ task.title }}</h3>
  165. <span class="task-priority">{{ getPriorityLabel(task.priority) }}</span>
  166. </div>
  167. <div class="todo-info">
  168. <p>{{ task.description }}</p>
  169. <p class="task-deadline">截止时间: {{ task.deadline | date:'yyyy-MM-dd HH:mm' }}</p>
  170. </div>
  171. <div class="todo-actions">
  172. <button (click)="navigateToTask(task)" class="btn-handle">处理任务</button>
  173. </div>
  174. </div>
  175. }
  176. </div>
  177. </section>
  178. <!-- 超期项目提醒 -->
  179. @if (showAlert && overdueProjects.length > 0) {
  180. <div class="overdue-alert">
  181. <div class="alert-content">
  182. <h3>⚠️ 超期项目提醒</h3>
  183. <ul>
  184. @for (project of overdueProjects.slice(0, 3); track $index) {
  185. <li>
  186. {{ project.name }} ({{ project.designerName }} 负责) - 超期{{ project.overdueDays }}天
  187. </li>
  188. }
  189. </ul>
  190. <div class="alert-actions">
  191. <button (click)="viewAllOverdueProjects()" class="btn-view-all">查看全部</button>
  192. <button (click)="closeAlert()" class="btn-close">关闭</button>
  193. </div>
  194. </div>
  195. </div>
  196. }
  197. </main>