seimin 1 kuukausi sitten
vanhempi
commit
2b0489334b
48 muutettua tiedostoa jossa 5169 lisäystä ja 64 poistoa
  1. 89 1
      src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.component.html
  2. 63 0
      src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.component.less
  3. 270 4
      src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.component.ts
  4. 2 0
      src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.module.ts
  5. 89 1
      src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.component.html
  6. 70 0
      src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.component.less
  7. 271 4
      src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.component.ts
  8. 2 2
      src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.module.ts
  9. 89 1
      src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.component.html
  10. 70 0
      src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.component.less
  11. 271 4
      src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.component.ts
  12. 2 0
      src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.module.ts
  13. 89 1
      src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.component.html
  14. 70 0
      src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.component.less
  15. 271 4
      src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.component.ts
  16. 2 0
      src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.module.ts
  17. 89 1
      src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.component.html
  18. 70 0
      src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.component.less
  19. 271 4
      src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.component.ts
  20. 2 0
      src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.module.ts
  21. 89 1
      src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.component.html
  22. 70 0
      src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.component.less
  23. 271 4
      src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.component.ts
  24. 2 0
      src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.module.ts
  25. 89 1
      src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.component.html
  26. 70 0
      src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.component.less
  27. 271 4
      src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.component.ts
  28. 2 0
      src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.module.ts
  29. 89 1
      src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.component.html
  30. 70 0
      src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.component.less
  31. 271 4
      src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.component.ts
  32. 2 0
      src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.module.ts
  33. 89 1
      src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.component.html
  34. 70 0
      src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.component.less
  35. 271 4
      src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.component.ts
  36. 2 0
      src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.module.ts
  37. 89 1
      src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.component.html
  38. 70 0
      src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.component.less
  39. 271 4
      src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.component.ts
  40. 2 2
      src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.module.ts
  41. 89 1
      src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.component.html
  42. 63 0
      src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.component.less
  43. 271 4
      src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.component.ts
  44. 2 0
      src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.module.ts
  45. 89 1
      src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.component.html
  46. 70 0
      src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.component.less
  47. 271 4
      src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.component.ts
  48. 2 0
      src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.module.ts

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.component.html

@@ -1 +1,89 @@
1
-楼栋统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 63 - 0
src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.component.less

@@ -5,4 +5,67 @@
5 5
   right: 0;
6 6
   bottom: 0;
7 7
   left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
8 71
 }

+ 270 - 4
src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.component.ts

@@ -1,11 +1,277 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-building-statistics",
4 10
   templateUrl: "./building-statistics.component.html",
5 11
   styleUrls: ["./building-statistics.component.less"],
6 12
 })
7
-export class BuildingStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class BuildingStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/building-statistics/building-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { BuildingStatisticsRoutingModule } from './building-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     BuildingStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class BuildingStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.component.html

@@ -1 +1,89 @@
1
-一级故障现象
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-category-one-statistics",
4 10
   templateUrl: "./category-one-statistics.component.html",
5 11
   styleUrls: ["./category-one-statistics.component.less"],
6 12
 })
7
-export class CategoryOneStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class CategoryOneStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 2
src/app/views/new-statistics/maintenance-statistics/category-one-statistics/category-one-statistics.module.ts

@@ -4,7 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { CategoryOneStatisticsRoutingModule } from './category-one-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
-import { VirtualScrollerModule } from 'ngx-virtual-scroller';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
8 8
 
9 9
 
10 10
 @NgModule({
@@ -15,7 +15,7 @@ import { VirtualScrollerModule } from 'ngx-virtual-scroller';
15 15
     CommonModule,
16 16
     CategoryOneStatisticsRoutingModule,
17 17
     ShareModule,
18
-    VirtualScrollerModule,
18
+    SearchMoreModule,
19 19
   ]
20 20
 })
21 21
 export class CategoryOneStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.component.html

