|
|
@ -1,4 +1,4 @@ |
|
|
import { Component, ElementRef, QueryList, ViewChildren } from '@angular/core' |
|
|
import { Component, ElementRef, inject, QueryList, ViewChild, ViewChildren } from '@angular/core' |
|
|
import { FormControl, FormGroup } from '@angular/forms' |
|
|
import { FormControl, FormGroup } from '@angular/forms' |
|
|
import { ApiService } from 'app/services' |
|
|
import { ApiService } from 'app/services' |
|
|
import { SharedModule } from 'app/shared/shared.module' |
|
|
import { SharedModule } from 'app/shared/shared.module' |
|
|
@ -13,12 +13,113 @@ import { |
|
|
startOfYear, |
|
|
startOfYear, |
|
|
endOfYear, |
|
|
endOfYear, |
|
|
format, |
|
|
format, |
|
|
|
|
|
addDays, |
|
|
|
|
|
addWeeks, |
|
|
|
|
|
addMonths, |
|
|
|
|
|
addYears, |
|
|
|
|
|
parseISO, |
|
|
} from 'date-fns' |
|
|
} from 'date-fns' |
|
|
import { finalize } from 'rxjs' |
|
|
import { finalize, lastValueFrom } from 'rxjs' |
|
|
|
|
|
|
|
|
import { init, EChartsType } from 'echarts' |
|
|
import { init, EChartsType } from 'echarts' |
|
|
|
|
|
import { Utils } from 'app/utils' |
|
|
|
|
|
import { NzMessageService } from 'ng-zorro-antd/message' |
|
|
|
|
|
import { NzModalService } from 'ng-zorro-antd/modal' |
|
|
|
|
|
import { LOCALSTORAGKEY } from 'app/constants' |
|
|
|
|
|
|
|
|
function getDateRange(n: number): { startDate: string; endDate: string } { |
|
|
type Task = { |
|
|
|
|
|
createTime: string |
|
|
|
|
|
deviceComplete: number |
|
|
|
|
|
deviceTotal: number |
|
|
|
|
|
formKey: string |
|
|
|
|
|
status: number |
|
|
|
|
|
taskName: string |
|
|
|
|
|
taskTypeName: string |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type AnalysisResult = { |
|
|
|
|
|
dataAfterFormat: { name: string; totalTask: number }[] |
|
|
|
|
|
analysis: { |
|
|
|
|
|
averageTaskPerDay: number |
|
|
|
|
|
maxTasksInADay: number |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function analyzeTasks(n: number, data: Task[]): AnalysisResult { |
|
|
|
|
|
const dateFormats = ['yyyy-MM-dd', 'yyyy-MM', 'yyyy'] |
|
|
|
|
|
const formatDate = (date: string, formatPattern: string) => format(parseISO(date), formatPattern) |
|
|
|
|
|
|
|
|
|
|
|
const groupTasksBy = (tasks: Task[], formatPattern: string) => { |
|
|
|
|
|
return tasks.reduce( |
|
|
|
|
|
(acc, task) => { |
|
|
|
|
|
const dateKey = formatDate(task.createTime, formatPattern) |
|
|
|
|
|
acc[dateKey] = (acc[dateKey] || 0) + 1 |
|
|
|
|
|
return acc |
|
|
|
|
|
}, |
|
|
|
|
|
{} as Record<string, number>, |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let formatPattern: string |
|
|
|
|
|
if (n === 3) { |
|
|
|
|
|
formatPattern = dateFormats[1] // "yyyy-MM" for monthly grouping
|
|
|
|
|
|
} else { |
|
|
|
|
|
formatPattern = dateFormats[0] // "yyyy-MM-dd" for daily grouping
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const dateGroup = groupTasksBy(data, formatPattern) |
|
|
|
|
|
|
|
|
|
|
|
const dataAfterFormat = Object.entries(dateGroup).map(([name, totalTask]) => ({ |
|
|
|
|
|
name, |
|
|
|
|
|
totalTask, |
|
|
|
|
|
})) |
|
|
|
|
|
|
|
|
|
|
|
const totalTasks = dataAfterFormat.reduce((sum, item) => sum + item.totalTask, 0) |
|
|
|
|
|
const maxTasksInADay = Math.max(...dataAfterFormat.map((item) => item.totalTask)) |
|
|
|
|
|
const daysCount = Object.keys(dateGroup).length |
|
|
|
|
|
|
|
|
|
|
|
const analysis = { |
|
|
|
|
|
averageTaskPerDay: daysCount ? totalTasks / daysCount : 0, |
|
|
|
|
|
maxTasksInADay, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
dataAfterFormat, |
|
|
|
|
|
analysis, |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
interface DateRange { |
|
|
|
|
|
startDate: string |
|
|
|
|
|
endDate: string |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function calculateDateRange(type: number, startTime: Date): DateRange { |
|
|
|
|
|
let endTime: Date |
|
|
|
|
|
|
|
|
|
|
|
switch (type) { |
|
|
|
|
|
case 0: |
|
|
|
|
|
endTime = addDays(startTime, 1) |
|
|
|
|
|
break |
|
|
|
|
|
case 1: |
|
|
|
|
|
endTime = addWeeks(startTime, 1) |
|
|
|
|
|
break |
|
|
|
|
|
case 2: |
|
|
|
|
|
endTime = addMonths(startTime, 1) |
|
|
|
|
|
break |
|
|
|
|
|
case 3: |
|
|
|
|
|
endTime = addYears(startTime, 1) |
|
|
|
|
|
break |
|
|
|
|
|
default: |
|
|
|
|
|
throw new Error('Invalid type. Expected 0, 1, 2, or 3.') |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
startDate: format(startTime, 'yyyy-MM-dd'), |
|
|
|
|
|
endDate: format(endTime, 'yyyy-MM-dd'), |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
function getDateRange1(n: number): { startDate: string; endDate: string } { |
|
|
const today = new Date() |
|
|
const today = new Date() |
|
|
|
|
|
|
|
|
let startDate: Date |
|
|
let startDate: Date |
|
|
@ -51,6 +152,17 @@ function getDateRange(n: number): { startDate: string; endDate: string } { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const gaisuTpl = `本周执行了{job},合计处置{taskTotal}条任务,涉及设备{deviceTotal}台/次,整体任务完成率{process}%!` |
|
|
|
|
|
|
|
|
|
|
|
const taskTpl = `{taskType}执行{taskTotal}条,已完成任务{completed}、未完成任务{uncomplete},整体任务完成率{process}%,平均任务处理数{avgNum},最高日处理任务数{highNum}。
|
|
|
|
|
|
涉及设备数{deviceTotal},完成处置设备{deviceComplete},待处置设备数{deviceUnComplete}。 |
|
|
|
|
|
` |
|
|
|
|
|
|
|
|
|
|
|
const planTpl = `1、按时保质完成{task}的任务内容
|
|
|
|
|
|
2、补充完成上周期待处理任务 |
|
|
|
|
|
3、响应临时或手动指派任务 |
|
|
|
|
|
` |
|
|
|
|
|
|
|
|
@Component({ |
|
|
@Component({ |
|
|
selector: 'app-flow-report', |
|
|
selector: 'app-flow-report', |
|
|
standalone: true, |
|
|
standalone: true, |
|
|
@ -61,18 +173,22 @@ function getDateRange(n: number): { startDate: string; endDate: string } { |
|
|
export class FlowReportComponent { |
|
|
export class FlowReportComponent { |
|
|
constructor(private api: ApiService) {} |
|
|
constructor(private api: ApiService) {} |
|
|
|
|
|
|
|
|
formKeys: NzSafeAny[] = [] |
|
|
formKeys: string[] = ['eam_device_repair', 'eam_device_inspection', 'eam_device_maintenance'] |
|
|
|
|
|
|
|
|
reportType: number = 0 |
|
|
reportType: number = 0 |
|
|
|
|
|
|
|
|
range: Date[] = [] |
|
|
range: Date[] = [] |
|
|
|
|
|
|
|
|
|
|
|
date = new Date() |
|
|
|
|
|
|
|
|
data: NzSafeAny |
|
|
data: NzSafeAny |
|
|
|
|
|
|
|
|
loading = false |
|
|
loading = false |
|
|
|
|
|
|
|
|
today = format(new Date(), 'yyyy年MM月dd日') |
|
|
today = format(new Date(), 'yyyy年MM月dd日') |
|
|
|
|
|
|
|
|
|
|
|
@ViewChild('reportTpl') reportTpl!: ElementRef<HTMLDivElement> |
|
|
|
|
|
|
|
|
reportTypeText = new Map([ |
|
|
reportTypeText = new Map([ |
|
|
[0, '今日'], |
|
|
[0, '今日'], |
|
|
[1, '本周'], |
|
|
[1, '本周'], |
|
|
@ -80,45 +196,148 @@ export class FlowReportComponent { |
|
|
[3, '本年'], |
|
|
[3, '本年'], |
|
|
]) |
|
|
]) |
|
|
|
|
|
|
|
|
gaishu = ` |
|
|
taskTypeNameMap = new Map([ |
|
|
1、本周 |
|
|
['weibao', '报修维修'], |
|
|
2、继续对所有锅炉和电梯设备进行定期巡检,确保设备安全稳定运行。 |
|
|
['xunjian', '设备巡检'], |
|
|
3、根据本周巡检结果,对设备维护计划进行必要的调整,以提高设备运行效率和安全性。` |
|
|
['baoyang', '设备保养'], |
|
|
|
|
|
]) |
|
|
|
|
|
|
|
|
plan = ` |
|
|
taskTypeData: Record<'weibao' | 'xunjian' | 'baoyang', NzSafeAny[]> = { |
|
|
1、安排专业人员对{锅炉001}进行返修,确保设备尽快恢复正常运行。 |
|
|
weibao: [], |
|
|
2、继续对所有锅炉和电梯设备进行定期巡检,确保设备安全稳定运行。 |
|
|
xunjian: [], |
|
|
3、根据本周巡检结果,对设备维护计划进行必要的调整,以提高设备运行效率和安全性。 |
|
|
baoyang: [], |
|
|
` |
|
|
} |
|
|
|
|
|
taskTypeLineData: Record<string, AnalysisResult> = { |
|
|
|
|
|
weibao: { dataAfterFormat: [], analysis: { averageTaskPerDay: 0, maxTasksInADay: 0 } }, |
|
|
|
|
|
xunjian: { dataAfterFormat: [], analysis: { averageTaskPerDay: 0, maxTasksInADay: 0 } }, |
|
|
|
|
|
baoyang: { dataAfterFormat: [], analysis: { averageTaskPerDay: 0, maxTasksInADay: 0 } }, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
zongjie = ` |
|
|
taskTypeText: Record<'weibao' | 'xunjian' | 'baoyang', string> = { |
|
|
本周的巡检和检修工作总体顺利,除了锅炉001需要返修外,其他设备均运行正常。 |
|
|
weibao: '', |
|
|
我们将继续密切关注设备状态,并及时处理任何潜在问题,以确保公司运营的顺畅和安全。 |
|
|
xunjian: '', |
|
|
请各部门继续配合我们的工作,如有任何问题或建议,请及时与我们联系。 |
|
|
baoyang: '', |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
` |
|
|
gaishu = '' |
|
|
|
|
|
|
|
|
|
|
|
plan = `` |
|
|
|
|
|
|
|
|
|
|
|
zongjie = `` |
|
|
|
|
|
|
|
|
|
|
|
title = '工作报表' |
|
|
|
|
|
|
|
|
|
|
|
footer = '' |
|
|
|
|
|
|
|
|
@ViewChildren('itemElement') itemElements!: QueryList<ElementRef> |
|
|
@ViewChildren('itemElement') itemElements!: QueryList<ElementRef> |
|
|
|
|
|
|
|
|
|
|
|
echartsImgMap = new Map<string, { pie: string; line: string }>() |
|
|
|
|
|
|
|
|
ngOnInit() { |
|
|
ngOnInit() { |
|
|
this.onTypeChange(this.reportType) |
|
|
this.onTypeChange(this.reportType) |
|
|
|
|
|
this.initReport() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
initReport() { |
|
|
|
|
|
let cache: any = {} |
|
|
|
|
|
try { |
|
|
|
|
|
cache = JSON.parse(localStorage.getItem(LOCALSTORAGKEY.report) || '{}') |
|
|
|
|
|
} catch (error) {} |
|
|
|
|
|
if (!cache._v) { |
|
|
|
|
|
return |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { gaishu, footer, zongjie, plan, title, taskTypeText, ...data } = cache |
|
|
|
|
|
|
|
|
|
|
|
this.data = data |
|
|
|
|
|
this.gaishu = gaishu |
|
|
|
|
|
this.plan = plan |
|
|
|
|
|
this.zongjie = zongjie |
|
|
|
|
|
this.title = title |
|
|
|
|
|
this.footer = footer |
|
|
|
|
|
this.taskTypeText = taskTypeText |
|
|
|
|
|
|
|
|
|
|
|
this.genReport(true) |
|
|
|
|
|
} |
|
|
ngAfterViewInit() {} |
|
|
ngAfterViewInit() {} |
|
|
|
|
|
|
|
|
onTypeChange(n: number) { |
|
|
onTypeChange(n: number) { |
|
|
const { startDate, endDate } = getDateRange(n) |
|
|
const { endDate } = calculateDateRange(n, this.date) |
|
|
this.range = [new Date(startDate), new Date(endDate)] |
|
|
this.range = [new Date(this.date), new Date(endDate)] |
|
|
this.onChange() |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
onStartDateChange() { |
|
|
|
|
|
const { endDate } = calculateDateRange(this.reportType, this.date) |
|
|
|
|
|
this.range = [new Date(this.date), new Date(endDate)] |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
print() { |
|
|
|
|
|
this.edited = false |
|
|
|
|
|
window.print() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
msg = inject(NzMessageService) |
|
|
|
|
|
taskTypeName = new Set<string>() |
|
|
|
|
|
heji: NzSafeAny = {} |
|
|
|
|
|
|
|
|
|
|
|
edited = false |
|
|
|
|
|
edit() { |
|
|
|
|
|
if (this.edited) { |
|
|
|
|
|
this.modal.confirm({ |
|
|
|
|
|
nzTitle: '请确认是否保存?', |
|
|
|
|
|
nzContent: '保存将覆盖原有内容', |
|
|
|
|
|
nzOnOk: async () => { |
|
|
|
|
|
localStorage.setItem( |
|
|
|
|
|
LOCALSTORAGKEY.report, |
|
|
|
|
|
JSON.stringify({ |
|
|
|
|
|
_v: Date.now(), |
|
|
|
|
|
...this.data, |
|
|
|
|
|
gaishu: this.gaishu, |
|
|
|
|
|
plan: this.plan, |
|
|
|
|
|
zongjie: this.zongjie, |
|
|
|
|
|
title: this.title, |
|
|
|
|
|
footer: this.footer, |
|
|
|
|
|
taskTypeText: this.taskTypeText, |
|
|
|
|
|
}), |
|
|
|
|
|
) |
|
|
|
|
|
this.edited = false |
|
|
|
|
|
// await this.getReportData()
|
|
|
|
|
|
// this.genReport()
|
|
|
|
|
|
}, |
|
|
|
|
|
}) |
|
|
|
|
|
} else { |
|
|
|
|
|
this.edited = true |
|
|
} |
|
|
} |
|
|
onChange() { |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getRangeDate() { |
|
|
let startDate = '' |
|
|
let startDate = '' |
|
|
let endDate = '' |
|
|
let endDate = '' |
|
|
this.loading = true |
|
|
|
|
|
if (this.range.length === 2) { |
|
|
if (this.range.length === 2) { |
|
|
startDate = format(this.range[0], 'yyyy-MM-dd') |
|
|
startDate = format(this.range[0], 'yyyy-MM-dd') |
|
|
endDate = format(this.range[1], 'yyyy-MM-dd') |
|
|
endDate = format(this.range[1], 'yyyy-MM-dd') |
|
|
} |
|
|
} |
|
|
|
|
|
return { startDate, endDate } |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
modal = inject(NzModalService) |
|
|
|
|
|
onCreate() { |
|
|
|
|
|
this.modal.confirm({ |
|
|
|
|
|
nzTitle: '请确认是否生成新报告?', |
|
|
|
|
|
nzContent: '当前操作会清空报告内容,并重新生成新报告。请对原有报告进行妥善处理', |
|
|
|
|
|
nzOkText: '确认生成', |
|
|
|
|
|
nzOnOk: async () => { |
|
|
|
|
|
await this.getReportData() |
|
|
|
|
|
this.genReport() |
|
|
|
|
|
}, |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async getReportData() { |
|
|
|
|
|
this.loading = true |
|
|
|
|
|
const { startDate, endDate } = this.getRangeDate() |
|
|
|
|
|
|
|
|
|
|
|
const res = await lastValueFrom( |
|
|
this.api |
|
|
this.api |
|
|
.getReportData({ |
|
|
.getReportData({ |
|
|
formKeys: this.formKeys, |
|
|
formKeys: this.formKeys, |
|
|
@ -130,88 +349,257 @@ export class FlowReportComponent { |
|
|
finalize(() => { |
|
|
finalize(() => { |
|
|
this.loading = false |
|
|
this.loading = false |
|
|
}), |
|
|
}), |
|
|
|
|
|
), |
|
|
) |
|
|
) |
|
|
.subscribe((res) => { |
|
|
|
|
|
this.data = res.body |
|
|
this.data = res.body |
|
|
|
|
|
} |
|
|
|
|
|
async genReport(cached = false) { |
|
|
|
|
|
const odata = this.data |
|
|
|
|
|
this.heji = { |
|
|
|
|
|
job: '', |
|
|
|
|
|
taskTotal: odata.taskList.length, |
|
|
|
|
|
deviceTotal: 0, |
|
|
|
|
|
process: 0, |
|
|
|
|
|
deviceComplete: 0, |
|
|
|
|
|
weibao: { |
|
|
|
|
|
total: 0, |
|
|
|
|
|
complete: 0, |
|
|
|
|
|
uncomplete: 0, |
|
|
|
|
|
deviceTotal: 0, |
|
|
|
|
|
deviceComplete: 0, |
|
|
|
|
|
deviceUnComplete: 0, |
|
|
|
|
|
}, |
|
|
|
|
|
xunjian: { |
|
|
|
|
|
total: 0, |
|
|
|
|
|
complete: 0, |
|
|
|
|
|
uncomplete: 0, |
|
|
|
|
|
deviceTotal: 0, |
|
|
|
|
|
deviceComplete: 0, |
|
|
|
|
|
deviceUnComplete: 0, |
|
|
|
|
|
}, |
|
|
|
|
|
baoyang: { |
|
|
|
|
|
total: 0, |
|
|
|
|
|
complete: 0, |
|
|
|
|
|
uncomplete: 0, |
|
|
|
|
|
deviceTotal: 0, |
|
|
|
|
|
deviceComplete: 0, |
|
|
|
|
|
deviceUnComplete: 0, |
|
|
|
|
|
}, |
|
|
|
|
|
} as any |
|
|
|
|
|
|
|
|
|
|
|
odata.taskList.forEach((i: any) => { |
|
|
|
|
|
this.heji.deviceTotal += i.deviceTotal |
|
|
|
|
|
this.heji.deviceComplete += i.deviceComplete |
|
|
|
|
|
this.taskTypeName.add(i.taskTypeName) |
|
|
|
|
|
const deviceUnComplete = i.deviceTotal - i.deviceComplete |
|
|
|
|
|
switch (i.taskTypeName) { |
|
|
|
|
|
case '设备保养': |
|
|
|
|
|
this.heji.baoyang.total += 1 |
|
|
|
|
|
this.heji.baoyang.complete += i.status === 3 ? 1 : 0 |
|
|
|
|
|
this.heji.baoyang.uncomplete += i.status !== 3 ? 1 : 0 |
|
|
|
|
|
this.heji.baoyang.deviceComplete += i.status === 3 ? i.deviceComplete : 0 |
|
|
|
|
|
this.heji.baoyang.deviceUnComplete += i.status === 3 ? deviceUnComplete : 0 |
|
|
|
|
|
this.heji.baoyang.deviceTotal += i.status === 3 ? i.deviceTotal : 0 |
|
|
|
|
|
this.taskTypeData.baoyang.push(i) |
|
|
|
|
|
break |
|
|
|
|
|
case '设备巡检': |
|
|
|
|
|
this.heji.xunjian.total += 1 |
|
|
|
|
|
this.heji.xunjian.complete += i.status === 3 ? 1 : 0 |
|
|
|
|
|
this.heji.xunjian.uncomplete += i.status !== 3 ? 1 : 0 |
|
|
|
|
|
this.heji.xunjian.deviceComplete += i.status === 3 ? i.deviceComplete : 0 |
|
|
|
|
|
this.heji.xunjian.deviceUnComplete += i.status === 3 ? deviceUnComplete : 0 |
|
|
|
|
|
this.heji.xunjian.deviceTotal += i.status === 3 ? i.deviceTotal : 0 |
|
|
|
|
|
this.taskTypeData.xunjian.push(i) |
|
|
|
|
|
break |
|
|
|
|
|
case '报修维修': |
|
|
|
|
|
this.heji.weibao.total += 1 |
|
|
|
|
|
this.heji.weibao.complete += i.status === 3 ? 1 : 0 |
|
|
|
|
|
this.heji.weibao.uncomplete += i.status !== 3 ? 1 : 0 |
|
|
|
|
|
this.heji.weibao.deviceComplete += i.status === 3 ? i.deviceComplete : 0 |
|
|
|
|
|
this.heji.weibao.deviceUnComplete += i.status === 3 ? deviceUnComplete : 0 |
|
|
|
|
|
this.heji.weibao.deviceTotal += i.status === 3 ? i.deviceTotal : 0 |
|
|
|
|
|
this.taskTypeData.weibao.push(i) |
|
|
|
|
|
break |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
this.taskTypeLineData = { |
|
|
|
|
|
weibao: analyzeTasks(this.reportType, this.taskTypeData.weibao), |
|
|
|
|
|
xunjian: analyzeTasks(this.reportType, this.taskTypeData.xunjian), |
|
|
|
|
|
baoyang: analyzeTasks(this.reportType, this.taskTypeData.baoyang), |
|
|
|
|
|
} |
|
|
|
|
|
this.heji.job = Array.from(this.taskTypeName).filter(Boolean).join('、') |
|
|
|
|
|
this.heji.process = Math.round((this.heji.deviceComplete / this.heji.deviceTotal || 0) * 100).toFixed(2) |
|
|
|
|
|
|
|
|
|
|
|
if (!cached) { |
|
|
|
|
|
this.title = '工作报表' |
|
|
|
|
|
this.zongjie = '' |
|
|
|
|
|
this.gaishu = gaisuTpl.replace(/\{(.*?)\}/g, (_, key) => this.heji[key] ?? '') |
|
|
|
|
|
const p: any = { task: this.heji.job } |
|
|
|
|
|
this.plan = planTpl.replace(/\{(.*?)\}/g, (_, key) => p[key] ?? '') |
|
|
|
|
|
this.footer = ` |
|
|
|
|
|
${odata.organizationName}-${odata.userName} |
|
|
|
|
|
${this.today} |
|
|
|
|
|
` |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Object.entries(this.taskTypeText).forEach(([k, v]) => { |
|
|
|
|
|
// {taskType}执行{taskTotal}条,已完成任务{completed}、未完成任务{uncomplete},整体任务完成率{process}%,平均处理时间{avgTime}!平均任务处理数{avgNum},最高日处理任务数{highNum}。
|
|
|
|
|
|
// 涉及设备数{deviceTotal},完成处置设备{deviceComplete},待处置设备数{deviceUnComplete}。
|
|
|
|
|
|
const analysis = (this.taskTypeLineData[k] as AnalysisResult).analysis |
|
|
|
|
|
const data: any = { |
|
|
|
|
|
taskType: this.taskTypeNameMap.get(k), |
|
|
|
|
|
taskTotal: this.heji[k].total, |
|
|
|
|
|
completed: this.heji[k].complete, |
|
|
|
|
|
uncomplete: this.heji[k].uncomplete, |
|
|
|
|
|
process: Math.round((this.heji[k].complete / this.heji[k].total || 0) * 100).toFixed(2), |
|
|
|
|
|
|
|
|
|
|
|
avgNum: analysis.averageTaskPerDay, |
|
|
|
|
|
highNum: analysis.maxTasksInADay, |
|
|
|
|
|
deviceTotal: this.heji[k].deviceTotal, |
|
|
|
|
|
deviceComplete: this.heji[k].deviceComplete, |
|
|
|
|
|
deviceUnComplete: this.heji[k].deviceTotal - this.heji[k].deviceComplete, |
|
|
|
|
|
} |
|
|
|
|
|
this.taskTypeText[k as 'weibao' | 'xunjian' | 'baoyang'] = taskTpl.replace( |
|
|
|
|
|
/\{(.*?)\}/g, |
|
|
|
|
|
(_, key) => data[key] ?? '', |
|
|
|
|
|
) |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
setTimeout(() => { |
|
|
console.log('this.data', this.itemElements) |
|
|
|
|
|
this.itemElements.forEach((itemElement, index) => { |
|
|
this.itemElements.forEach((itemElement, index) => { |
|
|
console.log(`Element ${index}: `, itemElement.nativeElement) |
|
|
const ele = itemElement.nativeElement as HTMLDivElement |
|
|
this.renderPie(itemElement.nativeElement, []) |
|
|
const type = ele.dataset['type'] as 'weibao' | 'xunjian' | 'baoyang' |
|
|
this.renderLine(itemElement.nativeElement, []) |
|
|
const img = { pie: '', line: '' } |
|
|
|
|
|
this.echartsImgMap.set(type, img) |
|
|
|
|
|
this.renderPie(itemElement.nativeElement, [this.heji[type]['total'], this.heji[type]['complete']], img) |
|
|
|
|
|
this.renderLine(itemElement.nativeElement, this.taskTypeLineData[type].dataAfterFormat, img) |
|
|
}) |
|
|
}) |
|
|
}, 0) |
|
|
}, 0) |
|
|
}) |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
renderLine(el: HTMLElement, data: NzSafeAny[]) { |
|
|
renderLine(el: HTMLElement, data: NzSafeAny[], img: NzSafeAny) { |
|
|
el = el.querySelector('.line') as HTMLDivElement |
|
|
el = el.querySelector('.line') as HTMLDivElement |
|
|
if (el) { |
|
|
if (el) { |
|
|
const lineRef = init(el) |
|
|
const lineRef = init(el) |
|
|
const name: string[] = [] |
|
|
const name: string[] = [] |
|
|
const value: number[] = [] |
|
|
const value: number[] = [] |
|
|
|
|
|
|
|
|
data?.forEach((i: NzSafeAny) => { |
|
|
data?.forEach((i: NzSafeAny) => { |
|
|
name.push(i.name) |
|
|
name.push(i.name) |
|
|
value.push(i.value) |
|
|
value.push(i.totalTask) |
|
|
}) |
|
|
}) |
|
|
|
|
|
|
|
|
lineRef.setOption({ |
|
|
lineRef.setOption({ |
|
|
xAxis: { |
|
|
xAxis: { |
|
|
type: 'category', |
|
|
type: 'category', |
|
|
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], |
|
|
data: name, |
|
|
}, |
|
|
}, |
|
|
yAxis: { |
|
|
yAxis: { |
|
|
type: 'value', |
|
|
type: 'value', |
|
|
}, |
|
|
}, |
|
|
series: [ |
|
|
series: [ |
|
|
{ |
|
|
{ |
|
|
data: [820, 932, 901, 934, 1290, 1330, 1320], |
|
|
data: value, |
|
|
type: 'line', |
|
|
type: 'line', |
|
|
smooth: true, |
|
|
smooth: true, |
|
|
}, |
|
|
}, |
|
|
], |
|
|
], |
|
|
}) |
|
|
}) |
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
img.line = lineRef.getDataURL() |
|
|
|
|
|
}, 1000) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
renderPie(el: HTMLElement, data: NzSafeAny[]) { |
|
|
renderPie(el: HTMLElement, data: NzSafeAny[], img: NzSafeAny) { |
|
|
el = el.querySelector('.pie') as HTMLDivElement |
|
|
el = el.querySelector('.pie') as HTMLDivElement |
|
|
if (el) { |
|
|
if (el) { |
|
|
const pieRef = init(el) |
|
|
const pieRef = init(el) |
|
|
let data: NzSafeAny[] = [] |
|
|
|
|
|
const odata: NzSafeAny[] = data ?? [] |
|
|
|
|
|
const total = odata.reduce((a: number, b: any) => a + Math.abs(b.value), 0) |
|
|
|
|
|
|
|
|
|
|
|
data = odata.map((i: NzSafeAny) => { |
|
|
|
|
|
const value = Math.abs(i.value) |
|
|
|
|
|
const percent = ((value / total) * 100).toFixed(2) |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
|
...i, |
|
|
|
|
|
percent, |
|
|
|
|
|
value, |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
pieRef.setOption({ |
|
|
pieRef.setOption({ |
|
|
title: { |
|
|
// title: [
|
|
|
text: '', |
|
|
// //标题组件,数组里的一个对象表示一个标题组件
|
|
|
}, |
|
|
// { text: '任务执行数据分析', top: 'left', textStyle: { color: '#000' } },
|
|
|
|
|
|
// ],
|
|
|
series: [ |
|
|
series: [ |
|
|
|
|
|
//系列
|
|
|
{ |
|
|
{ |
|
|
name: 'Access From', |
|
|
name: '任务执行效率', |
|
|
type: 'pie', |
|
|
type: 'pie', //pie类型的图实现环形图
|
|
|
radius: ['40%', '70%'], |
|
|
radius: ['60%', '90%'], //数组的话,表示内圆和外圆的半径大小,相对于宽高中较小的那一个。
|
|
|
avoidLabelOverlap: false, |
|
|
center: ['50%', '50%'], //圆心坐标
|
|
|
|
|
|
avoidLabelOverlap: false, //是否启用防止标签重叠策略
|
|
|
|
|
|
startAngle: 270, //第一个数据开始绘制的角度,以正交直角坐标系为标准
|
|
|
label: { |
|
|
label: { |
|
|
show: false, |
|
|
//每个数据的标签
|
|
|
position: 'center', |
|
|
show: true, //设置为true则显示第一个数据
|
|
|
|
|
|
position: 'center', //位置居中
|
|
|
|
|
|
formatter: '任务完成 \n{d}%', //{d}表示数据在总数据中的百分比
|
|
|
|
|
|
fontSize: 20, |
|
|
|
|
|
fontWeight: 'bold', |
|
|
|
|
|
}, |
|
|
|
|
|
color: ['#695BF9', '#1E3E55'], //系列的颜色
|
|
|
|
|
|
emphasis: { |
|
|
|
|
|
scale: false, //表示不放大item
|
|
|
|
|
|
}, |
|
|
|
|
|
labelLine: { |
|
|
|
|
|
show: true, |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
data: [ |
|
|
data: [ |
|
|
{ value: 1048, name: 'Search Engine' }, |
|
|
{ value: data[0] || 0, name: '' }, |
|
|
{ value: 735, name: 'Direct' }, |
|
|
{ |
|
|
|
|
|
value: data[1] || 0, |
|
|
|
|
|
name: '', |
|
|
|
|
|
emphasis: { |
|
|
|
|
|
label: { |
|
|
|
|
|
show: false, //这个数据高亮时不显示label,就不会显示替遮住第一个数据的label值了
|
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
|
|
|
}, |
|
|
], |
|
|
], |
|
|
}, |
|
|
}, |
|
|
], |
|
|
], |
|
|
}) |
|
|
}) |
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
img.pie = pieRef.getDataURL() |
|
|
|
|
|
}, 1000) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export() { |
|
|
|
|
|
const { startDate, endDate } = this.getRangeDate() |
|
|
|
|
|
const vals = { |
|
|
|
|
|
endDate, |
|
|
|
|
|
inspectDeviceComplete: this.heji.xunjian.deviceComplete, |
|
|
|
|
|
inspectDeviceUnComplete: this.heji.xunjian.deviceUnComplete, |
|
|
|
|
|
inspectTaskAnalysis: this.taskTypeText['xunjian'], |
|
|
|
|
|
inspectTaskBar: this.echartsImgMap.get('xunjian')?.line, |
|
|
|
|
|
inspectTaskPie: this.echartsImgMap.get('xunjian')?.pie, |
|
|
|
|
|
inspectTaskTotal: this.heji.xunjian.total, |
|
|
|
|
|
maintainDeviceComplete: this.heji.baoyang.deviceComplete, |
|
|
|
|
|
maintainDeviceUnComplete: this.heji.baoyang.deviceUnComplete, |
|
|
|
|
|
maintainTaskAnalysis: this.taskTypeText['baoyang'], |
|
|
|
|
|
maintainTaskBar: this.echartsImgMap.get('baoyang')?.line, |
|
|
|
|
|
maintainTaskPie: this.echartsImgMap.get('baoyang')?.pie, |
|
|
|
|
|
maintainTaskTotal: this.heji.baoyang.total, |
|
|
|
|
|
repairDeviceComplete: this.heji.weibao.deviceComplete, |
|
|
|
|
|
repairDeviceUnComplete: this.heji.weibao.deviceComplete, |
|
|
|
|
|
repairTaskAnalysis: this.taskTypeText['weibao'], |
|
|
|
|
|
repairTaskBar: this.echartsImgMap.get('weibao')?.line, |
|
|
|
|
|
repairTaskPie: this.echartsImgMap.get('weibao')?.pie, |
|
|
|
|
|
repairTaskTotal: this.heji.weibao.total, |
|
|
|
|
|
sign: this.footer, |
|
|
|
|
|
startDate, |
|
|
|
|
|
summarize: this.zongjie, |
|
|
|
|
|
workOverview: this.gaishu, |
|
|
|
|
|
workPlan: this.plan, |
|
|
|
|
|
} |
|
|
|
|
|
this.api.downloadWord(vals).subscribe((res) => { |
|
|
|
|
|
Utils.downLoadFile( |
|
|
|
|
|
res, |
|
|
|
|
|
'application/vnd.openxmlformats-officedocument.wordprocessingml.document;charset=utf-8', |
|
|
|
|
|
) |
|
|
|
|
|
this.msg.remove() |
|
|
|
|
|
this.msg.success('下载成功') |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|