work-orders.component.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import { Component, OnInit, inject, signal, computed } from '@angular/core';
  2. import { CommonModule } from '@angular/common';
  3. import { RouterModule } from '@angular/router';
  4. import { FormsModule } from '@angular/forms';
  5. import { FaIconComponent } from '@fortawesome/angular-fontawesome';
  6. import {
  7. faTicket, faFilter, faCircleCheck, faClock, faXmark,
  8. faPlus, faChevronDown, faChevronUp, faTriangleExclamation
  9. } from '@fortawesome/free-solid-svg-icons';
  10. import { PageHeaderComponent } from '../../../shared/components/page-header/page-header.component';
  11. import { StatCardComponent } from '../../../shared/components/stat-card/stat-card.component';
  12. import { DataTableComponent } from '../../../shared/components/data-table/data-table.component';
  13. import { FilterBarComponent, FilterOption } from '../../../shared/components/filter-bar/filter-bar.component';
  14. import { ConfirmDialogComponent } from '../../../shared/components/confirm-dialog/confirm-dialog.component';
  15. import { MessageStripComponent } from '../../../shared/components/message-strip/message-strip.component';
  16. import { EmptyStateComponent } from '../../../shared/components/empty-state/empty-state.component';
  17. import { MockDataService } from '../../../core/services/mock-data.service';
  18. import { WorkOrder } from '../../../core/models';
  19. @Component({
  20. selector: 'app-work-orders',
  21. standalone: true,
  22. imports: [
  23. CommonModule, RouterModule, FormsModule, FaIconComponent,
  24. PageHeaderComponent, StatCardComponent, DataTableComponent,
  25. FilterBarComponent, ConfirmDialogComponent, MessageStripComponent,
  26. EmptyStateComponent
  27. ],
  28. templateUrl: './work-orders.component.html'
  29. })
  30. export class WorkOrdersComponent implements OnInit {
  31. private mockData = inject(MockDataService);
  32. readonly faTicket = faTicket;
  33. readonly faCircleCheck = faCircleCheck;
  34. readonly faClock = faClock;
  35. readonly faXmark = faXmark;
  36. readonly faChevronDown = faChevronDown;
  37. readonly faChevronUp = faChevronUp;
  38. readonly faTriangleExclamation = faTriangleExclamation;
  39. workOrders = signal<WorkOrder[]>([]);
  40. loading = signal(true);
  41. expandedId = signal<string | null>(null);
  42. showConfirmDialog = signal(false);
  43. selectedOrder = signal<WorkOrder | null>(null);
  44. confirmAction = signal<'resolve' | 'close'>('resolve');
  45. confirmLoading = signal(false);
  46. successMessage = signal('');
  47. filters = signal<FilterOption[]>([
  48. { key: 'priority', label: '优先级', type: 'select', options: [
  49. { label: '全部', value: '' },
  50. { label: '高', value: 'high' },
  51. { label: '中', value: 'medium' },
  52. { label: '低', value: 'low' }
  53. ], value: '' },
  54. { key: 'status', label: '状态', type: 'select', options: [
  55. { label: '全部', value: '' },
  56. { label: '待处理', value: 'open' },
  57. { label: '处理中', value: 'in_progress' },
  58. { label: '已解决', value: 'resolved' },
  59. { label: '已关闭', value: 'closed' }
  60. ], value: '' }
  61. ]);
  62. activeFilterCount = computed(() => this.filters().filter(f => f.value !== '').length);
  63. filteredOrders = computed(() => {
  64. let orders = this.workOrders();
  65. const pf = this.filters()[0].value;
  66. const sf = this.filters()[1].value;
  67. if (pf) orders = orders.filter(o => o.priority === pf);
  68. if (sf) orders = orders.filter(o => o.status === sf);
  69. return orders;
  70. });
  71. openCount = computed(() => this.workOrders().filter(o => o.status === 'open').length);
  72. inProgressCount = computed(() => this.workOrders().filter(o => o.status === 'in_progress').length);
  73. resolvedCount = computed(() => this.workOrders().filter(o => o.status === 'resolved').length);
  74. tableColumns = [
  75. { key: 'title', label: '工单标题', sortable: true },
  76. { key: 'groupName', label: '群名称', sortable: true },
  77. { key: 'assignedToName', label: '负责人', sortable: true },
  78. { key: 'priority', label: '优先级', template: 'status' as const },
  79. { key: 'status', label: '状态', template: 'status' as const },
  80. { key: 'deadline', label: '截止日期', sortable: true },
  81. { key: 'createdAt', label: '创建时间', sortable: true }
  82. ];
  83. ngOnInit(): void {
  84. this.loadData();
  85. }
  86. loadData(): void {
  87. this.loading.set(true);
  88. this.workOrders.set([]);
  89. this.loading.set(false);
  90. }
  91. toggleExpand(id: string): void {
  92. this.expandedId.update(curr => curr === id ? null : id);
  93. }
  94. onFilterChange(filters: FilterOption[]): void {
  95. this.filters.set(filters);
  96. }
  97. onApply(): void {}
  98. onReset(): void {
  99. this.filters.update(fs => fs.map(f => ({ ...f, value: '' })));
  100. }
  101. onRowClick(order: WorkOrder): void {
  102. this.toggleExpand(order.id);
  103. }
  104. openResolveDialog(order: WorkOrder): void {
  105. this.selectedOrder.set(order);
  106. this.confirmAction.set('resolve');
  107. this.showConfirmDialog.set(true);
  108. }
  109. openCloseDialog(order: WorkOrder): void {
  110. this.selectedOrder.set(order);
  111. this.confirmAction.set('close');
  112. this.showConfirmDialog.set(true);
  113. }
  114. onConfirm(): void {
  115. const order = this.selectedOrder();
  116. if (!order) return;
  117. this.confirmLoading.set(true);
  118. setTimeout(() => {
  119. this.workOrders.update(orders => {
  120. const next = orders.map(o => {
  121. if (o.id === order.id) {
  122. const newStatus = this.confirmAction() === 'resolve' ? 'resolved' as const : 'closed' as const;
  123. return {
  124. ...o,
  125. status: newStatus,
  126. resolvedAt: new Date(),
  127. resolution: this.confirmAction() === 'resolve' ? '已处理完成' : '已关闭工单',
  128. resolutionLog: [...o.resolutionLog, `[${new Date().toLocaleString('zh-CN')}] ${this.confirmAction() === 'resolve' ? '已解决' : '已关闭'}`]
  129. };
  130. }
  131. return o;
  132. });
  133. this.mockData.saveWorkOrders(next);
  134. return next;
  135. });
  136. this.confirmLoading.set(false);
  137. this.showConfirmDialog.set(false);
  138. this.selectedOrder.set(null);
  139. this.successMessage.set(`工单「${order.title}」已${this.confirmAction() === 'resolve' ? '解决' : '关闭'}`);
  140. setTimeout(() => this.successMessage.set(''), 3000);
  141. }, 500);
  142. }
  143. onCancel(): void {
  144. this.showConfirmDialog.set(false);
  145. this.selectedOrder.set(null);
  146. }
  147. }