@@ -1 +1,89 @@
1
-故障来源统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-category-source-statistics",
4 10
   templateUrl: "./category-source-statistics.component.html",
5 11
   styleUrls: ["./category-source-statistics.component.less"],
6 12
 })
7
-export class CategorySourceStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class CategorySourceStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/category-source-statistics/category-source-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { CategorySourceStatisticsRoutingModule } from './category-source-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     CategorySourceStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class CategorySourceStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.component.html

@@ -1 +1,89 @@
1
-三级故障现象
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-category-three-statistics",
4 10
   templateUrl: "./category-three-statistics.component.html",
5 11
   styleUrls: ["./category-three-statistics.component.less"],
6 12
 })
7
-export class CategoryThreeStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class CategoryThreeStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/category-three-statistics/category-three-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { CategoryThreeStatisticsRoutingModule } from './category-three-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     CategoryThreeStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class CategoryThreeStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.component.html

@@ -1 +1,89 @@
1
-二级故障现象
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-category-two-statistics",
4 10
   templateUrl: "./category-two-statistics.component.html",
5 11
   styleUrls: ["./category-two-statistics.component.less"],
6 12
 })
7
-export class CategoryTwoStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class CategoryTwoStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/category-two-statistics/category-two-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { CategoryTwoStatisticsRoutingModule } from './category-two-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     CategoryTwoStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class CategoryTwoStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.component.html

@@ -1 +1,89 @@
1
-科室评价统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-department-evaluate-statistics",
4 10
   templateUrl: "./department-evaluate-statistics.component.html",
5 11
   styleUrls: ["./department-evaluate-statistics.component.less"],
6 12
 })
7
-export class DepartmentEvaluateStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class DepartmentEvaluateStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/department-evaluate-statistics/department-evaluate-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { DepartmentEvaluateStatisticsRoutingModule } from './department-evaluate-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     DepartmentEvaluateStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class DepartmentEvaluateStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.component.html

@@ -1 +1,89 @@
1
-科室工单统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-department-incident-statistics",
4 10
   templateUrl: "./department-incident-statistics.component.html",
5 11
   styleUrls: ["./department-incident-statistics.component.less"],
6 12
 })
7
-export class DepartmentIncidentStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class DepartmentIncidentStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/department-incident-statistics/department-incident-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { DepartmentIncidentStatisticsRoutingModule } from './department-incident-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     DepartmentIncidentStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class DepartmentIncidentStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.component.html

@@ -1 +1,89 @@
1
-科室来源统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-department-source-statistics",
4 10
   templateUrl: "./department-source-statistics.component.html",
5 11
   styleUrls: ["./department-source-statistics.component.less"],
6 12
 })
7
-export class DepartmentSourceStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class DepartmentSourceStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/department-source-statistics/department-source-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { DepartmentSourceStatisticsRoutingModule } from './department-source-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     DepartmentSourceStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class DepartmentSourceStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.component.html

@@ -1 +1,89 @@
1
-楼层统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-floor-statistics",
4 10
   templateUrl: "./floor-statistics.component.html",
5 11
   styleUrls: ["./floor-statistics.component.less"],
6 12
 })
7
-export class FloorStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class FloorStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/floor-statistics/floor-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { FloorStatisticsRoutingModule } from './floor-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     FloorStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class FloorStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.component.html

@@ -1 +1,89 @@
1
-处理组统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-group-statistics",
4 10
   templateUrl: "./group-statistics.component.html",
5 11
   styleUrls: ["./group-statistics.component.less"],
6 12
 })
7
-export class GroupStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class GroupStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 2
src/app/views/new-statistics/maintenance-statistics/group-statistics/group-statistics.module.ts

@@ -4,7 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { GroupStatisticsRoutingModule } from './group-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
-import { VirtualScrollerModule } from 'ngx-virtual-scroller';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
8 8
 
