| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- import { Component, Input, Output, EventEmitter } from '@angular/core';
- import { CommonModule } from '@angular/common';
- /**
- * 紧急事件接口
- */
- export interface UrgentEvent {
- id: string;
- title: string;
- description: string;
- eventType: 'review' | 'delivery' | 'phase_deadline' | 'custom';
- deadline: Date;
- projectId: string;
- projectName: string;
- designerName?: string;
- urgencyLevel: 'critical' | 'high' | 'medium';
- overdueDays?: number;
- phaseName?: string;
- }
- /**
- * 紧急事件面板组件(可复用)
- *
- * 功能:
- * 1. 显示紧急事件列表
- * 2. 支持加载状态、空状态、错误状态
- * 3. 支持点击查看项目详情
- * 4. 自动计算逾期天数
- */
- @Component({
- selector: 'app-urgent-events-panel',
- standalone: true,
- imports: [CommonModule],
- template: `
- <div class="todo-column todo-column-urgent">
- <!-- 面板头部 -->
- <div class="column-header">
- <h3>
- <svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor">
- <path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>
- </svg>
- {{ title }}
- @if (events.length > 0) {
- <span class="task-count urgent">({{ events.length }})</span>
- }
- </h3>
- <span class="column-subtitle">{{ subtitle }}</span>
- </div>
-
- <!-- 加载状态 -->
- @if (loading) {
- <div class="loading-state">
- <svg class="spinner" viewBox="0 0 50 50">
- <circle cx="25" cy="25" r="20" fill="none" stroke-width="4"></circle>
- </svg>
- <p>{{ loadingText }}</p>
- </div>
- }
-
- <!-- 空状态 -->
- @if (!loading && events.length === 0) {
- <div class="empty-state">
- <svg viewBox="0 0 24 24" width="64" height="64" fill="#d1d5db">
- <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z"/>
- </svg>
- <p>{{ emptyText }}</p>
- <p class="hint">{{ emptyHint }}</p>
- </div>
- }
-
- <!-- 紧急事件列表 -->
- @if (!loading && events.length > 0) {
- <div class="todo-list-compact urgent-list">
- @for (event of events; track event.id) {
- <div class="todo-item-compact urgent-item" [attr.data-urgency]="event.urgencyLevel">
- <!-- 左侧紧急程度色条 -->
- <div class="urgency-indicator" [attr.data-urgency]="event.urgencyLevel"></div>
-
- <!-- 事件内容 -->
- <div class="task-content">
- <!-- 标题行 -->
- <div class="task-header">
- <span class="task-title">{{ event.title }}</span>
- <div class="task-badges">
- <span class="badge badge-urgency" [attr.data-urgency]="event.urgencyLevel">
- @if (event.urgencyLevel === 'critical') { 🔴 紧急 }
- @else if (event.urgencyLevel === 'high') { 🟠 重要 }
- @else { 🟡 注意 }
- </span>
- <span class="badge badge-event-type">
- @if (event.eventType === 'review') { 对图 }
- @else if (event.eventType === 'delivery') { 交付 }
- @else if (event.eventType === 'phase_deadline') { {{ event.phaseName }} }
- @else { {{ event.eventType }} }
- </span>
- </div>
- </div>
-
- <!-- 描述 -->
- <div class="task-description">
- {{ event.description }}
- </div>
-
- <!-- 项目信息行 -->
- <div class="task-meta">
- <span class="project-info">
- <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
- <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
- </svg>
- 项目: {{ event.projectName }}
- </span>
- @if (event.designerName) {
- <span class="designer-info">
- <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
- <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
- </svg>
- 设计师: {{ event.designerName }}
- </span>
- }
- </div>
-
- <!-- 底部信息行 -->
- <div class="task-footer">
- <span class="deadline-info" [class.overdue]="event.overdueDays && event.overdueDays > 0">
- <svg viewBox="0 0 24 24" width="12" height="12" fill="currentColor">
- <path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/>
- </svg>
- 截止: {{ event.deadline | date:'MM-dd HH:mm' }}
- @if (event.overdueDays && event.overdueDays > 0) {
- <span class="overdue-label">(逾期{{ event.overdueDays }}天)</span>
- }
- @else if (event.overdueDays && event.overdueDays < 0) {
- <span class="upcoming-label">(还剩{{ -event.overdueDays }}天)</span>
- }
- @else {
- <span class="today-label">(今天)</span>
- }
- </span>
-
- <button
- class="btn-action btn-view-project"
- (click)="onViewProject(event.projectId)">
- 查看项目
- </button>
- </div>
- </div>
- </div>
- }
- </div>
- }
- </div>
- `,
- styles: [`
- /* 组件样式继承父组件的样式类 */
- :host {
- display: block;
- width: 100%;
- height: 100%;
- }
- `]
- })
- export class UrgentEventsPanelComponent {
- // 输入属性
- @Input() events: UrgentEvent[] = [];
- @Input() loading: boolean = false;
- @Input() title: string = '紧急事件';
- @Input() subtitle: string = '自动计算的截止事件';
- @Input() loadingText: string = '计算紧急事件中...';
- @Input() emptyText: string = '暂无紧急事件';
- @Input() emptyHint: string = '所有项目时间节点正常 ✅';
-
- // 输出事件
- @Output() viewProject = new EventEmitter<string>();
-
- /**
- * 查看项目详情
- */
- onViewProject(projectId: string): void {
- this.viewProject.emit(projectId);
- }
- }
|