123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- <div class="workload-calendar-container">
- <header class="page-header" role="navigation" aria-label="工作量日历控制">
- <h1>负载日历</h1>
- <div class="controls">
- <div class="view-switch" role="tablist" aria-label="视图切换">
- <button [class.active]="view==='day'" (click)="switchView('day')" role="tab" [attr.aria-selected]="view==='day'" title="日视图">日</button>
- <button [class.active]="view==='week'" (click)="switchView('week')" role="tab" [attr.aria-selected]="view==='week'" title="周视图">周</button>
- <button [class.active]="view==='month'" (click)="switchView('month')" role="tab" [attr.aria-selected]="view==='month'" title="月视图">月</button>
- </div>
- <div class="date-nav">
- <button (click)="navigateDate('prev')" aria-label="上一周期">‹</button>
- <span class="month-label" aria-live="polite">{{ monthLabel }}</span>
- <button (click)="navigateDate('next')" aria-label="下一周期">›</button>
- <button class="today" (click)="setToday()" title="返回今天">今天</button>
- </div>
- <div class="filters">
- <label for="designerSelect">设计师:</label>
- <select id="designerSelect" [(ngModel)]="selectedDesigner" (change)="onDesignerChange()">
- <option value="all">全部</option>
- @for (d of designers; track d) {
- <option [value]="d">{{ d }}</option>
- }
- </select>
- <label class="overdue-toggle" for="overdueOnly">
- <input id="overdueOnly" type="checkbox" [(ngModel)]="showOverdueOnly" (change)="onOverdueOnlyChange()" />
- 仅看超期
- </label>
- <!-- 新增:快捷范围按钮 -->
- <div class="quick-range" role="group" aria-label="快捷范围">
- <button [class.active]="quickRange==='all'" (click)="onQuickRangeSelect('all')">全部</button>
- <button [class.active]="quickRange==='today'" (click)="onQuickRangeSelect('today')">今天</button>
- <button [class.active]="quickRange==='3d'" (click)="onQuickRangeSelect('3d')">3天内</button>
- <button [class.active]="quickRange==='7d'" (click)="onQuickRangeSelect('7d')">7天内</button>
- </div>
- <!-- 新增:阶段筛选(按5大阶段归并) -->
- <label for="phaseSelect">阶段:</label>
- <select id="phaseSelect" [(ngModel)]="selectedPhase" (change)="onPhaseChange()">
- <option value="all">全部</option>
- @for (p of phases; track p) {
- <option [value]="p">{{ p }}</option>
- }
- </select>
- </div>
- </div>
- </header>
- @if (view==='month') {
- <section class="calendar-section" aria-label="月视图">
- <div class="weekdays">
- <div class="weekday">一</div>
- <div class="weekday">二</div>
- <div class="weekday">三</div>
- <div class="weekday">四</div>
- <div class="weekday">五</div>
- <div class="weekday weekend">六</div>
- <div class="weekday weekend">日</div>
- </div>
- <div class="calendar-grid">
- @for (d of monthDays; track d.date) {
- <div class="day"
- [class.other-month]="!d.currentMonth"
- [class.today]="isSameDay(d.date, today)"
- [class.selected]="isSameDay(d.date, selectedDate)"
- [class.weekend]="isWeekend(d.date)"
- (click)="selectDate(d.date)"
- title="查看 {{ d.date | date:'yyyy-MM-dd' }} 的任务">
- <div class="date-label" [title]="d.date | date:'fullDate'" (click)="selectDate(d.date)">{{ d.date | date:'MM/dd' }}</div>
- <div class="tasks">
- @if (!isExpanded(d.date)) {
- @for (t of d.tasks.slice(0,3); track t.id) {
- <button class="task-chip" type="button" (click)="navigateToProject(t, $event)" [class.overdue]="t.isOverdue" [class.high]="t.priority==='high'" [class.due-soon]="isDueSoon(t.deadline)" title="进入项目:{{t.projectName}}">
- <span class="task-title">{{ t.title }}</span>
- <span class="assignee" title="按设计师筛选" (click)="filterByDesigner(t.assignee, $event)">{{ t.assignee }}</span>
- </button>
- }
- @if (d.tasks.length > 3) {
- <button class="more-btn" (click)="toggleExpand(d.date, $event)" aria-label="展开更多">+{{ d.tasks.length - 3 }}</button>
- }
- } @else {
- @for (t of d.tasks; track t.id) {
- <button class="task-chip" type="button" (click)="navigateToProject(t, $event)" [class.overdue]="t.isOverdue" [class.high]="t.priority==='high'" [class.due-soon]="isDueSoon(t.deadline)" title="进入项目:{{t.projectName}}">
- <span class="task-title">{{ t.title }}</span>
- <span class="assignee" title="按设计师筛选" (click)="filterByDesigner(t.assignee, $event)">{{ t.assignee }}</span>
- </button>
- }
- <button class="more-btn" (click)="toggleExpand(d.date, $event)" aria-label="收起">收起</button>
- }
- @if (d.tasks.length === 0) {
- <div class="no-task" aria-hidden="true">—</div>
- }
- </div>
- </div>
- }
- </div>
- </section>
- }
- @if (view==='week') {
- <section class="calendar-section" aria-label="周视图">
- <div class="week-grid">
- @for (d of weekDays; track d.date) {
- <div class="week-day" [class.today]="isSameDay(d.date, today)" [class.selected]="isSameDay(d.date, selectedDate)" [class.weekend]="isWeekend(d.date)" (click)="selectDate(d.date)">
- <div class="date-label" (click)="selectDate(d.date)">{{ d.date | date:'EEE MM/dd' }}</div>
- <div class="tasks">
- @for (t of d.tasks; track t.id) {
- <button class="task-chip" type="button" (click)="navigateToProject(t, $event)" [class.overdue]="t.isOverdue" [class.high]="t.priority==='high'" [class.due-soon]="isDueSoon(t.deadline)" title="进入项目:{{t.projectName}}">
- <span class="task-title">{{ t.title }}</span>
- <span class="assignee" title="按设计师筛选" (click)="filterByDesigner(t.assignee, $event)">{{ t.assignee }}</span>
- </button>
- }
- @if (d.tasks.length === 0) {
- <div class="no-task" aria-hidden="true">—</div>
- }
- </div>
- </div>
- }
- </div>
- </section>
- }
- @if (view==='day') {
- <section class="calendar-section" aria-label="日视图">
- <div class="day-panel">
- <div class="date-label large">{{ selectedDate | date:'yyyy-MM-dd EEEE' }}</div>
- <div class="tasks">
- @for (t of dayTasks; track t.id) {
- <div class="task-row" [class.overdue]="t.isOverdue" [class.due-soon]="isDueSoon(t.deadline)" title="{{t.title}} - {{t.projectName}} / {{t.assignee}}" (click)="navigateToProject(t, $event)">
- <div class="title">{{ t.title }}</div>
- <div class="project">{{ t.projectName }}</div>
- <div class="assignee"><button type="button" class="linklike" (click)="filterByDesigner(t.assignee, $event)" title="按设计师筛选">{{ t.assignee }}</button></div>
- <div class="priority" [class.high]="t.priority==='high'">{{ t.priority }}</div>
- </div>
- }
- @if (dayTasks.length === 0) {
- <div class="no-task">今日暂无任务</div>
- }
- </div>
- </div>
- </section>
- }
- <section class="status-board" aria-label="设计师工作状态">
- <h2>设计师工作状态</h2>
- <div class="status-list">
- @for (s of designerStatuses; track s.name) {
- <div class="status-item" [class]="s.cls">
- <div class="name">{{ s.name }}</div>
- <div class="meta">任务数:{{ s.tasksCount }};超期:{{ s.overdue }}</div>
- <div class="label">{{ s.label }}</div>
- </div>
- }
- </div>
- </section>
- </div>
|