9 9
 
10 10
 @NgModule({
@@ -15,7 +15,7 @@ import { VirtualScrollerModule } from 'ngx-virtual-scroller';
15 15
     CommonModule,
16 16
     GroupStatisticsRoutingModule,
17 17
     ShareModule,
18
-    VirtualScrollerModule,
18
+    SearchMoreModule,
19 19
   ]
20 20
 })
21 21
 export class GroupStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.component.html

@@ -1 +1,89 @@
1
-三方公司统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 63 - 0
src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.component.less

@@ -5,4 +5,67 @@
5 5
   right: 0;
6 6
   bottom: 0;
7 7
   left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
8 71
 }

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-tripartite-company-statistics",
4 10
   templateUrl: "./tripartite-company-statistics.component.html",
5 11
   styleUrls: ["./tripartite-company-statistics.component.less"],
6 12
 })
7
-export class TripartiteCompanyStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class TripartiteCompanyStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/tripartite-company-statistics/tripartite-company-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { TripartiteCompanyStatisticsRoutingModule } from './tripartite-company-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     TripartiteCompanyStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class TripartiteCompanyStatisticsModule { }

+ 89 - 1
src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.component.html

@@ -1 +1,89 @@
1
-处理人统计
1
+<div class="searchDataWrap">
2
+  <div class="searchData">
3
+    <div class="searchDataItem">
4
+      <span class="label">建单时间</span>:
5
+      <nz-range-picker [(ngModel)]="dateRange" [nzAllowClear]="false" (ngModelChange)="changeDate($event)" (nzOnCalendarChange)="onCalendarChangeDate($event)">
6
+      </nz-range-picker>
7
+    </div>
8
+    <div class="searchDataItem">
9
+      <span class="label">报修科室</span>:
10
+      <nz-select class="selectItem" [nzDropdownMatchSelectWidth]="false" nzServerSearch nzShowSearch (nzOnSearch)="changeRepairDeptInp($event)" nzAllowClear nzPlaceHolder="请选择报修科室" [(ngModel)]="repairDeptId" (nzOpenChange)="openChangeRepairDept($event)">
11
+      <ng-container *ngFor="let option of repairDeptList">
12
+        <nz-option *ngIf="!isLoading" [nzLabel]="option.dept" [nzValue]="option.id"></nz-option>
13
+      </ng-container>
14
+      <nz-option *ngIf="isLoading" nzDisabled nzCustomContent>
15
+        <i nz-icon nzType="loading" class="loading-icon"></i> 搜索中...
16
+      </nz-option>
17
+    </nz-select>
18
+    </div>
19
+  </div>
20
+  <div class="operation">
21
+    <i class="icon_transport transport-gengduo" (click)="showMore()"></i>
22
+    <button nz-button class="btn default" (click)="search()">查询</button>
23
+    <button nz-button class="btn default ml8" (click)="reset()">重置</button>
24
+    <button nz-button class="btn default ml8" (click)="excelExport()" [nzLoading]="excelExportLoading">导出</button>
25
+  </div>
26
+</div>
27
+<div class="moreFilter" *ngIf="fieldConfig.fields.groupDTO || fieldConfig.fields.userDTO || fieldConfig.fields.category1DTO || fieldConfig.fields.category2DTO || fieldConfig.fields.category3DTO || fieldConfig.fields.sourceDTO">
28
+  <span>{{fieldConfig.fields.groupDTO?.groupName}}</span>
29
+  <span>{{fieldConfig.fields.userDTO?.name}}</span>
30
+  <span>{{fieldConfig.fields.category1DTO?.category}}</span>
31
+  <span>{{fieldConfig.fields.category2DTO?.category}}</span>
32
+  <span>{{fieldConfig.fields.category3DTO?.category}}</span>
33
+  <span>{{fieldConfig.fields.sourceDTO?.name}}</span>
34
+</div>
35
+<nz-table class="table" [nzData]="listOfData" nzSize="middle" [nzShowPagination]="false" [nzLoading]="loading1" [nzScroll]="{ y: tableHeight + 'px' }" [nzFooter]="footerTpl">
36
+  <thead (nzSortChange)="sort($event)" nzSingleSort>
37
+    <tr>
38
+      <th nzWidth="10%" nzShowSort nzSortKey="startDate" [(nzSort)]="sortCurrent.startDate">时间</th>
39
+      <th nzWidth="9%" nzShowSort nzSortKey="sum" [(nzSort)]="sortCurrent.sum">工单总数</th>
40
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResponseTime" [(nzSort)]="sortCurrent.avgResponseTime">平均响应时间</th>
41
+      <th nzWidth="9%" nzShowSort nzSortKey="avgResolvedTime" [(nzSort)]="sortCurrent.avgResolvedTime">平均解决时间</th>
42
+      <th nzWidth="9%" nzShowSort nzSortKey="resolvedOverNum" [(nzSort)]="sortCurrent.resolvedOverNum">超时单数</th>
43
+      <th nzWidth="9%" nzShowSort nzSortKey="overTimeNum" [(nzSort)]="sortCurrent.overTimeNum">挂起单数</th>
44
+      <th nzWidth="9%" nzShowSort nzSortKey="consumablePrice" [(nzSort)]="sortCurrent.consumablePrice">耗材费用(元)</th>
45
+      <th nzWidth="9%" nzShowSort nzSortKey="workHourPrice" [(nzSort)]="sortCurrent.workHourPrice">工时费用(元)</th>
46
+      <th nzWidth="9%" nzShowSort nzSortKey="totalPrice" [(nzSort)]="sortCurrent.totalPrice">总费用(元)</th>
47
+      <th nzWidth="9%" nzShowSort nzSortKey="negativeNum" [(nzSort)]="sortCurrent.negativeNum">差评单数</th>
48
+      <th nzWidth="9%" nzShowSort nzSortKey="favorableRate" [(nzSort)]="sortCurrent.favorableRate">好评率</th>
49
+    </tr>
50
+  </thead>
51
+  <tbody>
52
+    <tr *ngFor="let data of listOfData">
53
+      <td>{{ data.startDate }}</td>
54
+      <td>{{ data.sum }}</td>
55
+      <td>{{ data.avgResponseTime }}</td>
56
+      <td>{{ data.avgResolvedTime }}</td>
57
+      <td>{{ data.resolvedOverNum }}</td>
58
+      <td>{{ data.overTimeNum }}</td>
59
+      <td>{{ data.consumablePrice }}</td>
60
+      <td>{{ data.workHourPrice }}</td>
61
+      <td>{{ data.totalPrice }}</td>
62
+      <td>{{ data.negativeNum }}</td>
63
+      <td>{{ data.favorableRate }}</td>
64
+    </tr>
65
+  </tbody>
66
+  <ng-template #footerTpl>
67
+    <table class="footTable">
68
+      <tr *ngFor="let data of listOfDataEnd">
69
+        <td style="width: 10%">{{ data.startDate }}</td>
70
+        <td style="width: 9%">{{ data.sum }}</td>
71
+        <td style="width: 9%">{{ data.avgResponseTime }}</td>
72
+        <td style="width: 9%">{{ data.avgResolvedTime }}</td>
73
+        <td style="width: 9%">{{ data.resolvedOverNum }}</td>
74
+        <td style="width: 9%">{{ data.overTimeNum }}</td>
75
+        <td style="width: 9%">{{ data.consumablePrice }}</td>
76
+        <td style="width: 9%">{{ data.workHourPrice }}</td>
77
+        <td style="width: 9%">{{ data.totalPrice }}</td>
78
+        <td style="width: 9%">{{ data.negativeNum }}</td>
79
+        <td style="width: 9%">{{ data.favorableRate }}</td>
80
+      </tr>
81
+    </table>
82
+  </ng-template>
83
+</nz-table>
84
+<div class="pagination">
85
+  <nz-pagination [(nzPageIndex)]="pageIndex" [(nzTotal)]="listLength" [(nzPageSize)]="pageSize" (nzPageIndexChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)" (nzPageSizeChange)="getList(pageIndex, sortCurrentKey, sortCurrentValue)"></nz-pagination>
86
+</div>
87
+
88
+<!-- 详细搜索 -->
89
+<app-search-more [fieldConfig]="fieldConfig" *ngIf="showSearchMore" [hosId]="hosId" [queryType]="queryType"  [dutyId]="dutyId"  [parentDutyId]="parentDutyId" (cancelEvent)="cancelEvent()" (submitEvent)="submitEvent($event)"></app-search-more>

+ 70 - 0
src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.component.less

@@ -1 +1,71 @@
1 1
 @import "../../../../../../src/theme.less";
2
+:host{
3
+  position: absolute;
4
+  top: 0;
5
+  right: 0;
6
+  bottom: 0;
7
+  left: 0;
8
+  ::ng-deep .ant-table-footer{
9
+    padding: 16px 0;
10
+    width: calc(100% - 16px);
11
+    font-weight: bold;
12
+  }
13
+  tr, th{
14
+    text-align: center;
15
+  }
16
+  .searchDataWrap{
17
+    display: flex;
18
+    align-items: center;
19
+    justify-content: space-between;
20
+    .searchData{
21
+      padding: 16px;
22
+      display: flex;
23
+      align-items: center;
24
+      .searchDataItem{
25
+        margin-right: 24px;
26
+        .label{
27
+          font-size: 16px;
28
+        }
29
+        .selectItem{
30
+          width: 224px;
31
+        }
32
+      }
33
+    }
34
+    .operation{
35
+      margin-right: 16px;
36
+      display: flex;
37
+      align-items: center;
38
+      cursor: pointer;
39
+      .icon_transport{
40
+        margin-right: 16px;
41
+        font-size: 24px;
42
+      }
43
+      .btn{
44
+        &.default{
45
+          height: 32px;
46
+          line-height: 32px;
47
+          min-width: 70px;
48
+        }
49
+      }
50
+    }
51
+  }
52
+
53
+  .table{
54
+    margin: 0 8px;
55
+  }
56
+
57
+  .moreFilter{
58
+    margin-bottom: 16px;
59
+    span{
60
+      margin-left: 16px;
61
+      color: @primary-color;
62
+    }
63
+  }
64
+
65
+  .pagination{
66
+    padding: 16px;
67
+    display: flex;
68
+    justify-content: flex-end;
69
+    align-items: center;
70
+  }
71
+}

+ 271 - 4
src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.component.ts

@@ -1,11 +1,278 @@
1
-import { Component, OnInit } from "@angular/core";
1
+import { debounceTime } from 'rxjs/operators';
2
+import { Subject } from 'rxjs';
3
+import { NzMessageService } from 'ng-zorro-antd/message';
4
+import { format, addMonths, startOfMonth, endOfMonth, startOfDay, endOfDay } from 'date-fns';
5
+import { Component, OnInit, HostListener, AfterViewInit } from "@angular/core";
6
+import { MainService } from 'src/app/services/main.service';
7
+import { ActivatedRoute } from '@angular/router';
2 8
 @Component({
3 9
   selector: "app-user-statistics",
4 10
   templateUrl: "./user-statistics.component.html",
5 11
   styleUrls: ["./user-statistics.component.less"],
6 12
 })
7
-export class UserStatisticsComponent implements OnInit {
8
-  constructor() {}
13
+export class UserStatisticsComponent implements OnInit, AfterViewInit {
14
+  constructor(
15
+    private mainService: MainService,
16
+    private message: NzMessageService,
17
+    private route: ActivatedRoute,
18
+  ) {}
9 19
 
10
-  ngOnInit() {}
20
+  listOfData: any[] = []; //表格数据
21
+  listOfDataEnd: any[] = []; //表格合计
22
+  pageIndex: number = 1; //表格当前页码
23
+  pageSize: number = 30; //表格每页展示条数
24
+  listLength: number = 0; //表格总数据量
25
+
26
+  repairDeptId;//报修科室id
27
+
28
+  searchTimerSubject = new Subject();
29
+
30
+  ngOnInit() {
31
+    this.searchTimerSubject.pipe(debounceTime(500)).subscribe((v) => {
32
+      let fun = v[0];
33
+      fun.call(this, v[1]);
34
+    });
35
+    this.initSessionData();
36
+    this.search();
37
+  }
38
+
39
+  ngAfterViewInit(){
40
+    this.onResize();
41
+  }
42
+
43
+  tableHeight:number = 0;
44
+  @HostListener('window:resize')
45
+  onResize(): void {
46
+    setTimeout(() => {
47
+      this.tableHeight = window.innerHeight - 64 - 64 - 36 - 48 - 8 - 45 - 54 - this.getMoreFilter;
48
+      console.log('this.tableHeight:', this.tableHeight)
49
+    }, 0)
50
+  }
51
+
52
+  get getMoreFilter(){
53
+    let flag = this.fieldConfig.fields.groupDTO || this.fieldConfig.fields.userDTO || this.fieldConfig.fields.category1DTO || this.fieldConfig.fields.category2DTO || this.fieldConfig.fields.category3DTO || this.fieldConfig.fields.sourceDTO;
54
+    return flag ? 21 : 0;
55
+  }
56
+
57
+  // 初始化缓存数据
58
+  queryType:any;
59
+  hosId:any;
60
+  dutyId:any;
61
+  parentDutyId:any;
62
+  initSessionData(){
63
+    let maintenanceStatistics = JSON.parse(sessionStorage.getItem('maintenanceStatistics'));
64
+    let queryType:any = maintenanceStatistics.queryType;
65
+    let hosId:any = maintenanceStatistics.hospitalId;
66
+    let dutyId:any = maintenanceStatistics.dutyId;
67
+
68
+    queryType = queryType ? +queryType : undefined;
69
+    hosId = hosId ? +hosId : undefined;
70
+    dutyId = dutyId ? +dutyId : undefined;
71
+
72
+    this.queryType = queryType;
73
+    if(queryType == 1){
74
+      this.hosId = undefined;
75
+      this.dutyId = undefined;
76
+      this.parentDutyId = undefined;
77
+    }else if(queryType == 2){
78
+      this.hosId = hosId;
79
+      this.dutyId = undefined;
80
+      this.parentDutyId = undefined;
81
+    }else if(queryType == 3){
82
+      this.hosId = undefined;
83
+      this.dutyId = dutyId;
84
+      this.parentDutyId = undefined;
85
+    }else if(queryType == 4){
86
+      this.hosId = undefined;
87
+      this.dutyId = undefined;
88
+      this.parentDutyId = dutyId;
89
+    }
90
+  }
91
+
92
+  get getHosId(){
93
+    return this.parentDutyId || this.dutyId || this.hosId;
94
+  }
95
+
96
+  // 表格数据
97
+  loading1 = false;
98
+  getList(num?: number, field?: string, sort?: string) {
99
+    if (num !== undefined) {
100
+      this.pageIndex = num;
101
+    }
102
+    let postData:any = {
103
+      idx: this.pageIndex - 1,
104
+      sum: this.pageSize,
105
+      startDate: this.dateRange[0],
106
+      endDate: this.dateRange[1],
107
+      hosId: this.hosId,
108
+      dutyId: this.dutyId,
109
+      parentDutyId: this.parentDutyId,
110
+      repairDeptId: this.repairDeptId,
111
+      groupId: this.fieldConfig.fields.groupId,
112
+      userId: this.fieldConfig.fields.userId,
113
+      categoryId: this.fieldConfig.fields.categoryId,
114
+      sourceId: this.fieldConfig.fields.sourceId,
115
+      hierarchy: this.fieldConfig.fields.hierarchy,
116
+    };
117
+    if (field && sort) {
118
+      postData.sort = `${field} ${sort === "ascend" ? `asc` : `desc`}`
119
+    }
120
+    this.loading1 = true;
121
+    this.mainService
122
+      .postCustom("itsm/report", "incidentWorkOrder", postData)
123
+      .subscribe((result) => {
124
+        this.loading1 = false;
125
+        this.listOfData = result.dataList.filter((v, i) => { return i != result.dataList.length - 1 });
126
+        this.listOfDataEnd = result.dataList.filter((v, i) => { return i == result.dataList.length - 1 });
127
+        this.listLength = result.totalCount;
128
+      });
129
+  }
130
+
131
+  // 列表排序
132
+  sortCurrent = {};
133
+  sortCurrentKey: string = "";
134
+  sortCurrentValue: string | null = "";
135
+  sort(e) {
136
+    const { key, value } = e;
137
+    this.sortCurrentKey = key;
138
+    this.sortCurrentValue = value;
139
+    this.getList(this.pageIndex, this.sortCurrentKey, this.sortCurrentValue);
140
+  }
141
+
142
+  // 搜索
143
+  search() {
144
+    this.getList(1, this.sortCurrentKey, this.sortCurrentValue);
145
+  }
146
+
147
+  // 日期选择
148
+  dateRange: any = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')];
149
+  changeDate(result?): void {
150
+    result[0] = format(startOfDay(result[0]), 'yyyy-MM-dd HH:mm:ss');
151
+    result[1] = format(endOfDay(result[1]), 'yyyy-MM-dd HH:mm:ss');
152
+    this.dateRange = result;
153
+  }
154
+
155
+  onCalendarChangeDate(dateArr){
156
+    console.log(dateArr)
157
+    if(dateArr.length == 2){
158
+      this.dateRange = [format(startOfDay(dateArr[0]), 'yyyy-MM-dd HH:mm:ss'), format(endOfDay(dateArr[1]), 'yyyy-MM-dd HH:mm:ss')];
159
+    }
160
+  }
161
+
162
+  // 导出
163
+  excelExportLoading:any = false;
164
+  excelExport(){
165
+    this.excelExportLoading = this.message.loading("导出中..", {
166
+      nzDuration: 0,
167
+    }).messageId;
168
+    let postData:any = {
169
+      startDate: this.dateRange[0],
170
+      endDate: this.dateRange[1],
171
+      hosId: this.hosId,
172
+      dutyId: this.dutyId,
173
+      parentDutyId: this.parentDutyId,
174
+      repairDeptId: this.repairDeptId,
175
+      groupId: this.fieldConfig.fields.groupId,
176
+      userId: this.fieldConfig.fields.userId,
177
+      categoryId: this.fieldConfig.fields.categoryId,
178
+      sourceId: this.fieldConfig.fields.sourceId,
179
+      hierarchy: this.fieldConfig.fields.hierarchy,
180
+    };
181
+    if (this.sortCurrentKey && this.sortCurrentValue) {
182
+      postData.sort = `${this.sortCurrentKey} ${this.sortCurrentValue === "ascend" ? `asc` : `desc`}`
183
+    }
184
+    this.mainService
185
+      .postExportCustom("itsm/export", "incidentWorkOrder", postData)
186
+      .subscribe((data) => {
187
+        this.message.remove(this.excelExportLoading);
188
+        this.excelExportLoading = false;
189
+        this.message.success('导出成功');
190
+        var file = new Blob([data], {
191
+          type: "application/vnd.ms-excel",
192
+        });
193
+        //trick to download store a file having its URL
194
+        var fileURL = URL.createObjectURL(file);
195
+        var a = document.createElement("a");
196
+        a.href = fileURL;
197
+        a.target = "_blank";
198
+        a.download = `${this.route.parent.routeConfig.data.title}.xls`;
199
+        document.body.appendChild(a);
200
+        a.click();
201
+      },(err) => {
202
+        this.message.remove(this.excelExportLoading);
203
+        this.excelExportLoading = false;
204
+        this.message.error('导出失败');
205
+      });
206
+  }
207
+  // 重置
208
+  reset(){
209
+    this.sortCurrentKey = "";
210
+		this.sortCurrentValue = "";
211
+		this.sortCurrent = {};
212
+    this.dateRange = [format(startOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss'), format(endOfMonth(addMonths(new Date(), -1)), 'yyyy-MM-dd HH:mm:ss')]
213
+    this.repairDeptId = undefined;
214
+    this.fieldConfig.fields = {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined};
215
+    this.search();
216
+  }
217
+
218
+  // 科室搜索
219
+  changeRepairDeptInp(e) {
220
+    this.searchTimer(this.getRepairDeptList, e);
221
+  }
222
+
223
+  // 防抖
224
+  isLoading = false;
225
+  searchTimer(fun, e) {
226
+    this.isLoading = true;
227
+    this.searchTimerSubject.next([fun, e]);
228
+  }
229
+
230
+  openChangeRepairDept(flag){
231
+    flag && this.getRepairDeptList();
232
+  }
233
+
234
+  // 获取报修科室列表
235
+  repairDeptList:any[] = [];
236
+  getRepairDeptList(keyword?) {
237
+    let data = {
238
+      department: {
239
+        cascadeHosId: this.getHosId,
240
+        dept: keyword,
241
+        searchType: 1,
242
+      },
243
+      idx: 0,
244
+      sum: 20,
245
+    };
246
+    this.isLoading = true;
247
+    this.mainService
248
+      .getFetchDataList("data", "department", data)
249
+      .subscribe((data) => {
250
+        this.isLoading = false;
251
+        this.repairDeptList = data.list;
252
+      });
253
+  }
254
+
255
+  // 详细搜索
256
+  fieldConfig:any = {
257
+    fields: {groupId: undefined, userId: undefined, categoryId: undefined, sourceId: undefined, hierarchy: undefined},
258
+    config: {groupAndUser: true, category123: true, source: true},
259
+  }
260
+  showSearchMore:boolean = false;
261
+  showMore(){
262
+    this.showSearchMore = true;
263
+  }
264
+
265
+  cancelEvent(){
266
+    this.showSearchMore = false;
267
+  }
268
+
269
+  submitEvent(fields){
270
+    this.showSearchMore = false;
271
+    this.fieldConfig.fields = fields;
272
+    console.log('this.fieldConfig.fields:', this.fieldConfig.fields)
273
+    this.search();
274
+    this.onResize();
275
+  }
11 276
 }
277
+
278
+

+ 2 - 0
src/app/views/new-statistics/maintenance-statistics/user-statistics/user-statistics.module.ts

@@ -4,6 +4,7 @@ import { CommonModule } from '@angular/common';
4 4
 
5 5
 import { UserStatisticsRoutingModule } from './user-statistics-routing.module';
6 6
 import { ShareModule } from 'src/app/share/share.module';
7
+import { SearchMoreModule } from '../../components/search-more/search-more.module';
7 8
 
8 9
 
9 10
 @NgModule({
@@ -14,6 +15,7 @@ import { ShareModule } from 'src/app/share/share.module';
14 15
     CommonModule,
15 16
     UserStatisticsRoutingModule,
16 17
     ShareModule,
18
+    SearchMoreModule,
17 19
   ]
18 20
 })
19 21
 export class UserStatisticsModule { }